91 lines
1.9 KiB
Go
91 lines
1.9 KiB
Go
package main
|
|
|
|
import "math"
|
|
import "image"
|
|
|
|
type World interface {
|
|
At (image.Point) int
|
|
}
|
|
|
|
type DefaultWorld struct {
|
|
Data []int
|
|
Stride int
|
|
}
|
|
|
|
func (world DefaultWorld) At (position image.Point) int {
|
|
if position.X < 0 { return 0 }
|
|
if position.Y < 0 { return 0 }
|
|
if position.X >= world.Stride { return 0 }
|
|
index := position.X + position.Y * world.Stride
|
|
if index >= len(world.Data) { return 0 }
|
|
return world.Data[index]
|
|
}
|
|
|
|
type Camera struct {
|
|
X, Y float64
|
|
Angle float64
|
|
Fov float64
|
|
}
|
|
|
|
func (camera *Camera) Point () (image.Point) {
|
|
return image.Pt(int(camera.X), int(camera.Y))
|
|
}
|
|
|
|
func (camera *Camera) Rotate (by float64) {
|
|
camera.Angle += by
|
|
if camera.Angle < 0 { camera.Angle += math.Pi * 2 }
|
|
if camera.Angle > math.Pi * 2 { camera.Angle = 0 }
|
|
}
|
|
|
|
func (camera *Camera) Walk (by float64) {
|
|
dx, dy := camera.Delta()
|
|
camera.X += dx * by
|
|
camera.Y += dy * by
|
|
}
|
|
|
|
func (camera *Camera) Strafe (by float64) {
|
|
dx, dy := camera.OffsetDelta()
|
|
camera.X += dx * by
|
|
camera.Y += dy * by
|
|
}
|
|
|
|
func (camera *Camera) Delta () (x float64, y float64) {
|
|
return math.Cos(camera.Angle), math.Sin(camera.Angle)
|
|
}
|
|
|
|
func (camera *Camera) OffsetDelta () (x float64, y float64) {
|
|
offset := math.Pi / 2
|
|
return math.Cos(camera.Angle + offset), math.Sin(camera.Angle + offset)
|
|
}
|
|
|
|
type Ray struct {
|
|
X, Y float64
|
|
Angle float64
|
|
Precision int
|
|
}
|
|
|
|
func (ray *Ray) Cast (world World, max int) (distance float64) {
|
|
precision := 64
|
|
|
|
dX := math.Cos(ray.Angle) / float64(precision)
|
|
dY := math.Sin(ray.Angle) / float64(precision)
|
|
origX, origY := ray.X, ray.Y
|
|
|
|
wall := 0
|
|
depth := 0
|
|
for wall == 0 && depth < max * precision {
|
|
ray.X += dX
|
|
ray.Y += dY
|
|
wall = world.At(ray.Point())
|
|
depth ++
|
|
}
|
|
|
|
distanceX := origX - ray.X
|
|
distanceY := origY - ray.Y
|
|
return math.Sqrt(distanceX * distanceX + distanceY * distanceY)
|
|
}
|
|
|
|
func (ray *Ray) Point () (image.Point) {
|
|
return image.Pt(int(ray.X), int(ray.Y))
|
|
}
|