package main import ( "fmt" "gridpathingtest/sauce" "image/color" "math" "github.com/hajimehoshi/ebiten/v2" "github.com/hajimehoshi/ebiten/v2/ebitenutil" "github.com/hajimehoshi/ebiten/v2/inpututil" "github.com/hajimehoshi/ebiten/v2/vector" "github.com/tinne26/etxt" "github.com/tinne26/fonts/liberation/lbrtserif" ) var ( txt *etxt.Renderer ) const ( CellSize = 20 ) type Game struct { world *sauce.World cellX, cellY int fromX, fromY int toX, toY int path []sauce.Node pathSuccess bool whichFromTo bool } func NewGame() *Game { g := &Game{} g.world = sauce.NewWorld(3, 3) g.world.HueristicLine(10, 0, 10, 10, 1) g.world.HueristicLine(10, 13, 10, 30, 1) g.fromX = -1 g.fromY = -1 g.toX = -1 g.toY = -1 return g } var ( lastOutsideWidth int lastOutsideHeight int lastScreenWidth int lastScreenHeight int ) func (g *Game) Layout(outsideWidth, outsideHeight int) (screenWidth, screenHeight int) { if lastOutsideWidth == outsideWidth && lastOutsideHeight == outsideHeight { return lastScreenWidth, lastScreenHeight } lastOutsideWidth = outsideWidth lastOutsideHeight = outsideHeight scale := ebiten.DeviceScaleFactor() txt.SetScale(scale) lastScreenWidth, lastScreenHeight = int(math.Ceil(float64(outsideWidth)*scale)), int(math.Ceil(float64(outsideHeight)*scale)) return lastScreenWidth, lastScreenHeight } func (g *Game) Update() error { cursorX, cursorY := ebiten.CursorPosition() g.cellX = cursorX / CellSize g.cellY = cursorY / CellSize if cell := g.world.At(g.cellX, g.cellY); cell != nil { var reroll bool if inpututil.IsMouseButtonJustPressed(ebiten.MouseButtonLeft) { cell.Hueristic++ reroll = true } else if inpututil.IsMouseButtonJustPressed(ebiten.MouseButtonRight) { cell.Hueristic-- reroll = true } else if inpututil.IsMouseButtonJustPressed(ebiten.MouseButtonMiddle) { if !g.whichFromTo { g.fromX, g.fromY = g.cellX, g.cellY } else { g.toX, g.toY = g.cellX, g.cellY } g.whichFromTo = !g.whichFromTo reroll = true } if reroll { if g.fromX != -1 && g.fromY != -1 && g.toX != -1 && g.toY != -1 { g.path, g.pathSuccess = sauce.FindPath(g.world, g.fromX, g.fromY, g.toX, g.toY) } } } return nil } func (g *Game) Draw(screen *ebiten.Image) { for i, chunk := range g.world.Chunks { cx, cy := float32(chunk.X*CellSize), float32(chunk.Y*CellSize) c := color.NRGBA{255, 255, 255, 255} c.G = 255 - uint8(i*100/len(g.world.Chunks)) for x := 0; x < chunk.Width(); x++ { for y := 0; y < chunk.Height(); y++ { cell := chunk.At(x, y) if cell == nil { continue } px := cx + float32(x*CellSize) py := cy + float32(y*CellSize) c.A = 255 - cell.Hueristic*255/10 if g.cellX == chunk.X+x && g.cellY == chunk.Y+y { c.R = 0 c.B = 0 } else { c.R = 255 c.B = 255 c.G = 255 - uint8(i*100/len(g.world.Chunks)) } if g.fromX == chunk.X+x && g.fromY == chunk.Y+y { c.R = 0 c.G = 0 } if g.toX == chunk.X+x && g.toY == chunk.Y+y { c.B = 0 c.G = 0 } vector.DrawFilledRect(screen, px, py, CellSize, CellSize, c, false) vector.StrokeRect(screen, px, py, CellSize, CellSize, 1, color.Black, false) s := fmt.Sprintf("%d", cell.Hueristic) txt.Draw(screen, s, int(px+CellSize/2), int(py+CellSize/2)) } } } // Draw path dots overtop. for _, node := range g.path { x := node.X*CellSize + CellSize/2 y := node.Y*CellSize + CellSize/2 c := color.RGBA{0, 255, 0, 255} if !g.pathSuccess { c = color.RGBA{255, 0, 0, 255} } vector.DrawFilledCircle(screen, float32(x), float32(y), 5, c, false) } ebitenutil.DebugPrint(screen, fmt.Sprintf("TPS: %0.2f\nFPS: %0.2f", ebiten.ActualTPS(), ebiten.ActualFPS())) } func main() { g := NewGame() txt = etxt.NewRenderer() txt.SetFont(lbrtserif.Font()) txt.Utils().SetCache8MiB() txt.SetColor(color.Black) txt.SetAlign(etxt.Center) txt.SetSize(12) ebiten.SetWindowSize(1280, 720) if err := ebiten.RunGameWithOptions(g, &ebiten.RunGameOptions{ GraphicsLibrary: ebiten.GraphicsLibraryOpenGL, }); err != nil { panic(err) } }