backrooms!!!!!
This commit is contained in:
		
							parent
							
								
									e966771f5b
								
							
						
					
					
						commit
						20fa445cdd
					
				@ -44,7 +44,7 @@ func run () {
 | 
				
			|||||||
	warningButton := basicElements.NewButton("popups.DialogKindWarning")
 | 
						warningButton := basicElements.NewButton("popups.DialogKindWarning")
 | 
				
			||||||
	warningButton.OnClick (func () {
 | 
						warningButton.OnClick (func () {
 | 
				
			||||||
		popups.NewDialog (
 | 
							popups.NewDialog (
 | 
				
			||||||
			popups.DialogKindQuestion,
 | 
								popups.DialogKindWarning,
 | 
				
			||||||
			"Warning",
 | 
								"Warning",
 | 
				
			||||||
			"They are fast approaching.")
 | 
								"They are fast approaching.")
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
@ -53,7 +53,7 @@ func run () {
 | 
				
			|||||||
	errorButton := basicElements.NewButton("popups.DialogKindError")
 | 
						errorButton := basicElements.NewButton("popups.DialogKindError")
 | 
				
			||||||
	errorButton.OnClick (func () {
 | 
						errorButton.OnClick (func () {
 | 
				
			||||||
		popups.NewDialog (
 | 
							popups.NewDialog (
 | 
				
			||||||
			popups.DialogKindQuestion,
 | 
								popups.DialogKindError,
 | 
				
			||||||
			"Error",
 | 
								"Error",
 | 
				
			||||||
			"There is nowhere left to go.")
 | 
								"There is nowhere left to go.")
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 | 
				
			|||||||
@ -13,9 +13,9 @@ type Game struct {
 | 
				
			|||||||
	controlState ControlState
 | 
						controlState ControlState
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func NewGame (world World) (game *Game) {
 | 
					func NewGame (world World, textures Textures) (game *Game) {
 | 
				
			||||||
	game = &Game {
 | 
						game = &Game {
 | 
				
			||||||
		Raycaster: NewRaycaster(world),
 | 
							Raycaster: NewRaycaster(world, textures),
 | 
				
			||||||
		stopChan: make(chan bool),
 | 
							stopChan: make(chan bool),
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	game.Raycaster.OnControlStateChange (func (state ControlState) {
 | 
						game.Raycaster.OnControlStateChange (func (state ControlState) {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,10 +1,16 @@
 | 
				
			|||||||
package main
 | 
					package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import "bytes"
 | 
				
			||||||
 | 
					import _ "embed"
 | 
				
			||||||
 | 
					import _ "image/png"
 | 
				
			||||||
import "git.tebibyte.media/sashakoshka/tomo"
 | 
					import "git.tebibyte.media/sashakoshka/tomo"
 | 
				
			||||||
import "git.tebibyte.media/sashakoshka/tomo/layouts/basic"
 | 
					import "git.tebibyte.media/sashakoshka/tomo/layouts/basic"
 | 
				
			||||||
import "git.tebibyte.media/sashakoshka/tomo/elements/basic"
 | 
					import "git.tebibyte.media/sashakoshka/tomo/elements/basic"
 | 
				
			||||||
import _ "git.tebibyte.media/sashakoshka/tomo/backends/x"
 | 
					import _ "git.tebibyte.media/sashakoshka/tomo/backends/x"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//go:embed wall.png
 | 
				
			||||||
 | 
					var wallTextureBytes []uint8
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func main () {
 | 
					func main () {
 | 
				
			||||||
	tomo.Run(run)
 | 
						tomo.Run(run)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -16,20 +22,28 @@ func run () {
 | 
				
			|||||||
	container := basicElements.NewContainer(basicLayouts.Vertical { true, true })
 | 
						container := basicElements.NewContainer(basicLayouts.Vertical { true, true })
 | 
				
			||||||
	window.Adopt(container)
 | 
						window.Adopt(container)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	game := NewGame (DefaultWorld {
 | 
						wallTexture, _ := TextureFrom(bytes.NewReader(wallTextureBytes))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						game := NewGame (World {
 | 
				
			||||||
		Data: []int {
 | 
							Data: []int {
 | 
				
			||||||
		        1,1,1,1,1,1,1,1,1,1,
 | 
							        1,1,1,1,1,1,1,1,1,1,1,1,1,
 | 
				
			||||||
		        1,0,0,0,0,0,0,0,0,1,
 | 
							        1,0,0,0,0,0,0,0,0,0,0,0,1,
 | 
				
			||||||
		        1,0,0,0,0,0,0,0,0,1,
 | 
							        1,0,1,1,1,1,1,1,1,0,0,0,1,
 | 
				
			||||||
		        1,0,0,1,1,0,1,0,0,1,
 | 
							        1,0,0,0,0,0,0,0,1,1,1,0,1,
 | 
				
			||||||
		        1,0,0,1,0,0,1,0,0,1,
 | 
							        1,0,0,0,0,0,0,0,1,0,0,0,1,
 | 
				
			||||||
		        1,0,0,1,0,0,1,0,0,1,
 | 
							        1,0,0,0,0,0,0,0,1,0,1,1,1,
 | 
				
			||||||
		        1,0,0,1,0,1,1,0,0,1,
 | 
							        1,1,1,1,1,1,1,1,1,0,0,0,1,
 | 
				
			||||||
		        1,0,0,0,0,0,0,0,0,1,
 | 
							        1,0,0,0,0,0,0,0,1,1,0,1,1,
 | 
				
			||||||
		        1,0,0,0,0,0,0,0,0,1,
 | 
							        1,0,0,1,0,0,0,0,0,0,0,0,1,
 | 
				
			||||||
		        1,1,1,1,1,1,1,1,1,1,
 | 
							        1,0,1,1,1,0,0,0,0,0,0,0,1,
 | 
				
			||||||
 | 
							        1,0,0,1,0,0,0,0,0,0,0,0,1,
 | 
				
			||||||
 | 
							        1,0,0,0,0,0,0,0,0,0,0,0,1,
 | 
				
			||||||
 | 
							        1,0,0,0,0,1,0,0,0,0,0,0,1,
 | 
				
			||||||
 | 
							        1,1,1,1,1,1,1,1,1,1,1,1,1,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		Stride: 10,
 | 
							Stride: 13,
 | 
				
			||||||
 | 
						}, Textures {
 | 
				
			||||||
 | 
							wallTexture,
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	container.Adopt(basicElements.NewLabel("Explore a 3D world!", false), false)
 | 
						container.Adopt(basicElements.NewLabel("Explore a 3D world!", false), false)
 | 
				
			||||||
 | 
				
			|||||||
@ -3,16 +3,12 @@ package main
 | 
				
			|||||||
import "math"
 | 
					import "math"
 | 
				
			||||||
import "image"
 | 
					import "image"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type World interface {
 | 
					type World struct {
 | 
				
			||||||
	At (image.Point) int
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type DefaultWorld struct {
 | 
					 | 
				
			||||||
	Data   []int
 | 
						Data   []int
 | 
				
			||||||
	Stride int
 | 
						Stride int
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (world DefaultWorld) At (position image.Point) int {
 | 
					func (world World) At (position image.Point) int {
 | 
				
			||||||
	if position.X < 0 { return 0 }
 | 
						if position.X < 0 { return 0 }
 | 
				
			||||||
	if position.Y < 0 { return 0 }
 | 
						if position.Y < 0 { return 0 }
 | 
				
			||||||
	if position.X >= world.Stride { return 0 }
 | 
						if position.X >= world.Stride { return 0 }
 | 
				
			||||||
@ -98,21 +94,30 @@ type Ray struct {
 | 
				
			|||||||
	Angle  float64
 | 
						Angle  float64
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (ray *Ray) Cast (world World, max int) (distance float64, hit Vector) {
 | 
					func (ray *Ray) Cast (
 | 
				
			||||||
 | 
						world World,
 | 
				
			||||||
 | 
						max int,
 | 
				
			||||||
 | 
					) (
 | 
				
			||||||
 | 
						distance float64,
 | 
				
			||||||
 | 
						hit Vector,
 | 
				
			||||||
 | 
						wall int,
 | 
				
			||||||
 | 
						horizontal bool,
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
	// return ray.castV(world, max)
 | 
						// return ray.castV(world, max)
 | 
				
			||||||
	if world.At(ray.Point()) > 0 {
 | 
						cellAt := world.At(ray.Point())
 | 
				
			||||||
		return 0, Vector { }
 | 
						if cellAt > 0 {
 | 
				
			||||||
 | 
							return 0, Vector { }, cellAt, false
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	hDistance, hPos := ray.castH(world, max)
 | 
						hDistance, hPos, hWall := ray.castH(world, max)
 | 
				
			||||||
	vDistance, vPos := ray.castV(world, max)
 | 
						vDistance, vPos, vWall := ray.castV(world, max)
 | 
				
			||||||
	if hDistance < vDistance {
 | 
						if hDistance < vDistance {
 | 
				
			||||||
		return hDistance, hPos
 | 
							return hDistance, hPos, hWall, true
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		return vDistance, vPos
 | 
							return vDistance, vPos, vWall, false
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (ray *Ray) castH (world World, max int) (distance float64, hit Vector) {
 | 
					func (ray *Ray) castH (world World, max int) (distance float64, hit Vector, wall int) {
 | 
				
			||||||
	var position Vector
 | 
						var position Vector
 | 
				
			||||||
	var delta    Vector
 | 
						var delta    Vector
 | 
				
			||||||
	ray.Angle = math.Mod(ray.Angle, math.Pi * 2)
 | 
						ray.Angle = math.Mod(ray.Angle, math.Pi * 2)
 | 
				
			||||||
@ -130,7 +135,7 @@ func (ray *Ray) castH (world World, max int) (distance float64, hit Vector) {
 | 
				
			|||||||
		delta.Y = 1
 | 
							delta.Y = 1
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		// facing straight left or right
 | 
							// facing straight left or right
 | 
				
			||||||
		return float64(max), Vector { }
 | 
							return float64(max), Vector { }, 0
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	position.X = ray.X + (ray.Y - position.Y) / tan
 | 
						position.X = ray.X + (ray.Y - position.Y) / tan
 | 
				
			||||||
	delta.X    = -delta.Y / tan
 | 
						delta.X    = -delta.Y / tan
 | 
				
			||||||
@ -144,10 +149,10 @@ func (ray *Ray) castH (world World, max int) (distance float64, hit Vector) {
 | 
				
			|||||||
		steps ++
 | 
							steps ++
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return position.Sub(ray.Vector).Hypot(), position
 | 
						return position.Sub(ray.Vector).Hypot(), position, world.At(position.Point())
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (ray *Ray) castV (world World, max int) (distance float64, hit Vector) {
 | 
					func (ray *Ray) castV (world World, max int) (distance float64, hit Vector, wall int) {
 | 
				
			||||||
	var position Vector
 | 
						var position Vector
 | 
				
			||||||
	var delta    Vector
 | 
						var delta    Vector
 | 
				
			||||||
	tan := math.Tan(math.Pi - ray.Angle)
 | 
						tan := math.Tan(math.Pi - ray.Angle)
 | 
				
			||||||
@ -162,7 +167,7 @@ func (ray *Ray) castV (world World, max int) (distance float64, hit Vector) {
 | 
				
			|||||||
		delta.X = 1
 | 
							delta.X = 1
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		// facing straight left or right
 | 
							// facing straight left or right
 | 
				
			||||||
		return float64(max), Vector { }
 | 
							return float64(max), Vector { }, 0
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	position.Y = ray.Y + (ray.X - position.X) * tan
 | 
						position.Y = ray.Y + (ray.X - position.X) * tan
 | 
				
			||||||
	delta.Y    = -delta.X * tan
 | 
						delta.Y    = -delta.X * tan
 | 
				
			||||||
@ -176,6 +181,5 @@ func (ray *Ray) castV (world World, max int) (distance float64, hit Vector) {
 | 
				
			|||||||
		steps ++
 | 
							steps ++
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return position.Sub(ray.Vector).Hypot(), position
 | 
						return position.Sub(ray.Vector).Hypot(), position, world.At(position.Point())
 | 
				
			||||||
	return
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -28,20 +28,24 @@ type Raycaster struct {
 | 
				
			|||||||
	Camera
 | 
						Camera
 | 
				
			||||||
	controlState ControlState
 | 
						controlState ControlState
 | 
				
			||||||
	world World
 | 
						world World
 | 
				
			||||||
 | 
						textures Textures
 | 
				
			||||||
	onControlStateChange func (ControlState)
 | 
						onControlStateChange func (ControlState)
 | 
				
			||||||
 | 
						renderDistance int
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func NewRaycaster (world World) (element *Raycaster) {
 | 
					func NewRaycaster (world World, textures Textures) (element *Raycaster) {
 | 
				
			||||||
	element = &Raycaster {
 | 
						element = &Raycaster {
 | 
				
			||||||
		Camera: Camera {
 | 
							Camera: Camera {
 | 
				
			||||||
			Vector: Vector {
 | 
								Vector: Vector {
 | 
				
			||||||
				X: 1.5,
 | 
									X: 1,
 | 
				
			||||||
				Y: 1.5,
 | 
									Y: 1,
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			Angle: math.Pi / 3,
 | 
								Angle: math.Pi / 3,
 | 
				
			||||||
			Fov:   1,
 | 
								Fov:   1,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		world: world,
 | 
							world: world,
 | 
				
			||||||
 | 
							textures: textures,
 | 
				
			||||||
 | 
							renderDistance: 8,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	element.Core, element.core = core.NewCore(element.drawAll)
 | 
						element.Core, element.core = core.NewCore(element.drawAll)
 | 
				
			||||||
	element.FocusableCore,
 | 
						element.FocusableCore,
 | 
				
			||||||
@ -113,22 +117,26 @@ func (element *Raycaster) drawAll () {
 | 
				
			|||||||
		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, hitPoint, wall, horizontal := ray.Cast (
 | 
				
			||||||
		distanceFac := float64(distance) / 8
 | 
								element.world, element.renderDistance)
 | 
				
			||||||
		distance *= math.Cos(ray.Angle - element.Camera.Angle)
 | 
							distance *= math.Cos(ray.Angle - element.Camera.Angle)
 | 
				
			||||||
 | 
							textureX := math.Mod(hitPoint.X + hitPoint.Y, 1)
 | 
				
			||||||
 | 
							if textureX < 0 { textureX += 1 }
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		wallHeight := height
 | 
							wallHeight := height
 | 
				
			||||||
		if distance > 0 {
 | 
							if distance > 0 {
 | 
				
			||||||
			wallHeight = int((float64(height) / 2.0) / float64(distance))
 | 
								wallHeight = int((float64(height) / 2.0) / float64(distance))
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							shade := 1.0
 | 
				
			||||||
 | 
							if horizontal {
 | 
				
			||||||
 | 
								shade *= 0.7
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							shade *= 1 - distance / float64(element.renderDistance)
 | 
				
			||||||
 | 
							if shade < 0 { shade = 0 }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		ceilingColor := color.RGBA { 0x00, 0x00, 0x00, 0xFF }
 | 
							ceilingColor := color.RGBA { 0x00, 0x00, 0x00, 0xFF }
 | 
				
			||||||
		wallColor    := color.RGBA { 0xCC, 0x33, 0x22, 0xFF }
 | 
							floorColor   := color.RGBA { 0x39, 0x49, 0x25, 0xFF }
 | 
				
			||||||
		floorColor   := color.RGBA { 0x11, 0x50, 0x22, 0xFF }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// fmt.Println(float64(distance) / 32)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		wallColor  = artist.LerpRGBA(wallColor, ceilingColor, distanceFac)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// draw
 | 
							// draw
 | 
				
			||||||
		data, stride := element.core.Buffer()
 | 
							data, stride := element.core.Buffer()
 | 
				
			||||||
@ -136,16 +144,26 @@ func (element *Raycaster) drawAll () {
 | 
				
			|||||||
		wallEnd   := height / 2 + wallHeight + bounds.Min.Y
 | 
							wallEnd   := height / 2 + wallHeight + bounds.Min.Y
 | 
				
			||||||
		if wallStart < 0            { wallStart = 0 }
 | 
							if wallStart < 0            { wallStart = 0 }
 | 
				
			||||||
		if wallEnd   > bounds.Max.Y { wallEnd   = bounds.Max.Y }
 | 
							if wallEnd   > bounds.Max.Y { wallEnd   = bounds.Max.Y }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for y := bounds.Min.Y; y < wallStart; y ++ {
 | 
							for y := bounds.Min.Y; y < wallStart; y ++ {
 | 
				
			||||||
			data[y * stride + x + bounds.Min.X] = ceilingColor
 | 
								data[y * stride + x + bounds.Min.X] = ceilingColor
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							slicePoint := 0.0
 | 
				
			||||||
 | 
							slicePointDelta := 1 / float64(wallEnd - wallStart)
 | 
				
			||||||
		for y := wallStart; y < wallEnd; y ++ {
 | 
							for y := wallStart; y < wallEnd; y ++ {
 | 
				
			||||||
 | 
								wallColor := element.textures.At (wall, Vector {
 | 
				
			||||||
 | 
									textureX,
 | 
				
			||||||
 | 
									slicePoint,
 | 
				
			||||||
 | 
								})
 | 
				
			||||||
 | 
								wallColor = shadeColor(wallColor, shade)
 | 
				
			||||||
			data[y * stride + x + bounds.Min.X] = wallColor
 | 
								data[y * stride + x + bounds.Min.X] = wallColor
 | 
				
			||||||
 | 
									
 | 
				
			||||||
 | 
								slicePoint += slicePointDelta
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
		for y := wallEnd; y < bounds.Max.Y; y ++ {
 | 
							for y := wallEnd; y < bounds.Max.Y; y ++ {
 | 
				
			||||||
			floorFac := float64(y - (height / 2)) / float64(height / 2)
 | 
								data[y * stride + x + bounds.Min.X] = floorColor
 | 
				
			||||||
			data[y * stride + x + bounds.Min.X] =
 | 
					 | 
				
			||||||
				artist.LerpRGBA(ceilingColor, floorColor, floorFac)
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// increment angle
 | 
							// increment angle
 | 
				
			||||||
@ -155,11 +173,20 @@ func (element *Raycaster) drawAll () {
 | 
				
			|||||||
	// element.drawMinimap()
 | 
						// element.drawMinimap()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func shadeColor (c color.RGBA, brightness float64) color.RGBA {
 | 
				
			||||||
 | 
						return color.RGBA {
 | 
				
			||||||
 | 
							uint8(float64(c.R) * brightness),
 | 
				
			||||||
 | 
							uint8(float64(c.G) * brightness),
 | 
				
			||||||
 | 
							uint8(float64(c.B) * brightness),
 | 
				
			||||||
 | 
							c.A,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (element *Raycaster) drawMinimap () {
 | 
					func (element *Raycaster) drawMinimap () {
 | 
				
			||||||
	bounds := element.Bounds()
 | 
						bounds := element.Bounds()
 | 
				
			||||||
	scale  := 16
 | 
						scale  := 8
 | 
				
			||||||
	for y := 0; y < 10; y ++ {
 | 
						for y := 0; y < len(element.world.Data) / element.world.Stride; y ++ {
 | 
				
			||||||
	for x := 0; x < 10; x ++ {
 | 
						for x := 0; x < element.world.Stride; x ++ {
 | 
				
			||||||
		cellPt := image.Pt(x, y)
 | 
							cellPt := image.Pt(x, y)
 | 
				
			||||||
		cell   := element.world.At(cellPt)
 | 
							cell   := element.world.At(cellPt)
 | 
				
			||||||
		cellBounds :=
 | 
							cellBounds :=
 | 
				
			||||||
@ -168,7 +195,7 @@ func (element *Raycaster) drawMinimap () {
 | 
				
			|||||||
				cellPt.Add(image.Pt(1, 1)).Mul(scale),
 | 
									cellPt.Add(image.Pt(1, 1)).Mul(scale),
 | 
				
			||||||
			}.Add(bounds.Min)
 | 
								}.Add(bounds.Min)
 | 
				
			||||||
		cellColor  := color.RGBA { 0x22, 0x22, 0x22, 0xFF }
 | 
							cellColor  := color.RGBA { 0x22, 0x22, 0x22, 0xFF }
 | 
				
			||||||
		if cell == 1 {
 | 
							if cell > 0 {
 | 
				
			||||||
			cellColor = color.RGBA { 0xFF, 0xFF, 0xFF, 0xFF }
 | 
								cellColor = color.RGBA { 0xFF, 0xFF, 0xFF, 0xFF }
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		artist.FillRectangle (
 | 
							artist.FillRectangle (
 | 
				
			||||||
@ -182,9 +209,8 @@ func (element *Raycaster) drawMinimap () {
 | 
				
			|||||||
		element.Camera.Add(element.Camera.Delta()).
 | 
							element.Camera.Add(element.Camera.Delta()).
 | 
				
			||||||
		Mul(float64(scale)).Point().Add(bounds.Min)
 | 
							Mul(float64(scale)).Point().Add(bounds.Min)
 | 
				
			||||||
	ray := Ray { Vector: element.Camera.Vector, Angle: element.Camera.Angle }
 | 
						ray := Ray { Vector: element.Camera.Vector, Angle: element.Camera.Angle }
 | 
				
			||||||
	_, hit := ray.Cast(element.world, 8)
 | 
						_, hit, _, _ := ray.Cast(element.world, 8)
 | 
				
			||||||
	hitPt := hit.Mul(float64(scale)).Point().Add(bounds.Min)
 | 
						hitPt := hit.Mul(float64(scale)).Point().Add(bounds.Min)
 | 
				
			||||||
	// fmt.Println(rayDistance)
 | 
					 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	playerBounds := image.Rectangle { playerPt, playerPt }.Inset(scale / -8)
 | 
						playerBounds := image.Rectangle { playerPt, playerPt }.Inset(scale / -8)
 | 
				
			||||||
	artist.FillEllipse (
 | 
						artist.FillEllipse (
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										43
									
								
								examples/raycaster/texture.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								examples/raycaster/texture.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,43 @@
 | 
				
			|||||||
 | 
					package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import "io"
 | 
				
			||||||
 | 
					import "image"
 | 
				
			||||||
 | 
					import "image/color"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Textures []Texture
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Texture struct {
 | 
				
			||||||
 | 
						Data   []color.RGBA
 | 
				
			||||||
 | 
						Stride int
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (texture Textures) At (wall int, offset Vector) color.RGBA {
 | 
				
			||||||
 | 
						wall --
 | 
				
			||||||
 | 
						if wall < 0 || wall >= len(texture) { return color.RGBA { } }
 | 
				
			||||||
 | 
						image := texture[wall]
 | 
				
			||||||
 | 
						xOffset := int(offset.X * float64(image.Stride))
 | 
				
			||||||
 | 
						yOffset := int(offset.Y * float64(len(image.Data) / image.Stride))
 | 
				
			||||||
 | 
						return image.Data[xOffset + yOffset * image.Stride]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TextureFrom (source io.Reader) (texture Texture, err error) {
 | 
				
			||||||
 | 
						sourceImage, _, err := image.Decode(source)
 | 
				
			||||||
 | 
						if err != nil { return }
 | 
				
			||||||
 | 
						bounds := sourceImage.Bounds()
 | 
				
			||||||
 | 
						texture.Stride = bounds.Dx()
 | 
				
			||||||
 | 
						texture.Data = make([]color.RGBA, bounds.Dx() * bounds.Dy())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						index := 0
 | 
				
			||||||
 | 
						for y := bounds.Min.Y; y < bounds.Max.Y; y ++ {
 | 
				
			||||||
 | 
						for x := bounds.Min.X; x < bounds.Max.X; x ++ {
 | 
				
			||||||
 | 
							r, g, b, a := sourceImage.At(x, y).RGBA()
 | 
				
			||||||
 | 
							texture.Data[index] = color.RGBA {
 | 
				
			||||||
 | 
								R: uint8(r >> 8),
 | 
				
			||||||
 | 
								G: uint8(g >> 8),
 | 
				
			||||||
 | 
								B: uint8(b >> 8),
 | 
				
			||||||
 | 
								A: uint8(a >> 8),
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							index ++
 | 
				
			||||||
 | 
						}}
 | 
				
			||||||
 | 
						return texture, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								examples/raycaster/wall.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								examples/raycaster/wall.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 1.5 KiB  | 
		Reference in New Issue
	
	Block a user