minor adjustments to LevelState

This commit is contained in:
Carlo Ghisolfi 2026-10-04 20:19:27 +02:00
parent c2f76d4222
commit f44d7c7858
4 changed files with 345 additions and 33 deletions

1
.gitignore vendored
View file

@ -1 +1,2 @@
*pycache* *pycache*
*guy_originale.py*

327
gui_originale.py Normal file
View file

@ -0,0 +1,327 @@
import pygame
from constants import *
from enum import Enum
class ButtonTypes(Enum):
PLAY = "play"
RESUME = "resume"
MENU = "menu"
DELETE = "delete"
QUIT = "quit"
RETRY = "retry"
FW = "fw"
BW = "bw"
GO = "go"
class MenuType(Enum):
PAUSE = 0
COMPLETED = 1
START = 2
SELECT = 3
# Button class that can store a value
class Button:
def __init__(self, x, y, value, type=ButtonTypes.PLAY):
# value is a utility field that can store something useful for the use of the button
self.x = x
self.y = y
self.value = value
self.original_image, self.dark_image = self.load_image(type)
self.image = self.original_image.convert_alpha()
# Collide rect measures based on the type
if type == ButtonTypes.FW or type == ButtonTypes.BW:
width = 105
height = 82
elif type == ButtonTypes.GO:
width = 83
height = 63
else:
width = 232
height = 82
self.rect = pygame.Rect(
x,
y,
int(width * SCALE_FACTOR),
int(height * SCALE_FACTOR)
)
self.image_rect = self.image.get_rect(
center=self.rect.center
)
def load_image(self, type):
if type == ButtonTypes.MENU:
image = pygame.transform.scale_by(pygame.image.load('assets/menu_btn.png'), SCALE_FACTOR)
dark_image = pygame.transform.scale_by(pygame.image.load('assets/menu_dark_btn.png').convert_alpha(), SCALE_FACTOR)
elif type == ButtonTypes.QUIT:
image = pygame.transform.scale_by(pygame.image.load('assets/quit_btn.png'), SCALE_FACTOR)
dark_image = pygame.transform.scale_by(pygame.image.load('assets/quit_dark_btn.png').convert_alpha(), SCALE_FACTOR)
elif type == ButtonTypes.DELETE:
image = pygame.transform.scale_by(pygame.image.load('assets/delete_btn.png'), SCALE_FACTOR)
dark_image = pygame.transform.scale_by(pygame.image.load('assets/delete_dark_btn.png').convert_alpha(), SCALE_FACTOR)
elif type == ButtonTypes.RESUME:
image = pygame.transform.scale_by(pygame.image.load('assets/resume_btn.png'), SCALE_FACTOR)
dark_image = pygame.transform.scale_by(pygame.image.load('assets/resume_dark_btn.png').convert_alpha(), SCALE_FACTOR)
elif type == ButtonTypes.PLAY:
image = pygame.transform.scale_by(pygame.image.load('assets/play_btn.png'), SCALE_FACTOR)
dark_image = pygame.transform.scale_by(pygame.image.load('assets/play_dark_btn.png').convert_alpha(), SCALE_FACTOR)
elif type == ButtonTypes.RETRY:
image = pygame.transform.scale_by(pygame.image.load('assets/retry_btn.png'), SCALE_FACTOR)
dark_image = pygame.transform.scale_by(pygame.image.load('assets/retry_dark_btn.png').convert_alpha(), SCALE_FACTOR)
elif type == ButtonTypes.FW:
image = pygame.transform.scale_by(pygame.image.load('assets/fw_btn.png'), SCALE_FACTOR)
dark_image = pygame.transform.scale_by(pygame.image.load('assets/fw_dark_btn.png').convert_alpha(), SCALE_FACTOR)
elif type == ButtonTypes.BW:
image = pygame.transform.scale_by(pygame.image.load('assets/bw_btn.png'), SCALE_FACTOR)
dark_image = pygame.transform.scale_by(pygame.image.load('assets/bw_dark_btn.png').convert_alpha(), SCALE_FACTOR)
elif type == ButtonTypes.GO:
image = pygame.transform.scale_by(pygame.image.load('assets/go_btn.png'), SCALE_FACTOR)
dark_image = pygame.transform.scale_by(pygame.image.load('assets/go_dark_btn.png').convert_alpha(), SCALE_FACTOR)
return image, dark_image
def draw(self, screen, mouse, font):
#text_surface = text_outline_perfect(font, self.text, WHITE, DARK)
#text_rect = text_surface.get_rect(center=self.rect.center)
# shadow_rect = sahdow_surface.get_rect(center=self.rect.center)
if self.rect.collidepoint(mouse):
screen.blit(self.dark_image, self.image_rect)
else:
screen.blit(self.image, self.image_rect)
#pygame.draw.rect(screen, (255, 0, 255), self.rect, 2)
#screen.blit(text_surface, text_rect)
def clicked(self, mouse):
return self.rect.collidepoint(mouse)
# Easy, text area
class TextArea:
def __init__(self, x, y, text, color):
self.text = text
self.rect = pygame.Rect(x, y, 0, 0)
self.color = color
def draw(self, screen, font):
text_surface = font.render(self.text, True, self.color)
self.rect = text_surface.get_rect(center=self.rect.center)
screen.blit(text_surface, self.rect)
class EntryState(Enum):
UNLOCKED = 0
LOCKED = 1
class SelectEntry:
def __init__(self, x, y, text, value, state):
self.x = x
self.y = y
self.text = text
self.btn = Button(0, 0, value, ButtonTypes.GO)
self.area = TextArea(0, 0, text, DARK)
self.icon = self.load_icon(state)
self.icon_rect = self.icon.get_rect()
self.value = value
# Calculate full width
#self.width = self.btn.rect.width + self.area.rect.width + self.icon_rect.width
self.width = 500
self.height = self.btn.rect.height
self.rect = pygame.Rect(x, y, self.width, self.height)
def clicked(self, mouse):
return self.btn.clicked(mouse)
def load_icon(self, state):
if state == EntryState.LOCKED:
return pygame.image.load("assets/locked.png").convert_alpha()
elif state == EntryState.UNLOCKED:
return pygame.image.load("assets/unlocked.png").convert_alpha()
def draw(self, screen, mouse, font):
self.btn.rect.y = self.rect.y
self.btn.image_rect.y = self.rect.y
self.area.rect.y = self.rect.y
self.icon_rect.y = self.rect.y
x = self.rect.x + 20
self.btn.rect.x = x
self.btn.image_rect.x = x
x += self.btn.rect.width*2
self.area.rect.x = x
self.icon_rect.x = 800
self.btn.draw(screen, mouse, font)
self.area.draw(screen, font)
screen.blit(self.icon, self.icon_rect)
# Single page menu class
class MenuPage:
def __init__(self, type):
self.top_text_area = None
self.bottom_text_area = None
self.buttons = []
self.entries = []
self.bg_image = self.load_card(type)
def load_card(self, type):
if type == MenuType.PAUSE:
return pygame.transform.scale_by(pygame.image.load('assets/paused_card.png').convert_alpha(), SCALE_FACTOR)
elif type == MenuType.COMPLETED:
return pygame.transform.scale_by(pygame.image.load('assets/completed_card.png').convert_alpha(), SCALE_FACTOR)
elif type == MenuType.START:
return pygame.transform.scale_by(pygame.image.load('assets/menu_card.png').convert_alpha(), SCALE_FACTOR)
elif type == MenuType.SELECT:
return pygame.transform.scale_by(pygame.image.load('assets/select_card.png').convert_alpha(), SCALE_FACTOR)
# Button methods
def add_button(self, value, type):
self.buttons.append(Button(0, 0, value, type))
def add_entry(self, text, value, state):
self.entries.append(SelectEntry(0, 0, text, value, state))
def add_top_text(self, text):
self.top_text_area = TextArea(0, 0, text, DARK)
def add_bottom_text(self, text):
self.bottom_text_area = TextArea(0, 0, text, DARK)
def draw(self, screen, mouse, btn_font, text_font):
center_x, center_y = screen.get_rect().center
# Draw the card image
screen.blit(self.bg_image, (center_x-self.bg_image.get_width()/2, center_y-self.bg_image.get_height()/2))
spacing = BTN_HEIGHT * 0.5
elements = []
if self.top_text_area is not None:
elements.append(self.top_text_area)
elements.extend(self.buttons)
elements.extend(self.entries)
if self.bottom_text_area is not None:
elements.append(self.bottom_text_area)
# Calculate the dimensions
heights = []
for element in elements:
if isinstance(element, TextArea):
text_surface = text_font.render(element.text, True, WHITE)
heights.append(text_surface.get_height())
elif isinstance(element, Button):
heights.append(element.image.get_height()/2)
else:
heights.append(element.height)
self.total_height = sum(heights) + spacing * (len(elements) - 1)
y = center_y - self.total_height / 2
for element, height in zip(elements, heights):
element.rect.centerx = center_x
element.rect.y = y
if isinstance(element, Button):
element.image_rect.center = element.rect.center
element.draw(screen, mouse, btn_font)
elif isinstance(element, TextArea):
element.draw(screen, text_font)
else:
element.draw(screen, mouse, text_font)
y += height + spacing
def handle_event(self, event, mouse):
if event.type == pygame.QUIT:
return "quit_game"
if event.type == pygame.MOUSEBUTTONDOWN:
for button in self.buttons:
if button.clicked(mouse):
return button.value
for entry in self.entries:
if entry.clicked(mouse):
return entry.value
return None
# Multi-page menu, automatically creates new page 3 buttons per page
class Menu:
def __init__(self, menu_type):
self.bottom_buttons = [Button(0, 0, None, ButtonTypes.BW), Button(0, 0, "menu", ButtonTypes.MENU), Button(0, 0, None, ButtonTypes.FW)]
self.pages = []
self.menu_type = menu_type
# Creating the first page
self.pages.append(MenuPage(self.menu_type))
self.current_page_i = 0
# For now the paged menu can only have pages with just buttons, no top or bottom text
def add_button(self, value, type):
current_page = self.pages[-1]
if len(current_page.buttons) >= MAX_BTN:
current_page = MenuPage(self.menu_type)
self.pages.append(current_page)
current_page.add_button(value, type)
def add_entry(self, text, value, state):
current_page = self.pages[-1]
if len(current_page.entries) >= MAX_BTN:
current_page = MenuPage(self.menu_type)
self.pages.append(current_page)
current_page.add_entry(text, value, state)
def draw(self, screen, mouse, btn_font, text_font):
center_x, center_y = screen.get_rect().center
spacing = BTN_HEIGHT * 0.5
self.pages[self.current_page_i].draw(screen, mouse, btn_font, text_font)
# bottom y, OK
bottom_y = center_y + self.pages[self.current_page_i].total_height / 2 + spacing
# Calculate total width
group_width = 0
for button in self.bottom_buttons:
group_width += button.rect.width
x = center_x - group_width / 2.5
for button in self.bottom_buttons:
button.rect.centerx = x
button.rect.y = bottom_y
button.image_rect.center = button.rect.center
x += group_width / 2.5
for button in self.bottom_buttons:
button.draw(screen, mouse, btn_font)
def handle_event(self, event, mouse):
if event.type == pygame.QUIT:
return "quit_game"
# Maybe in the future the index can wrap around
if event.type == pygame.MOUSEBUTTONDOWN:
if self.bottom_buttons[0].clicked(mouse):
if self.current_page_i > 0:
self.current_page_i -= 1
return None
if self.bottom_buttons[1].clicked(mouse):
return self.bottom_buttons[1].value
if self.bottom_buttons[2].clicked(mouse):
if self.current_page_i < len(self.pages) - 1:
self.current_page_i += 1
return None
return self.pages[self.current_page_i].handle_event(event, mouse)
return None

View file

@ -12,16 +12,16 @@ from new_gui import *
# Enum and Tables # Enum and Tables
# ------------------------------------------------------------------------------- # -------------------------------------------------------------------------------
class TileTypes(Enum): class TileTypes(Enum):
FLOOR = 0 FLOOR = '.'
WALL = 1 WALL = '#'
RED_PLATE = 2 RED_PLATE = 'r'
RED_DOOR = 3 RED_DOOR = 'R'
ORANGE_PLATE = 4 ORANGE_PLATE = 'o'
ORANGE_DOOR = 5 ORANGE_DOOR = 'O'
TEAL_PLATE = 6 TEAL_PLATE = 't'
TEAL_DOOR = 7 TEAL_DOOR = 'T'
BLUE_ARRIVE = 8 BLUE_ARRIVE = 'B'
GREEN_ARRIVE = 9 GREEN_ARRIVE = 'G'
TILE_FILES = { TILE_FILES = {
TileTypes.FLOOR: "assets/floor.svg", TileTypes.FLOOR: "assets/floor.svg",
@ -93,22 +93,17 @@ class Level:
doors = {} doors = {}
plates = {} plates = {}
for (row, col), character in np.ndenumerate(self.map): for (row, col), character in np.ndenumerate(self.map):
if character in ('R'): if character in ('R', 'T', 'O'):
# Todo: choose type based on character # Todo: choose type based on character
doors[character] = Door(col, row, TileTypes.RED_DOOR) doors[character] = Door(col, row, TileTypes(character))
if character.lower() in plates: if character.lower() in plates:
plates[character.lower()].set_door(doors[character]) plates[character.lower()].set_door(doors[character])
if character in ('r'): if character in ('r', 't', 'o'):
# Todo: choose type based on character # Todo: choose type based on character
plates[character] = PressurePlate(col, row, TileTypes.RED_PLATE) plates[character] = PressurePlate(col, row, TileTypes(character))
if character.upper() in doors: if character.upper() in doors:
plates[character].set_door(doors[character.upper()]) plates[character].set_door(doors[character.upper()])
#for (row, col), character in np.ndenumerate(self.map):
# if character == 'r':
# plates.append(PressurePlate(col, row, TileTypes.RED_PLATE))
return doors, plates return doors, plates
@ -128,10 +123,6 @@ class Level:
# Draw the appropriate tile color # Draw the appropriate tile color
if character == '#': if character == '#':
screen.blit(self.wall_tile, rect) screen.blit(self.wall_tile, rect)
# elif character == 'R' and pressing != "red":
# screen.blit(self.red_door, rect)
# elif character == 'r':
# screen.blit(self.red_press, rect)
elif character == 'B': elif character == 'B':
screen.blit(self.blue_arrive, rect) screen.blit(self.blue_arrive, rect)
elif character == 'G': elif character == 'G':
@ -194,7 +185,7 @@ class LevelState:
if dir == Direction.HORIZ: if dir == Direction.HORIZ:
next_x = x + speed next_x = x + speed
if (self.level.map[y, next_x] == '#' or if (self.level.map[y, next_x] == '#' or
(self.level.map[y, next_x] == 'R' and self.pressing != "red") or (self.level.map[y, next_x] == 'R' and not self.level.plates['r'].is_pressed()) or
(next_x == self.players[1-self.curr_player_i].x and y == self.players[1-self.curr_player_i].y)): (next_x == self.players[1-self.curr_player_i].x and y == self.players[1-self.curr_player_i].y)):
return x return x
@ -202,7 +193,7 @@ class LevelState:
else: else:
next_y = y + speed next_y = y + speed
if (self.level.map[next_y, x] == '#' or if (self.level.map[next_y, x] == '#' or
(self.level.map[next_y, x] == 'R' and self.pressing != "red") or (self.level.map[next_y, x] == 'R' and not self.level.plates['r'].is_pressed()) or
(next_y == self.players[1-self.curr_player_i].y and x == self.players[1-self.curr_player_i].x)): (next_y == self.players[1-self.curr_player_i].y and x == self.players[1-self.curr_player_i].x)):
return y return y
@ -213,14 +204,7 @@ class LevelState:
p1 = self.players[0] p1 = self.players[0]
p2 = self.players[1] p2 = self.players[1]
# check for pressure on plates # Pressure plate check
# TODO: Add the other types of plates to press
if (self.level.map[p1.y, p1.x] == "r" and p1.powers[p1.current_power_i] == Powers.PRESS.value) or \
(self.level.map[p2.y, p2.x] == "r" and p2.powers[p2.current_power_i] == Powers.PRESS.value):
self.pressing = "red"
else:
self.pressing = "none"
for plate in self.level.plates.values(): for plate in self.level.plates.values():
if((p1.rect.x, p1.rect.y) == (plate.x, plate.y) and if((p1.rect.x, p1.rect.y) == (plate.x, plate.y) and
p1.powers[p1.current_power_i] == Powers.PRESS.value) or ((p2.rect.x, p2.rect.y) == (plate.x, plate.y) and p1.powers[p1.current_power_i] == Powers.PRESS.value) or ((p2.rect.x, p2.rect.y) == (plate.x, plate.y) and

Binary file not shown.