From 97038023d5de1b6361cac572746036ad81d9f0cf Mon Sep 17 00:00:00 2001 From: Matteo Benedetto Date: Mon, 23 Dec 2024 00:59:48 +0100 Subject: [PATCH] Aggiungi supporto per la risoluzione personalizzata e gestione della pausa nel gioco --- .env | 3 +- engine/controls.py | 4 +- engine/sdl2.py | 28 +++++++++--- rats.py | 59 ++++++++++++++++++++++---- requirements.txt | 3 +- scores.txt | 3 ++ units/__pycache__/rat.cpython-313.pyc | Bin 9673 -> 9704 bytes units/bomb.py | 11 +++-- units/points.py | 2 +- units/rat.py | 4 +- 10 files changed, 93 insertions(+), 24 deletions(-) create mode 100644 scores.txt diff --git a/.env b/.env index e3b97ec..6fc2b7d 100644 --- a/.env +++ b/.env @@ -1 +1,2 @@ -SDL_VIDEODRIVER=x11 \ No newline at end of file +SDL_VIDEODRIVER=x11 +RESOLUTION=1920x1080 \ No newline at end of file diff --git a/engine/controls.py b/engine/controls.py index dd73ea4..7ae4719 100644 --- a/engine/controls.py +++ b/engine/controls.py @@ -13,7 +13,7 @@ class KeyBindings: self.new_rat() elif key == "D": if self.units: - self.units[random.choice(list(self.units.keys()))].die() + self.units[random.choice(list(self.units.keys()))].die(score=5) elif key == "M": self.audio = not self.audio elif key == "F": @@ -32,6 +32,8 @@ class KeyBindings: self.spawn_bomb(self.pointer) elif key == "UpRelease" or key == "DownRelease" or key == "LeftRelease" or key == "RightRelease": self.stop_scrolling() + elif key == "P": + self.pause = not self.pause # elif key == "mouse": # adjusted_coords = (coords[0]//self.cell_size*2, coords[1]//self.cell_size*2) # self.pointer = adjusted_coords diff --git a/engine/sdl2.py b/engine/sdl2.py index 5ca115b..f52f569 100644 --- a/engine/sdl2.py +++ b/engine/sdl2.py @@ -1,6 +1,8 @@ import os import sdl2 import sdl2.ext +from sdl2.ext.compat import byteify + from PIL import Image class GameWindow: @@ -9,8 +11,8 @@ class GameWindow: self.cell_size = cell_size self.width = width * cell_size self.height = height * cell_size - self.actual_screen_size = (640, 480) - if self.width > self.actual_screen_size[0] or self.height > self.actual_screen_size[1]: + self.actual_screen_size = os.environ.get("RESOLUTION", "640x480").split("x") + if self.width > int(self.actual_screen_size[0]) or self.height > int(self.actual_screen_size[1]): self.target_size = self.actual_screen_size else: self.target_size = (self.width, self.height) @@ -22,6 +24,8 @@ class GameWindow: self.max_h_offset = self.target_size[1] - self.height print(f"Screen size: {self.width}x{self.height}") sdl2.ext.init(joystick=True) + sdl2.SDL_Init(sdl2.SDL_INIT_AUDIO) + self.window = sdl2.ext.Window(title=title, size=self.target_size,)# flags=sdl2.SDL_WINDOW_FULLSCREEN) self.delay = 30 self.load_joystick() @@ -63,7 +67,7 @@ class GameWindow: def draw_text(self, text, font, position, color): sprite = self.factory.from_text(text, color=color, fontmanager=font) if position == "center": - sprite.position = (self.size[0] // 2 - sprite.size[0] // 2, self.size[1] // 2 - sprite.size[1] // 2) + sprite.position = (self.target_size[0] // 2 - sprite.size[0] // 2, self.target_size[1] // 2 - sprite.size[1] // 2) else: sprite.position = position self.renderer.copy(sprite, dstrect=sprite.position) @@ -75,8 +79,6 @@ class GameWindow: self.renderer.copy(sprite, dstrect=sprite.position) def draw_rectangle(self, x, y, width, height, tag, outline="red", filling=None): - if not self.is_in_visible_area(x, y): - return x, y = x + self.w_offset, y + self.h_offset if filling: self.renderer.fill((x, y, width, height), sdl2.ext.Color(*filling)) @@ -92,6 +94,21 @@ class GameWindow: def delete_tag(self, tag): pass + def win_screen(self, text, image=None): + self.draw_rectangle(50 - self.w_offset, 50 - self.h_offset, + self.target_size[0] - 100, self.target_size[1] - 100, "win", filling=(255, 255, 255)) + self.draw_text(text, self.fonts[50], "center", sdl2.ext.Color(0, 0, 0)) + if image: + image_size = self.get_image_size(image) + self.draw_image(self.target_size[0] // 2 - image_size[0] // 2, + self.target_size[1] // 2 - image_size[1] // 2-150, image, "win") + + + def pause_screen(self, text): + self.draw_rectangle(50 - self.w_offset, 50 - self.h_offset, + self.target_size[0] - 100, self.target_size[1] - 100, "pause", filling=(255, 255, 255)) + self.draw_text(text, self.fonts[50], "center", sdl2.ext.Color(0, 0, 0)) + def get_image_size(self, image): return image.size @@ -174,6 +191,7 @@ class GameWindow: self.h_offset = y def play_sound(self, sound_file): + return sample = sdl2.sdlmixer.Mix_LoadWAV(byteify(sound_file, "utf-8")) if sample is None: diff --git a/rats.py b/rats.py index 3ad7ca7..7c4af38 100644 --- a/rats.py +++ b/rats.py @@ -1,12 +1,12 @@ #!/usr/bin/python3 -import cProfile -import pstats + import random from units import rat, bomb import uuid -import subprocess from engine import maze, sdl2 as engine, controls import os +import datetime +import subprocess class MiceMaze(controls.KeyBindings): def __init__(self, maze_file): @@ -23,7 +23,10 @@ class MiceMaze(controls.KeyBindings): self.unit_positions = {} self.unit_positions_before = {} self.scrolling_direction = None + self.pause = False + self.game_end = (False, None) self.scrolling = False + self.sounds = {} for _ in range(5): self.new_rat() @@ -55,8 +58,41 @@ class MiceMaze(controls.KeyBindings): variant = x*y % 4 tile = self.grasses[variant] if cell else self.tunnel self.engine.draw_image(x * self.cell_size, y * self.cell_size, tile, tag="maze") - + def game_over(self): + if self.game_end[0]: + if not self.game_end[1]: + self.engine.win_screen("Game Over: Mice are too many!", image=self.assets["BMP_WEWIN"]) + else: + self.engine.win_screen(f"You Win! Points: {self.points}", image=self.assets["BMP_WEWIN"]) + + + return True + if len(self.units) >= 150: + self.stop_sound() + self.play_sound("WEWIN.WAV") + self.game_end = (True, False) + return True + if not len(self.units): + self.stop_sound() + self.play_sound("VICTORY.WAV") + self.game_end = (True, True) + self.save_score() + return True + + def save_score(self): + with open("scores.txt", "a") as f: + f.write(f"{datetime.datetime.now()} - {self.points}\n") + + def read_score(self): + with open("scores.txt") as f: + return f.read().splitlines() + def update_maze(self): + if self.pause: + self.engine.pause_screen("Paused") + return + if self.game_over(): + return self.engine.delete_tag("unit") self.engine.delete_tag("effect") self.engine.draw_pointer(self.pointer[0] * self.cell_size, self.pointer[1] * self.cell_size) @@ -87,10 +123,17 @@ class MiceMaze(controls.KeyBindings): ) self.engine.scroll_view(self.pointer) - def play_sound(self, sound_file): + def play_sound(self, sound_file,tag="main"): if self.audio: - subprocess.Popen(["aplay", f"sound/{sound_file}"]) - #self.engine.play_sound(f"sound/{sound_file}") + if len(self.sounds) > 5: + self.sounds.pop(next(iter(self.sounds))).kill() + self.sounds[f"{tag}_{random.random()}"] = subprocess.Popen(["aplay", f"sound/{sound_file}"]) + + def stop_sound(self, tag=None): + for key, value in self.sounds.copy().items(): + if tag is None or tag in key: + value.kill() + del self.sounds[key] def graphics_load(self): self.tunnel = self.engine.load_image("Rat/BMP_TUNNEL.png") @@ -131,8 +174,6 @@ class MiceMaze(controls.KeyBindings): self.engine.new_cycle(100, self.scroll) if __name__ == "__main__": - profiler = cProfile.Profile() - profiler.enable() solver = MiceMaze('maze.json') solver.run() diff --git a/requirements.txt b/requirements.txt index 5a0ddaf..428dd2a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1 @@ -pysdl2 -pysdl2-dll \ No newline at end of file +pysdl2 \ No newline at end of file diff --git a/scores.txt b/scores.txt new file mode 100644 index 0000000..5f6de70 --- /dev/null +++ b/scores.txt @@ -0,0 +1,3 @@ +2024-12-23 00:31:05.911787 - 25 +2024-12-23 00:34:28.819938 - 50 +2024-12-23 00:56:30.216347 - 25 diff --git a/units/__pycache__/rat.cpython-313.pyc b/units/__pycache__/rat.cpython-313.pyc index b794d63adbf5a8f8362eb2a601e448c745bd6706..1ff24fda64caf37311e0315af9bff4f6a8cf40d1 100644 GIT binary patch delta 403 zcmX@<{lc5~GcPX}0}$L>n2{d7kyltmj2Xm*0yZEG;(tCi*-T`=SSV94qb0KfLpp;d zlb`rvZ1KN zHfJl!F)?;e?ou{o?3{c+`9vgGl@&;pABYeI5oJI^lcNZyOYA|4aJ!@rB;7app^6G) g-()sbL(wjfz*G>y2_hOmMBii|RVl_r znTn)=LPbG9q8KDUIY3m3(Qb0Ks2%fF4$I9OMcdezisB~Q$Sh&hoBU8lh0$s=yKEy9 zQ&HmNiSiwGnGPJ zJQL^w3Gjdju=eK7MT%xjj9rsgDw{HPOunytA`+~^3Z%jhM2LcjG9aPJQH0YK_8>*L qUC|4Y?wzEn!q_`mRn<_m6U3haA~-<=*pa=HvsI-SXHITYO#%QzluU^L diff --git a/units/bomb.py b/units/bomb.py index 4523772..87458c2 100644 --- a/units/bomb.py +++ b/units/bomb.py @@ -53,7 +53,8 @@ class Timer(Bomb): if self.age == AGE_THRESHOLD: self.die() - def die(self, unit=None): + def die(self, unit=None, score=None): + score = 10 print("BOOM") if not unit: unit = self @@ -68,11 +69,15 @@ class Timer(Bomb): for victim in self.game.unit_positions.get((x, y), []): if victim.id in self.game.units: if victim.partial_move >= 0.5: - victim.die() + victim.die(score=score) + if score < 160: + score *= 2 for victim in self.game.unit_positions_before.get((x, y), []): if victim.id in self.game.units: if victim.partial_move < 0.5: - victim.die() + victim.die(score=score) + if score < 160: + score *= 2 else: break if direction == "N": diff --git a/units/points.py b/units/points.py index 072bb4c..4088731 100644 --- a/units/points.py +++ b/units/points.py @@ -30,7 +30,7 @@ class Point(Unit): def collisions(self): pass - def die(self, unit=None): + def die(self, unit=None, score=None): if not unit: unit = self self.game.units.pop(unit.id) diff --git a/units/rat.py b/units/rat.py index 162c291..a797f38 100644 --- a/units/rat.py +++ b/units/rat.py @@ -96,11 +96,11 @@ class Rat(Unit): if "fuck" in dir(self): self.fuck(unit) - def die(self, unit=None): + def die(self, unit=None, score=10): if not unit: unit = self self.game.units.pop(unit.id) - self.game.spawn_unit(Point, unit.position_before) + self.game.spawn_unit(Point, unit.position_before, value=score) def draw(self): direction = self.calculate_rat_direction()