Private
Public Access
1
0

add teacher and milestone quotes: implement random quotes, speech bubbles, and milestone achievements display
Some checks failed
Dynamic Branch Deploy / build-and-deploy (push) Failing after 1m35s

This commit is contained in:
Sebastian Unterschütz
2026-04-22 19:53:15 +02:00
parent 8454557f16
commit 568ce516e7
3 changed files with 115 additions and 3 deletions

View File

@@ -260,6 +260,9 @@ func (g *Game) UpdateGame() {
if len(g.trail) > 8 {
g.trail = g.trail[1:]
}
// --- Zitate & Meilensteine ---
g.updateQuotes()
}
// --- 6. KAMERA LOGIK (mit Smoothing) ---
@@ -604,6 +607,13 @@ func (g *Game) drawStatusUI(screen *ebiten.Image, snap renderSnapshot) {
if snap.isDead {
g.drawSpectatorOverlay(screen, snap)
}
// --- MEILENSTEIN-QUOTE ---
if time.Now().Before(g.milestoneQuoteTime) {
msg := fmt.Sprintf("🎉 %d PUNKTE! \"%s\"", g.lastMilestone, g.milestoneQuote.Text)
tw := float32(len(msg) * 7)
text.Draw(screen, msg, basicfont.Face7x13, int(float32(snap.canvasW)/2-tw/2), 60, color.RGBA{255, 255, 0, 255})
}
}
}
@@ -781,6 +791,64 @@ func (g *Game) TriggerShake(frames int, intensity float64) {
}
}
// updateQuotes verarbeitet die Logik für zufällige Lehrer-Sprüche und Meilensteine.
func (g *Game) updateQuotes() {
g.stateMutex.Lock()
status := g.gameState.Status
myScore := 0
for _, p := range g.gameState.Players {
if p.Name == g.playerName {
myScore = p.Score
break
}
}
g.stateMutex.Unlock()
if status != "RUNNING" {
return
}
now := time.Now()
// 1. Zufällige Lehrer-Sprüche (alle 10-25 Sekunden)
if now.After(g.teacherQuoteTime) {
g.teacherQuote = game.GetRandomQuote()
// Nächster Spruch in 15-30 Sekunden
g.teacherQuoteTime = now.Add(time.Duration(15+rand.Intn(15)) * time.Second)
}
// 2. Meilensteine (alle 1000 Punkte)
milestone := (myScore / 1000) * 1000
if milestone > 0 && milestone > g.lastMilestone {
g.lastMilestone = milestone
g.milestoneQuote = game.GetRandomQuote()
g.milestoneQuoteTime = now.Add(4 * time.Second) // 4 Sekunden anzeigen
log.Printf("🎉 Meilenstein erreicht: %d Punkte!", milestone)
}
}
// drawSpeechBubble zeichnet eine einfache Sprechblase mit Text.
func (g *Game) drawSpeechBubble(screen *ebiten.Image, x, y float32, msg string) {
// Text-Breite grob schätzen (Face7x13: ca 7px pro Zeichen)
tw := float32(len(msg) * 7)
th := float32(15)
padding := float32(8)
bx := x + 10
by := y - th - padding*2
bw := tw + padding*2
bh := th + padding*2
// Hintergrund
vector.DrawFilledRect(screen, bx, by, bw, bh, color.RGBA{255, 255, 255, 220}, false)
vector.StrokeRect(screen, bx, by, bw, bh, 2, color.Black, false)
// Kleiner Pfeil
vector.DrawFilledCircle(screen, bx, by+bh/2, 5, color.RGBA{255, 255, 255, 220}, false)
text.Draw(screen, msg, basicfont.Face7x13, int(bx+padding), int(by+padding+10), color.Black)
}
// drawTeacher zeichnet den Lehrer-Charakter am linken Bildschirmrand.
func (g *Game) drawTeacher(screen *ebiten.Image, snap renderSnapshot) {
if snap.status != "RUNNING" && snap.status != "COUNTDOWN" {
@@ -825,8 +893,13 @@ func (g *Game) drawTeacher(screen *ebiten.Image, snap renderSnapshot) {
// Legs
vector.DrawFilledRect(screen, bodyX+1, groundY, bodyW/2-2, float32(snap.canvasH), color.RGBA{60, 10, 10, alpha}, false)
vector.DrawFilledRect(screen, bodyX+bodyW/2+1, groundY, bodyW/2-2, float32(snap.canvasH), color.RGBA{60, 10, 10, alpha}, false)
}
// --- SPRECHBLASE ---
if time.Now().Before(g.teacherQuoteTime.Add(-10 * time.Second)) && g.teacherQuote.Text != "" {
// Wir zeigen den Spruch für 5-10 Sekunden an
g.drawSpeechBubble(screen, teacherCX+15, bodyY-20, g.teacherQuote.Text)
}
}
// Warning text — blinks when close
if danger > 0.55 {
if (time.Now().UnixMilli()/300)%2 == 0 {