Private
Public Access
1
0

fix game
All checks were successful
Dynamic Branch Deploy / build-and-deploy (push) Successful in 6m53s

This commit is contained in:
Sebastian Unterschütz
2026-03-22 17:43:51 +01:00
parent 0aa81a2edc
commit ced5011718
2 changed files with 430 additions and 475 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -16,7 +16,6 @@ import (
"github.com/hajimehoshi/ebiten/v2/inpututil" "github.com/hajimehoshi/ebiten/v2/inpututil"
"github.com/hajimehoshi/ebiten/v2/text" "github.com/hajimehoshi/ebiten/v2/text"
"github.com/hajimehoshi/ebiten/v2/vector" "github.com/hajimehoshi/ebiten/v2/vector"
"github.com/nats-io/nats.go"
"golang.org/x/image/font/basicfont" "golang.org/x/image/font/basicfont"
"git.zb-server.de/ZB-Server/EscapeFromTeacher/pkg/game" "git.zb-server.de/ZB-Server/EscapeFromTeacher/pkg/game"
@@ -30,14 +29,12 @@ const (
StateLobby = 1 StateLobby = 1
StateGame = 2 StateGame = 2
StateLeaderboard = 3 StateLeaderboard = 3
RefFloorY = 540 // Server-Welt Boden-Position (unveränderlich) RefFloorY = 540 // Server-Welt Boden-Position (unveränderlich)
RefFloorYMobile = 270 // Nicht mehr verwendet
) )
var ( var (
ColText = color.White ColText = color.White
ColBtnNormal = color.RGBA{40, 44, 52, 255} ColBtnNormal = color.RGBA{40, 44, 52, 255}
ColBtnHover = color.RGBA{60, 66, 78, 255}
ColSky = color.RGBA{135, 206, 235, 255} ColSky = color.RGBA{135, 206, 235, 255}
ColGrass = color.RGBA{34, 139, 34, 255} ColGrass = color.RGBA{34, 139, 34, 255}
ColDirt = color.RGBA{101, 67, 33, 255} ColDirt = color.RGBA{101, 67, 33, 255}
@@ -55,8 +52,7 @@ type InputState struct {
// --- GAME STRUCT --- // --- GAME STRUCT ---
type Game struct { type Game struct {
appState int appState int
conn *nats.EncodedConn
wsConn *wsConn // WebSocket für WASM wsConn *wsConn // WebSocket für WASM
connGeneration int // Erhöht bei jedem Disconnect; macht alte WS-Handler ungültig connGeneration int // Erhöht bei jedem Disconnect; macht alte WS-Handler ungültig
isConnecting bool // Guard gegen mehrfaches connectAndStart() isConnecting bool // Guard gegen mehrfaches connectAndStart()
@@ -227,63 +223,42 @@ func (g *Game) Update() error {
g.pendingInputCount = len(g.pendingInputs) g.pendingInputCount = len(g.pendingInputs)
g.predictionMutex.Unlock() g.predictionMutex.Unlock()
// Aktuellen Status einmalig (thread-safe) lesen
g.stateMutex.Lock()
currentStatus := g.gameState.Status
g.stateMutex.Unlock()
// Game Over Handling // Game Over Handling
if g.appState == StateGame && g.gameState.Status == "GAMEOVER" { if g.appState == StateGame && currentStatus == "GAMEOVER" {
// Back Button (oben links) - Touch Support
backBtnW, backBtnH := 120, 40 backBtnW, backBtnH := 120, 40
backBtnX, backBtnY := 20, 20 if isHit(20, 20, backBtnW, backBtnH) {
if isHit(backBtnX, backBtnY, backBtnW, backBtnH) { g.returnToMenu()
g.appState = StateMenu
g.connected = false
g.scoreSubmitted = false
g.teamName = ""
g.activeField = ""
if g.conn != nil {
g.conn.Drain()
g.conn.Close()
}
g.gameState = game.GameState{Players: make(map[string]game.PlayerState)}
log.Println("🔙 Zurück zum Menü (Back Button)") log.Println("🔙 Zurück zum Menü (Back Button)")
return nil return nil
} }
// ESC zurück zum Menü
if inpututil.IsKeyJustPressed(ebiten.KeyEscape) { if inpututil.IsKeyJustPressed(ebiten.KeyEscape) {
g.appState = StateMenu g.returnToMenu()
g.connected = false
g.scoreSubmitted = false
g.teamName = ""
g.activeField = ""
if g.conn != nil {
g.conn.Drain()
g.conn.Close()
}
g.gameState = game.GameState{Players: make(map[string]game.PlayerState)}
log.Println("🔙 Zurück zum Menü (ESC)") log.Println("🔙 Zurück zum Menü (ESC)")
return nil return nil
} }
// Host: Team-Name Eingabe
if g.isHost { if g.isHost {
g.handleGameOverInput() g.handleGameOverInput()
} }
} }
// COUNTDOWN/RUNNING-Übergang: AppState auf StateGame setzen + JS benachrichtigen // COUNTDOWN/RUNNING-Übergang: AppState auf StateGame setzen + JS benachrichtigen
newStatus := g.gameState.Status if (currentStatus == "COUNTDOWN" || currentStatus == "RUNNING") && g.appState != StateGame {
if (newStatus == "COUNTDOWN" || newStatus == "RUNNING") && g.appState != StateGame { log.Printf("🎮 Spiel startet! Status: %s -> %s", g.lastStatus, currentStatus)
log.Printf("🎮 Spiel startet! Status: %s -> %s", g.lastStatus, newStatus)
g.appState = StateGame g.appState = StateGame
g.notifyGameStarted() g.notifyGameStarted()
} }
if newStatus == "RUNNING" && g.lastStatus != "RUNNING" { if currentStatus == "RUNNING" && g.lastStatus != "RUNNING" {
g.audio.PlayMusic() g.audio.PlayMusic()
} }
// Musik stoppen wenn Game Over if currentStatus == "GAMEOVER" && g.lastStatus == "RUNNING" {
if g.gameState.Status == "GAMEOVER" && g.lastStatus == "RUNNING" {
g.audio.StopMusic() g.audio.StopMusic()
} }
g.lastStatus = g.gameState.Status g.lastStatus = currentStatus
switch g.appState { switch g.appState {
case StateMenu: case StateMenu:
@@ -418,14 +393,13 @@ func (g *Game) updateLobby() {
} }
// Zurück Button // Zurück Button
backW, backH := 100, 40 if isHit(50, 50, 100, 40) {
if isHit(50, 50, backW, backH) { g.disconnectFromServer()
if g.conn != nil {
g.conn.Close()
}
g.appState = StateMenu g.appState = StateMenu
g.connected = false g.connected = false
g.stateMutex.Lock()
g.gameState = game.GameState{Players: make(map[string]game.PlayerState)} g.gameState = game.GameState{Players: make(map[string]game.PlayerState)}
g.stateMutex.Unlock()
} }
// Lobby State Change Detection (für HTML-Updates) // Lobby State Change Detection (für HTML-Updates)
@@ -692,12 +666,6 @@ func GetFloorYFromHeight(screenHeight int) float64 {
return floorY return floorY
} }
// GetFloorY - Wrapper der versucht die Höhe zu bekommen (deprecated, benutze GetFloorYFromHeight)
func GetFloorY() float64 {
_, h := ebiten.WindowSize()
return GetFloorYFromHeight(h)
}
// GetScale gibt den Scale-Faktor zurück um die Spielwelt an den Bildschirm anzupassen // GetScale gibt den Scale-Faktor zurück um die Spielwelt an den Bildschirm anzupassen
// Auf Mobile: Scale < 1.0 (rauszoomen, damit mehr sichtbar ist) // Auf Mobile: Scale < 1.0 (rauszoomen, damit mehr sichtbar ist)
// Auf Desktop: Scale = 1.0 (normale Größe) // Auf Desktop: Scale = 1.0 (normale Größe)
@@ -748,15 +716,6 @@ func WorldToScreenYWithHeight(worldY float64, screenHeight int) float64 {
return worldY + yOffset return worldY + yOffset
} }
// WorldToScreenY - Legacy wrapper (versucht WindowSize zu verwenden, funktioniert nicht in WASM!)
func WorldToScreenY(worldY float64) float64 {
_, h := ebiten.WindowSize()
if h == 0 {
h = ScreenHeight // Fallback
}
return WorldToScreenYWithHeight(worldY, h)
}
func isHit(x, y, w, h int) bool { func isHit(x, y, w, h int) bool {
if inpututil.IsMouseButtonJustPressed(ebiten.MouseButtonLeft) { if inpututil.IsMouseButtonJustPressed(ebiten.MouseButtonLeft) {
mx, my := ebiten.CursorPosition() mx, my := ebiten.CursorPosition()
@@ -854,6 +813,19 @@ func (g *Game) handleGameOverInput() {
} }
} }
// returnToMenu trennt die Verbindung und setzt den App-State zurück auf das Hauptmenü.
func (g *Game) returnToMenu() {
g.disconnectFromServer()
g.appState = StateMenu
g.connected = false
g.scoreSubmitted = false
g.teamName = ""
g.activeField = ""
g.stateMutex.Lock()
g.gameState = game.GameState{Players: make(map[string]game.PlayerState)}
g.stateMutex.Unlock()
}
func generateRoomCode() string { func generateRoomCode() string {
mrand.Seed(time.Now().UnixNano()) mrand.Seed(time.Now().UnixNano())
chars := "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" chars := "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
@@ -1006,14 +978,17 @@ func (g *Game) DrawLeaderboard(screen *ebiten.Image) {
// Titel // Titel
text.Draw(screen, "=== TOP 10 LEADERBOARD ===", basicfont.Face7x13, ScreenWidth/2-100, 80, color.RGBA{255, 215, 0, 255}) text.Draw(screen, "=== TOP 10 LEADERBOARD ===", basicfont.Face7x13, ScreenWidth/2-100, 80, color.RGBA{255, 215, 0, 255})
// Leaderboard abrufen wenn leer // Leaderboard abrufen wenn leer (prüfen ohne Lock, dann ggf. nachladen)
g.leaderboardMutex.Lock() g.leaderboardMutex.Lock()
if len(g.leaderboard) == 0 && g.connected { empty := len(g.leaderboard) == 0
g.leaderboardMutex.Unlock() g.leaderboardMutex.Unlock()
if empty && g.connected {
g.requestLeaderboard() g.requestLeaderboard()
g.leaderboardMutex.Lock()
} }
g.leaderboardMutex.Lock()
y := 150 y := 150
if len(g.leaderboard) == 0 { if len(g.leaderboard) == 0 {
text.Draw(screen, "Noch keine Einträge...", basicfont.Face7x13, ScreenWidth/2-80, y, color.Gray{150}) text.Draw(screen, "Noch keine Einträge...", basicfont.Face7x13, ScreenWidth/2-80, y, color.Gray{150})