The raycaster is faster but more bg=uggyh agghgfghgfhgfgh

This commit is contained in:
Sasha Koshka 2023-02-21 13:30:32 -05:00
parent e9e1ccc35e
commit e966771f5b
2 changed files with 185 additions and 43 deletions

View File

@ -21,14 +21,43 @@ func (world DefaultWorld) At (position image.Point) int {
return world.Data[index] return world.Data[index]
} }
type Camera struct { type Vector struct {
X, Y float64 X, Y float64
Angle float64
Fov float64
} }
func (camera *Camera) Point () (image.Point) { func (vector Vector) Point () (image.Point) {
return image.Pt(int(camera.X), int(camera.Y)) return image.Pt(int(vector.X), int(vector.Y))
}
func (vector Vector) Add (other Vector) Vector {
return Vector {
vector.X + other.X,
vector.Y + other.Y,
}
}
func (vector Vector) Sub (other Vector) Vector {
return Vector {
vector.X - other.X,
vector.Y - other.Y,
}
}
func (vector Vector) Mul (by float64) Vector {
return Vector {
vector.X * by,
vector.Y * by,
}
}
func (vector Vector) Hypot () float64 {
return math.Hypot(vector.X, vector.Y)
}
type Camera struct {
Vector
Angle float64
Fov float64
} }
func (camera *Camera) Rotate (by float64) { func (camera *Camera) Rotate (by float64) {
@ -38,53 +67,115 @@ func (camera *Camera) Rotate (by float64) {
} }
func (camera *Camera) Walk (by float64) { func (camera *Camera) Walk (by float64) {
dx, dy := camera.Delta() delta := camera.Delta()
camera.X += dx * by camera.X += delta.X * by
camera.Y += dy * by camera.Y += delta.Y * by
} }
func (camera *Camera) Strafe (by float64) { func (camera *Camera) Strafe (by float64) {
dx, dy := camera.OffsetDelta() delta := camera.OffsetDelta()
camera.X += dx * by camera.X += delta.X * by
camera.Y += dy * by camera.Y += delta.Y * by
} }
func (camera *Camera) Delta () (x float64, y float64) { func (camera *Camera) Delta () Vector {
return math.Cos(camera.Angle), math.Sin(camera.Angle) return Vector {
math.Cos(camera.Angle),
math.Sin(camera.Angle),
}
} }
func (camera *Camera) OffsetDelta () (x float64, y float64) { func (camera *Camera) OffsetDelta () Vector {
offset := math.Pi / 2 offset := math.Pi / 2
return math.Cos(camera.Angle + offset), math.Sin(camera.Angle + offset) return Vector {
math.Cos(camera.Angle + offset),
math.Sin(camera.Angle + offset),
}
} }
type Ray struct { type Ray struct {
X, Y float64 Vector
Angle float64 Angle float64
Precision int
} }
func (ray *Ray) Cast (world World, max int) (distance float64) { func (ray *Ray) Cast (world World, max int) (distance float64, hit Vector) {
precision := 64 // return ray.castV(world, max)
if world.At(ray.Point()) > 0 {
dX := math.Cos(ray.Angle) / float64(precision) return 0, Vector { }
dY := math.Sin(ray.Angle) / float64(precision) }
origX, origY := ray.X, ray.Y hDistance, hPos := ray.castH(world, max)
vDistance, vPos := ray.castV(world, max)
wall := 0 if hDistance < vDistance {
depth := 0 return hDistance, hPos
for wall == 0 && depth < max * precision { } else {
ray.X += dX return vDistance, vPos
ray.Y += dY }
wall = world.At(ray.Point())
depth ++
} }
distanceX := origX - ray.X func (ray *Ray) castH (world World, max int) (distance float64, hit Vector) {
distanceY := origY - ray.Y var position Vector
return math.Sqrt(distanceX * distanceX + distanceY * distanceY) var delta Vector
ray.Angle = math.Mod(ray.Angle, math.Pi * 2)
if ray.Angle < 0 {
ray.Angle += math.Pi * 2
}
tan := math.Tan(math.Pi - ray.Angle)
if ray.Angle > math.Pi {
// facing up
position.Y = math.Floor(ray.Y) - (1.0 / 64)
delta.Y = -1
} else if ray.Angle < math.Pi {
// facing down
position.Y = math.Floor(ray.Y) + 1
delta.Y = 1
} else {
// facing straight left or right
return float64(max), Vector { }
}
position.X = ray.X + (ray.Y - position.Y) / tan
delta.X = -delta.Y / tan
// cast da ray
steps := 0
for {
cell := world.At(position.Point())
if cell > 0 || steps > max { break }
position = position.Add(delta)
steps ++
} }
func (ray *Ray) Point () (image.Point) { return position.Sub(ray.Vector).Hypot(), position
return image.Pt(int(ray.X), int(ray.Y)) }
func (ray *Ray) castV (world World, max int) (distance float64, hit Vector) {
var position Vector
var delta Vector
tan := math.Tan(math.Pi - ray.Angle)
offsetAngle := math.Mod(ray.Angle + math.Pi / 2, math.Pi * 2)
if offsetAngle > math.Pi {
// facing left
position.X = math.Floor(ray.X) - (1.0 / 64)
delta.X = -1
} else if offsetAngle < math.Pi {
// facing right
position.X = math.Floor(ray.X) + 1
delta.X = 1
} else {
// facing straight left or right
return float64(max), Vector { }
}
position.Y = ray.Y + (ray.X - position.X) * tan
delta.Y = -delta.X * tan
// cast da ray
steps := 0
for {
cell := world.At(position.Point())
if cell > 0 || steps > max { break }
position = position.Add(delta)
steps ++
}
return position.Sub(ray.Vector).Hypot(), position
return
} }

View File

@ -1,6 +1,8 @@
package main package main
// import "fmt"
import "math" import "math"
import "image"
import "image/color" import "image/color"
import "git.tebibyte.media/sashakoshka/tomo/input" import "git.tebibyte.media/sashakoshka/tomo/input"
import "git.tebibyte.media/sashakoshka/tomo/config" import "git.tebibyte.media/sashakoshka/tomo/config"
@ -32,9 +34,11 @@ type Raycaster struct {
func NewRaycaster (world World) (element *Raycaster) { func NewRaycaster (world World) (element *Raycaster) {
element = &Raycaster { element = &Raycaster {
Camera: Camera { Camera: Camera {
X: 2, Vector: Vector {
Y: 2, X: 1.5,
Angle: 1, Y: 1.5,
},
Angle: math.Pi / 3,
Fov: 1, Fov: 1,
}, },
world: world, world: world,
@ -103,16 +107,13 @@ func (element *Raycaster) drawAll () {
width := bounds.Dx() width := bounds.Dx()
height := bounds.Dy() height := bounds.Dy()
ray := Ray { ray := Ray { Angle: element.Camera.Angle - element.Camera.Fov / 2 }
Angle: element.Camera.Angle - element.Camera.Fov / 2,
Precision: 64,
}
for x := 0; x < width; x ++ { for x := 0; x < width; x ++ {
ray.X = element.Camera.X ray.X = element.Camera.X
ray.Y = element.Camera.Y ray.Y = element.Camera.Y
distance := ray.Cast(element.world, 8) distance, _ := ray.Cast(element.world, 8)
distanceFac := float64(distance) / 8 distanceFac := float64(distance) / 8
distance *= math.Cos(ray.Angle - element.Camera.Angle) distance *= math.Cos(ray.Angle - element.Camera.Angle)
@ -150,4 +151,54 @@ func (element *Raycaster) drawAll () {
// increment angle // increment angle
ray.Angle += element.Camera.Fov / float64(width) ray.Angle += element.Camera.Fov / float64(width)
} }
// element.drawMinimap()
}
func (element *Raycaster) drawMinimap () {
bounds := element.Bounds()
scale := 16
for y := 0; y < 10; y ++ {
for x := 0; x < 10; x ++ {
cellPt := image.Pt(x, y)
cell := element.world.At(cellPt)
cellBounds :=
image.Rectangle {
cellPt.Mul(scale),
cellPt.Add(image.Pt(1, 1)).Mul(scale),
}.Add(bounds.Min)
cellColor := color.RGBA { 0x22, 0x22, 0x22, 0xFF }
if cell == 1 {
cellColor = color.RGBA { 0xFF, 0xFF, 0xFF, 0xFF }
}
artist.FillRectangle (
element.core,
artist.NewUniform(cellColor),
cellBounds.Inset(1))
}}
playerPt := element.Camera.Mul(float64(scale)).Point().Add(bounds.Min)
playerAnglePt :=
element.Camera.Add(element.Camera.Delta()).
Mul(float64(scale)).Point().Add(bounds.Min)
ray := Ray { Vector: element.Camera.Vector, Angle: element.Camera.Angle }
_, hit := ray.Cast(element.world, 8)
hitPt := hit.Mul(float64(scale)).Point().Add(bounds.Min)
// fmt.Println(rayDistance)
playerBounds := image.Rectangle { playerPt, playerPt }.Inset(scale / -8)
artist.FillEllipse (
element.core,
artist.Uhex(0xFFFFFFFF),
playerBounds)
artist.Line (
element.core,
artist.Uhex(0xFFFFFFFF), 1,
playerPt,
playerAnglePt)
artist.Line (
element.core,
artist.Uhex(0x00FF00FF), 1,
playerPt,
hitPt)
} }