From f1dff8d64cc3e5f7b648d5d070ce40cbdbb7141c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Untersch=C3=BCtz?= Date: Wed, 22 Apr 2026 23:52:32 +0200 Subject: [PATCH] add offline moving platform logic: implement dynamic platform detection and movement handling in offline mode --- cmd/client/offline_logic.go | 30 ++++++++++++++++--------- cmd/client/prediction.go | 44 +++++++++++++++++++++++++++++++++++++ pkg/game/world.go | 4 ++++ pkg/physics/physics.go | 10 ++++++++- 4 files changed, 77 insertions(+), 11 deletions(-) diff --git a/cmd/client/offline_logic.go b/cmd/client/offline_logic.go index 0fdce8b..849fa33 100644 --- a/cmd/client/offline_logic.go +++ b/cmd/client/offline_logic.go @@ -202,21 +202,26 @@ func (g *Game) spawnOfflineChunk(atX float64) { chunkDef := g.world.ChunkLibrary[randomID] for i, obj := range chunkDef.Objects { asset, ok := g.world.Manifest.Assets[obj.AssetID] - // In Solo gibt es keine MovingPlatformData, Plattformen sind statisch - if ok && asset.Type == "moving_platform" { + if !ok { + continue + } + + // Check ob es eine bewegende Plattform ist (entweder Typ oder explizite Daten) + if obj.MovingPlatform != nil { + mpData := obj.MovingPlatform p := &MovingPlatform{ ChunkID: randomID, ObjectIdx: i, AssetID: obj.AssetID, - StartX: atX + obj.X, - StartY: obj.Y, - EndX: atX + obj.X, - EndY: obj.Y, - Speed: 0, + StartX: atX + mpData.StartX, + StartY: mpData.StartY, + EndX: atX + mpData.EndX, + EndY: mpData.EndY, + Speed: mpData.Speed, Direction: 1.0, - IsActive: false, - CurrentX: atX + obj.X, - CurrentY: obj.Y, + IsActive: true, + CurrentX: atX + mpData.StartX, + CurrentY: mpData.StartY, HitboxW: asset.Hitbox.W, HitboxH: asset.Hitbox.H, DrawOffX: asset.DrawOffX, @@ -225,6 +230,11 @@ func (g *Game) spawnOfflineChunk(atX float64) { HitboxOffY: asset.Hitbox.OffsetY, } g.offlineMovingPlatforms = append(g.offlineMovingPlatforms, p) + } else if asset.Type == "moving_platform" || asset.Type == "platform" { + // Statische Plattform (oder Fallback) + // Wir fügen sie NICHT zu offlineMovingPlatforms hinzu, da sie über + // den statischen World-Collider Check in physics.go bereits erfasst wird. + // (Vorausgesetzt der Typ ist "platform") } } } diff --git a/cmd/client/prediction.go b/cmd/client/prediction.go index 16ecaa0..5bef7b5 100644 --- a/cmd/client/prediction.go +++ b/cmd/client/prediction.go @@ -2,6 +2,7 @@ package main import ( "log" + "math" "time" "git.zb-server.de/ZB-Server/EscapeFromTeacher/pkg/config" @@ -9,6 +10,26 @@ import ( "git.zb-server.de/ZB-Server/EscapeFromTeacher/pkg/physics" ) +// CheckMovingPlatformLanding prüft ob der Spieler auf einer bewegenden Plattform steht +func (g *Game) CheckMovingPlatformLanding(x, y, w, h float64) *MovingPlatform { + playerRect := game.Rect{OffsetX: x, OffsetY: y, W: w, H: h} + + for _, mp := range g.offlineMovingPlatforms { + mpRect := game.Rect{ + OffsetX: mp.CurrentX + mp.DrawOffX + mp.HitboxOffX, + OffsetY: mp.CurrentY + mp.DrawOffY + mp.HitboxOffY, + W: mp.HitboxW, + H: mp.HitboxH, + } + + // Etwas großzügigerer Check nach oben + if game.CheckRectCollision(playerRect, mpRect) { + return mp + } + } + return nil +} + // ApplyInput wendet einen Input auf den vorhergesagten Zustand an // Nutzt die gemeinsame Physik-Engine aus pkg/physics func (g *Game) ApplyInput(input InputState) { @@ -20,6 +41,29 @@ func (g *Game) ApplyInput(input InputState) { return } + // --- OFFLINE: Mit Plattform mitbewegen --- + if g.isOffline && g.predictedGround { + pConst := physics.DefaultPlayerConstants() + mp := g.CheckMovingPlatformLanding( + g.predictedX+pConst.DrawOffX+pConst.HitboxOffX, + g.predictedY+pConst.DrawOffY+pConst.HitboxOffY, + pConst.Width, + pConst.Height, + ) + if mp != nil { + // Berechne Plattform-Geschwindigkeit + dx := mp.EndX - mp.StartX + dy := mp.EndY - mp.StartY + dist := math.Sqrt(dx*dx + dy*dy) + if dist > 0.1 { + vx := (dx / dist) * (mp.Speed / 20.0) * mp.Direction + vy := (dy / dist) * (mp.Speed / 20.0) * mp.Direction + g.predictedX += vx + g.predictedY += vy + } + } + } + // Horizontale Bewegung mit analogem Joystick moveX := 0.0 if input.Left { diff --git a/pkg/game/world.go b/pkg/game/world.go index 43a0a87..e45920d 100644 --- a/pkg/game/world.go +++ b/pkg/game/world.go @@ -77,6 +77,10 @@ func (w *World) GenerateColliders(activeChunks []ActiveChunk) []Collider { } for _, obj := range chunk.Objects { + if obj.MovingPlatform != nil { + continue // Überspringe bewegende Plattformen, werden dynamisch geprüft + } + def, ok := w.Manifest.Assets[obj.AssetID] if !ok { fmt.Printf("⚠️ Asset '%s' nicht in Manifest!\n", obj.AssetID) diff --git a/pkg/physics/physics.go b/pkg/physics/physics.go index 8bec23d..0d40c3b 100644 --- a/pkg/physics/physics.go +++ b/pkg/physics/physics.go @@ -218,6 +218,10 @@ func (c *ClientCollisionChecker) CheckCollision(x, y, w, h float64) (bool, strin for _, activeChunk := range c.ActiveChunks { if chunk, ok := c.World.ChunkLibrary[activeChunk.ChunkID]; ok { for _, obj := range chunk.Objects { + if obj.MovingPlatform != nil { + continue // Wird separat als MovingPlatform geprüft + } + if assetDef, ok := c.World.Manifest.Assets[obj.AssetID]; ok { if assetDef.Hitbox.W > 0 && assetDef.Hitbox.H > 0 { colliderRect := game.Rect{ @@ -228,7 +232,11 @@ func (c *ClientCollisionChecker) CheckCollision(x, y, w, h float64) (bool, strin } if game.CheckRectCollision(playerRect, colliderRect) { - return true, assetDef.Hitbox.Type + colType := assetDef.Hitbox.Type + if colType == "" { + colType = assetDef.Type + } + return true, colType } } }