add Sprechblasen
All checks were successful
Dynamic Branch Deploy / build-and-deploy (push) Successful in 2m21s
All checks were successful
Dynamic Branch Deploy / build-and-deploy (push) Successful in 2m21s
This commit is contained in:
1
types.go
1
types.go
@@ -57,6 +57,7 @@ type ActiveObstacle struct {
|
||||
Y float64 `json:"y"`
|
||||
Width float64 `json:"w"`
|
||||
Height float64 `json:"h"`
|
||||
Speech string `json:"speech,omitempty"`
|
||||
}
|
||||
|
||||
type ActivePlatform struct {
|
||||
|
||||
99
websocket.go
99
websocket.go
@@ -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) {
|
||||
var createdObs []ActiveObstacle
|
||||
var createdPlats []ActivePlatform
|
||||
|
||||
// Initialisierung beim ersten Lauf
|
||||
if s.NextSpawnTick == 0 {
|
||||
s.NextSpawnTick = tick + 50
|
||||
}
|
||||
|
||||
// Ist es Zeit für etwas Neues?
|
||||
if tick >= s.NextSpawnTick {
|
||||
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 {
|
||||
// =================================================
|
||||
// OPTION A: CHUNK SPAWNING
|
||||
// =================================================
|
||||
idx := int(s.RNG.NextRange(0, float64(chunkCount)))
|
||||
chunk := s.Chunks[idx]
|
||||
chunk := defaultConfig.Chunks[idx]
|
||||
|
||||
// 1. Plattformen übernehmen
|
||||
for _, p := range chunk.Platforms {
|
||||
createdPlats = append(createdPlats, ActivePlatform{X: spawnX + p.X, Y: p.Y, Width: p.Width, Height: p.Height})
|
||||
}
|
||||
for _, o := range chunk.Obstacles {
|
||||
createdObs = append(createdObs, ActiveObstacle{ID: o.ID, Type: o.Type, X: spawnX + o.X, Y: o.Y, Width: o.Width, Height: o.Height})
|
||||
createdPlats = append(createdPlats, ActivePlatform{
|
||||
X: spawnX + p.X,
|
||||
Y: p.Y,
|
||||
Width: p.Width,
|
||||
Height: p.Height,
|
||||
})
|
||||
}
|
||||
|
||||
width := chunk.TotalWidth
|
||||
if width == 0 {
|
||||
width = 2000
|
||||
// 2. Hindernisse übernehmen & Speech berechnen
|
||||
for _, o := range chunk.Obstacles {
|
||||
|
||||
// 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 {
|
||||
// Random Logic
|
||||
// =================================================
|
||||
// OPTION B: RANDOM SPAWNING
|
||||
// =================================================
|
||||
|
||||
// Lücke berechnen
|
||||
gap := 400 + int(s.RNG.NextRange(0, 500))
|
||||
s.NextSpawnTick = tick + int(float64(gap)/speed)
|
||||
|
||||
// Pool bilden (Boss Phase?)
|
||||
defs := defaultConfig.Obstacles
|
||||
if len(defs) > 0 {
|
||||
// Boss Check
|
||||
isBoss := (tick % 1500) > 1200
|
||||
var pool []ObstacleDef
|
||||
|
||||
for _, d := range defs {
|
||||
if isBoss {
|
||||
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)
|
||||
|
||||
if def != nil {
|
||||
// RNG Calls to keep sync (optional now, but good practice)
|
||||
if def.CanTalk && s.RNG.NextFloat() > 0.7 {
|
||||
}
|
||||
// Powerup Rarity (90% Chance, dass es NICHT spawnt)
|
||||
if def.Type == "powerup" && s.RNG.NextFloat() > 0.1 {
|
||||
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{
|
||||
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
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user