goonscape/main.go

264 lines
6.0 KiB
Go
Raw Normal View History

2024-09-30 10:04:38 +02:00
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()
}
}