Private
Public Access
1
0

add offline moving platform logic: implement dynamic platform detection and movement handling in offline mode
All checks were successful
Dynamic Branch Deploy / build-and-deploy (push) Successful in 1m49s

This commit is contained in:
Sebastian Unterschütz
2026-04-22 23:52:32 +02:00
parent 0e15b3fe53
commit f1dff8d64c
4 changed files with 77 additions and 11 deletions

View File

@@ -202,21 +202,26 @@ func (g *Game) spawnOfflineChunk(atX float64) {
chunkDef := g.world.ChunkLibrary[randomID] chunkDef := g.world.ChunkLibrary[randomID]
for i, obj := range chunkDef.Objects { for i, obj := range chunkDef.Objects {
asset, ok := g.world.Manifest.Assets[obj.AssetID] asset, ok := g.world.Manifest.Assets[obj.AssetID]
// In Solo gibt es keine MovingPlatformData, Plattformen sind statisch if !ok {
if ok && asset.Type == "moving_platform" { continue
}
// Check ob es eine bewegende Plattform ist (entweder Typ oder explizite Daten)
if obj.MovingPlatform != nil {
mpData := obj.MovingPlatform
p := &MovingPlatform{ p := &MovingPlatform{
ChunkID: randomID, ChunkID: randomID,
ObjectIdx: i, ObjectIdx: i,
AssetID: obj.AssetID, AssetID: obj.AssetID,
StartX: atX + obj.X, StartX: atX + mpData.StartX,
StartY: obj.Y, StartY: mpData.StartY,
EndX: atX + obj.X, EndX: atX + mpData.EndX,
EndY: obj.Y, EndY: mpData.EndY,
Speed: 0, Speed: mpData.Speed,
Direction: 1.0, Direction: 1.0,
IsActive: false, IsActive: true,
CurrentX: atX + obj.X, CurrentX: atX + mpData.StartX,
CurrentY: obj.Y, CurrentY: mpData.StartY,
HitboxW: asset.Hitbox.W, HitboxW: asset.Hitbox.W,
HitboxH: asset.Hitbox.H, HitboxH: asset.Hitbox.H,
DrawOffX: asset.DrawOffX, DrawOffX: asset.DrawOffX,
@@ -225,6 +230,11 @@ func (g *Game) spawnOfflineChunk(atX float64) {
HitboxOffY: asset.Hitbox.OffsetY, HitboxOffY: asset.Hitbox.OffsetY,
} }
g.offlineMovingPlatforms = append(g.offlineMovingPlatforms, p) 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")
} }
} }
} }

View File

@@ -2,6 +2,7 @@ package main
import ( import (
"log" "log"
"math"
"time" "time"
"git.zb-server.de/ZB-Server/EscapeFromTeacher/pkg/config" "git.zb-server.de/ZB-Server/EscapeFromTeacher/pkg/config"
@@ -9,6 +10,26 @@ import (
"git.zb-server.de/ZB-Server/EscapeFromTeacher/pkg/physics" "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 // ApplyInput wendet einen Input auf den vorhergesagten Zustand an
// Nutzt die gemeinsame Physik-Engine aus pkg/physics // Nutzt die gemeinsame Physik-Engine aus pkg/physics
func (g *Game) ApplyInput(input InputState) { func (g *Game) ApplyInput(input InputState) {
@@ -20,6 +41,29 @@ func (g *Game) ApplyInput(input InputState) {
return 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 // Horizontale Bewegung mit analogem Joystick
moveX := 0.0 moveX := 0.0
if input.Left { if input.Left {

View File

@@ -77,6 +77,10 @@ func (w *World) GenerateColliders(activeChunks []ActiveChunk) []Collider {
} }
for _, obj := range chunk.Objects { for _, obj := range chunk.Objects {
if obj.MovingPlatform != nil {
continue // Überspringe bewegende Plattformen, werden dynamisch geprüft
}
def, ok := w.Manifest.Assets[obj.AssetID] def, ok := w.Manifest.Assets[obj.AssetID]
if !ok { if !ok {
fmt.Printf("⚠️ Asset '%s' nicht in Manifest!\n", obj.AssetID) fmt.Printf("⚠️ Asset '%s' nicht in Manifest!\n", obj.AssetID)

View File

@@ -218,6 +218,10 @@ func (c *ClientCollisionChecker) CheckCollision(x, y, w, h float64) (bool, strin
for _, activeChunk := range c.ActiveChunks { for _, activeChunk := range c.ActiveChunks {
if chunk, ok := c.World.ChunkLibrary[activeChunk.ChunkID]; ok { if chunk, ok := c.World.ChunkLibrary[activeChunk.ChunkID]; ok {
for _, obj := range chunk.Objects { 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, ok := c.World.Manifest.Assets[obj.AssetID]; ok {
if assetDef.Hitbox.W > 0 && assetDef.Hitbox.H > 0 { if assetDef.Hitbox.W > 0 && assetDef.Hitbox.H > 0 {
colliderRect := game.Rect{ colliderRect := game.Rect{
@@ -228,7 +232,11 @@ func (c *ClientCollisionChecker) CheckCollision(x, y, w, h float64) (bool, strin
} }
if game.CheckRectCollision(playerRect, colliderRect) { if game.CheckRectCollision(playerRect, colliderRect) {
return true, assetDef.Hitbox.Type colType := assetDef.Hitbox.Type
if colType == "" {
colType = assetDef.Type
}
return true, colType
} }
} }
} }