Private
Public Access
1
0

Implement core game functionalities: client prediction, coin collection, scoring, game state synchronization, and player management.

This commit is contained in:
Sebastian Unterschütz
2026-01-01 16:46:39 +01:00
parent 4b2995846e
commit 5e6b8a2304
9 changed files with 902 additions and 203 deletions

129
pkg/server/scoring.go Normal file
View File

@@ -0,0 +1,129 @@
package server
import (
"fmt"
"log"
"git.zb-server.de/ZB-Server/EscapeFromTeacher/pkg/game"
)
// CheckCoinCollision prüft ob Spieler Coins einsammelt
func (r *Room) CheckCoinCollision(p *ServerPlayer) {
if !p.IsAlive || p.IsSpectator {
return
}
playerHitbox := game.Rect{
OffsetX: p.X + r.pDrawOffX + r.pHitboxOffX,
OffsetY: p.Y + r.pDrawOffY + r.pHitboxOffY,
W: r.pW,
H: r.pH,
}
// Durch alle aktiven Chunks iterieren
for _, activeChunk := range r.ActiveChunks {
chunkDef, exists := r.World.ChunkLibrary[activeChunk.ChunkID]
if !exists {
continue
}
// Durch alle Objekte im Chunk
for objIdx, obj := range chunkDef.Objects {
assetDef, ok := r.World.Manifest.Assets[obj.AssetID]
if !ok {
continue
}
// Nur Coins prüfen
if assetDef.Type != "coin" {
continue
}
// Eindeutiger Key für diesen Coin
coinKey := fmt.Sprintf("%s_%d", activeChunk.ChunkID, objIdx)
// Wurde bereits eingesammelt?
if r.CollectedCoins[coinKey] {
continue
}
// Coin-Hitbox
coinHitbox := game.Rect{
OffsetX: activeChunk.X + obj.X + assetDef.Hitbox.OffsetX,
OffsetY: obj.Y + assetDef.Hitbox.OffsetY,
W: assetDef.Hitbox.W,
H: assetDef.Hitbox.H,
}
// Kollision?
if game.CheckRectCollision(playerHitbox, coinHitbox) {
// Coin einsammeln!
r.CollectedCoins[coinKey] = true
p.Score += 200
log.Printf("💰 %s hat Coin eingesammelt! Score: %d", p.Name, p.Score)
}
}
}
}
// UpdateDistanceScore aktualisiert Distanz-basierte Punkte
func (r *Room) UpdateDistanceScore() {
if r.Status != "RUNNING" {
return
}
// Anzahl lebender Spieler zählen
aliveCount := 0
for _, p := range r.Players {
if p.IsAlive && !p.IsSpectator {
aliveCount++
}
}
if aliveCount == 0 {
return
}
// Multiplier = Anzahl lebender Spieler
multiplier := float64(aliveCount)
// Akkumulator erhöhen: multiplier Punkte pro Sekunde
// Bei 60 FPS: multiplier / 60.0 Punkte pro Tick
r.ScoreAccum += multiplier / 60.0
// Wenn Akkumulator >= 1.0, Punkte vergeben
if r.ScoreAccum >= 1.0 {
pointsToAdd := int(r.ScoreAccum)
r.ScoreAccum -= float64(pointsToAdd)
for _, p := range r.Players {
if p.IsAlive && !p.IsSpectator {
p.Score += pointsToAdd
}
}
}
}
// KillPlayer markiert Spieler als tot
func (r *Room) KillPlayer(p *ServerPlayer) {
if !p.IsAlive {
return
}
p.IsAlive = false
p.IsSpectator = true
log.Printf("💀 %s ist gestorben! Final Score: %d", p.Name, p.Score)
// Prüfen ob alle tot sind
aliveCount := 0
for _, pl := range r.Players {
if pl.IsAlive && !pl.IsSpectator {
aliveCount++
}
}
if aliveCount == 0 && r.Status == "RUNNING" {
log.Printf("🏁 Alle Spieler tot - Game Over!")
r.Status = "GAMEOVER"
}
}