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 {
 | 
			
		||||
	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
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -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