package screens import ( "image/color" "github.com/hajimehoshi/ebiten/v2" "github.com/hajimehoshi/ebiten/v2/inpututil" "github.com/hajimehoshi/ebiten/v2/text/v2" ) // An interface for managing FPS cap settings. type FPSCapSetting interface { String() string Cycle() } // Displays and manages game settings like FPS monitor and FPS cap. // This screen can be accessed from both the title screen and pause menu. type SettingsScreen struct { selectedIndex int fpsMonitorValue *bool fpsCapValue FPSCapSetting } // Creates a new settings screen instance. func NewSettingsScreen() *SettingsScreen { return &SettingsScreen{ selectedIndex: 0, } } // Sets the FPS monitor toggle reference. func (s *SettingsScreen) SetFPSMonitor(enabled *bool) { s.fpsMonitorValue = enabled } // Sets the FPS cap setting reference. func (s *SettingsScreen) SetFPSCap(cap FPSCapSetting) { s.fpsCapValue = cap } // Processes settings screen input. // Returns true if the user wants to go back. func (s *SettingsScreen) Update() bool { if inpututil.IsKeyJustPressed(ebiten.KeyEscape) { return true } settingsCount := 2 if inpututil.IsKeyJustPressed(ebiten.KeyArrowUp) || inpututil.IsKeyJustPressed(ebiten.KeyW) { s.selectedIndex-- if s.selectedIndex < 0 { s.selectedIndex = 0 } } if inpututil.IsKeyJustPressed(ebiten.KeyArrowDown) || inpututil.IsKeyJustPressed(ebiten.KeyS) { s.selectedIndex++ if s.selectedIndex >= settingsCount { s.selectedIndex = settingsCount - 1 } } if inpututil.IsKeyJustPressed(ebiten.KeyEnter) || inpututil.IsKeyJustPressed(ebiten.KeySpace) { if s.selectedIndex == 0 && s.fpsMonitorValue != nil { *s.fpsMonitorValue = !*s.fpsMonitorValue } else if s.selectedIndex == 1 && s.fpsCapValue != nil { s.fpsCapValue.Cycle() } } return false } // Renders the settings screen. func (s *SettingsScreen) Draw(screen *ebiten.Image, screenWidth, screenHeight int, title string) { // Draw background screen.Fill(color.RGBA{R: 20, G: 20, B: 30, A: 255}) // Draw title titleX := (screenWidth / 2) - (len(title) * 7 / 2) titleY := screenHeight/3 - 50 s.drawText(screen, title, color.White, titleX, titleY) // Draw settings options startY := screenHeight/2 - 20 leftMargin := screenWidth/2 - 120 fpsMonitorText := "FPS Monitor: " if s.fpsMonitorValue != nil && *s.fpsMonitorValue { fpsMonitorText += "ON" } else { fpsMonitorText += "OFF" } if s.selectedIndex == 0 { indicatorX := leftMargin - 20 s.drawText(screen, ">", color.RGBA{R: 255, G: 200, B: 0, A: 255}, indicatorX, startY) s.drawText(screen, fpsMonitorText, color.RGBA{R: 255, G: 255, B: 100, A: 255}, leftMargin, startY) } else { s.drawText(screen, fpsMonitorText, color.RGBA{R: 180, G: 180, B: 200, A: 255}, leftMargin, startY) } fpsCapText := "FPS Cap: " if s.fpsCapValue != nil { fpsCapText += s.fpsCapValue.String() } else { fpsCapText += "60 FPS" } capY := startY + 40 if s.selectedIndex == 1 { indicatorX := leftMargin - 20 s.drawText(screen, ">", color.RGBA{R: 255, G: 200, B: 0, A: 255}, indicatorX, capY) s.drawText(screen, fpsCapText, color.RGBA{R: 255, G: 255, B: 100, A: 255}, leftMargin, capY) } else { s.drawText(screen, fpsCapText, color.RGBA{R: 180, G: 180, B: 200, A: 255}, leftMargin, capY) } // Draw hint text hintText := "Enter/Space to toggle, ESC to go back" hintX := (screenWidth / 2) - (len(hintText) * 7 / 2) hintY := screenHeight - 50 s.drawText(screen, hintText, color.RGBA{R: 120, G: 120, B: 150, A: 255}, hintX, hintY) } func (s *SettingsScreen) drawText(screen *ebiten.Image, txt string, clr color.Color, x, y int) { op := &text.DrawOptions{} op.GeoM.Translate(float64(x), float64(y)-basicFaceAscent) op.ColorScale.ScaleWithColor(clr) text.Draw(screen, txt, basicFace, op) } // Resets the settings screen to its initial state. func (s *SettingsScreen) Reset() { s.selectedIndex = 0 }