Integrate shared physics engine for player movement and collision handling, refine 20 TPS gameplay logic, and enhance client prediction with server-reconciliation updates.
All checks were successful
Dynamic Branch Deploy / build-and-deploy (push) Successful in 7m51s
All checks were successful
Dynamic Branch Deploy / build-and-deploy (push) Successful in 7m51s
This commit is contained in:
@@ -1,11 +1,12 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"git.zb-server.de/ZB-Server/EscapeFromTeacher/pkg/config"
|
||||
"git.zb-server.de/ZB-Server/EscapeFromTeacher/pkg/game"
|
||||
"git.zb-server.de/ZB-Server/EscapeFromTeacher/pkg/physics"
|
||||
)
|
||||
|
||||
// ApplyInput wendet einen Input auf den vorhergesagten Zustand an
|
||||
// Nutzt die gemeinsame Physik-Engine aus pkg/physics
|
||||
func (g *Game) ApplyInput(input InputState) {
|
||||
// Horizontale Bewegung mit analogem Joystick
|
||||
moveX := 0.0
|
||||
@@ -20,39 +21,42 @@ func (g *Game) ApplyInput(input InputState) {
|
||||
moveX = input.JoyX
|
||||
}
|
||||
|
||||
// Geschwindigkeit skaliert mit Joystick-Intensität
|
||||
// Bewegung relativ zum Scroll (symmetrisch)
|
||||
speed := config.RunSpeed + (moveX * config.PlayerSpeed)
|
||||
g.predictedX += speed
|
||||
|
||||
// Gravitation
|
||||
g.predictedVY += config.Gravity
|
||||
if g.predictedVY > config.MaxFall {
|
||||
g.predictedVY = config.MaxFall
|
||||
// Physik-State vorbereiten
|
||||
state := physics.PlayerPhysicsState{
|
||||
X: g.predictedX,
|
||||
Y: g.predictedY,
|
||||
VX: g.predictedVX,
|
||||
VY: g.predictedVY,
|
||||
OnGround: g.predictedGround,
|
||||
OnWall: g.predictedOnWall,
|
||||
}
|
||||
|
||||
// Fast Fall
|
||||
if input.Down {
|
||||
g.predictedVY = config.FastFall
|
||||
// Physik-Input vorbereiten
|
||||
physicsInput := physics.PhysicsInput{
|
||||
InputX: moveX,
|
||||
Jump: input.Jump,
|
||||
Down: input.Down,
|
||||
}
|
||||
|
||||
// Sprung
|
||||
if input.Jump && g.predictedGround {
|
||||
g.predictedVY = -config.JumpVelocity
|
||||
g.predictedGround = false
|
||||
// Kollisions-Checker vorbereiten
|
||||
g.stateMutex.Lock()
|
||||
collisionChecker := &physics.ClientCollisionChecker{
|
||||
World: g.world,
|
||||
ActiveChunks: g.gameState.WorldChunks,
|
||||
MovingPlatforms: g.gameState.MovingPlatforms,
|
||||
}
|
||||
g.stateMutex.Unlock()
|
||||
|
||||
// Vertikale Bewegung
|
||||
g.predictedY += g.predictedVY
|
||||
// Gemeinsame Physik anwenden (1:1 wie Server)
|
||||
physics.ApplyPhysics(&state, physicsInput, g.currentSpeed, collisionChecker, physics.DefaultPlayerConstants())
|
||||
|
||||
// Einfache Boden-Kollision (hardcoded für jetzt)
|
||||
if g.predictedY >= 540 {
|
||||
g.predictedY = 540
|
||||
g.predictedVY = 0
|
||||
g.predictedGround = true
|
||||
} else {
|
||||
g.predictedGround = false
|
||||
}
|
||||
// Ergebnis zurückschreiben
|
||||
g.predictedX = state.X
|
||||
g.predictedY = state.Y
|
||||
g.predictedVX = state.VX
|
||||
g.predictedVY = state.VY
|
||||
g.predictedGround = state.OnGround
|
||||
g.predictedOnWall = state.OnWall
|
||||
}
|
||||
|
||||
// ReconcileWithServer gleicht lokale Prediction mit Server-State ab
|
||||
@@ -70,14 +74,15 @@ func (g *Game) ReconcileWithServer(serverState game.PlayerState) {
|
||||
}
|
||||
}
|
||||
|
||||
// Temporäre Position für Replay
|
||||
// Temporäre Position für Replay (jetzt MIT Y-Achse)
|
||||
replayX := serverState.X
|
||||
replayY := serverState.Y
|
||||
replayVX := serverState.VX
|
||||
replayVY := serverState.VY
|
||||
replayGround := serverState.OnGround
|
||||
replayOnWall := serverState.OnWall
|
||||
|
||||
// Replay alle noch nicht bestätigten Inputs
|
||||
// Replay alle noch nicht bestätigten Inputs mit VOLLER Physik
|
||||
if len(g.pendingInputs) > 0 {
|
||||
for seq := g.lastServerSeq + 1; seq <= g.inputSequence; seq++ {
|
||||
if input, ok := g.pendingInputs[seq]; ok {
|
||||
@@ -85,12 +90,14 @@ func (g *Game) ReconcileWithServer(serverState game.PlayerState) {
|
||||
oldX, oldY := g.predictedX, g.predictedY
|
||||
oldVX, oldVY := g.predictedVX, g.predictedVY
|
||||
oldGround := g.predictedGround
|
||||
oldOnWall := g.predictedOnWall
|
||||
|
||||
g.predictedX = replayX
|
||||
g.predictedY = replayY
|
||||
g.predictedVX = replayVX
|
||||
g.predictedVY = replayVY
|
||||
g.predictedGround = replayGround
|
||||
g.predictedOnWall = replayOnWall
|
||||
|
||||
g.ApplyInput(input)
|
||||
|
||||
@@ -99,6 +106,7 @@ func (g *Game) ReconcileWithServer(serverState game.PlayerState) {
|
||||
replayVX = g.predictedVX
|
||||
replayVY = g.predictedVY
|
||||
replayGround = g.predictedGround
|
||||
replayOnWall = g.predictedOnWall
|
||||
|
||||
// Zurücksetzen
|
||||
g.predictedX = oldX
|
||||
@@ -106,25 +114,44 @@ func (g *Game) ReconcileWithServer(serverState game.PlayerState) {
|
||||
g.predictedVX = oldVX
|
||||
g.predictedVY = oldVY
|
||||
g.predictedGround = oldGround
|
||||
g.predictedOnWall = oldOnWall
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Berechne Differenz zwischen aktueller Prediction und Server-Replay
|
||||
// Berechne Differenz zwischen Client-Prediction und Server-Replay (X und Y)
|
||||
diffX := replayX - g.predictedX
|
||||
diffY := replayY - g.predictedY
|
||||
dist := diffX*diffX + diffY*diffY
|
||||
|
||||
// Nur korrigieren wenn Differenz signifikant
|
||||
// Bei 20 TPS größerer Threshold wegen größerer normaler Abweichungen
|
||||
const threshold = 5.0 // Erhöht für 20 TPS (war 2.0)
|
||||
if diffX*diffX+diffY*diffY > threshold*threshold {
|
||||
// Speichere Korrektur für sanfte Interpolation
|
||||
g.correctionX = diffX
|
||||
g.correctionY = diffY
|
||||
// Speichere Korrektur-Magnitude für Debug
|
||||
g.correctionX = diffX
|
||||
g.correctionY = diffY
|
||||
|
||||
// Bei sehr kleinen Abweichungen (<2px): Sofort korrigieren um Drift zu vermeiden
|
||||
if dist < 4.0 { // 2px threshold
|
||||
g.predictedX = replayX
|
||||
g.predictedY = replayY
|
||||
} else if dist > 100*100 {
|
||||
// Bei sehr großen Abweichungen (>100px): Sofort korrigieren (Teleport/Respawn)
|
||||
g.predictedX = replayX
|
||||
g.predictedY = replayY
|
||||
g.correctionCount++
|
||||
} else if dist > 1.0 {
|
||||
// Bei normalen Abweichungen: Sanfte Interpolation
|
||||
// Bei 20 TPS: Aggressivere Interpolation
|
||||
interpFactor := 0.5 // 50% pro Tick
|
||||
if dist > 50*50 {
|
||||
interpFactor = 0.8 // 80% bei großen Abweichungen
|
||||
}
|
||||
g.predictedX += diffX * interpFactor
|
||||
g.predictedY += diffY * interpFactor
|
||||
g.correctionCount++
|
||||
}
|
||||
|
||||
// Velocity und Ground immer sofort übernehmen
|
||||
// Velocity und Ground Status vom Server übernehmen
|
||||
g.predictedVX = replayVX
|
||||
g.predictedVY = replayVY
|
||||
g.predictedGround = replayGround
|
||||
g.predictedOnWall = replayOnWall
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user