package game import ( "fmt" "image/color" "math" "github.com/hajimehoshi/ebiten/v2" "github.com/hajimehoshi/ebiten/v2/vector" "gitea.brasse-pc.eu/brasse/metro-puzzle-jp/internal/buildinfo" ) // TitleScene är titelskärmen: premissen i text och menyn Fortsätt/Starta, // Tutorial, Inställningar, Avsluta (Enter två gånger). type TitleScene struct { sel int t float64 confirm bool // Avsluta valt en gång } // NewTitleScene öppnar titelskärmen. func NewTitleScene() *TitleScene { return &TitleScene{} } const titleItems = 4 func (s *TitleScene) Update(g *Game) error { s.t += dt if mv := menuMove(); mv != 0 { s.sel = (s.sel + mv + titleItems) % titleItems s.confirm = false } if backJustPressed() { s.confirm = false } if !confirmJustPressed() { return nil } g.Audio.Play(SoundConfirm, 0.6) switch s.sel { case 0: g.SetScene(NewMapScene(g)) case 1: g.SetScene(NewTutorialScene(s)) case 2: g.SetScene(NewSettingsScene(s)) case 3: if s.confirm { return ebiten.Termination } s.confirm = true } return nil } func (s *TitleScene) Draw(g *Game, screen *ebiten.Image) { a := g.Assets screen.Fill(color.RGBA{24, 20, 37, 255}) // Räls längs nederkanten med ett tåg som rullar förbi. railY := ScreenH - 28 for x := 0; x < ScreenW; x += TileSize { var op ebiten.DrawImageOptions op.GeoM.Translate(float64(x), float64(railY)) screen.DrawImage(a.Rails, &op) } tx := math.Mod(s.t*40, float64(ScreenW+6*TileSize)) - 3*TileSize for i := 0; i < 3; i++ { var op ebiten.DrawImageOptions op.GeoM.Translate(tx+float64(i*TileSize), float64(railY-TileSize+4)) screen.DrawImage(a.Train, &op) } a.DrawBig(screen, a.T("game.title"), 16, 8, colKnown) ver := fmt.Sprintf("%s (%s)", buildinfo.Version, buildinfo.Mode) a.Draw(screen, ver, ScreenW-8-a.Width(ver), 10, colDim) y := 30 for _, l := range a.wrapLine(plainLine(a.T("title.premise"), colText), ScreenW-32) { a.drawLines(screen, []line{l}, 16, y) y += LineH } start := a.T("menu.continue") if g.Progress.TotalStars() == 0 && len(g.Progress.Levels) == 0 { start = a.T("menu.start") } items := [titleItems]string{start, a.T("title.tutorial"), a.T("menu.settings"), a.T("menu.quit")} y += 6 for i, it := range items { col := colText if i == s.sel { vector.DrawFilledRect(screen, 12, float32(y-2), 130, LineH, colBar, false) col = colKnown a.Draw(screen, "▶", 14, y, colKnown) } a.Draw(screen, it, 26, y, col) y += LineH } if s.confirm { a.Draw(screen, a.T("title.quit_confirm"), 16, y+2, colWarn) } a.Draw(screen, a.T("title.hint"), 8, ScreenH-12, colDim) } // LangScene visas första gången spelet startar: välj språk. type LangScene struct{ sel int } var langChoices = []string{"sv", "en"} func (s *LangScene) Update(g *Game) error { if mv := menuMove(); mv != 0 { s.sel = (s.sel + mv + len(langChoices)) % len(langChoices) } if confirmJustPressed() { g.State.Settings.Lang = langChoices[s.sel] g.applySettings() g.Save() g.Audio.Play(SoundConfirm, 0.6) g.SetScene(NewTitleScene()) } return nil } func (s *LangScene) Draw(g *Game, screen *ebiten.Image) { a := g.Assets screen.Fill(color.RGBA{24, 20, 37, 255}) a.DrawBig(screen, a.T("game.title"), 16, 10, colKnown) a.Draw(screen, "Välj språk / Choose language", 16, 50, colText) y := 72 for i, l := range langChoices { col := colText if i == s.sel { vector.DrawFilledRect(screen, 12, float32(y-2), 130, LineH+2, colBar, false) col = colKnown a.Draw(screen, "▶", 14, y, colKnown) } a.Draw(screen, a.T("lang."+l), 26, y, col) y += LineH + 1 } a.Draw(screen, "Pilar + Enter / Arrows + Enter", 16, y+8, colDim) } // PauseScene är pausmenyn i en bana (Esc): Fortsätt, Lämna banan, // Inställningar, Avsluta spelet (Enter två gånger). Esc igen fortsätter. type PauseScene struct { from *LevelScene sel int confirm bool } const pauseItems = 4 // NewPauseScene pausar banan. func NewPauseScene(from *LevelScene) *PauseScene { return &PauseScene{from: from} } func (s *PauseScene) Update(g *Game) error { if backJustPressed() { g.SetScene(s.from) return nil } if mv := menuMove(); mv != 0 { s.sel = (s.sel + mv + pauseItems) % pauseItems s.confirm = false } if !confirmJustPressed() { return nil } g.Audio.Play(SoundConfirm, 0.6) switch s.sel { case 0: g.SetScene(s.from) case 1: if s.from.endless { g.endEndless() } g.SetScene(NewMapScene(g)) case 2: g.SetScene(NewSettingsScene(s)) case 3: if s.confirm { return ebiten.Termination } s.confirm = true } return nil } func (s *PauseScene) Draw(g *Game, screen *ebiten.Image) { s.from.Draw(g, screen) a := g.Assets vector.DrawFilledRect(screen, 0, 0, ScreenW, ScreenH, color.RGBA{0, 0, 0, 120}, false) vector.DrawFilledRect(screen, 40, 40, ScreenW-80, 104, colPanel, false) vector.DrawFilledRect(screen, 40, 40, ScreenW-80, 2, colWarn, false) a.DrawBig(screen, a.T("pause.title"), 48, 46, colText) items := [pauseItems]string{a.T("pause.resume"), a.T("pause.leave"), a.T("menu.settings"), a.T("pause.quit")} y := 68 for i, it := range items { col := colText if i == s.sel { vector.DrawFilledRect(screen, 44, float32(y-2), ScreenW-88, LineH+2, colBar, false) col = colKnown } a.Draw(screen, it, 50, y, col) y += LineH + 2 } msg := a.T("pause.hint") if s.confirm { msg = a.T("pause.quit_confirm") } for _, l := range a.wrapLine(plainLine(msg, colDim), ScreenW-96) { a.drawLines(screen, []line{l}, 48, y+2) y += LineH } }