Compare commits
6 Commits
feature/mu
...
develop
Author | SHA1 | Date | |
---|---|---|---|
5c5040cd42 | |||
2b9ece3c10 | |||
4bfb5af362 | |||
c7f7c083b1 | |||
1c42ec2802 | |||
7ab75e8128 |
11
LICENSE
Normal file
11
LICENSE
Normal file
@ -0,0 +1,11 @@
|
||||
“Commons Clause” License Condition v1.0
|
||||
|
||||
The Software is provided to you by the Licensor under the License, as defined below, subject to the following condition.
|
||||
|
||||
Without limiting other conditions in the License, the grant of rights under the License will not include, and the License does not grant to you, right to Sell the Software.
|
||||
|
||||
For purposes of the foregoing, “Sell” means practicing any or all of the rights granted to you under the License to provide to third parties, for a fee or other consideration (including without limitation fees for hosting or consulting/ support services related to the Software), a product or service whose value derives, entirely or substantially, from the functionality of the Software. Any license notice or attribution required by the License must also include this Commons Cause License Condition notice.
|
||||
|
||||
Software: GoonScape
|
||||
License: Commons Clause v1.0
|
||||
Licensor: bdnugget
|
54
camera.go
Normal file
54
camera.go
Normal file
@ -0,0 +1,54 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"math"
|
||||
|
||||
rl "github.com/gen2brain/raylib-go/raylib"
|
||||
)
|
||||
|
||||
func UpdateCamera(camera *rl.Camera3D, player rl.Vector3, deltaTime float32) {
|
||||
// Update camera based on mouse wheel
|
||||
wheelMove := rl.GetMouseWheelMove()
|
||||
if wheelMove != 0 {
|
||||
cameraDistance += -wheelMove * 5
|
||||
if cameraDistance < 10 {
|
||||
cameraDistance = 10
|
||||
}
|
||||
if cameraDistance > 250 {
|
||||
cameraDistance = 250
|
||||
}
|
||||
}
|
||||
|
||||
// Orbit camera around the player using arrow keys
|
||||
if rl.IsKeyDown(rl.KeyRight) {
|
||||
cameraYaw += 100 * deltaTime
|
||||
}
|
||||
if rl.IsKeyDown(rl.KeyLeft) {
|
||||
cameraYaw -= 100 * deltaTime
|
||||
}
|
||||
if rl.IsKeyDown(rl.KeyUp) {
|
||||
cameraPitch -= 50 * deltaTime
|
||||
if cameraPitch < 20 {
|
||||
cameraPitch = 20
|
||||
}
|
||||
}
|
||||
if rl.IsKeyDown(rl.KeyDown) {
|
||||
cameraPitch += 50 * deltaTime
|
||||
if cameraPitch > 85 {
|
||||
cameraPitch = 85
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate the new camera position using spherical coordinates
|
||||
cameraYawRad := float64(cameraYaw) * rl.Deg2rad
|
||||
cameraPitchRad := float64(cameraPitch) * rl.Deg2rad
|
||||
cameraPos := rl.Vector3{
|
||||
X: player.X + cameraDistance*float32(math.Cos(cameraYawRad))*float32(math.Cos(cameraPitchRad)),
|
||||
Y: player.Y + cameraDistance*float32(math.Sin(cameraPitchRad)),
|
||||
Z: player.Z + cameraDistance*float32(math.Sin(cameraYawRad))*float32(math.Cos(cameraPitchRad)),
|
||||
}
|
||||
|
||||
// Update the camera's position and target
|
||||
camera.Position = cameraPos
|
||||
camera.Target = rl.NewVector3(player.X, player.Y, player.Z)
|
||||
}
|
12
constants.go
Normal file
12
constants.go
Normal file
@ -0,0 +1,12 @@
|
||||
package main
|
||||
|
||||
import "time"
|
||||
|
||||
const (
|
||||
MapWidth = 50
|
||||
MapHeight = 50
|
||||
TileSize = 32
|
||||
TileHeight = 2.0
|
||||
TickRate = 2600 * time.Millisecond // Server tick rate (600ms)
|
||||
serverAddr = "localhost:6969"
|
||||
)
|
@ -1 +0,0 @@
|
||||
package utils
|
@ -1 +0,0 @@
|
||||
package utils
|
2
go.mod
2
go.mod
@ -3,7 +3,7 @@ module goonscape
|
||||
go 1.23.0
|
||||
|
||||
require (
|
||||
gitea.boner.be/bdnugget/goonserver v0.0.0-20241011122434-4bd5303cfd46
|
||||
gitea.boner.be/bdnugget/goonserver v0.0.0-20241011195320-f16e8647dc6b
|
||||
github.com/gen2brain/raylib-go/raylib v0.0.0-20240930075631-c66f9e2942fe
|
||||
google.golang.org/protobuf v1.35.1
|
||||
)
|
||||
|
4
go.sum
4
go.sum
@ -1,5 +1,5 @@
|
||||
gitea.boner.be/bdnugget/goonserver v0.0.0-20241011122434-4bd5303cfd46 h1:T2D4QcmvBqzGoHO0VJGNUd1k2lLmUcyg6Rc/vN4/Im8=
|
||||
gitea.boner.be/bdnugget/goonserver v0.0.0-20241011122434-4bd5303cfd46/go.mod h1:inR1bKrr/vcTba+G1KzmmY6vssMq9oGNOk836VwPa4c=
|
||||
gitea.boner.be/bdnugget/goonserver v0.0.0-20241011195320-f16e8647dc6b h1:hdhCZH0YGqCsnSl6ru+8I7rxvCyOj5pCtf92urwyruA=
|
||||
gitea.boner.be/bdnugget/goonserver v0.0.0-20241011195320-f16e8647dc6b/go.mod h1:inR1bKrr/vcTba+G1KzmmY6vssMq9oGNOk836VwPa4c=
|
||||
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/gen2brain/raylib-go/raylib v0.0.0-20240930075631-c66f9e2942fe h1:mInjrbJkUglTM7tBmXG+epnPCE744aj15J7vjJwM4gs=
|
||||
|
88
input.go
Normal file
88
input.go
Normal file
@ -0,0 +1,88 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
rl "github.com/gen2brain/raylib-go/raylib"
|
||||
)
|
||||
|
||||
func GetTileAtMouse(camera *rl.Camera3D) (Tile, bool) {
|
||||
if !rl.IsMouseButtonPressed(rl.MouseLeftButton) {
|
||||
return Tile{}, false
|
||||
}
|
||||
mouse := rl.GetMousePosition()
|
||||
ray := rl.GetMouseRay(mouse, *camera)
|
||||
|
||||
for x := 0; x < MapWidth; x++ {
|
||||
for y := 0; y < MapHeight; y++ {
|
||||
tile := mapGrid[x][y]
|
||||
|
||||
// Define the bounding box for each tile based on its position and height
|
||||
tilePos := rl.NewVector3(float32(x*TileSize), tile.Height*TileHeight, float32(y*TileSize))
|
||||
boxMin := rl.Vector3Subtract(tilePos, rl.NewVector3(TileSize/2, TileHeight/2, TileSize/2))
|
||||
boxMax := rl.Vector3Add(tilePos, rl.NewVector3(TileSize/2, TileHeight/2, TileSize/2))
|
||||
|
||||
// Check if the ray intersects the bounding box
|
||||
if RayIntersectsBox(ray, boxMin, boxMax) {
|
||||
fmt.Println("Clicked:", tile.X, tile.Y)
|
||||
return tile, true
|
||||
}
|
||||
}
|
||||
}
|
||||
return Tile{}, false
|
||||
}
|
||||
|
||||
func HandleInput(player *Player, camera *rl.Camera) {
|
||||
clickedTile, clicked := GetTileAtMouse(camera)
|
||||
if clicked {
|
||||
path := FindPath(mapGrid[player.PosTile.X][player.PosTile.Y], clickedTile)
|
||||
if path != nil {
|
||||
// Exclude the first tile (current position)
|
||||
if len(path) > 1 {
|
||||
player.TargetPath = path[1:]
|
||||
player.ActionQueue = append(player.ActionQueue, Action{Type: MoveAction, X: clickedTile.X, Y: clickedTile.Y})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to test ray-box intersection (slab method)
|
||||
func RayIntersectsBox(ray rl.Ray, boxMin, boxMax rl.Vector3) bool {
|
||||
tmin := (boxMin.X - ray.Position.X) / ray.Direction.X
|
||||
tmax := (boxMax.X - ray.Position.X) / ray.Direction.X
|
||||
|
||||
if tmin > tmax {
|
||||
tmin, tmax = tmax, tmin
|
||||
}
|
||||
|
||||
tymin := (boxMin.Z - ray.Position.Z) / ray.Direction.Z
|
||||
tymax := (boxMax.Z - ray.Position.Z) / ray.Direction.Z
|
||||
|
||||
if tymin > tymax {
|
||||
tymin, tymax = tymax, tymin
|
||||
}
|
||||
|
||||
if (tmin > tymax) || (tymin > tmax) {
|
||||
return false
|
||||
}
|
||||
|
||||
if tymin > tmin {
|
||||
tmin = tymin
|
||||
}
|
||||
if tymax < tmax {
|
||||
tmax = tymax
|
||||
}
|
||||
|
||||
tzmin := (boxMin.Y - ray.Position.Y) / ray.Direction.Y
|
||||
tzmax := (boxMax.Y - ray.Position.Y) / ray.Direction.Y
|
||||
|
||||
if tzmin > tzmax {
|
||||
tzmin, tzmax = tzmax, tzmin
|
||||
}
|
||||
|
||||
if (tmin > tzmax) || (tzmin > tmax) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
529
main.go
529
main.go
@ -1,294 +1,24 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"math"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
pb "gitea.boner.be/bdnugget/goonserver/actions"
|
||||
rl "github.com/gen2brain/raylib-go/raylib"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
const (
|
||||
MapWidth = 50
|
||||
MapHeight = 50
|
||||
TileSize = 32
|
||||
TileHeight = 2.0
|
||||
TickRate = 2600 * time.Millisecond // Server tick rate (600ms)
|
||||
serverAddr = "localhost:6969"
|
||||
)
|
||||
|
||||
var (
|
||||
cameraDistance = float32(20.0)
|
||||
cameraYaw = float32(145.0)
|
||||
cameraPitch = float32(45.0) // Adjusted for a more overhead view
|
||||
mapGrid = InitMap()
|
||||
)
|
||||
|
||||
type Tile struct {
|
||||
X, Y int
|
||||
Height float32
|
||||
Walkable bool
|
||||
}
|
||||
|
||||
type ActionType int
|
||||
|
||||
const (
|
||||
MoveAction ActionType = iota
|
||||
)
|
||||
|
||||
type Action struct {
|
||||
Type ActionType
|
||||
X, Y int // Target position for movement
|
||||
}
|
||||
|
||||
type Player struct {
|
||||
PosActual rl.Vector3
|
||||
PosTile Tile
|
||||
TargetPath []Tile
|
||||
Speed float32
|
||||
ActionQueue []Action // Queue for player actions
|
||||
}
|
||||
|
||||
// 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: 1.0 + float32(x%5), // Example height
|
||||
Walkable: true, // Set to false for obstacles
|
||||
}
|
||||
}
|
||||
}
|
||||
return mapGrid
|
||||
}
|
||||
|
||||
func DrawMap(mapGrid [][]Tile) {
|
||||
for x := 0; x < MapWidth; x++ {
|
||||
for y := 0; y < MapHeight; y++ {
|
||||
tile := mapGrid[x][y]
|
||||
// Interpolate height between adjacent tiles for a smoother landscape
|
||||
height := tile.Height
|
||||
if x > 0 {
|
||||
height += mapGrid[x-1][y].Height
|
||||
}
|
||||
if y > 0 {
|
||||
height += mapGrid[x][y-1].Height
|
||||
}
|
||||
if x > 0 && y > 0 {
|
||||
height += mapGrid[x-1][y-1].Height
|
||||
}
|
||||
height /= 4.0
|
||||
// Draw each tile as a 3D cube based on its height
|
||||
tilePos := rl.Vector3{
|
||||
X: float32(x * TileSize), // X-axis for horizontal position
|
||||
Y: height * TileHeight, // Y-axis for height (Z in 3D is Y here)
|
||||
Z: float32(y * TileSize), // Z-axis for depth (Y in 3D is Z here)
|
||||
}
|
||||
color := rl.Color{R: uint8(height * 25), G: 100, B: 100, A: 64}
|
||||
rl.DrawCube(tilePos, TileSize, TileHeight, TileSize, color) // Draw a cube representing the tile
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func DrawPlayer(player Player, model *rl.Model, mapGrid [][]Tile) {
|
||||
// Draw the player based on its actual position (PosActual) and current tile height
|
||||
playerPos := rl.Vector3{
|
||||
X: player.PosActual.X,
|
||||
Y: mapGrid[player.PosTile.X][player.PosTile.Y].Height*TileHeight + 16.0,
|
||||
Z: player.PosActual.Z,
|
||||
}
|
||||
// rl.DrawCube(playerPos, 16, 16, 16, rl.Green) // Draw player cube
|
||||
rl.DrawModel(*model, playerPos, 16, rl.White)
|
||||
|
||||
// Draw highlight around target tile
|
||||
if len(player.TargetPath) > 0 {
|
||||
targetTile := player.TargetPath[len(player.TargetPath)-1] // last tile in the slice
|
||||
targetPos := rl.Vector3{
|
||||
X: float32(targetTile.X * TileSize),
|
||||
Y: mapGrid[targetTile.X][targetTile.Y].Height * TileHeight,
|
||||
Z: float32(targetTile.Y * TileSize),
|
||||
}
|
||||
rl.DrawCubeWires(targetPos, TileSize, TileHeight, TileSize, rl.Green)
|
||||
|
||||
nextTile := player.TargetPath[0] // first tile in the slice
|
||||
nextPos := rl.Vector3{
|
||||
X: float32(nextTile.X * TileSize),
|
||||
Y: mapGrid[nextTile.X][nextTile.Y].Height * TileHeight,
|
||||
Z: float32(nextTile.Y * TileSize),
|
||||
}
|
||||
rl.DrawCubeWires(nextPos, TileSize, TileHeight, TileSize, rl.Yellow)
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to test ray-box intersection (slab method)
|
||||
func RayIntersectsBox(ray rl.Ray, boxMin, boxMax rl.Vector3) bool {
|
||||
tmin := (boxMin.X - ray.Position.X) / ray.Direction.X
|
||||
tmax := (boxMax.X - ray.Position.X) / ray.Direction.X
|
||||
|
||||
if tmin > tmax {
|
||||
tmin, tmax = tmax, tmin
|
||||
}
|
||||
|
||||
tymin := (boxMin.Z - ray.Position.Z) / ray.Direction.Z
|
||||
tymax := (boxMax.Z - ray.Position.Z) / ray.Direction.Z
|
||||
|
||||
if tymin > tymax {
|
||||
tymin, tymax = tymax, tymin
|
||||
}
|
||||
|
||||
if (tmin > tymax) || (tymin > tmax) {
|
||||
return false
|
||||
}
|
||||
|
||||
if tymin > tmin {
|
||||
tmin = tymin
|
||||
}
|
||||
if tymax < tmax {
|
||||
tmax = tymax
|
||||
}
|
||||
|
||||
tzmin := (boxMin.Y - ray.Position.Y) / ray.Direction.Y
|
||||
tzmax := (boxMax.Y - ray.Position.Y) / ray.Direction.Y
|
||||
|
||||
if tzmin > tzmax {
|
||||
tzmin, tzmax = tzmax, tzmin
|
||||
}
|
||||
|
||||
if (tmin > tzmax) || (tzmin > tmax) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func GetTileAtMouse(mapGrid [][]Tile, camera *rl.Camera3D) (Tile, bool) {
|
||||
if !rl.IsMouseButtonPressed(rl.MouseLeftButton) {
|
||||
return Tile{}, false
|
||||
}
|
||||
mouse := rl.GetMousePosition()
|
||||
ray := rl.GetMouseRay(mouse, *camera)
|
||||
|
||||
for x := 0; x < MapWidth; x++ {
|
||||
for y := 0; y < MapHeight; y++ {
|
||||
tile := mapGrid[x][y]
|
||||
|
||||
// Define the bounding box for each tile based on its position and height
|
||||
tilePos := rl.NewVector3(float32(x*TileSize), tile.Height*TileHeight, float32(y*TileSize))
|
||||
boxMin := rl.Vector3Subtract(tilePos, rl.NewVector3(TileSize/2, TileHeight/2, TileSize/2))
|
||||
boxMax := rl.Vector3Add(tilePos, rl.NewVector3(TileSize/2, TileHeight/2, TileSize/2))
|
||||
|
||||
// Check if the ray intersects the bounding box
|
||||
if RayIntersectsBox(ray, boxMin, boxMax) {
|
||||
fmt.Println("Clicked:", tile.X, tile.Y)
|
||||
return tile, true
|
||||
}
|
||||
}
|
||||
}
|
||||
return Tile{}, false
|
||||
}
|
||||
|
||||
func (player *Player) MoveTowards(target Tile, deltaTime float32, mapGrid [][]Tile) {
|
||||
// Calculate the direction vector to the target tile
|
||||
targetPos := rl.Vector3{
|
||||
X: float32(target.X * TileSize),
|
||||
Y: mapGrid[target.X][target.Y].Height * TileHeight,
|
||||
Z: float32(target.Y * TileSize),
|
||||
}
|
||||
|
||||
// Calculate direction and normalize it for smooth movement
|
||||
direction := rl.Vector3Subtract(targetPos, player.PosActual)
|
||||
distance := rl.Vector3Length(direction)
|
||||
if distance > 0 {
|
||||
direction = rl.Vector3Scale(direction, player.Speed*deltaTime/distance)
|
||||
}
|
||||
|
||||
// Move the player towards the target tile
|
||||
if distance > 1.0 {
|
||||
player.PosActual = rl.Vector3Add(player.PosActual, direction)
|
||||
} else {
|
||||
// Snap to the target tile when close enough
|
||||
player.PosActual = targetPos
|
||||
player.PosTile = target // Update player's tile
|
||||
player.TargetPath = player.TargetPath[1:] // Move to next tile in path if any
|
||||
}
|
||||
}
|
||||
|
||||
func HandleInput(player *Player, mapGrid [][]Tile, camera *rl.Camera) {
|
||||
clickedTile, clicked := GetTileAtMouse(mapGrid, camera)
|
||||
if clicked {
|
||||
path := FindPath(mapGrid, mapGrid[player.PosTile.X][player.PosTile.Y], clickedTile)
|
||||
if path != nil {
|
||||
// Exclude the first tile (current position)
|
||||
if len(path) > 1 {
|
||||
player.TargetPath = path[1:]
|
||||
player.ActionQueue = append(player.ActionQueue, Action{Type: MoveAction, X: clickedTile.X, Y: clickedTile.Y})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func UpdateCamera(camera *rl.Camera3D, player rl.Vector3, deltaTime float32) {
|
||||
// Update camera based on mouse wheel
|
||||
wheelMove := rl.GetMouseWheelMove()
|
||||
if wheelMove != 0 {
|
||||
cameraDistance += -wheelMove * 5
|
||||
if cameraDistance < 10 {
|
||||
cameraDistance = 10
|
||||
}
|
||||
if cameraDistance > 250 {
|
||||
cameraDistance = 250
|
||||
}
|
||||
}
|
||||
|
||||
// Orbit camera around the player using arrow keys
|
||||
if rl.IsKeyDown(rl.KeyRight) {
|
||||
cameraYaw += 100 * deltaTime
|
||||
}
|
||||
if rl.IsKeyDown(rl.KeyLeft) {
|
||||
cameraYaw -= 100 * deltaTime
|
||||
}
|
||||
if rl.IsKeyDown(rl.KeyUp) {
|
||||
cameraPitch -= 50 * deltaTime
|
||||
if cameraPitch < 20 {
|
||||
cameraPitch = 20
|
||||
}
|
||||
}
|
||||
if rl.IsKeyDown(rl.KeyDown) {
|
||||
cameraPitch += 50 * deltaTime
|
||||
if cameraPitch > 85 {
|
||||
cameraPitch = 85
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate the new camera position using spherical coordinates
|
||||
cameraYawRad := float64(cameraYaw) * rl.Deg2rad
|
||||
cameraPitchRad := float64(cameraPitch) * rl.Deg2rad
|
||||
cameraPos := rl.Vector3{
|
||||
X: player.X + cameraDistance*float32(math.Cos(cameraYawRad))*float32(math.Cos(cameraPitchRad)),
|
||||
Y: player.Y + cameraDistance*float32(math.Sin(cameraPitchRad)),
|
||||
Z: player.Z + cameraDistance*float32(math.Sin(cameraYawRad))*float32(math.Cos(cameraPitchRad)),
|
||||
}
|
||||
|
||||
// Update the camera's position and target
|
||||
camera.Position = cameraPos
|
||||
camera.Target = rl.NewVector3(player.X, player.Y, player.Z)
|
||||
}
|
||||
|
||||
func main() {
|
||||
rl.InitWindow(1024, 768, "GoonScape")
|
||||
defer rl.CloseWindow()
|
||||
rl.InitAudioDevice()
|
||||
defer rl.CloseAudioDevice()
|
||||
|
||||
mapGrid := InitMap()
|
||||
|
||||
player := Player{
|
||||
PosActual: rl.NewVector3(5*TileSize, 0, 5*TileSize),
|
||||
PosTile: mapGrid[5][5],
|
||||
@ -309,29 +39,32 @@ func main() {
|
||||
log.Fatalf("Failed to connect to server: %v", err)
|
||||
}
|
||||
log.Printf("Player ID: %d", playerID)
|
||||
player.ID = playerID
|
||||
defer conn.Close()
|
||||
|
||||
go HandleServerCommunication(conn, playerID, &player)
|
||||
otherPlayers := make(map[int32]*Player)
|
||||
|
||||
playerModel := rl.LoadModel("resources/models/goonion.obj")
|
||||
defer rl.UnloadModel(playerModel)
|
||||
playerTexture := rl.LoadTexture("resources/models/goonion.png")
|
||||
defer rl.UnloadTexture(playerTexture)
|
||||
rl.SetMaterialTexture(playerModel.Materials, rl.MapDiffuse, playerTexture)
|
||||
go HandleServerCommunication(conn, playerID, &player, otherPlayers)
|
||||
|
||||
coomerModel := rl.LoadModel("resources/models/coomer.obj")
|
||||
defer rl.UnloadModel(coomerModel)
|
||||
coomerTexture := rl.LoadTexture("resources/models/coomer.png")
|
||||
defer rl.UnloadTexture(coomerTexture)
|
||||
rl.SetMaterialTexture(coomerModel.Materials, rl.MapDiffuse, coomerTexture)
|
||||
models, err := LoadModels()
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to load models: %v", err)
|
||||
}
|
||||
defer UnloadModels(models)
|
||||
|
||||
rl.SetTargetFPS(60)
|
||||
modelIndex := int(playerID) % len(models)
|
||||
player.Model = models[modelIndex].Model
|
||||
player.Texture = models[modelIndex].Texture
|
||||
|
||||
// Music
|
||||
music := rl.LoadMusicStream("resources/audio/GoonScape2.mp3")
|
||||
music, err := LoadMusic("resources/audio/GoonScape2.mp3")
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to load music: %v", err)
|
||||
}
|
||||
defer UnloadMusic(music)
|
||||
rl.PlayMusicStream(music)
|
||||
rl.SetMusicVolume(music, 0.5)
|
||||
defer rl.UnloadMusicStream(music)
|
||||
|
||||
rl.SetTargetFPS(60)
|
||||
|
||||
for !rl.WindowShouldClose() {
|
||||
|
||||
@ -341,11 +74,11 @@ func main() {
|
||||
deltaTime := rl.GetFrameTime()
|
||||
|
||||
// Handle input
|
||||
HandleInput(&player, mapGrid, &camera)
|
||||
HandleInput(&player, &camera)
|
||||
|
||||
// Update player
|
||||
if len(player.TargetPath) > 0 {
|
||||
player.MoveTowards(player.TargetPath[0], deltaTime, mapGrid)
|
||||
player.MoveTowards(player.TargetPath[0], deltaTime)
|
||||
}
|
||||
|
||||
// Update camera
|
||||
@ -355,193 +88,63 @@ func main() {
|
||||
rl.BeginDrawing()
|
||||
rl.ClearBackground(rl.RayWhite)
|
||||
rl.BeginMode3D(camera)
|
||||
DrawMap(mapGrid)
|
||||
DrawPlayer(player, &playerModel, mapGrid)
|
||||
DrawMap()
|
||||
DrawPlayer(player, player.Model)
|
||||
|
||||
rl.DrawModel(coomerModel, rl.NewVector3(5*TileSize+32, 32, 5*TileSize+32), 16, rl.White)
|
||||
|
||||
rl.DrawFPS(10, 10)
|
||||
for id, other := range otherPlayers {
|
||||
if len(other.TargetPath) > 0 {
|
||||
other.MoveTowards(other.TargetPath[0], deltaTime)
|
||||
}
|
||||
DrawPlayer(*other, models[int(id)%len(models)].Model)
|
||||
}
|
||||
|
||||
rl.EndMode3D()
|
||||
rl.DrawFPS(10, 10)
|
||||
rl.EndDrawing()
|
||||
}
|
||||
}
|
||||
|
||||
func ConnectToServer() (net.Conn, int32, error) {
|
||||
// Attempt to connect to the server
|
||||
conn, err := net.Dial("tcp", serverAddr)
|
||||
if err != nil {
|
||||
log.Printf("Failed to dial server: %v", err)
|
||||
return nil, 0, err
|
||||
func LoadModels() ([]struct {
|
||||
Model rl.Model
|
||||
Texture rl.Texture2D
|
||||
}, error) {
|
||||
goonerModel := rl.LoadModel("resources/models/goonion.obj")
|
||||
goonerTexture := rl.LoadTexture("resources/models/goonion.png")
|
||||
rl.SetMaterialTexture(goonerModel.Materials, rl.MapDiffuse, goonerTexture)
|
||||
|
||||
coomerModel := rl.LoadModel("resources/models/coomer.obj")
|
||||
coomerTexture := rl.LoadTexture("resources/models/coomer.png")
|
||||
rl.SetMaterialTexture(coomerModel.Materials, rl.MapDiffuse, coomerTexture)
|
||||
|
||||
shrekeModel := rl.LoadModel("resources/models/shreke.obj")
|
||||
shrekeTexture := rl.LoadTexture("resources/models/shreke.png")
|
||||
rl.SetMaterialTexture(shrekeModel.Materials, rl.MapDiffuse, shrekeTexture)
|
||||
|
||||
return []struct {
|
||||
Model rl.Model
|
||||
Texture rl.Texture2D
|
||||
}{
|
||||
{Model: goonerModel, Texture: goonerTexture},
|
||||
{Model: coomerModel, Texture: coomerTexture},
|
||||
{Model: shrekeModel, Texture: shrekeTexture},
|
||||
}, nil
|
||||
}
|
||||
|
||||
log.Println("Connected to server. Waiting for player ID...")
|
||||
// Buffer for incoming server message
|
||||
buf := make([]byte, 1024)
|
||||
n, err := conn.Read(buf)
|
||||
if err != nil {
|
||||
log.Printf("Error reading player ID from server: %v", err)
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
log.Printf("Received data: %x", buf[:n])
|
||||
|
||||
// Unmarshal server message to extract the player ID
|
||||
var response pb.ServerMessage
|
||||
if err := proto.Unmarshal(buf[:n], &response); err != nil {
|
||||
log.Printf("Failed to unmarshal server response: %v", err)
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
playerID := response.GetPlayerId()
|
||||
log.Printf("Successfully connected with player ID: %d", playerID)
|
||||
return conn, playerID, nil
|
||||
}
|
||||
|
||||
func HandleServerCommunication(conn net.Conn, playerID int32, player *Player) {
|
||||
for {
|
||||
// Check if there are actions in the player's queue
|
||||
if len(player.ActionQueue) > 0 {
|
||||
// Process the first action in the queue
|
||||
actionData := player.ActionQueue[0]
|
||||
action := &pb.Action{
|
||||
PlayerId: playerID,
|
||||
Type: pb.Action_MOVE,
|
||||
X: int32(actionData.X),
|
||||
Y: int32(actionData.Y),
|
||||
}
|
||||
|
||||
// Serialize the action
|
||||
data, err := proto.Marshal(action)
|
||||
if err != nil {
|
||||
log.Printf("Failed to marshal action: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
// Send action to server
|
||||
_, err = conn.Write(data)
|
||||
if err != nil {
|
||||
log.Printf("Failed to send action to server: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Remove the action from the queue once it's sent
|
||||
player.ActionQueue = player.ActionQueue[1:]
|
||||
}
|
||||
|
||||
// Add a delay based on the server's tick rate
|
||||
time.Sleep(TickRate)
|
||||
func UnloadModels(models []struct {
|
||||
Model rl.Model
|
||||
Texture rl.Texture2D
|
||||
}) {
|
||||
for _, model := range models {
|
||||
rl.UnloadModel(model.Model)
|
||||
rl.UnloadTexture(model.Texture)
|
||||
}
|
||||
}
|
||||
|
||||
// pathfinding
|
||||
type Node struct {
|
||||
Tile Tile
|
||||
Parent *Node
|
||||
G, H, F float32
|
||||
func LoadMusic(filename string) (rl.Music, error) {
|
||||
music := rl.LoadMusicStream(filename)
|
||||
return music, nil
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
fmt.Printf("Path found: %v\n", path)
|
||||
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
|
||||
fmt.Println("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
|
||||
func UnloadMusic(music rl.Music) {
|
||||
rl.UnloadMusicStream(music)
|
||||
}
|
||||
|
48
map.go
Normal file
48
map.go
Normal file
@ -0,0 +1,48 @@
|
||||
package main
|
||||
|
||||
import rl "github.com/gen2brain/raylib-go/raylib"
|
||||
|
||||
// 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: 1.0 + float32(x%5), // Example height
|
||||
Walkable: true, // Set to false for obstacles
|
||||
}
|
||||
}
|
||||
}
|
||||
return mapGrid
|
||||
}
|
||||
|
||||
func DrawMap() {
|
||||
for x := 0; x < MapWidth; x++ {
|
||||
for y := 0; y < MapHeight; y++ {
|
||||
tile := mapGrid[x][y]
|
||||
// Interpolate height between adjacent tiles for a smoother landscape
|
||||
height := tile.Height
|
||||
if x > 0 {
|
||||
height += mapGrid[x-1][y].Height
|
||||
}
|
||||
if y > 0 {
|
||||
height += mapGrid[x][y-1].Height
|
||||
}
|
||||
if x > 0 && y > 0 {
|
||||
height += mapGrid[x-1][y-1].Height
|
||||
}
|
||||
height /= 4.0
|
||||
// Draw each tile as a 3D cube based on its height
|
||||
tilePos := rl.Vector3{
|
||||
X: float32(x * TileSize), // X-axis for horizontal position
|
||||
Y: height * TileHeight, // Y-axis for height (Z in 3D is Y here)
|
||||
Z: float32(y * TileSize), // Z-axis for depth (Y in 3D is Z here)
|
||||
}
|
||||
color := rl.Color{R: uint8(height * 25), G: 100, B: 100, A: 64}
|
||||
rl.DrawCube(tilePos, TileSize, TileHeight, TileSize, color) // Draw a cube representing the tile
|
||||
}
|
||||
}
|
||||
}
|
121
network.go
Normal file
121
network.go
Normal file
@ -0,0 +1,121 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
pb "gitea.boner.be/bdnugget/goonserver/actions"
|
||||
rl "github.com/gen2brain/raylib-go/raylib"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
func ConnectToServer() (net.Conn, int32, error) {
|
||||
// Attempt to connect to the server
|
||||
conn, err := net.Dial("tcp", serverAddr)
|
||||
if err != nil {
|
||||
log.Printf("Failed to dial server: %v", err)
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
log.Println("Connected to server. Waiting for player ID...")
|
||||
// Buffer for incoming server message
|
||||
buf := make([]byte, 1024)
|
||||
n, err := conn.Read(buf)
|
||||
if err != nil {
|
||||
log.Printf("Error reading player ID from server: %v", err)
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
log.Printf("Received data: %x", buf[:n])
|
||||
|
||||
// Unmarshal server message to extract the player ID
|
||||
var response pb.ServerMessage
|
||||
if err := proto.Unmarshal(buf[:n], &response); err != nil {
|
||||
log.Printf("Failed to unmarshal server response: %v", err)
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
playerID := response.GetPlayerId()
|
||||
log.Printf("Successfully connected with player ID: %d", playerID)
|
||||
return conn, playerID, nil
|
||||
}
|
||||
|
||||
func HandleServerCommunication(conn net.Conn, playerID int32, player *Player, otherPlayers map[int32]*Player) {
|
||||
// Goroutine to handle sending player's actions to the server
|
||||
go func() {
|
||||
for {
|
||||
if len(player.ActionQueue) > 0 {
|
||||
// Process the first action in the queue
|
||||
actionData := player.ActionQueue[0]
|
||||
action := &pb.Action{
|
||||
PlayerId: playerID,
|
||||
Type: pb.Action_MOVE,
|
||||
X: int32(actionData.X),
|
||||
Y: int32(actionData.Y),
|
||||
}
|
||||
|
||||
// Serialize the action
|
||||
data, err := proto.Marshal(action)
|
||||
if err != nil {
|
||||
log.Printf("Failed to marshal action: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
// Send action to server
|
||||
_, err = conn.Write(data)
|
||||
if err != nil {
|
||||
log.Printf("Failed to send action to server: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Remove the action from the queue once it's sent
|
||||
player.ActionQueue = player.ActionQueue[1:]
|
||||
}
|
||||
|
||||
// Add a delay to match the server's tick rate
|
||||
time.Sleep(TickRate)
|
||||
}
|
||||
}()
|
||||
|
||||
// Main loop to handle receiving updates from the server
|
||||
for {
|
||||
buf := make([]byte, 4096)
|
||||
n, err := conn.Read(buf)
|
||||
if err != nil {
|
||||
log.Printf("Failed to read from server: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
var serverMessage pb.ServerMessage
|
||||
if err := proto.Unmarshal(buf[:n], &serverMessage); err != nil {
|
||||
log.Printf("Failed to unmarshal server message: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
// Update other players' states
|
||||
for _, state := range serverMessage.Players {
|
||||
if state.PlayerId != playerID {
|
||||
if otherPlayer, exists := otherPlayers[state.PlayerId]; exists {
|
||||
otherPlayer.PosTile = Tile{X: int(state.X), Y: int(state.Y)}
|
||||
otherPlayer.PosActual = rl.Vector3{
|
||||
X: float32(state.X * TileSize),
|
||||
Y: float32(state.Y * TileHeight),
|
||||
Z: float32(state.Y * TileSize),
|
||||
}
|
||||
otherPlayer.MoveTowards(Tile{X: int(state.X), Y: int(state.Y)}, 0)
|
||||
} else {
|
||||
otherPlayers[state.PlayerId] = &Player{
|
||||
PosTile: Tile{X: int(state.X), Y: int(state.Y)},
|
||||
PosActual: rl.Vector3{
|
||||
X: float32(state.X * TileSize),
|
||||
Y: float32(state.Y * TileHeight),
|
||||
Z: float32(state.Y * TileSize),
|
||||
},
|
||||
ID: state.PlayerId,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
114
pathfinding.go
Normal file
114
pathfinding.go
Normal file
@ -0,0 +1,114 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
type Node struct {
|
||||
Tile Tile
|
||||
Parent *Node
|
||||
G, H, F float32
|
||||
}
|
||||
|
||||
func FindPath(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
|
||||
}
|
||||
fmt.Printf("Path found: %v\n", path)
|
||||
return path
|
||||
}
|
||||
|
||||
// Generate neighbors
|
||||
neighbors := GetNeighbors(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
|
||||
fmt.Println("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(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
|
||||
}
|
63
player.go
Normal file
63
player.go
Normal file
@ -0,0 +1,63 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
rl "github.com/gen2brain/raylib-go/raylib"
|
||||
)
|
||||
|
||||
func DrawPlayer(player Player, model rl.Model) {
|
||||
// Draw the player based on its actual position (PosActual) and current tile height
|
||||
playerPos := rl.Vector3{
|
||||
X: player.PosActual.X,
|
||||
Y: mapGrid[player.PosTile.X][player.PosTile.Y].Height*TileHeight + 16.0,
|
||||
Z: player.PosActual.Z,
|
||||
}
|
||||
|
||||
rl.DrawModel(model, playerPos, 16, rl.White)
|
||||
|
||||
// Draw highlight around target tile
|
||||
if len(player.TargetPath) > 0 {
|
||||
targetTile := player.TargetPath[len(player.TargetPath)-1] // last tile in the slice
|
||||
targetPos := rl.Vector3{
|
||||
X: float32(targetTile.X * TileSize),
|
||||
Y: mapGrid[targetTile.X][targetTile.Y].Height * TileHeight,
|
||||
Z: float32(targetTile.Y * TileSize),
|
||||
}
|
||||
rl.DrawCubeWires(targetPos, TileSize, TileHeight, TileSize, rl.Green)
|
||||
|
||||
nextTile := player.TargetPath[0] // first tile in the slice
|
||||
nextPos := rl.Vector3{
|
||||
X: float32(nextTile.X * TileSize),
|
||||
Y: mapGrid[nextTile.X][nextTile.Y].Height * TileHeight,
|
||||
Z: float32(nextTile.Y * TileSize),
|
||||
}
|
||||
rl.DrawCubeWires(nextPos, TileSize, TileHeight, TileSize, rl.Yellow)
|
||||
}
|
||||
}
|
||||
|
||||
func (player *Player) MoveTowards(target Tile, deltaTime float32) {
|
||||
// Calculate the direction vector to the target tile
|
||||
targetPos := rl.Vector3{
|
||||
X: float32(target.X * TileSize),
|
||||
Y: mapGrid[target.X][target.Y].Height * TileHeight,
|
||||
Z: float32(target.Y * TileSize),
|
||||
}
|
||||
|
||||
// Calculate direction and normalize it for smooth movement
|
||||
direction := rl.Vector3Subtract(targetPos, player.PosActual)
|
||||
distance := rl.Vector3Length(direction)
|
||||
if distance > 0 {
|
||||
direction = rl.Vector3Scale(direction, player.Speed*deltaTime/distance)
|
||||
}
|
||||
|
||||
// Move the player towards the target tile
|
||||
if distance > 1.0 {
|
||||
player.PosActual = rl.Vector3Add(player.PosActual, direction)
|
||||
} else {
|
||||
// Snap to the target tile when close enough
|
||||
player.PosActual = targetPos
|
||||
player.PosTile = target // Update player's tile
|
||||
if len(player.TargetPath) > 1 {
|
||||
player.TargetPath = player.TargetPath[1:] // Move to next tile in path if any
|
||||
}
|
||||
}
|
||||
}
|
12
resources/models/shreke.mtl
Normal file
12
resources/models/shreke.mtl
Normal file
@ -0,0 +1,12 @@
|
||||
# Blender 3.6.0 MTL File: 'None'
|
||||
# www.blender.org
|
||||
|
||||
newmtl Material.001
|
||||
Ns 250.000000
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.450000
|
||||
d 1.000000
|
||||
illum 2
|
||||
map_Kd shreke.png
|
210035
resources/models/shreke.obj
Normal file
210035
resources/models/shreke.obj
Normal file
File diff suppressed because it is too large
Load Diff
BIN
resources/models/shreke.png
Normal file
BIN
resources/models/shreke.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.8 MiB |
31
types.go
Normal file
31
types.go
Normal file
@ -0,0 +1,31 @@
|
||||
package main
|
||||
|
||||
import rl "github.com/gen2brain/raylib-go/raylib"
|
||||
|
||||
type Tile struct {
|
||||
X, Y int
|
||||
Height float32
|
||||
Walkable bool
|
||||
}
|
||||
|
||||
type ActionType int
|
||||
|
||||
const (
|
||||
MoveAction ActionType = iota
|
||||
)
|
||||
|
||||
type Action struct {
|
||||
Type ActionType
|
||||
X, Y int // Target position for movement
|
||||
}
|
||||
|
||||
type Player struct {
|
||||
PosActual rl.Vector3
|
||||
PosTile Tile
|
||||
TargetPath []Tile
|
||||
Speed float32
|
||||
ActionQueue []Action // Queue for player actions
|
||||
Model rl.Model
|
||||
Texture rl.Texture2D
|
||||
ID int32
|
||||
}
|
@ -1 +0,0 @@
|
||||
package utils
|
Reference in New Issue
Block a user