refact
This commit is contained in:
+174
@@ -0,0 +1,174 @@
|
||||
package lib
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2"
|
||||
)
|
||||
|
||||
type State int
|
||||
|
||||
const (
|
||||
StateTitle State = iota
|
||||
StatePlay
|
||||
StateOver
|
||||
)
|
||||
|
||||
type Game struct {
|
||||
assets *Assets
|
||||
|
||||
state State
|
||||
playerLane int
|
||||
score int
|
||||
miss int
|
||||
rabbits []*Rabbit
|
||||
spawnTimer int
|
||||
frame int
|
||||
flash int
|
||||
|
||||
lcd *ebiten.Image
|
||||
}
|
||||
|
||||
func NewGame(a *Assets) *Game {
|
||||
return &Game{
|
||||
assets: a,
|
||||
state: StateTitle,
|
||||
playerLane: 2,
|
||||
lcd: ebiten.NewImage(LcdW, LcdH),
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Game) reset() {
|
||||
g.playerLane = 2
|
||||
g.score = 0
|
||||
g.miss = 0
|
||||
g.rabbits = g.rabbits[:0]
|
||||
g.spawnTimer = 0
|
||||
g.flash = 0
|
||||
}
|
||||
|
||||
// --- ebiten.Game ---
|
||||
|
||||
func (g *Game) Update() error {
|
||||
g.frame++
|
||||
switch g.state {
|
||||
case StateTitle, StateOver:
|
||||
if startPressed() {
|
||||
g.reset()
|
||||
g.state = StatePlay
|
||||
}
|
||||
case StatePlay:
|
||||
g.updatePlay()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *Game) Draw(screen *ebiten.Image) {
|
||||
screen.DrawImage(g.assets.Bg, nil)
|
||||
|
||||
switch g.state {
|
||||
case StateTitle:
|
||||
g.drawTitle(g.lcd)
|
||||
case StatePlay:
|
||||
g.drawPlay(g.lcd)
|
||||
case StateOver:
|
||||
g.drawOver(g.lcd)
|
||||
}
|
||||
|
||||
opts := &ebiten.DrawImageOptions{}
|
||||
opts.GeoM.Scale(LcdScale, LcdScale)
|
||||
opts.GeoM.Translate(LcdDrawX, LcdDrawY)
|
||||
screen.DrawImage(g.lcd, opts)
|
||||
}
|
||||
|
||||
func (g *Game) Layout(_, _ int) (int, int) {
|
||||
return ScreenW, ScreenH
|
||||
}
|
||||
|
||||
// --- play loop ---
|
||||
|
||||
func (g *Game) updatePlay() {
|
||||
if pressedRepeat(ebiten.KeyLeft, 12, 6) && g.playerLane > 0 {
|
||||
g.playerLane--
|
||||
}
|
||||
if pressedRepeat(ebiten.KeyRight, 12, 6) && g.playerLane < LaneCount-1 {
|
||||
g.playerLane++
|
||||
}
|
||||
|
||||
g.spawnTimer++
|
||||
interval := 70 - g.score/2
|
||||
if interval < 22 {
|
||||
interval = 22
|
||||
}
|
||||
if g.spawnTimer >= interval {
|
||||
g.spawnTimer = 0
|
||||
g.rabbits = append(g.rabbits, newRabbit(g.score))
|
||||
}
|
||||
|
||||
for i := len(g.rabbits) - 1; i >= 0; i-- {
|
||||
r := g.rabbits[i]
|
||||
r.T += r.Speed
|
||||
if r.T < 1 {
|
||||
continue
|
||||
}
|
||||
if r.Lane == g.playerLane {
|
||||
g.miss++
|
||||
g.flash = 12
|
||||
if g.miss >= MaxMiss {
|
||||
g.state = StateOver
|
||||
}
|
||||
} else {
|
||||
g.score++
|
||||
}
|
||||
g.rabbits = append(g.rabbits[:i], g.rabbits[i+1:]...)
|
||||
}
|
||||
|
||||
if g.flash > 0 {
|
||||
g.flash--
|
||||
}
|
||||
}
|
||||
|
||||
// --- scene composition ---
|
||||
|
||||
func (g *Game) drawPlay(dst *ebiten.Image) {
|
||||
dst.Fill(ColorBg)
|
||||
drawRoad(dst)
|
||||
drawHud(dst, g.assets.HudFont, g.score, g.miss)
|
||||
// far rabbits first so closer ones overlap on top
|
||||
sort.Slice(g.rabbits, func(i, j int) bool { return g.rabbits[i].T < g.rabbits[j].T })
|
||||
for _, r := range g.rabbits {
|
||||
r.Draw(dst, g.assets.Rabbit)
|
||||
}
|
||||
drawScooter(dst, g.assets.Scooter, LaneX[g.playerLane], PlayerY, g.flash > 0, g.frame)
|
||||
}
|
||||
|
||||
func (g *Game) drawTitle(dst *ebiten.Image) {
|
||||
dst.Fill(ColorBg)
|
||||
drawRoad(dst)
|
||||
for i := 0; i < LaneCount; i++ {
|
||||
drawScooter(dst, g.assets.Scooter, LaneX[i], PlayerY, false, g.frame)
|
||||
}
|
||||
for i := 1; i <= 3; i++ {
|
||||
demo := &Rabbit{
|
||||
Lane: (g.frame/30 + i) % LaneCount,
|
||||
T: float64((g.frame+i*25)%90) / 90.0,
|
||||
}
|
||||
demo.Draw(dst, g.assets.Rabbit)
|
||||
}
|
||||
if (g.frame/30)%2 == 0 {
|
||||
drawTextCentered(dst, "PRESS SPACE TO START", 120, 56, g.assets.HudFont, ColorFg)
|
||||
}
|
||||
drawTextCentered(dst, "ARROWS MOVE SPACE START", 120, 72, g.assets.HudFont, ColorFg)
|
||||
}
|
||||
|
||||
func (g *Game) drawOver(dst *ebiten.Image) {
|
||||
g.drawPlay(dst)
|
||||
rectFill(dst, 60, 50, 120, 36, ColorBg)
|
||||
rectStroke(dst, 60, 50, 120, 36, ColorFg)
|
||||
drawTextCentered(dst, "GAME OVER", 120, 54, g.assets.HudFont, ColorFg)
|
||||
drawTextCentered(dst, fmt.Sprintf("SCORE %03d", g.score), 120, 66, g.assets.HudFont, ColorFg)
|
||||
if (g.frame/30)%2 == 0 {
|
||||
drawTextCentered(dst, "SPACE = RETRY", 120, 76, g.assets.HudFont, ColorFg)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user