Add explosion stage 1 PNG assets for all directions

- Added BMP_1_EXPLOSION_DOWN.png to original and preview directories.
- Added BMP_1_EXPLOSION_LEFT.png to original and preview directories.
- Added BMP_1_EXPLOSION_RIGHT.png to original and preview directories.
- Added BMP_1_EXPLOSION_UP.png to original and preview directories.

These assets are part of the explosion animation for the game, enhancing visual effects during gameplay.
This commit is contained in:
2026-04-14 11:24:16 +02:00
parent eaafd92dc2
commit b243cf04d3
22 changed files with 98956 additions and 4 deletions
Binary file not shown.

Before

Width:  |  Height:  |  Size: 336 B

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 354 B

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 347 B

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 337 B

After

Width:  |  Height:  |  Size: 1.8 KiB

+2 -2
View File
@@ -281,7 +281,6 @@ class MiceMaze(
self.render_engine.delete_tag("unit")
self.render_engine.delete_tag("effect")
self.render_engine.delete_tag("cave")
self.render_engine.draw_pointer(self.pointer[0] * self.cell_size, self.pointer[1] * self.cell_size)
# Clear collision system for new frame
self.collision_system.clear()
@@ -333,13 +332,14 @@ class MiceMaze(
self.unit_positions.setdefault(unit.position, []).append(unit)
self.unit_positions_before.setdefault(unit.position_before, []).append(unit)
self.draw_cave_foreground()
self.render_engine.draw_pointer(self.pointer[0] * self.cell_size, self.pointer[1] * self.cell_size)
# Fourth pass: check collisions and draw
for unit in self.units.copy().values():
unit.collisions()
unit.draw()
self.draw_cave_foreground()
self.render_engine.update_status(f"Mice: {self.count_rats()} - Points: {self.points}")
self.refill_ammo()
+74
View File
@@ -0,0 +1,74 @@
#!/usr/bin/env python3
import json
import sys
from pathlib import Path
from PIL import Image
CHROMAKEY = [128, 128, 128, 255]
GREEN_LIGHT = [0, 255, 0, 255]
GREEN_DARK = [0, 128, 0, 255]
def is_green(pixel):
return pixel == GREEN_LIGHT or pixel == GREEN_DARK
def is_background(pixel):
return pixel == CHROMAKEY or is_green(pixel)
def cave_reference_path(sprite_name):
direction = sprite_name.rsplit("_", 1)[-1]
return Path("assets/Rat") / f"BMP_1_CAVE_{direction}.png"
def load_cave_grid(sprite_name):
cave_path = cave_reference_path(sprite_name)
cave_image = Image.open(cave_path).convert("RGBA")
width, height = cave_image.size
pixel_access = cave_image.load()
return [
[list(pixel_access[x, y]) for x in range(width)]
for y in range(height)
]
def enhance_pixels(name, pixels):
cave_pixels = load_cave_grid(name)
enhanced = []
for y, row in enumerate(pixels):
enhanced_row = []
for x, pixel in enumerate(row):
if is_background(pixel):
enhanced_row.append(cave_pixels[y][x][:])
else:
enhanced_row.append(pixel[:])
enhanced.append(enhanced_row)
return enhanced
def process_file(src_path, dst_path):
data = json.loads(src_path.read_text())
pixels = data["pixels"]
data["pixels"] = enhance_pixels(src_path.stem, pixels)
dst_path.write_text(json.dumps(data, indent=2))
def main():
if len(sys.argv) != 3:
raise SystemExit("usage: enhance_stage1_explosions.py <src_dir> <dst_dir>")
src_dir = Path(sys.argv[1])
dst_dir = Path(sys.argv[2])
dst_dir.mkdir(parents=True, exist_ok=True)
for src_path in sorted(src_dir.glob("BMP_1_EXPLOSION_*.json")):
dst_path = dst_dir / src_path.name
process_file(src_path, dst_path)
print(f"Wrote {dst_path}")
if __name__ == "__main__":
main()
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 336 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 354 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 347 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 337 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

+9
View File
@@ -44,6 +44,9 @@ class Bomb(Unit):
x_pos = self.position_before[0] * self.game.cell_size + (self.game.cell_size - image_size[0]) // 2 + partial_x
y_pos = self.position_before[1] * self.game.cell_size + (self.game.cell_size - image_size[1]) // 2 + partial_y
if self.is_hidden_in_tunnel(image_size):
return
self.game.render_engine.draw_image(x_pos, y_pos, image, anchor="nw", tag="unit")
class Timer(Bomb):
@@ -132,6 +135,9 @@ class Explosion(Bomb):
x_pos = self.position_before[0] * self.game.cell_size + (self.game.cell_size - image_size[0]) // 2 + partial_x
y_pos = self.position_before[1] * self.game.cell_size + (self.game.cell_size - image_size[1]) // 2 + partial_y
if self.is_hidden_in_tunnel(image_size):
return
self.game.render_engine.draw_image(x_pos, y_pos, image, anchor="nw", tag="unit")
@@ -186,4 +192,7 @@ class NuclearBomb(Unit):
x_pos = self.position[0] * self.game.cell_size + (self.game.cell_size - image_size[0]) // 2
y_pos = self.position[1] * self.game.cell_size + (self.game.cell_size - image_size[1]) // 2
if self.is_hidden_in_tunnel(image_size, position=self.position):
return
self.game.render_engine.draw_image(x_pos, y_pos, image, anchor="nw", tag="unit")
+2
View File
@@ -79,8 +79,10 @@ class Gas(Unit):
x_pos = self.position_before[0] * self.game.cell_size + (self.game.cell_size - image_size[0]) // 2 + partial_x
y_pos = self.position_before[1] * self.game.cell_size + (self.game.cell_size - image_size[1]) // 2 + partial_y
if not self.is_hidden_in_tunnel(image_size):
self.game.render_engine.draw_image(x_pos, y_pos, image, anchor="nw", tag="unit")
for cell in self.spreading_cells:
x_pos = cell[0] * self.game.cell_size + (self.game.cell_size - image_size[0]) // 2 + partial_x
y_pos = cell[1] * self.game.cell_size + (self.game.cell_size - image_size[1]) // 2 + partial_y
if not self.is_hidden_in_tunnel(image_size, position=cell):
self.game.render_engine.draw_image(x_pos, y_pos, image, anchor="nw", tag="unit")
+3
View File
@@ -56,6 +56,9 @@ class Mine(Unit):
x_pos = self.position[0] * self.game.cell_size + (self.game.cell_size - image_size[0]) // 2
y_pos = self.position[1] * self.game.cell_size + (self.game.cell_size - image_size[1]) // 2
if self.is_hidden_in_tunnel(image_size, position=self.position):
return
self.game.render_engine.draw_image(x_pos, y_pos, image, anchor="nw", tag="unit")
def die(self, score=None):
+16
View File
@@ -67,6 +67,22 @@ class Unit(ABC):
"""Handle collisions with other units. Default implementation does nothing."""
pass
def is_hidden_in_tunnel(self, image_size, position=None):
"""Return True when the sprite center falls inside a tunnel cell."""
if position is None:
position = self.position_before
x_pos = position[0] * self.game.cell_size + (self.game.cell_size - image_size[0]) // 2
y_pos = position[1] * self.game.cell_size + (self.game.cell_size - image_size[1]) // 2
center_x = int(x_pos + image_size[0] / 2)
center_y = int(y_pos + image_size[1] / 2)
cell_x = center_x // self.game.cell_size
cell_y = center_y // self.game.cell_size
if not self.game.map.in_bounds(cell_x, cell_y):
return False
return self.game.map.is_tunnel(cell_x, cell_y)
def die(self, score=None):
"""Remove unit from game and handle basic cleanup."""
if self.id in self.game.units: