Fix menu navigation: - Add proper item highlighting - Improve keyboard and mouse controls - Fix settings menu interaction - Update menu items continuously

This commit is contained in:
Rbanh 2025-02-23 13:04:38 -05:00
parent be7b7caf28
commit d1fb3a58b4
2 changed files with 73 additions and 71 deletions

View File

@ -62,10 +62,10 @@ class SettingsMenu:
self.title_surface = self.title_font.render("Settings", True, (0, 255, 0))
self.title_rect = self.title_surface.get_rect(center=(width//2, height//4))
# Initialize first item as hovered
if self.menu_items:
self.menu_items[0].hover = True
self.menu_items[0]._setup_font()
# Initialize first item as selected
self.selected_index = 0
self.menu_items[0].hover = True
self.menu_items[0]._setup_font()
def setup_menu_items(self):
start_y = self.height // 2
@ -85,15 +85,26 @@ class SettingsMenu:
]
def update(self):
# Handle mouse hover
mouse_pos = pygame.mouse.get_pos()
for item in self.menu_items:
item.update_hover(mouse_pos)
for i, item in enumerate(self.menu_items):
if item.rect.collidepoint(mouse_pos):
# Update selected index when mouse hovers
self.selected_index = i
item.hover = True
item._setup_font()
else:
# Keep keyboard selection visible
item.hover = (i == self.selected_index)
item._setup_font()
def handle_input(self, event):
if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
# Handle mouse clicks
mouse_pos = pygame.mouse.get_pos()
for item in self.menu_items:
for i, item in enumerate(self.menu_items):
if item.rect.collidepoint(mouse_pos):
self.selected_index = i
if item.action == 'toggle_wrap':
self.rules.wrap_around = not self.rules.wrap_around
item.text = f"Wrap Around: {'On' if self.rules.wrap_around else 'Off'}"
@ -104,42 +115,32 @@ class SettingsMenu:
item._setup_font()
elif item.action == 'back':
return 'back'
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
return 'back'
elif event.key == pygame.K_RETURN:
for item in self.menu_items:
if item.hover:
if item.action == 'toggle_wrap':
self.rules.wrap_around = not self.rules.wrap_around
item.text = f"Wrap Around: {'On' if self.rules.wrap_around else 'Off'}"
item._setup_font()
elif item.action == 'toggle_speed':
self.rules.speed_increase = not self.rules.speed_increase
item.text = f"Speed Increase: {'On' if self.rules.speed_increase else 'Off'}"
item._setup_font()
elif item.action == 'back':
return 'back'
item = self.menu_items[self.selected_index]
if item.action == 'toggle_wrap':
self.rules.wrap_around = not self.rules.wrap_around
item.text = f"Wrap Around: {'On' if self.rules.wrap_around else 'Off'}"
item._setup_font()
elif item.action == 'toggle_speed':
self.rules.speed_increase = not self.rules.speed_increase
item.text = f"Speed Increase: {'On' if self.rules.speed_increase else 'Off'}"
item._setup_font()
elif item.action == 'back':
return 'back'
elif event.key in (pygame.K_UP, pygame.K_DOWN):
# Find current hover index
current_hover = -1
for i, item in enumerate(self.menu_items):
if item.hover:
current_hover = i
break
# Move hover up or down
if current_hover == -1:
new_hover = 0
# Update selected index
if event.key == pygame.K_UP:
self.selected_index = (self.selected_index - 1) % len(self.menu_items)
else:
if event.key == pygame.K_UP:
new_hover = (current_hover - 1) % len(self.menu_items)
else:
new_hover = (current_hover + 1) % len(self.menu_items)
self.selected_index = (self.selected_index + 1) % len(self.menu_items)
# Update hover states
for i, item in enumerate(self.menu_items):
item.hover = (i == new_hover)
item.hover = (i == self.selected_index)
item._setup_font()
return None
@ -156,7 +157,7 @@ class SettingsMenu:
item.draw(screen)
# Draw controls
controls_text = "Arrow keys to navigate, Enter to select, Esc to go back"
controls_text = "Arrow keys or mouse to navigate, Enter to select, Esc to go back"
font = pygame.font.Font(None, 24)
controls_surface = font.render(controls_text, True, (100, 100, 100))
screen.blit(controls_surface,
@ -264,7 +265,11 @@ class Game:
self.reset_game()
def update(self):
if self.state == GameState.PLAYING:
if self.state == GameState.MENU:
self.menu.update()
elif self.state == GameState.SETTINGS:
self.settings_menu.update()
elif self.state == GameState.PLAYING:
# Move snake
if self.snake.move(pygame.time.get_ticks()):
# Handle wrap-around

View File

@ -22,22 +22,18 @@ class MenuItem:
self._setup_font()
def _setup_font(self):
"""Update the font surface with current color"""
self.font = pygame.font.Font(None, self.size)
self.surface = self.font.render(self.text, True, self.color)
color = (255, 255, 0) if self.hover else self.default_color # Yellow when hovered
self.surface = self.font.render(self.text, True, color)
self.rect = self.surface.get_rect(center=self.position)
def update_hover(self, mouse_pos):
"""Update hover state based on mouse position"""
old_hover = self.hover
self.hover = self.rect.collidepoint(mouse_pos)
if self.hover:
self.color = (255, 255, 0) # Yellow on hover
else:
self.color = self.default_color
if old_hover != self.hover:
self._setup_font()
def draw(self, screen):
screen.blit(self.surface, self.rect)
class Menu:
def __init__(self, width, height):
@ -54,10 +50,10 @@ class Menu:
self.subtitle_surface = self.subtitle_font.render("Choose Game Mode", True, (200, 200, 200))
self.subtitle_rect = self.subtitle_surface.get_rect(center=(width//2, height//4 + 50))
# Initialize first item as hovered
if self.menu_items:
self.menu_items[0].hover = True
self.menu_items[0]._setup_font()
# Initialize first item as selected
self.selected_index = 0
self.menu_items[0].hover = True
self.menu_items[0]._setup_font()
def setup_menu_items(self):
# Calculate positions for menu items
@ -76,44 +72,45 @@ class Menu:
def handle_input(self, event):
if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
# Handle mouse clicks
mouse_pos = pygame.mouse.get_pos()
for item in self.menu_items:
for i, item in enumerate(self.menu_items):
if item.rect.collidepoint(mouse_pos):
self.selected_index = i
return item.action
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_RETURN:
# Find the currently hovered item
for item in self.menu_items:
if item.hover:
return item.action
# Return the selected item's action
return self.menu_items[self.selected_index].action
elif event.key in (pygame.K_UP, pygame.K_DOWN):
# Find current hover index
current_hover = -1
for i, item in enumerate(self.menu_items):
if item.hover:
current_hover = i
break
# Move hover up or down
if current_hover == -1:
new_hover = 0
# Update selected index
if event.key == pygame.K_UP:
self.selected_index = (self.selected_index - 1) % len(self.menu_items)
else:
if event.key == pygame.K_UP:
new_hover = (current_hover - 1) % len(self.menu_items)
else:
new_hover = (current_hover + 1) % len(self.menu_items)
self.selected_index = (self.selected_index + 1) % len(self.menu_items)
# Update hover states
for i, item in enumerate(self.menu_items):
item.hover = (i == new_hover)
item.hover = (i == self.selected_index)
item._setup_font()
return None
def update(self):
# Handle mouse hover
mouse_pos = pygame.mouse.get_pos()
for item in self.menu_items:
item.update_hover(mouse_pos)
for i, item in enumerate(self.menu_items):
if item.rect.collidepoint(mouse_pos):
# Update selected index when mouse hovers
self.selected_index = i
item.hover = True
item._setup_font()
else:
# Keep keyboard selection visible
item.hover = (i == self.selected_index)
item._setup_font()
def draw(self, screen):
# Draw background
@ -129,7 +126,7 @@ class Menu:
# Draw version and controls
version_text = "v0.1.0"
controls_text = "Arrow keys to navigate, Enter to select"
controls_text = "Arrow keys or mouse to navigate, Enter to select"
font = pygame.font.Font(None, 24)
version_surface = font.render(version_text, True, (100, 100, 100))