OK
This commit is contained in:
@@ -30,6 +30,8 @@ class KeyBindings:
|
||||
self.spawn_bomb(self.pointer)
|
||||
elif key in keybindings.get("spawn_mine", []):
|
||||
self.spawn_mine(self.pointer)
|
||||
elif key in keybindings.get("spawn_nuclear_bomb", []):
|
||||
self.spawn_nuclear_bomb(self.pointer)
|
||||
elif key in keybindings.get("pause", []):
|
||||
self.game_status = "paused" if self.game_status == "game" else "game"
|
||||
elif key in keybindings.get("start_game", []):
|
||||
|
||||
@@ -6,11 +6,16 @@ class Graphics():
|
||||
self.tunnel = self.render_engine.load_image("Rat/BMP_TUNNEL.png", surface=True)
|
||||
self.grasses = [self.render_engine.load_image(f"Rat/BMP_1_GRASS_{i+1}.png", surface=True) for i in range(4)]
|
||||
self.rat_assets = {}
|
||||
self.rat_assets_textures = {}
|
||||
self.bomb_assets = {}
|
||||
for sex in ["MALE", "FEMALE", "BABY"]:
|
||||
self.rat_assets[sex] = {}
|
||||
for direction in ["UP", "DOWN", "LEFT", "RIGHT"]:
|
||||
self.rat_assets[sex][direction] = self.render_engine.load_image(f"Rat/BMP_{sex}_{direction}.png", transparent_color=(128, 128, 128))
|
||||
for sex in ["MALE", "FEMALE", "BABY"]:
|
||||
self.rat_assets_textures[sex] = {}
|
||||
for direction in ["UP", "DOWN", "LEFT", "RIGHT"]:
|
||||
self.rat_assets_textures[sex][direction] = self.render_engine.load_image(f"Rat/BMP_{sex}_{direction}.png", transparent_color=(128, 128, 128), surface=False)
|
||||
for n in range(5):
|
||||
self.bomb_assets[n] = self.render_engine.load_image(f"Rat/BMP_BOMB{n}.png", transparent_color=(128, 128, 128))
|
||||
self.assets = {}
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ class Scoring:
|
||||
for row in rows:
|
||||
table.append(row.split(" - "))
|
||||
table.sort(key=lambda x: int(x[1]), reverse=True)
|
||||
return table
|
||||
return table[:3]
|
||||
|
||||
def add_point(self, value):
|
||||
self.points += value
|
||||
+119
-11
@@ -54,6 +54,18 @@ class GameWindow:
|
||||
self.running = True
|
||||
self.delay = 30
|
||||
self.performance = 0
|
||||
self.last_status_text = ""
|
||||
self.stats_sprite = None
|
||||
self.mean_fps = 0
|
||||
self.fpss = []
|
||||
self.text_width = 0
|
||||
self.text_height = 0
|
||||
self.ammo_text = ""
|
||||
|
||||
# White flash effect state
|
||||
self.white_flash_active = False
|
||||
self.white_flash_start_time = 0
|
||||
self.white_flash_opacity = 255
|
||||
|
||||
# Input handling
|
||||
self.key_down, self.key_up, self.axis_scroll = key_callback
|
||||
@@ -151,7 +163,7 @@ class GameWindow:
|
||||
"""Draw background texture with current view offset"""
|
||||
self.renderer.copy(bg_texture, dstrect=sdl2.SDL_Rect(self.w_offset, self.h_offset, self.width, self.height))
|
||||
|
||||
def draw_image(self, x, y, sprite, tag, anchor="nw"):
|
||||
def draw_image(self, x, y, sprite, tag=None, anchor="nw"):
|
||||
"""Draw an image sprite at specified coordinates"""
|
||||
if not self.is_in_visible_area(x, y):
|
||||
return
|
||||
@@ -225,20 +237,50 @@ class GameWindow:
|
||||
# TODO: Fix outline parameter usage
|
||||
color = (0, 0, 255) if self.button_cursor == list(coords) else (0, 0, 0)
|
||||
self.draw_rectangle(x, y, width, height, "button", outline=color)
|
||||
self.draw_text(text, self.fonts[20], (x + 10, y + 10), (0, 0, 0))
|
||||
#self.draw_text(text, self.fonts[20], (x + 10, y + 10), (0, 0, 0))
|
||||
|
||||
def update_status(self, text):
|
||||
"""Update and display the status bar with FPS information"""
|
||||
fps = int(1000 / self.performance) if self.performance != 0 else 0
|
||||
status_text = f"FPS: {fps} - {text}"
|
||||
font = self.fonts[20]
|
||||
sprite = self.factory.from_text(status_text, color=sdl2.ext.Color(0, 0, 0), fontmanager=font)
|
||||
text_width, text_height = sprite.size
|
||||
|
||||
# Draw background for status text
|
||||
self.renderer.fill((3, 3, text_width + 10, text_height + 4), sdl2.ext.Color(255, 255, 255))
|
||||
self.draw_text(status_text, font, (8, 5), sdl2.ext.Color(0, 0, 0))
|
||||
# at 10% of probability print fps
|
||||
if len(self.fpss) > 20:
|
||||
self.mean_fps = round(sum(self.fpss) / len(self.fpss)) if self.fpss else fps
|
||||
#print(f"FPS: {self.mean_fps}")
|
||||
self.fpss.clear()
|
||||
else:
|
||||
self.fpss.append(fps)
|
||||
|
||||
status_text = f"FPS: {self.mean_fps} - {text}"
|
||||
if status_text != self.last_status_text:
|
||||
self.last_status_text = status_text
|
||||
font = self.fonts[20]
|
||||
self.stats_sprite = self.factory.from_text(status_text, color=sdl2.ext.Color(0, 0, 0), fontmanager=font)
|
||||
if self.text_width != self.stats_sprite.size[0] or self.text_height != self.stats_sprite.size[1]:
|
||||
self.text_width, self.text_height = self.stats_sprite.size
|
||||
# create a background for the status text using texture
|
||||
self.stats_background = self.factory.from_color(sdl2.ext.Color(255, 255, 255), (self.text_width + 10, self.text_height + 4))
|
||||
|
||||
# self.renderer.fill((3, 3, self.text_width + 10, self.text_height + 4), sdl2.ext.Color(255, 255, 255))
|
||||
self.renderer.copy(self.stats_background, dstrect=sdl2.SDL_Rect(3, 3, self.text_width + 10, self.text_height + 4))
|
||||
self.renderer.copy(self.stats_sprite, dstrect=sdl2.SDL_Rect(8, 5, self.text_width, self.text_height))
|
||||
|
||||
def update_ammo(self, ammo, assets):
|
||||
"""Update and display the ammo count"""
|
||||
ammo_text = f"{ammo['bomb']['count']}/{ammo['bomb']['max']} {ammo['mine']['count']}/{ammo['mine']['max']} {ammo['nuclear']['count']}/{ammo['nuclear']['max']} "
|
||||
if self.ammo_text != ammo_text:
|
||||
self.ammo_text = ammo_text
|
||||
font = self.fonts[20]
|
||||
self.ammo_sprite = self.factory.from_text(ammo_text, color=sdl2.ext.Color(0, 0, 0), fontmanager=font)
|
||||
text_width, text_height = self.ammo_sprite.size
|
||||
self.ammo_background = self.factory.from_color(sdl2.ext.Color(255, 255, 255), (text_width + 10, text_height + 4))
|
||||
text_width, text_height = self.ammo_sprite.size
|
||||
position = (self.target_size[0] - text_width - 10, self.target_size[1] - text_height - 5)
|
||||
#self.renderer.fill((position[0] - 5, position[1] - 2, text_width + 10, text_height + 4), sdl2.ext.Color(255, 255, 255))
|
||||
self.renderer.copy(self.ammo_background, dstrect=sdl2.SDL_Rect(position[0] - 5, position[1] - 2, text_width + 10, text_height + 4))
|
||||
self.renderer.copy(self.ammo_sprite, dstrect=sdl2.SDL_Rect(position[0], position[1], text_width, text_height))
|
||||
self.renderer.copy(assets["BMP_BOMB0"], dstrect=sdl2.SDL_Rect(position[0]+25, position[1], 20, 20))
|
||||
self.renderer.copy(assets["mine"], dstrect=sdl2.SDL_Rect(position[0]+80, position[1], 20, 20))
|
||||
self.renderer.copy(assets["BMP_NUCLEAR"], dstrect=sdl2.SDL_Rect(position[0]+130, position[1], 20, 20))
|
||||
# ======================
|
||||
# VIEW & NAVIGATION
|
||||
# ======================
|
||||
@@ -328,6 +370,10 @@ class GameWindow:
|
||||
# Execute main update
|
||||
kwargs["update"]()
|
||||
|
||||
# Update and draw white flash effect
|
||||
if self.update_white_flash():
|
||||
self.draw_white_flash()
|
||||
|
||||
# Handle SDL events
|
||||
events = sdl2.ext.get_events()
|
||||
for event in events:
|
||||
@@ -335,7 +381,11 @@ class GameWindow:
|
||||
self.running = False
|
||||
elif event.type == sdl2.SDL_KEYDOWN and self.key_down:
|
||||
key = sdl2.SDL_GetKeyName(event.key.keysym.sym).decode('utf-8')
|
||||
self.key_down(key)
|
||||
# Check for Right Ctrl key to trigger white flash
|
||||
if event.key.keysym.sym == sdl2.SDLK_RCTRL:
|
||||
self.trigger_white_flash()
|
||||
else:
|
||||
self.key_down(key)
|
||||
elif event.type == sdl2.SDL_KEYUP and self.key_up:
|
||||
key = sdl2.SDL_GetKeyName(event.key.keysym.sym).decode('utf-8')
|
||||
self.key_up(key)
|
||||
@@ -362,6 +412,64 @@ class GameWindow:
|
||||
# SPECIAL EFFECTS
|
||||
# ======================
|
||||
|
||||
def trigger_white_flash(self):
|
||||
"""Trigger the white flash effect"""
|
||||
self.white_flash_active = True
|
||||
self.white_flash_start_time = sdl2.SDL_GetTicks()
|
||||
self.white_flash_opacity = 255
|
||||
|
||||
def update_white_flash(self):
|
||||
"""Update the white flash effect and return True if it should be drawn"""
|
||||
if not self.white_flash_active:
|
||||
return False
|
||||
|
||||
current_time = sdl2.SDL_GetTicks()
|
||||
elapsed_time = current_time - self.white_flash_start_time
|
||||
|
||||
if elapsed_time < 1000: # First 1 second : full white
|
||||
self.white_flash_opacity = 255
|
||||
return True
|
||||
elif elapsed_time < 3000: # Next 2 seconds: fade out
|
||||
# Calculate fade based on remaining time (2000ms fade duration)
|
||||
fade_progress = (elapsed_time - 1000) / 2000.0 # 0.0 to 1.0
|
||||
self.white_flash_opacity = int(255 * (1.0 - fade_progress))
|
||||
return True
|
||||
else: # Effect is complete
|
||||
self.white_flash_active = False
|
||||
self.white_flash_opacity = 0
|
||||
return False
|
||||
|
||||
def draw_white_flash(self):
|
||||
"""Draw the white flash overlay"""
|
||||
if self.white_flash_opacity > 0:
|
||||
# Create a white surface with the current opacity
|
||||
white_surface = sdl2.SDL_CreateRGBSurface(
|
||||
0, self.target_size[0], self.target_size[1], 32,
|
||||
0x000000FF, # R mask
|
||||
0x0000FF00, # G mask
|
||||
0x00FF0000, # B mask
|
||||
0xFF000000 # A mask
|
||||
)
|
||||
|
||||
if white_surface:
|
||||
# Fill surface with white
|
||||
sdl2.SDL_FillRect(white_surface, None,
|
||||
sdl2.SDL_MapRGBA(white_surface.contents.format,
|
||||
255, 255, 255, self.white_flash_opacity))
|
||||
|
||||
# Convert to texture and draw
|
||||
white_texture = self.factory.from_surface(white_surface)
|
||||
white_texture.position = (0, 0)
|
||||
|
||||
# Enable alpha blending for the texture
|
||||
sdl2.SDL_SetTextureBlendMode(white_texture.texture, sdl2.SDL_BLENDMODE_BLEND)
|
||||
|
||||
# Draw the white overlay
|
||||
self.renderer.copy(white_texture, dstrect=sdl2.SDL_Rect(0, 0, self.target_size[0], self.target_size[1]))
|
||||
|
||||
# Clean up
|
||||
sdl2.SDL_FreeSurface(white_surface)
|
||||
|
||||
# ======================
|
||||
# UTILITY METHODS
|
||||
# ======================
|
||||
|
||||
+23
-4
@@ -17,19 +17,38 @@ class UnitManager:
|
||||
self.spawn_unit(rat_class, position)
|
||||
|
||||
def spawn_bomb(self, position):
|
||||
if self.ammo["bomb"]["count"] <= 0:
|
||||
return
|
||||
self.render_engine.play_sound("PUTDOWN.WAV")
|
||||
self.spawn_unit(bomb.Timer, position)
|
||||
self.ammo["bomb"]["count"] -= 1
|
||||
|
||||
def spawn_nuclear_bomb(self, position):
|
||||
"""Spawn a nuclear bomb at the specified position"""
|
||||
if self.ammo["nuclear"]["count"] <= 0:
|
||||
return
|
||||
if self.map.is_wall(position[0], position[1]):
|
||||
return
|
||||
self.render_engine.play_sound("NUCLEAR.WAV")
|
||||
self.ammo["nuclear"]["count"] -= 1
|
||||
self.spawn_unit(bomb.NuclearBomb, position)
|
||||
|
||||
def spawn_mine(self, position):
|
||||
if self.ammo["mine"]["count"] <= 0:
|
||||
return
|
||||
if self.map.is_wall(position[0], position[1]):
|
||||
return
|
||||
self.render_engine.play_sound("PUTDOWN.WAV")
|
||||
self.spawn_unit(mine.Mine, position)
|
||||
self.ammo["mine"]["count"] -= 1
|
||||
self.spawn_unit(mine.Mine, position, on_bottom=True)
|
||||
|
||||
def spawn_unit(self, unit, position, **kwargs):
|
||||
def spawn_unit(self, unit, position, on_bottom=False, **kwargs):
|
||||
id = uuid.uuid4()
|
||||
self.units[id] = unit(self, position, id, **kwargs)
|
||||
|
||||
if on_bottom:
|
||||
self.units = {id: unit(self, position, id, **kwargs), **self.units}
|
||||
else:
|
||||
self.units[id] = unit(self, position, id, **kwargs)
|
||||
|
||||
def choose_start(self):
|
||||
if not hasattr(self, '_valid_positions'):
|
||||
self._valid_positions = [
|
||||
|
||||
Reference in New Issue
Block a user