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.
|
Before Width: | Height: | Size: 336 B After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 354 B After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 347 B After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 337 B After Width: | Height: | Size: 1.8 KiB |
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
After Width: | Height: | Size: 336 B |
|
After Width: | Height: | Size: 354 B |
|
After Width: | Height: | Size: 347 B |
|
After Width: | Height: | Size: 337 B |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
@@ -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")
|
||||
@@ -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")
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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:
|
||||
|
||||