Private
Public Access
1
0
Files
EscapeFromTeacher/cmd/client/prediction.go
Sebastian Unterschütz 98e955aad9
All checks were successful
Dynamic Branch Deploy / build-and-deploy (push) Successful in 2m23s
Add analog joystick support with fine control adjustments, improve prediction smoothing, reduce correction thresholds, and enhance lobby and overlay UI responsiveness.
2026-01-04 19:43:09 +01:00

129 lines
3.1 KiB
Go

package main
import (
"git.zb-server.de/ZB-Server/EscapeFromTeacher/pkg/config"
"git.zb-server.de/ZB-Server/EscapeFromTeacher/pkg/game"
)
// ApplyInput wendet einen Input auf den vorhergesagten Zustand an
func (g *Game) ApplyInput(input InputState) {
// Horizontale Bewegung mit analogem Joystick
moveX := 0.0
if input.Left {
moveX = -1.0
} else if input.Right {
moveX = 1.0
}
// Wenn Joystick benutzt wird, überschreibe moveX mit analogem Wert
if input.JoyX != 0 {
moveX = input.JoyX
}
// Geschwindigkeit skaliert mit Joystick-Intensität
speed := config.RunSpeed + (moveX * 4.0)
g.predictedX += speed
// Gravitation
g.predictedVY += config.Gravity
if g.predictedVY > config.MaxFall {
g.predictedVY = config.MaxFall
}
// Fast Fall
if input.Down {
g.predictedVY = 15.0
}
// Sprung
if input.Jump && g.predictedGround {
g.predictedVY = -14.0
g.predictedGround = false
}
// Vertikale Bewegung
g.predictedY += g.predictedVY
// Einfache Boden-Kollision (hardcoded für jetzt)
if g.predictedY >= 540 {
g.predictedY = 540
g.predictedVY = 0
g.predictedGround = true
} else {
g.predictedGround = false
}
}
// ReconcileWithServer gleicht lokale Prediction mit Server-State ab
func (g *Game) ReconcileWithServer(serverState game.PlayerState) {
g.predictionMutex.Lock()
defer g.predictionMutex.Unlock()
// Server-bestätigte Sequenz
g.lastServerSeq = serverState.LastInputSeq
// Entferne alle bestätigten Inputs
for seq := range g.pendingInputs {
if seq <= g.lastServerSeq {
delete(g.pendingInputs, seq)
}
}
// Temporäre Position für Replay
replayX := serverState.X
replayY := serverState.Y
replayVX := serverState.VX
replayVY := serverState.VY
replayGround := serverState.OnGround
// Replay alle noch nicht bestätigten Inputs
if len(g.pendingInputs) > 0 {
for seq := g.lastServerSeq + 1; seq <= g.inputSequence; seq++ {
if input, ok := g.pendingInputs[seq]; ok {
// Temporär auf Replay-Position setzen
oldX, oldY := g.predictedX, g.predictedY
oldVX, oldVY := g.predictedVX, g.predictedVY
oldGround := g.predictedGround
g.predictedX = replayX
g.predictedY = replayY
g.predictedVX = replayVX
g.predictedVY = replayVY
g.predictedGround = replayGround
g.ApplyInput(input)
replayX = g.predictedX
replayY = g.predictedY
replayVX = g.predictedVX
replayVY = g.predictedVY
replayGround = g.predictedGround
// Zurücksetzen
g.predictedX = oldX
g.predictedY = oldY
g.predictedVX = oldVX
g.predictedVY = oldVY
g.predictedGround = oldGround
}
}
}
// Berechne Differenz zwischen aktueller Prediction und Server-Replay
diffX := replayX - g.predictedX
diffY := replayY - g.predictedY
// Nur korrigieren wenn Differenz signifikant (reduzierter Threshold für weniger Ruckeln)
const threshold = 2.0 // Reduziert von 5.0 auf 2.0
if diffX*diffX+diffY*diffY > threshold*threshold {
// Speichere Korrektur für sanfte Interpolation
g.correctionX = diffX
g.correctionY = diffY
}
// Velocity und Ground immer sofort übernehmen
g.predictedVX = replayVX
g.predictedVY = replayVY
g.predictedGround = replayGround
}