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"`
|
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 {
|
||||||
|
|||||||
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) {
|
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
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user