update workflows and game logic: add CERT_ISSUER support, enhance offline mode with countdown, and adjust default audio settings
All checks were successful
Dynamic Branch Deploy / build-and-deploy (push) Successful in 1m50s
All checks were successful
Dynamic Branch Deploy / build-and-deploy (push) Successful in 1m50s
This commit is contained in:
@@ -18,10 +18,11 @@ func (g *Game) startOfflineGame() {
|
||||
g.connected = false // Explizit offline
|
||||
g.appState = StateGame
|
||||
|
||||
// Initialen GameState lokal erstellen
|
||||
// Initialen GameState lokal erstellen (mit Countdown)
|
||||
g.stateMutex.Lock()
|
||||
g.gameState = game.GameState{
|
||||
Status: "RUNNING",
|
||||
Status: "COUNTDOWN",
|
||||
TimeLeft: 3,
|
||||
RoomID: "offline_solo",
|
||||
Players: make(map[string]game.PlayerState),
|
||||
WorldChunks: []game.ActiveChunk{{ChunkID: "start", X: 0}},
|
||||
@@ -30,7 +31,7 @@ func (g *Game) startOfflineGame() {
|
||||
CollectedCoins: make(map[string]bool),
|
||||
CollectedPowerups: make(map[string]bool),
|
||||
}
|
||||
|
||||
|
||||
// Lokalen Spieler hinzufügen
|
||||
g.gameState.Players[g.playerName] = game.PlayerState{
|
||||
ID: g.playerName,
|
||||
@@ -48,28 +49,48 @@ func (g *Game) startOfflineGame() {
|
||||
log.Println("⚠️ Warnung: Keine Chunks in Library geladen!")
|
||||
}
|
||||
|
||||
g.roundStartTime = time.Now()
|
||||
// Startzeit für Countdown
|
||||
g.roundStartTime = time.Now().Add(3 * time.Second)
|
||||
g.predictedX = 100
|
||||
g.predictedY = 200
|
||||
g.currentSpeed = config.RunSpeed
|
||||
|
||||
g.audio.PlayMusic()
|
||||
g.currentSpeed = 0 // Stillstand während Countdown
|
||||
|
||||
g.notifyGameStarted()
|
||||
log.Println("🕹️ Offline-Modus gestartet")
|
||||
log.Println("🕹️ Offline-Modus mit Countdown gestartet")
|
||||
}
|
||||
|
||||
// updateOfflineLoop simuliert die Server-Logik lokal
|
||||
func (g *Game) updateOfflineLoop() {
|
||||
if !g.isOffline || g.gameState.Status != "RUNNING" {
|
||||
if !g.isOffline || g.gameState.Status == "GAMEOVER" {
|
||||
return
|
||||
}
|
||||
|
||||
g.stateMutex.Lock()
|
||||
defer g.stateMutex.Unlock()
|
||||
|
||||
// 1. Status Logic (Countdown -> Running)
|
||||
if g.gameState.Status == "COUNTDOWN" {
|
||||
rem := time.Until(g.roundStartTime)
|
||||
g.gameState.TimeLeft = int(rem.Seconds()) + 1
|
||||
|
||||
if rem <= 0 {
|
||||
log.Println("🚀 Offline: GO!")
|
||||
g.gameState.Status = "RUNNING"
|
||||
g.gameState.TimeLeft = 0
|
||||
g.audio.PlayMusic()
|
||||
// Reset roundStartTime auf den tatsächlichen Spielstart für Schwierigkeits-Skalierung
|
||||
g.roundStartTime = time.Now()
|
||||
}
|
||||
return // Während Countdown keine weitere Logik (kein Scrolling, etc.)
|
||||
}
|
||||
|
||||
if g.gameState.Status != "RUNNING" {
|
||||
return
|
||||
}
|
||||
|
||||
elapsed := time.Since(g.roundStartTime).Seconds()
|
||||
|
||||
// 1. Schwierigkeit & Speed
|
||||
// 2. Schwierigkeit & Speed
|
||||
g.gameState.DifficultyFactor = elapsed / config.MaxDifficultySeconds
|
||||
if g.gameState.DifficultyFactor > 1.0 {
|
||||
g.gameState.DifficultyFactor = 1.0
|
||||
@@ -79,10 +100,10 @@ func (g *Game) updateOfflineLoop() {
|
||||
g.gameState.CurrentSpeed = config.RunSpeed + speedIncrease
|
||||
g.currentSpeed = g.gameState.CurrentSpeed
|
||||
|
||||
// 2. Scrolling
|
||||
// 3. Scrolling
|
||||
g.gameState.ScrollX += g.currentSpeed
|
||||
|
||||
// 3. Chunks nachladen
|
||||
// 4. Chunks nachladen
|
||||
mapEnd := 0.0
|
||||
for _, c := range g.gameState.WorldChunks {
|
||||
chunkDef := g.world.ChunkLibrary[c.ChunkID]
|
||||
@@ -96,7 +117,7 @@ func (g *Game) updateOfflineLoop() {
|
||||
g.spawnOfflineChunk(mapEnd)
|
||||
}
|
||||
|
||||
// 4. Entferne alte Chunks
|
||||
// 5. Entferne alte Chunks
|
||||
if len(g.gameState.WorldChunks) > 5 {
|
||||
if g.gameState.WorldChunks[0].X < g.gameState.ScrollX-2000 {
|
||||
// Bereinige auch Moving Platforms des alten Chunks
|
||||
@@ -112,15 +133,15 @@ func (g *Game) updateOfflineLoop() {
|
||||
}
|
||||
}
|
||||
|
||||
// 5. Update Moving Platforms
|
||||
// 6. Update Moving Platforms
|
||||
g.updateOfflineMovingPlatforms()
|
||||
|
||||
// 6. Player State Update (Score, Powerups, Collisions)
|
||||
// 7. Player State Update (Score, Powerups, Collisions)
|
||||
p, ok := g.gameState.Players[g.playerName]
|
||||
if ok && p.IsAlive {
|
||||
// Basis-Score aus Distanz
|
||||
p.Score = int(g.gameState.ScrollX / 10)
|
||||
|
||||
|
||||
// Synchronisiere Prediction-State zurück in GameState (für Rendering)
|
||||
p.X = g.predictedX
|
||||
p.Y = g.predictedY
|
||||
@@ -128,7 +149,7 @@ func (g *Game) updateOfflineLoop() {
|
||||
p.VY = g.predictedVY
|
||||
p.OnGround = g.predictedGround
|
||||
p.OnWall = g.predictedOnWall
|
||||
|
||||
|
||||
// Lokale Kollisionsprüfung für Coins/Powerups
|
||||
g.checkOfflineCollisions(&p)
|
||||
|
||||
@@ -177,25 +198,25 @@ func (g *Game) spawnOfflineChunk(atX float64) {
|
||||
X: atX,
|
||||
})
|
||||
|
||||
// Extrahiere Moving Platforms aus dem neuen Chunk
|
||||
// Extrahiere Plattformen aus dem neuen Chunk
|
||||
chunkDef := g.world.ChunkLibrary[randomID]
|
||||
for i, obj := range chunkDef.Objects {
|
||||
asset, ok := g.world.Manifest.Assets[obj.AssetID]
|
||||
if ok && asset.Type == "moving_platform" && obj.MovingPlatform != nil {
|
||||
mp := obj.MovingPlatform
|
||||
// In Solo gibt es keine MovingPlatformData, Plattformen sind statisch
|
||||
if ok && asset.Type == "moving_platform" {
|
||||
p := &MovingPlatform{
|
||||
ChunkID: randomID,
|
||||
ObjectIdx: i,
|
||||
AssetID: obj.AssetID,
|
||||
StartX: atX + mp.StartX,
|
||||
StartY: mp.StartY,
|
||||
EndX: atX + mp.EndX,
|
||||
EndY: mp.EndY,
|
||||
Speed: mp.Speed,
|
||||
StartX: atX + obj.X,
|
||||
StartY: obj.Y,
|
||||
EndX: atX + obj.X,
|
||||
EndY: obj.Y,
|
||||
Speed: 0,
|
||||
Direction: 1.0,
|
||||
IsActive: true,
|
||||
CurrentX: atX + mp.StartX,
|
||||
CurrentY: mp.StartY,
|
||||
IsActive: false,
|
||||
CurrentX: atX + obj.X,
|
||||
CurrentY: obj.Y,
|
||||
HitboxW: asset.Hitbox.W,
|
||||
HitboxH: asset.Hitbox.H,
|
||||
DrawOffX: asset.DrawOffX,
|
||||
@@ -256,7 +277,7 @@ func (g *Game) checkOfflineCollisions(p *game.PlayerState) {
|
||||
pDrawX = def.DrawOffX
|
||||
pDrawY = def.DrawOffY
|
||||
}
|
||||
|
||||
|
||||
pRect := game.Rect{
|
||||
OffsetX: p.X + pDrawX + pOffX,
|
||||
OffsetY: p.Y + pDrawY + pOffY,
|
||||
@@ -268,25 +289,29 @@ func (g *Game) checkOfflineCollisions(p *game.PlayerState) {
|
||||
chunkDef := g.world.ChunkLibrary[ac.ChunkID]
|
||||
for i, obj := range chunkDef.Objects {
|
||||
asset, ok := g.world.Manifest.Assets[obj.AssetID]
|
||||
if !ok { continue }
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
objID := fmt.Sprintf("%s_%d", ac.ChunkID, i)
|
||||
|
||||
// 1. COINS
|
||||
if asset.Type == "coin" {
|
||||
if g.gameState.CollectedCoins[objID] { continue }
|
||||
|
||||
if g.gameState.CollectedCoins[objID] {
|
||||
continue
|
||||
}
|
||||
|
||||
coinX := ac.X + obj.X + asset.DrawOffX + asset.Hitbox.OffsetX
|
||||
coinY := obj.Y + asset.DrawOffY + asset.Hitbox.OffsetY
|
||||
|
||||
|
||||
// Magnet-Effekt?
|
||||
if p.HasMagnet {
|
||||
playerCenterX := pRect.OffsetX + pRect.W/2
|
||||
playerCenterY := pRect.OffsetY + pRect.H/2
|
||||
coinCenterX := coinX + asset.Hitbox.W/2
|
||||
coinCenterY := coinY + asset.Hitbox.H/2
|
||||
|
||||
dist := math.Sqrt(math.Pow(playerCenterX - coinCenterX, 2) + math.Pow(playerCenterY - coinCenterY, 2))
|
||||
|
||||
dist := math.Sqrt(math.Pow(playerCenterX-coinCenterX, 2) + math.Pow(playerCenterY-coinCenterY, 2))
|
||||
if dist < 300 {
|
||||
// Münze wird eingesammelt wenn im Magnet-Radius
|
||||
g.gameState.CollectedCoins[objID] = true
|
||||
@@ -306,8 +331,10 @@ func (g *Game) checkOfflineCollisions(p *game.PlayerState) {
|
||||
|
||||
// 2. POWERUPS
|
||||
if asset.Type == "powerup" {
|
||||
if g.gameState.CollectedPowerups[objID] { continue }
|
||||
|
||||
if g.gameState.CollectedPowerups[objID] {
|
||||
continue
|
||||
}
|
||||
|
||||
puRect := game.Rect{
|
||||
OffsetX: ac.X + obj.X + asset.DrawOffX + asset.Hitbox.OffsetX,
|
||||
OffsetY: obj.Y + asset.DrawOffY + asset.Hitbox.OffsetY,
|
||||
@@ -318,7 +345,7 @@ func (g *Game) checkOfflineCollisions(p *game.PlayerState) {
|
||||
if game.CheckRectCollision(pRect, puRect) {
|
||||
g.gameState.CollectedPowerups[objID] = true
|
||||
g.audio.PlayPowerUp()
|
||||
|
||||
|
||||
switch obj.AssetID {
|
||||
case "jumpboost":
|
||||
p.HasDoubleJump = true
|
||||
|
||||
Reference in New Issue
Block a user