diff --git a/go.mod b/go.mod index 570b668..59b3467 100644 --- a/go.mod +++ b/go.mod @@ -2,9 +2,10 @@ module goonscape go 1.23.0 +require github.com/gen2brain/raylib-go/raylib v0.0.0-20240916050633-6bc3d79c96ad + require ( - github.com/ebitengine/purego v0.8.0 // indirect - github.com/gen2brain/raylib-go/raylib v0.0.0-20240916050633-6bc3d79c96ad // indirect - golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect - golang.org/x/sys v0.25.0 // indirect + github.com/ebitengine/purego v0.7.1 // indirect + golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect + golang.org/x/sys v0.20.0 // indirect ) diff --git a/go.sum b/go.sum index 6bc069b..97afe30 100644 --- a/go.sum +++ b/go.sum @@ -1,8 +1,8 @@ -github.com/ebitengine/purego v0.8.0 h1:JbqvnEzRvPpxhCJzJJ2y0RbiZ8nyjccVUrSM3q+GvvE= -github.com/ebitengine/purego v0.8.0/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= +github.com/ebitengine/purego v0.7.1 h1:6/55d26lG3o9VCZX8lping+bZcmShseiqlh2bnUDiPA= +github.com/ebitengine/purego v0.7.1/go.mod h1:ah1In8AOtksoNK6yk5z1HTJeUkC1Ez4Wk2idgGslMwQ= github.com/gen2brain/raylib-go/raylib v0.0.0-20240916050633-6bc3d79c96ad h1:kmIjqc2wOOn+MXw/pyuoYhhzfRFsZ+ESfkMWVt+WE7Y= github.com/gen2brain/raylib-go/raylib v0.0.0-20240916050633-6bc3d79c96ad/go.mod h1:BaY76bZk7nw1/kVOSQObPY1v1iwVE1KHAGMfvI6oK1Q= -golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk= -golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY= -golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= -golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM= +golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= +golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= diff --git a/main.go b/main.go index e69de29..76c67b1 100644 --- a/main.go +++ b/main.go @@ -0,0 +1,263 @@ +package main + +import ( + "math" + + rl "github.com/gen2brain/raylib-go/raylib" +) + +type Tile struct { + X, Y int + Height float32 + Walkable bool +} + +const ( + MapWidth = 100 + MapHeight = 100 + TileSize = 32 +) + +// Initialize the map with some height data +func InitMap() [][]Tile { + mapGrid := make([][]Tile, MapWidth) + for x := 0; x < MapWidth; x++ { + mapGrid[x] = make([]Tile, MapHeight) + for y := 0; y < MapHeight; y++ { + mapGrid[x][y] = Tile{ + X: x, + Y: y, + Height: float32((x + y) % 10), // Example height + Walkable: true, // Set to false for obstacles + } + } + } + return mapGrid +} + +type Player struct { + X, Y int // Current tile position + PosX, PosY float32 // Actual position for smooth movement + TargetPath []Tile + Speed float32 +} + +func DrawMap(mapGrid [][]Tile) { + for x := 0; x < MapWidth; x++ { + for y := 0; y < MapHeight; y++ { + tile := mapGrid[x][y] + // Simple top-down view: color based on height + color := rl.Color{R: uint8(tile.Height * 25), G: 100, B: 100, A: 255} + rl.DrawRectangle(int32(tile.X*TileSize), int32(tile.Y*TileSize-int(tile.Height)), TileSize, TileSize, color) + } + } +} + +func DrawPlayer(player Player, mapGrid [][]Tile) { + // Get current tile height + currentTile := mapGrid[player.X][player.Y] + // Draw player at PosX, PosY adjusted by height + rl.DrawCircle(int32(player.PosX), int32(player.PosY-currentTile.Height), 10, rl.Red) +} + +func GetTileAtMouse(mapGrid [][]Tile) (Tile, bool) { + if !rl.IsMouseButtonPressed(rl.MouseLeftButton) { + return Tile{}, false + } + mouseX := rl.GetMouseX() + mouseY := rl.GetMouseY() + tileX := mouseX / TileSize + tileY := (mouseY + int32(mapGrid[tileX][0].Height)) / TileSize + if tileX >= 0 && tileX < MapWidth && tileY >= 0 && tileY < MapHeight { + return mapGrid[tileX][tileY], true + } + return Tile{}, false +} + +// pathfinding +type Node struct { + Tile Tile + Parent *Node + G, H, F float32 +} + +func FindPath(mapGrid [][]Tile, start, end Tile) []Tile { + openList := []*Node{} + closedList := make(map[[2]int]bool) + + startNode := &Node{Tile: start, G: 0, H: heuristic(start, end)} + startNode.F = startNode.G + startNode.H + openList = append(openList, startNode) + + for len(openList) > 0 { + // Find node with lowest F + current := openList[0] + currentIndex := 0 + for i, node := range openList { + if node.F < current.F { + current = node + currentIndex = i + } + } + + // Move current to closed list + openList = append(openList[:currentIndex], openList[currentIndex+1:]...) + closedList[[2]int{current.Tile.X, current.Tile.Y}] = true + + // Check if reached the end + if current.Tile.X == end.X && current.Tile.Y == end.Y { + path := []Tile{} + node := current + for node != nil { + path = append([]Tile{node.Tile}, path...) + node = node.Parent + } + return path + } + + // Generate neighbors + neighbors := GetNeighbors(mapGrid, current.Tile) + for _, neighbor := range neighbors { + if !neighbor.Walkable || closedList[[2]int{neighbor.X, neighbor.Y}] { + continue + } + + tentativeG := current.G + distance(current.Tile, neighbor) + inOpen := false + var existingNode *Node + for _, node := range openList { + if node.Tile.X == neighbor.X && node.Tile.Y == neighbor.Y { + existingNode = node + inOpen = true + break + } + } + + if !inOpen || tentativeG < existingNode.G { + newNode := &Node{ + Tile: neighbor, + Parent: current, + G: tentativeG, + H: heuristic(neighbor, end), + } + newNode.F = newNode.G + newNode.H + if !inOpen { + openList = append(openList, newNode) + } + } + } + } + + // No path found + return nil +} + +func heuristic(a, b Tile) float32 { + return float32(abs(a.X-b.X) + abs(a.Y-b.Y)) +} + +func distance(a, b Tile) float32 { + _ = a + _ = b + return 1.0 //uniform cost for now +} + +func GetNeighbors(mapGrid [][]Tile, tile Tile) []Tile { + directions := [][2]int{ + {1, 0}, {-1, 0}, {0, 1}, {0, -1}, + {1, 1}, {-1, -1}, {1, -1}, {-1, 1}, + } + neighbors := []Tile{} + for _, dir := range directions { + nx, ny := tile.X+dir[0], tile.Y+dir[1] + if nx >= 0 && nx < MapWidth && ny >= 0 && ny < MapHeight { + neighbors = append(neighbors, mapGrid[nx][ny]) + } + } + return neighbors +} + +func abs(x int) int { + if x < 0 { + return -x + } + return x +} + +// end pathfinding + +func UpdatePlayer(player *Player, deltaTime float32, mapGrid [][]Tile) { + if len(player.TargetPath) > 0 { + targetTile := player.TargetPath[0] + targetX := float32(targetTile.X * TileSize) + targetY := float32(targetTile.Y*TileSize - int(targetTile.Height)) + + // Calculate direction + dirX := targetX - player.PosX + dirY := targetY - player.PosY + distance := float32(math.Sqrt(float64(dirX*dirX + dirY*dirY))) + + if distance < player.Speed*deltaTime { + // Snap to target tile + player.PosX = targetX + player.PosY = targetY + player.X = targetTile.X + player.Y = targetTile.Y + // Remove the reached tile from the path + player.TargetPath = player.TargetPath[1:] + } else { + // Move towards target + player.PosX += (dirX / distance) * player.Speed * deltaTime + player.PosY += (dirY / distance) * player.Speed * deltaTime + } + } +} + +func HandleInput(player *Player, mapGrid [][]Tile) { + clickedTile, clicked := GetTileAtMouse(mapGrid) + if clicked { + path := FindPath(mapGrid, mapGrid[player.X][player.Y], clickedTile) + if path != nil { + // Exclude the first tile (current position) + if len(path) > 1 { + player.TargetPath = path[1:] + } + } + } +} + +func main() { + rl.InitWindow(800, 600, "RuneScape-like Game") + defer rl.CloseWindow() + + mapGrid := InitMap() + + player := Player{ + X: 10, + Y: 10, + PosX: float32(10 * TileSize), + PosY: float32(10*TileSize - int(mapGrid[10][10].Height)), + Speed: 100.0, // pixels per second + } + + rl.SetTargetFPS(60) + + for !rl.WindowShouldClose() { + deltaTime := rl.GetFrameTime() + + // Handle input + HandleInput(&player, mapGrid) + + // Update player position + UpdatePlayer(&player, deltaTime, mapGrid) + + // Draw everything + rl.BeginDrawing() + rl.ClearBackground(rl.RayWhite) + + DrawMap(mapGrid) + DrawPlayer(player, mapGrid) + + rl.EndDrawing() + } +}