package game import ( "gitea.boner.be/bdnugget/goonscape/assets" "gitea.boner.be/bdnugget/goonscape/types" pb "gitea.boner.be/bdnugget/goonserver/actions" rl "github.com/gen2brain/raylib-go/raylib" ) type Game struct { Player *types.Player OtherPlayers map[int32]*types.Player Camera rl.Camera3D Models []types.ModelAsset Music rl.Music } func New() *Game { InitWorld() game := &Game{ Player: &types.Player{ PosActual: rl.NewVector3(5*types.TileSize, 0, 5*types.TileSize), PosTile: GetTile(5, 5), Speed: 50.0, TargetPath: []types.Tile{}, }, OtherPlayers: make(map[int32]*types.Player), Camera: rl.Camera3D{ Position: rl.NewVector3(0, 10, 10), Target: rl.NewVector3(0, 0, 0), Up: rl.NewVector3(0, 1, 0), Fovy: 45.0, Projection: rl.CameraPerspective, }, } return game } func (g *Game) LoadAssets() error { var err error g.Models, err = assets.LoadModels() if err != nil { return err } g.Music, err = assets.LoadMusic("resources/audio/GoonScape2.mp3") if err != nil { return err } return nil } func (g *Game) Update(deltaTime float32) { g.HandleInput() if len(g.Player.TargetPath) > 0 { g.Player.MoveTowards(g.Player.TargetPath[0], deltaTime, GetMapGrid()) } for _, other := range g.OtherPlayers { if len(other.TargetPath) > 0 { other.MoveTowards(other.TargetPath[0], deltaTime, GetMapGrid()) } } UpdateCamera(&g.Camera, g.Player.PosActual, deltaTime) } func (g *Game) DrawMap() { for x := 0; x < types.MapWidth; x++ { for y := 0; y < types.MapHeight; y++ { height := GetTileHeight(x, y) // Interpolate height for smoother landscape if x > 0 { height += GetTileHeight(x-1, y) } if y > 0 { height += GetTileHeight(x, y-1) } if x > 0 && y > 0 { height += GetTileHeight(x-1, y-1) } height /= 4.0 tilePos := rl.Vector3{ X: float32(x * types.TileSize), Y: height * types.TileHeight, Z: float32(y * types.TileSize), } color := rl.Color{R: uint8(height * 25), G: 100, B: 100, A: 64} rl.DrawCube(tilePos, types.TileSize, types.TileHeight, types.TileSize, color) } } } func (g *Game) DrawPlayer(player *types.Player, model rl.Model) { player.Lock() defer player.Unlock() grid := GetMapGrid() playerPos := rl.Vector3{ X: player.PosActual.X, Y: grid[player.PosTile.X][player.PosTile.Y].Height*types.TileHeight + 16.0, Z: player.PosActual.Z, } rl.DrawModel(model, playerPos, 16, rl.White) if len(player.TargetPath) > 0 { targetTile := player.TargetPath[len(player.TargetPath)-1] targetPos := rl.Vector3{ X: float32(targetTile.X * types.TileSize), Y: grid[targetTile.X][targetTile.Y].Height * types.TileHeight, Z: float32(targetTile.Y * types.TileSize), } rl.DrawCubeWires(targetPos, types.TileSize, types.TileHeight, types.TileSize, rl.Green) nextTile := player.TargetPath[0] nextPos := rl.Vector3{ X: float32(nextTile.X * types.TileSize), Y: grid[nextTile.X][nextTile.Y].Height * types.TileHeight, Z: float32(nextTile.Y * types.TileSize), } rl.DrawCubeWires(nextPos, types.TileSize, types.TileHeight, types.TileSize, rl.Yellow) } } func (g *Game) Render() { rl.BeginDrawing() rl.ClearBackground(rl.RayWhite) rl.BeginMode3D(g.Camera) g.DrawMap() g.DrawPlayer(g.Player, g.Player.Model) for id, other := range g.OtherPlayers { g.DrawPlayer(other, g.Models[int(id)%len(g.Models)].Model) } rl.EndMode3D() rl.DrawFPS(10, 10) rl.EndDrawing() } func (g *Game) Cleanup() { assets.UnloadModels(g.Models) assets.UnloadMusic(g.Music) } func (g *Game) HandleInput() { clickedTile, clicked := g.GetTileAtMouse() if clicked { path := FindPath(GetTile(g.Player.PosTile.X, g.Player.PosTile.Y), clickedTile) if path != nil && len(path) > 1 { g.Player.Lock() g.Player.TargetPath = path[1:] g.Player.ActionQueue = append(g.Player.ActionQueue, &pb.Action{ Type: pb.Action_MOVE, X: int32(clickedTile.X), Y: int32(clickedTile.Y), PlayerId: g.Player.ID, }) g.Player.Unlock() } } }