Private
Public Access
1
0

add Sprechblasen
All checks were successful
Dynamic Branch Deploy / build-and-deploy (push) Successful in 2m21s

This commit is contained in:
Sebastian Unterschütz
2025-11-30 19:00:59 +01:00
parent 61e82e0dba
commit 56dd8db9a3
2 changed files with 83 additions and 17 deletions

View File

@@ -57,6 +57,7 @@ type ActiveObstacle struct {
Y float64 `json:"y"` Y float64 `json:"y"`
Width float64 `json:"w"` Width float64 `json:"w"`
Height float64 `json:"h"` Height float64 `json:"h"`
Speech string `json:"speech,omitempty"`
} }
type ActivePlatform struct { type ActivePlatform struct {

View File

@@ -235,46 +235,93 @@ func handleWebSocket(w http.ResponseWriter, r *http.Request) {
} }
} }
// ... (generateFutureObjects bleibt gleich wie vorher) ... // Hilfsfunktion: Generiert Objekte für EINEN Tick in der Zukunft
func generateFutureObjects(s *SimState, tick int, speed float64) ([]ActiveObstacle, []ActivePlatform) { func generateFutureObjects(s *SimState, tick int, speed float64) ([]ActiveObstacle, []ActivePlatform) {
var createdObs []ActiveObstacle var createdObs []ActiveObstacle
var createdPlats []ActivePlatform var createdPlats []ActivePlatform
// Initialisierung beim ersten Lauf
if s.NextSpawnTick == 0 { if s.NextSpawnTick == 0 {
s.NextSpawnTick = tick + 50 s.NextSpawnTick = tick + 50
} }
// Ist es Zeit für etwas Neues?
if tick >= s.NextSpawnTick { if tick >= s.NextSpawnTick {
spawnX := SpawnXStart spawnX := SpawnXStart
chunkCount := len(s.Chunks) // --- ENTSCHEIDUNG: CHUNK vs RANDOM ---
// Wir nutzen die globalen Chunks (da Read-Only während des Spiels, ist Zugriff sicher)
chunkCount := len(defaultConfig.Chunks)
if chunkCount > 0 && s.RNG.NextFloat() > 0.8 { if chunkCount > 0 && s.RNG.NextFloat() > 0.8 {
// =================================================
// OPTION A: CHUNK SPAWNING
// =================================================
idx := int(s.RNG.NextRange(0, float64(chunkCount))) idx := int(s.RNG.NextRange(0, float64(chunkCount)))
chunk := s.Chunks[idx] chunk := defaultConfig.Chunks[idx]
// 1. Plattformen übernehmen
for _, p := range chunk.Platforms { for _, p := range chunk.Platforms {
createdPlats = append(createdPlats, ActivePlatform{X: spawnX + p.X, Y: p.Y, Width: p.Width, Height: p.Height}) createdPlats = append(createdPlats, ActivePlatform{
} X: spawnX + p.X,
for _, o := range chunk.Obstacles { Y: p.Y,
createdObs = append(createdObs, ActiveObstacle{ID: o.ID, Type: o.Type, X: spawnX + o.X, Y: o.Y, Width: o.Width, Height: o.Height}) Width: p.Width,
Height: p.Height,
})
} }
width := chunk.TotalWidth // 2. Hindernisse übernehmen & Speech berechnen
if width == 0 { for _, o := range chunk.Obstacles {
width = 2000
// Speech-Logik: Wir müssen die Original-Def finden, um zu wissen, ob er sprechen kann
speech := ""
for _, def := range defaultConfig.Obstacles {
if def.ID == o.ID {
// Wenn gefunden, würfeln wir
if def.CanTalk && len(def.SpeechLines) > 0 {
if s.RNG.NextFloat() > 0.7 { // 30% Wahrscheinlichkeit
sIdx := int(s.RNG.NextRange(0, float64(len(def.SpeechLines))))
speech = def.SpeechLines[sIdx]
} }
s.NextSpawnTick = tick + int(float64(width)/speed) }
break // Def gefunden, Loop abbrechen
}
}
createdObs = append(createdObs, ActiveObstacle{
ID: o.ID,
Type: o.Type,
X: spawnX + o.X,
Y: o.Y,
Width: o.Width,
Height: o.Height,
Speech: speech, // <--- HIER wird der Text gesetzt
})
}
// Timer setzen (Länge des Chunks)
width := float64(chunk.TotalWidth)
if width == 0 {
width = 2000.0
}
s.NextSpawnTick = tick + int(width/speed)
} else { } else {
// Random Logic // =================================================
// OPTION B: RANDOM SPAWNING
// =================================================
// Lücke berechnen
gap := 400 + int(s.RNG.NextRange(0, 500)) gap := 400 + int(s.RNG.NextRange(0, 500))
s.NextSpawnTick = tick + int(float64(gap)/speed) s.NextSpawnTick = tick + int(float64(gap)/speed)
// Pool bilden (Boss Phase?)
defs := defaultConfig.Obstacles defs := defaultConfig.Obstacles
if len(defs) > 0 { if len(defs) > 0 {
// Boss Check
isBoss := (tick % 1500) > 1200 isBoss := (tick % 1500) > 1200
var pool []ObstacleDef var pool []ObstacleDef
for _, d := range defs { for _, d := range defs {
if isBoss { if isBoss {
if d.ID == "principal" || d.ID == "trashcan" { if d.ID == "principal" || d.ID == "trashcan" {
@@ -287,18 +334,36 @@ func generateFutureObjects(s *SimState, tick int, speed float64) ([]ActiveObstac
} }
} }
// Objekt auswählen
def := s.RNG.PickDef(pool) def := s.RNG.PickDef(pool)
if def != nil { if def != nil {
// RNG Calls to keep sync (optional now, but good practice) // Powerup Rarity (90% Chance, dass es NICHT spawnt)
if def.CanTalk && s.RNG.NextFloat() > 0.7 {
}
if def.Type == "powerup" && s.RNG.NextFloat() > 0.1 { if def.Type == "powerup" && s.RNG.NextFloat() > 0.1 {
def = nil def = nil
} }
if def != nil { if def != nil {
// Speech Logik
speech := ""
if def.CanTalk && len(def.SpeechLines) > 0 {
if s.RNG.NextFloat() > 0.7 {
sIdx := int(s.RNG.NextRange(0, float64(len(def.SpeechLines))))
speech = def.SpeechLines[sIdx]
}
}
// Y-Position berechnen (Boden - Höhe - Offset)
spawnY := GroundY - def.Height - def.YOffset
createdObs = append(createdObs, ActiveObstacle{ createdObs = append(createdObs, ActiveObstacle{
ID: def.ID, Type: def.Type, X: spawnX, Y: GroundY - def.Height - def.YOffset, Width: def.Width, Height: def.Height, ID: def.ID,
Type: def.Type,
X: spawnX,
Y: spawnY,
Width: def.Width,
Height: def.Height,
Speech: speech, // <--- HIER wird der Text gesetzt
}) })
} }
} }