Generate random maze and fill in walls
This commit is contained in:
parent
b82216c2f9
commit
2f6acbf131
3 changed files with 421 additions and 374 deletions
350
game.go
Normal file
350
game.go
Normal file
|
@ -0,0 +1,350 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"math/rand"
|
||||
"os"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2"
|
||||
"github.com/hajimehoshi/ebiten/v2/ebitenutil"
|
||||
"github.com/hajimehoshi/ebiten/v2/inpututil"
|
||||
"github.com/solarlune/tetra3d"
|
||||
)
|
||||
|
||||
type Game struct {
|
||||
Width, Height int
|
||||
Scene *tetra3d.Scene
|
||||
Camera *tetra3d.Camera
|
||||
|
||||
truck *garbageTruck
|
||||
|
||||
wasm bool
|
||||
|
||||
debug int
|
||||
}
|
||||
|
||||
func NewGame() *Game {
|
||||
game := &Game{
|
||||
Width: 796,
|
||||
Height: 448,
|
||||
}
|
||||
|
||||
game.Init()
|
||||
|
||||
return game
|
||||
}
|
||||
|
||||
func (g *Game) Init() {
|
||||
g.Scene = tetra3d.NewScene("")
|
||||
|
||||
light := tetra3d.NewDirectionalLight("", 1, 1, 1, 1.0)
|
||||
light.Move(0, 14, 0)
|
||||
light.Rotate(1, 0, 0, -math.Pi/2)
|
||||
g.Scene.Root.AddChildren(light)
|
||||
|
||||
const (
|
||||
brightnessEastWest = 0.8
|
||||
brightnessNorthSouth = 1.0
|
||||
)
|
||||
{
|
||||
// West.
|
||||
l := tetra3d.NewDirectionalLight("", 1, 1, 1, brightnessEastWest)
|
||||
l.Move(0, 14, 0)
|
||||
l.Rotate(1, 0, 0, -math.Pi/2)
|
||||
l.Rotate(0, 1, 0, -math.Pi/2)
|
||||
g.Scene.Root.AddChildren(l)
|
||||
}
|
||||
{
|
||||
// East.
|
||||
l := tetra3d.NewDirectionalLight("", 1, 1, 1, brightnessEastWest)
|
||||
l.Move(0, 14, 0)
|
||||
l.Rotate(1, 0, 0, -math.Pi/2)
|
||||
l.Rotate(0, 1, 0, math.Pi/2)
|
||||
g.Scene.Root.AddChildren(l)
|
||||
}
|
||||
{
|
||||
// North.
|
||||
l := tetra3d.NewDirectionalLight("", 1, 1, 1, brightnessNorthSouth)
|
||||
l.Move(0, 14, 0)
|
||||
l.Rotate(1, 0, 0, -math.Pi/2)
|
||||
l.Rotate(1, 0, 0, math.Pi/2)
|
||||
g.Scene.Root.AddChildren(l)
|
||||
}
|
||||
{
|
||||
// South.
|
||||
l := tetra3d.NewDirectionalLight("", 1, 1, 1, brightnessNorthSouth)
|
||||
l.Move(0, 14, 0)
|
||||
l.Rotate(1, 0, 0, -math.Pi/2)
|
||||
l.Rotate(1, 0, 0, -math.Pi/2)
|
||||
g.Scene.Root.AddChildren(l)
|
||||
}
|
||||
|
||||
// Create road.
|
||||
{
|
||||
const planeSize = 10000
|
||||
plane := tetra3d.NewModel(tetra3d.NewPlaneMesh(2, 2), "plane")
|
||||
plane.Color.Set(40.0/255.0, 40.0/255.0, 40.0/255.0, 1)
|
||||
plane.Grow(planeSize, 0, planeSize)
|
||||
g.Scene.Root.AddChildren(plane)
|
||||
}
|
||||
|
||||
// Create garbage truck.
|
||||
g.truck = &garbageTruck{
|
||||
x: 4,
|
||||
y: 8,
|
||||
}
|
||||
{
|
||||
mesh := tetra3d.NewCubeMesh()
|
||||
model := tetra3d.NewModel(mesh, "")
|
||||
model.Color = tetra3d.NewColor(0.12, 0.44, 0.24, 1)
|
||||
model.Grow(-0.75, -0.25, -0.3)
|
||||
|
||||
g.truck.Model = model
|
||||
g.Scene.Root.AddChildren(g.truck.Model)
|
||||
}
|
||||
|
||||
const (
|
||||
lightX = 0.55
|
||||
headlightDistance = 0.85
|
||||
headlightShade = float32(0.75)
|
||||
)
|
||||
|
||||
// Headlights.
|
||||
{
|
||||
model := tetra3d.NewModel(tetra3d.NewCubeMesh(), "")
|
||||
model.Color = tetra3d.NewColor(headlightShade, headlightShade, headlightShade, 1)
|
||||
model.Grow(-0.75, -0.75, -0.75)
|
||||
model.Move(lightX, 0, headlightDistance)
|
||||
g.truck.Model.AddChildren(model)
|
||||
}
|
||||
{
|
||||
model := tetra3d.NewModel(tetra3d.NewCubeMesh(), "")
|
||||
model.Color = tetra3d.NewColor(headlightShade, headlightShade, headlightShade, 1)
|
||||
model.Grow(-0.75, -0.75, -0.75)
|
||||
model.Move(-lightX, 0, headlightDistance)
|
||||
g.truck.Model.AddChildren(model)
|
||||
}
|
||||
|
||||
// Brake lights.
|
||||
{
|
||||
model := tetra3d.NewModel(tetra3d.NewCubeMesh(), "")
|
||||
model.Color = tetra3d.NewColor(0.6, 0, 0, 1)
|
||||
model.Grow(-0.75, -0.75, -0.75)
|
||||
model.Move(lightX, 0, -0.85)
|
||||
g.truck.Model.AddChildren(model)
|
||||
}
|
||||
{
|
||||
model := tetra3d.NewModel(tetra3d.NewCubeMesh(), "")
|
||||
model.Color = tetra3d.NewColor(0.6, 0, 0, 1)
|
||||
model.Grow(-0.75, -0.75, -0.75)
|
||||
model.Move(-lightX, 0, -0.85)
|
||||
g.truck.Model.AddChildren(model)
|
||||
}
|
||||
|
||||
// Create camera.
|
||||
g.Camera = tetra3d.NewCamera(g.Width, g.Height)
|
||||
g.Camera.Move(0, 12, 0)
|
||||
g.Camera.Rotate(1, 0, 0, -math.Pi/2)
|
||||
g.Scene.Root.AddChildren(g.Camera)
|
||||
|
||||
// Generate a random maze.
|
||||
const (
|
||||
mazeW, mazeH = 13, 11
|
||||
)
|
||||
maze := newMaze(mazeW, mazeH)
|
||||
|
||||
// TODO Place behind a build constant.
|
||||
for y := 0; y < mazeH; y++ {
|
||||
for x := 0; x < mazeW; x++ {
|
||||
if maze[y][x] {
|
||||
fmt.Print("..")
|
||||
} else {
|
||||
fmt.Print(" ")
|
||||
}
|
||||
}
|
||||
fmt.Print("\n")
|
||||
}
|
||||
|
||||
// Add walls.
|
||||
|
||||
wallAt := func(x, y int) bool {
|
||||
if x < 0 || y < 0 || x > mazeW-1 || y > mazeH-1 {
|
||||
return true
|
||||
}
|
||||
return maze[y][x]
|
||||
}
|
||||
|
||||
buildingScale := 2.5
|
||||
buildingSize := 7.0
|
||||
|
||||
addPlane := func(x float64, y float64, z float64, colorR float32, colorG float32, colorB float32) *tetra3d.Model {
|
||||
if colorR == -1 {
|
||||
for {
|
||||
colorR, colorG, colorB = float32(rand.Intn(256))/255.0, float32(rand.Intn(256))/255.0, float32(rand.Intn(256))/255.0
|
||||
if colorR >= 0.5 || colorG >= 0.5 || colorB >= 0.5 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
p := tetra3d.NewPlaneMesh(4, 4)
|
||||
plane := tetra3d.NewModel(p, "")
|
||||
plane.Color.Set(colorR, colorG, colorB, 1)
|
||||
plane.Move(x, y, z)
|
||||
g.Scene.Root.AddChildren(plane)
|
||||
return plane
|
||||
}
|
||||
|
||||
wallColors := make([][][]float32, mazeH)
|
||||
for y := range wallColors {
|
||||
wallColors[y] = make([][]float32, mazeW)
|
||||
}
|
||||
|
||||
wallColor := func(x, y int) (colorR, colorG, colorB float32) {
|
||||
// Check for existing wall color.
|
||||
colors := wallColors[y][x]
|
||||
if len(colors) == 3 {
|
||||
return colors[0], colors[1], colors[2]
|
||||
}
|
||||
|
||||
// Generate new wall color.
|
||||
r := rand.New(rand.NewSource(int64(y*mazeW + x)))
|
||||
for {
|
||||
colorR, colorG, colorB = float32(r.Intn(256))/255.0, float32(r.Intn(256))/255.0, float32(r.Intn(256))/255.0
|
||||
if colorR >= 0.5 || colorG >= 0.5 || colorB >= 0.5 {
|
||||
wallColors[y][x] = []float32{colorR, colorG, colorB}
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addWallWest := func(x, y int) {
|
||||
colorR, colorG, colorB := wallColor(x, y)
|
||||
|
||||
plane := addPlane(float64(x)*buildingSize, 0, float64(y)*buildingSize, colorR, colorG, colorB)
|
||||
plane.Grow(buildingScale*10, 0, buildingScale*2.4)
|
||||
plane.Rotate(0, 0, 1, -math.Pi/2)
|
||||
}
|
||||
|
||||
addWallEast := func(x, y int) {
|
||||
colorR, colorG, colorB := wallColor(x, y)
|
||||
x-- // Adjust position.
|
||||
|
||||
plane := addPlane(float64(x)*buildingSize, 0, float64(y)*buildingSize, colorR, colorG, colorB)
|
||||
plane.Grow(buildingScale*10, 0, buildingScale*2.4)
|
||||
plane.Rotate(0, 0, 1, math.Pi/2)
|
||||
}
|
||||
|
||||
addWallNorth := func(x, y int) {
|
||||
colorR, colorG, colorB := wallColor(x, y)
|
||||
|
||||
plane := addPlane(float64(x)*buildingSize, 0, float64(y)*buildingSize, colorR, colorG, colorB)
|
||||
plane.Grow(buildingScale*2.4, 0, buildingScale*10)
|
||||
plane.Rotate(1, 0, 0, math.Pi/2)
|
||||
plane.Move(-buildingSize/2, 0, buildingSize/2)
|
||||
}
|
||||
|
||||
addWallSouth := func(x, y int) {
|
||||
colorR, colorG, colorB := wallColor(x, y)
|
||||
y-- // Adjust position.
|
||||
|
||||
plane := addPlane(float64(x)*buildingSize, 0, float64(y)*buildingSize, colorR, colorG, colorB)
|
||||
plane.Grow(buildingScale*2.4, 0, buildingScale*10)
|
||||
plane.Rotate(1, 0, 0, -math.Pi/2)
|
||||
plane.Move(-buildingSize/2, 0, buildingSize/2)
|
||||
}
|
||||
|
||||
for y := range maze {
|
||||
for x := range maze[y] {
|
||||
if wallAt(x, y) {
|
||||
continue
|
||||
}
|
||||
|
||||
if wallAt(x-1, y) {
|
||||
addWallWest(x-1, y)
|
||||
}
|
||||
if wallAt(x+1, y) {
|
||||
addWallEast(x+1, y)
|
||||
}
|
||||
if wallAt(x, y-1) {
|
||||
addWallNorth(x, y-1)
|
||||
}
|
||||
if wallAt(x, y+1) {
|
||||
addWallSouth(x, y+1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Game) Update() error {
|
||||
if ebiten.IsWindowBeingClosed() {
|
||||
os.Exit(0)
|
||||
return nil
|
||||
}
|
||||
|
||||
if !g.wasm && ebiten.IsKeyPressed(ebiten.KeyEscape) {
|
||||
os.Exit(0)
|
||||
return nil
|
||||
}
|
||||
|
||||
if inpututil.IsKeyJustPressed(ebiten.KeyV) && ebiten.IsKeyPressed(ebiten.KeyControl) && ebiten.IsKeyPressed(ebiten.KeyShift) {
|
||||
g.debug++
|
||||
if g.debug > 1 {
|
||||
g.debug = 0
|
||||
}
|
||||
}
|
||||
|
||||
const moveSize = 1
|
||||
moveX, moveY := 0, 0
|
||||
if ebiten.IsKeyPressed(ebiten.KeyLeft) || ebiten.IsKeyPressed(ebiten.KeyA) {
|
||||
moveX -= moveSize
|
||||
}
|
||||
if ebiten.IsKeyPressed(ebiten.KeyRight) || ebiten.IsKeyPressed(ebiten.KeyD) {
|
||||
moveX += moveSize
|
||||
}
|
||||
if ebiten.IsKeyPressed(ebiten.KeyUp) || ebiten.IsKeyPressed(ebiten.KeyW) {
|
||||
moveY -= moveSize
|
||||
}
|
||||
if ebiten.IsKeyPressed(ebiten.KeyDown) || ebiten.IsKeyPressed(ebiten.KeyS) {
|
||||
moveY += moveSize
|
||||
}
|
||||
braking := ebiten.IsKeyPressed(ebiten.KeySpace)
|
||||
|
||||
// Update truck.
|
||||
t := g.truck
|
||||
t.MoveX, t.MoveY, t.Braking = moveX, moveY, braking
|
||||
t.Update()
|
||||
|
||||
// Move truck model and camera.
|
||||
g.truck.Model.SetLocalPosition(t.x, g.truck.Model.LocalPosition().Y, t.y)
|
||||
g.truck.Model.SetLocalRotation(tetra3d.NewMatrix4().Rotated(0, 1, 0, -t.angle+math.Pi))
|
||||
g.Camera.SetLocalPosition(t.x, g.Camera.LocalPosition().Y, t.y)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *Game) Draw(screen *ebiten.Image) {
|
||||
// Clear the Camera.
|
||||
g.Camera.Clear()
|
||||
|
||||
// Render the scene.
|
||||
g.Camera.RenderScene(g.Scene)
|
||||
|
||||
// Draw the resulting color texture.
|
||||
screen.DrawImage(g.Camera.ColorTexture(), nil)
|
||||
|
||||
if g.debug == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
// Print twice to increase shadow.
|
||||
for i := 0; i < 2; i++ {
|
||||
pos := g.Camera.LocalPosition()
|
||||
ebitenutil.DebugPrintAt(screen, fmt.Sprintf("FPS %.0f\nTPS %.0f\nX %.2f\nY %.2f \nZ %.2f", ebiten.ActualFPS(), ebiten.ActualTPS(), pos.X, pos.Y, pos.Z), 1, 0)
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Game) Layout(_, _ int) (int, int) {
|
||||
return g.Width, g.Height
|
||||
}
|
375
main.go
375
main.go
|
@ -1,384 +1,11 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"image/color"
|
||||
"math"
|
||||
"math/rand"
|
||||
"os"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/inpututil"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/ebitenutil"
|
||||
"github.com/hajimehoshi/ebiten/v2"
|
||||
|
||||
_ "embed"
|
||||
|
||||
"github.com/solarlune/tetra3d"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2"
|
||||
)
|
||||
|
||||
type Game struct {
|
||||
Width, Height int
|
||||
Scene *tetra3d.Scene
|
||||
Camera *tetra3d.Camera
|
||||
|
||||
truck *garbageTruck
|
||||
|
||||
wasm bool
|
||||
|
||||
debug int
|
||||
}
|
||||
|
||||
func NewGame() *Game {
|
||||
game := &Game{
|
||||
Width: 796,
|
||||
Height: 448,
|
||||
}
|
||||
|
||||
game.Init()
|
||||
|
||||
return game
|
||||
}
|
||||
|
||||
func (g *Game) Init() {
|
||||
const mapSize = 128
|
||||
|
||||
// Create a new Scene and name it.
|
||||
g.Scene = tetra3d.NewScene("mainScene")
|
||||
|
||||
// Turn off lighting.
|
||||
g.Scene.World.LightingOn = true
|
||||
|
||||
g.truck = &garbageTruck{
|
||||
x: 5,
|
||||
y: 5,
|
||||
}
|
||||
|
||||
// Top
|
||||
light := tetra3d.NewDirectionalLight("camera light", 1, 1, 1, 1.0)
|
||||
light.Move(0, 14, 0)
|
||||
light.Rotate(1, 0, 0, -math.Pi/2)
|
||||
//light.Move(0, 1, -2)
|
||||
light.On = true
|
||||
g.Scene.Root.AddChildren(light)
|
||||
|
||||
const (
|
||||
sideBrightness = 0.8
|
||||
backBrightness = 0.6
|
||||
frontBrightness = 1.0
|
||||
)
|
||||
|
||||
{
|
||||
// Left side
|
||||
//l := tetra3d.NewDirectionalLight("", 1, 1, 1, 0.6)
|
||||
l := tetra3d.NewDirectionalLight("", 1, 1, 1, sideBrightness)
|
||||
l.Move(0, 14, 0)
|
||||
l.Rotate(1, 0, 0, -math.Pi/2)
|
||||
l.Rotate(0, 1, 0, -math.Pi/2)
|
||||
//light.Move(0, 1, -2)
|
||||
l.On = true
|
||||
g.Scene.Root.AddChildren(l)
|
||||
}
|
||||
{
|
||||
// Right side
|
||||
l := tetra3d.NewDirectionalLight("", 1, 1, 1, sideBrightness)
|
||||
l.Move(0, 14, 0)
|
||||
l.Rotate(1, 0, 0, -math.Pi/2)
|
||||
l.Rotate(0, 1, 0, math.Pi/2)
|
||||
//light.Move(0, 1, -2)
|
||||
l.On = true
|
||||
g.Scene.Root.AddChildren(l)
|
||||
}
|
||||
{
|
||||
// Back side
|
||||
l := tetra3d.NewDirectionalLight("", 1, 1, 1, backBrightness)
|
||||
l.Move(0, 14, 0)
|
||||
l.Rotate(1, 0, 0, -math.Pi/2)
|
||||
l.Rotate(1, 0, 0, -math.Pi/2)
|
||||
//light.Move(0, 1, -2)
|
||||
l.On = true
|
||||
g.Scene.Root.AddChildren(l)
|
||||
}
|
||||
{
|
||||
// Front side
|
||||
l := tetra3d.NewDirectionalLight("", 1, 1, 1, frontBrightness)
|
||||
l.Move(0, 14, 0)
|
||||
l.Rotate(1, 0, 0, -math.Pi/2)
|
||||
l.Rotate(1, 0, 0, math.Pi/2)
|
||||
//light.Move(0, 1, -2)
|
||||
l.On = true
|
||||
g.Scene.Root.AddChildren(l)
|
||||
}
|
||||
|
||||
const planeSize = 10000
|
||||
|
||||
{
|
||||
plane := tetra3d.NewModel(tetra3d.NewPlaneMesh(2, 2), "plane")
|
||||
plane.Color.Set(40.0/255.0, 40.0/255.0, 40.0/255.0, 1)
|
||||
plane.Grow(planeSize, 0, planeSize)
|
||||
g.Scene.Root.AddChildren(plane)
|
||||
}
|
||||
|
||||
// Create a cube, set the color, add it to the scene.
|
||||
buildingScale := 2.5
|
||||
buildingSize := 7.0
|
||||
|
||||
addPlane := func(x float64, y float64, z float64, colorR float32, colorG float32, colorB float32) *tetra3d.Model {
|
||||
if colorR == -1 {
|
||||
for {
|
||||
colorR, colorG, colorB = float32(rand.Intn(256))/255.0, float32(rand.Intn(256))/255.0, float32(rand.Intn(256))/255.0
|
||||
if colorR >= 0.5 || colorG >= 0.5 || colorB >= 0.5 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
p := tetra3d.NewPlaneMesh(4, 4)
|
||||
plane := tetra3d.NewModel(p, "")
|
||||
plane.Color.Set(colorR, colorG, colorB, 1)
|
||||
plane.Move(x, y, z)
|
||||
//plane.Move(0, 0, +buildingSize/2)
|
||||
|
||||
g.Scene.Root.AddChildren(plane)
|
||||
return plane
|
||||
}
|
||||
|
||||
addCube := func(x float64, y float64, z float64, colorR float32, colorG float32, colorB float32) {
|
||||
if colorR == -1 {
|
||||
colorR, colorG, colorB = float32(rand.Intn(256))/255.0, float32(rand.Intn(256))/255.0, float32(rand.Intn(256))/255.0
|
||||
}
|
||||
|
||||
c := tetra3d.NewCubeMesh()
|
||||
cube := tetra3d.NewModel(c, "")
|
||||
|
||||
cube.Color.Set(colorR, colorG, colorB, 1)
|
||||
|
||||
//cube.Color.Set(117.0/255.0, 79.0/255.0, 8.0/255.0, 1)
|
||||
|
||||
cube.Move(x, y, z)
|
||||
cube.Grow(buildingScale, 7, buildingScale)
|
||||
//cube.SetWorldScale(2, 3.5, 2)
|
||||
cube.Move(0, 12, 0)
|
||||
|
||||
g.Scene.Root.AddChildren(cube)
|
||||
}
|
||||
|
||||
// Add bounding area walls.
|
||||
for x := 0.0; x < 10; x++ {
|
||||
{
|
||||
// Front.
|
||||
plane := addPlane(x*buildingSize, 0, 0, -1, -1, -1)
|
||||
plane.Grow(buildingScale*2.4, 0, buildingScale*10)
|
||||
plane.Move(buildingSize/2, 0, 0)
|
||||
plane.Rotate(1, 0, 0, math.Pi/2)
|
||||
}
|
||||
|
||||
{
|
||||
// Back.
|
||||
//plane := addPlane(x*buildingSize, 0, mapSize*buildingSize, -1, -1, -1)
|
||||
//plane.Rotate(1, 0, 0, -math.Pi/2)
|
||||
}
|
||||
}
|
||||
for y := 0.0; y < 10; y++ {
|
||||
{
|
||||
// Left.
|
||||
plane := addPlane(0, 0, y*buildingSize, -1, -1, -1)
|
||||
plane.Grow(buildingScale*10, 0, buildingScale*2.4)
|
||||
plane.Move(0, 0, buildingSize/2)
|
||||
plane.Rotate(0, 0, 1, -math.Pi/2)
|
||||
}
|
||||
|
||||
{
|
||||
// Right.
|
||||
//plane := addPlane(x*buildingSize, 0, mapSize*buildingSize, -1, -1, -1)
|
||||
//plane.Rotate(1, 0, 0, -math.Pi/2)
|
||||
}
|
||||
}
|
||||
|
||||
buildingSpacing := 10.5
|
||||
_ = buildingSpacing
|
||||
|
||||
// Second set.
|
||||
for y := 0.0; y < 10; y++ {
|
||||
{
|
||||
// Left.
|
||||
}
|
||||
|
||||
{
|
||||
// Right.
|
||||
plane := addPlane(buildingSize*1, 0, (y+1)*buildingSize, -1, -1, -1)
|
||||
plane.Grow(buildingScale*10, 0, buildingScale*2.4)
|
||||
plane.Move(0, 0, buildingSize/2)
|
||||
plane.Rotate(0, 0, 1, math.Pi/2)
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
plane := addPlane(buildingSize*1, 0, buildingSize*1, -1, -1, -1)
|
||||
plane.Grow(buildingScale*2.4, 0, buildingScale*10)
|
||||
plane.Move(buildingSize/2, 0, 0)
|
||||
plane.Rotate(1, 0, 0, -math.Pi/2)
|
||||
}
|
||||
{
|
||||
plane := addPlane(buildingSize*2, 0, buildingSize*1, -1, -1, -1)
|
||||
plane.Grow(buildingScale*2.4, 0, buildingScale*10)
|
||||
plane.Move(buildingSize/2, 0, 0)
|
||||
plane.Rotate(1, 0, 0, -math.Pi/2)
|
||||
}
|
||||
{
|
||||
plane := addPlane(buildingSize*3, 0, buildingSize*1, -1, -1, -1)
|
||||
plane.Grow(buildingScale*2.4, 0, buildingScale*10)
|
||||
plane.Move(buildingSize/2, 0, 0)
|
||||
plane.Rotate(1, 0, 0, -math.Pi/2)
|
||||
}
|
||||
|
||||
_ = addCube
|
||||
/* for y := 0.0; y < 10; y++ {
|
||||
addCube(buildingSpacing*1, 0, buildingSpacing*1+y*buildingSize, -1, -1, -1)
|
||||
}
|
||||
*/
|
||||
// Add inner-city buildings.
|
||||
/*for x := 0; x < 10; x++ {
|
||||
for y := 0; y < 10; y++ {
|
||||
addCube(float64(x)*buildingSize, 0, float64(y)*buildingSize, -1, -1, -1)
|
||||
}
|
||||
|
||||
}*/
|
||||
|
||||
// Garbage truck.
|
||||
{
|
||||
{
|
||||
mesh := tetra3d.NewCubeMesh()
|
||||
model := tetra3d.NewModel(mesh, "")
|
||||
model.Color = tetra3d.NewColor(0.12, 0.44, 0.24, 1)
|
||||
model.Grow(-0.75, -0.25, -0.3)
|
||||
|
||||
g.truck.Model = model
|
||||
g.Scene.Root.AddChildren(g.truck.Model)
|
||||
}
|
||||
|
||||
const (
|
||||
lightX = 0.55
|
||||
headlightDistance = 0.85
|
||||
headlightShade = float32(0.75)
|
||||
)
|
||||
|
||||
// Headlights.
|
||||
{
|
||||
model := tetra3d.NewModel(tetra3d.NewCubeMesh(), "")
|
||||
model.Color = tetra3d.NewColor(headlightShade, headlightShade, headlightShade, 1)
|
||||
model.Grow(-0.75, -0.75, -0.75)
|
||||
model.Move(lightX, 0, headlightDistance)
|
||||
g.truck.Model.AddChildren(model)
|
||||
}
|
||||
{
|
||||
model := tetra3d.NewModel(tetra3d.NewCubeMesh(), "")
|
||||
model.Color = tetra3d.NewColor(headlightShade, headlightShade, headlightShade, 1)
|
||||
model.Grow(-0.75, -0.75, -0.75)
|
||||
model.Move(-lightX, 0, headlightDistance)
|
||||
g.truck.Model.AddChildren(model)
|
||||
}
|
||||
|
||||
// Brake lights.
|
||||
{
|
||||
model := tetra3d.NewModel(tetra3d.NewCubeMesh(), "")
|
||||
model.Color = tetra3d.NewColor(0.6, 0, 0, 1)
|
||||
model.Grow(-0.75, -0.75, -0.75)
|
||||
model.Move(lightX, 0, -0.85)
|
||||
g.truck.Model.AddChildren(model)
|
||||
}
|
||||
{
|
||||
model := tetra3d.NewModel(tetra3d.NewCubeMesh(), "")
|
||||
model.Color = tetra3d.NewColor(0.6, 0, 0, 1)
|
||||
model.Grow(-0.75, -0.75, -0.75)
|
||||
model.Move(-lightX, 0, -0.85)
|
||||
g.truck.Model.AddChildren(model)
|
||||
}
|
||||
}
|
||||
|
||||
// Create a camera, move it back.
|
||||
g.Camera = tetra3d.NewCamera(g.Width, g.Height)
|
||||
g.Camera.Move(0, 12, 0)
|
||||
g.Camera.Rotate(1, 0, 0, -math.Pi/2)
|
||||
g.Scene.Root.AddChildren(g.Camera)
|
||||
|
||||
}
|
||||
|
||||
func (g *Game) Update() error {
|
||||
if ebiten.IsWindowBeingClosed() {
|
||||
os.Exit(0)
|
||||
return nil
|
||||
}
|
||||
|
||||
if !g.wasm && ebiten.IsKeyPressed(ebiten.KeyEscape) {
|
||||
os.Exit(0)
|
||||
return nil
|
||||
}
|
||||
|
||||
if inpututil.IsKeyJustPressed(ebiten.KeyV) && ebiten.IsKeyPressed(ebiten.KeyControl) && ebiten.IsKeyPressed(ebiten.KeyShift) {
|
||||
g.debug++
|
||||
if g.debug > 1 {
|
||||
g.debug = 0
|
||||
}
|
||||
}
|
||||
|
||||
const moveSize = 1
|
||||
moveX, moveY := 0, 0
|
||||
if ebiten.IsKeyPressed(ebiten.KeyLeft) || ebiten.IsKeyPressed(ebiten.KeyA) {
|
||||
moveX -= moveSize
|
||||
}
|
||||
if ebiten.IsKeyPressed(ebiten.KeyRight) || ebiten.IsKeyPressed(ebiten.KeyD) {
|
||||
moveX += moveSize
|
||||
}
|
||||
if ebiten.IsKeyPressed(ebiten.KeyUp) || ebiten.IsKeyPressed(ebiten.KeyW) {
|
||||
moveY -= moveSize
|
||||
}
|
||||
if ebiten.IsKeyPressed(ebiten.KeyDown) || ebiten.IsKeyPressed(ebiten.KeyS) {
|
||||
moveY += moveSize
|
||||
}
|
||||
braking := ebiten.IsKeyPressed(ebiten.KeySpace)
|
||||
|
||||
// Update truck.
|
||||
t := g.truck
|
||||
t.MoveX, t.MoveY, t.Braking = moveX, moveY, braking
|
||||
t.Update()
|
||||
|
||||
// Move truck model and camera.
|
||||
g.truck.Model.SetLocalPosition(t.x, g.truck.Model.LocalPosition().Y, t.y)
|
||||
g.truck.Model.SetLocalRotation(tetra3d.NewMatrix4().Rotated(0, 1, 0, -t.angle+math.Pi))
|
||||
g.Camera.SetLocalPosition(t.x, g.Camera.LocalPosition().Y, t.y)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *Game) Draw(screen *ebiten.Image) {
|
||||
// Clear the screen with a color.
|
||||
screen.Fill(color.RGBA{60, 70, 80, 255})
|
||||
|
||||
// Clear the Camera.
|
||||
g.Camera.Clear()
|
||||
|
||||
// Render the scene.
|
||||
g.Camera.RenderScene(g.Scene)
|
||||
|
||||
// Draw the resulting color texture.
|
||||
screen.DrawImage(g.Camera.ColorTexture(), nil)
|
||||
|
||||
if g.debug > 0 {
|
||||
// Print twice to increase shadow.
|
||||
for i := 0; i < 2; i++ {
|
||||
ebitenutil.DebugPrintAt(screen, fmt.Sprintf("FPS %.0f\nTPS %.0f", ebiten.ActualFPS(), ebiten.ActualTPS()), 1, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Game) Layout(w, h int) (int, int) {
|
||||
// This is a fixed aspect ratio; we can change this to, say, extend for wider displays by using the provided w argument and
|
||||
// calculating the height from the aspect ratio, then calling Camera.Resize() with the new width and height.
|
||||
return g.Width, g.Height
|
||||
}
|
||||
|
||||
func main() {
|
||||
ebiten.SetWindowTitle("Garbage Day")
|
||||
ebiten.SetRunnableOnUnfocused(true)
|
||||
|
|
70
maze.go
Normal file
70
maze.go
Normal file
|
@ -0,0 +1,70 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"math/rand"
|
||||
)
|
||||
|
||||
// The code for generating mazes was copied and adapted from the following page:
|
||||
// https://stackoverflow.com/questions/75563271/stuck-on-recursive-division-maze
|
||||
|
||||
func fillMazeRow(grid [][]bool, row, left, right int) {
|
||||
for left <= right {
|
||||
grid[row][left] = true
|
||||
left++
|
||||
}
|
||||
}
|
||||
|
||||
func fillMazeCol(grid [][]bool, col, top, bottom int) {
|
||||
for top <= bottom {
|
||||
grid[top][col] = true
|
||||
top++
|
||||
}
|
||||
}
|
||||
|
||||
func divideMaze(grid [][]bool, top, bottom, left, right int) {
|
||||
// Check base case: if just one corridor, then there's nothing to divide
|
||||
if bottom-top <= 2 || right-left <= 2 {
|
||||
return
|
||||
}
|
||||
// Make the probability equal for all possible dividing-wall positions
|
||||
// irrespective of their direction.
|
||||
// A wall is always at an even index, not 0
|
||||
choice := rand.Intn((bottom-top+right-left)/2-2)*2 + 2
|
||||
if choice >= bottom-top { // The wall will be vertical
|
||||
splitCol := choice - (bottom - top) + left + 2
|
||||
fillMazeCol(grid, splitCol, top, bottom)
|
||||
// Create a hole (always at an odd index):
|
||||
grid[rand.Intn((bottom-top)/2)*2+1+top][splitCol] = false
|
||||
// Recur on the two created areas
|
||||
divideMaze(grid, top, bottom, left, splitCol)
|
||||
divideMaze(grid, top, bottom, splitCol, right)
|
||||
} else { // The wall will be horizontal
|
||||
splitRow := choice + top
|
||||
fillMazeRow(grid, splitRow, left, right)
|
||||
// Create a hole (always at an odd index):
|
||||
grid[splitRow][rand.Intn((right-left)/2)*2+1+left] = false
|
||||
// Recur on the two created areas
|
||||
divideMaze(grid, top, splitRow, left, right)
|
||||
divideMaze(grid, splitRow, bottom, left, right)
|
||||
}
|
||||
}
|
||||
|
||||
func newMaze(width, height int) [][]bool {
|
||||
if (height-2)%2 != 1 || (width-2)%2 != 1 {
|
||||
log.Fatal("Grid dimensions should be odd and greater than 1")
|
||||
}
|
||||
// Create grid with no walls
|
||||
grid := make([][]bool, height)
|
||||
for y := range grid {
|
||||
grid[y] = make([]bool, width)
|
||||
}
|
||||
// Build surrounding walls
|
||||
fillMazeRow(grid, 0, 0, width-1)
|
||||
fillMazeRow(grid, height-1, 0, width-1)
|
||||
fillMazeCol(grid, 0, 0, height-1)
|
||||
fillMazeCol(grid, width-1, 0, height-1)
|
||||
// Main algorithm
|
||||
divideMaze(grid, 0, height-1, 0, width-1)
|
||||
return grid
|
||||
}
|
Loading…
Reference in a new issue