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]
}
type Camera struct {
X, Y float64
Angle float64
Fov float64
type Vector struct {
X, Y float64
}
func (camera *Camera) Point () (image.Point) {
return image.Pt(int(camera.X), int(camera.Y))
func (vector Vector) Point () (image.Point) {
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) {
@ -38,53 +67,115 @@ func (camera *Camera) Rotate (by float64) {
}
func (camera *Camera) Walk (by float64) {
dx, dy := camera.Delta()
camera.X += dx * by
camera.Y += dy * by
delta := camera.Delta()
camera.X += delta.X * by
camera.Y += delta.Y * by
}
func (camera *Camera) Strafe (by float64) {
dx, dy := camera.OffsetDelta()
camera.X += dx * by
camera.Y += dy * by
delta := camera.OffsetDelta()
camera.X += delta.X * by
camera.Y += delta.Y * by
}
func (camera *Camera) Delta () (x float64, y float64) {
return math.Cos(camera.Angle), math.Sin(camera.Angle)
func (camera *Camera) Delta () Vector {
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
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 {
X, Y float64
Vector
Angle float64
Precision int
}
func (ray *Ray) Cast (world World, max int) (distance float64) {
precision := 64
func (ray *Ray) Cast (world World, max int) (distance float64, hit Vector) {
// return ray.castV(world, max)
if world.At(ray.Point()) > 0 {
return 0, Vector { }
}
hDistance, hPos := ray.castH(world, max)
vDistance, vPos := ray.castV(world, max)
if hDistance < vDistance {
return hDistance, hPos
} else {
return vDistance, vPos
}
}
dX := math.Cos(ray.Angle) / float64(precision)
dY := math.Sin(ray.Angle) / float64(precision)
origX, origY := ray.X, ray.Y
func (ray *Ray) castH (world World, max int) (distance float64, hit Vector) {
var position Vector
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
wall := 0
depth := 0
for wall == 0 && depth < max * precision {
ray.X += dX
ray.Y += dY
wall = world.At(ray.Point())
depth ++
// cast da ray
steps := 0
for {
cell := world.At(position.Point())
if cell > 0 || steps > max { break }
position = position.Add(delta)
steps ++
}
distanceX := origX - ray.X
distanceY := origY - ray.Y
return math.Sqrt(distanceX * distanceX + distanceY * distanceY)
return position.Sub(ray.Vector).Hypot(), position
}
func (ray *Ray) Point () (image.Point) {
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
// import "fmt"
import "math"
import "image"
import "image/color"
import "git.tebibyte.media/sashakoshka/tomo/input"
import "git.tebibyte.media/sashakoshka/tomo/config"
@ -32,9 +34,11 @@ type Raycaster struct {
func NewRaycaster (world World) (element *Raycaster) {
element = &Raycaster {
Camera: Camera {
X: 2,
Y: 2,
Angle: 1,
Vector: Vector {
X: 1.5,
Y: 1.5,
},
Angle: math.Pi / 3,
Fov: 1,
},
world: world,
@ -103,16 +107,13 @@ func (element *Raycaster) drawAll () {
width := bounds.Dx()
height := bounds.Dy()
ray := Ray {
Angle: element.Camera.Angle - element.Camera.Fov / 2,
Precision: 64,
}
ray := Ray { Angle: element.Camera.Angle - element.Camera.Fov / 2 }
for x := 0; x < width; x ++ {
ray.X = element.Camera.X
ray.Y = element.Camera.Y
distance := ray.Cast(element.world, 8)
distance, _ := ray.Cast(element.world, 8)
distanceFac := float64(distance) / 8
distance *= math.Cos(ray.Angle - element.Camera.Angle)
@ -150,4 +151,54 @@ func (element *Raycaster) drawAll () {
// increment angle
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)
}