The raycaster is faster but more bg=uggyh agghgfghgfhgfgh
This commit is contained in:
parent
e9e1ccc35e
commit
e966771f5b
@ -21,14 +21,43 @@ func (world DefaultWorld) At (position image.Point) int {
|
||||
return world.Data[index]
|
||||
}
|
||||
|
||||
type Camera struct {
|
||||
type Vector struct {
|
||||
X, Y float64
|
||||
Angle float64
|
||||
Fov 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
|
||||
|
||||
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 ++
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
distanceX := origX - ray.X
|
||||
distanceY := origY - ray.Y
|
||||
return math.Sqrt(distanceX * distanceX + distanceY * distanceY)
|
||||
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
|
||||
|
||||
// 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 image.Pt(int(ray.X), int(ray.Y))
|
||||
return position.Sub(ray.Vector).Hypot(), position
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
Reference in New Issue
Block a user