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("unit")
|
||||||
self.render_engine.delete_tag("effect")
|
self.render_engine.delete_tag("effect")
|
||||||
self.render_engine.delete_tag("cave")
|
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
|
# Clear collision system for new frame
|
||||||
self.collision_system.clear()
|
self.collision_system.clear()
|
||||||
@@ -333,13 +332,14 @@ class MiceMaze(
|
|||||||
self.unit_positions.setdefault(unit.position, []).append(unit)
|
self.unit_positions.setdefault(unit.position, []).append(unit)
|
||||||
self.unit_positions_before.setdefault(unit.position_before, []).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
|
# Fourth pass: check collisions and draw
|
||||||
for unit in self.units.copy().values():
|
for unit in self.units.copy().values():
|
||||||
unit.collisions()
|
unit.collisions()
|
||||||
unit.draw()
|
unit.draw()
|
||||||
|
|
||||||
self.draw_cave_foreground()
|
|
||||||
|
|
||||||
self.render_engine.update_status(f"Mice: {self.count_rats()} - Points: {self.points}")
|
self.render_engine.update_status(f"Mice: {self.count_rats()} - Points: {self.points}")
|
||||||
self.refill_ammo()
|
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 |
@@ -43,6 +43,9 @@ class Bomb(Unit):
|
|||||||
|
|
||||||
x_pos = self.position_before[0] * self.game.cell_size + (self.game.cell_size - image_size[0]) // 2 + partial_x
|
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
|
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")
|
self.game.render_engine.draw_image(x_pos, y_pos, image, anchor="nw", tag="unit")
|
||||||
|
|
||||||
@@ -131,6 +134,9 @@ class Explosion(Bomb):
|
|||||||
|
|
||||||
x_pos = self.position_before[0] * self.game.cell_size + (self.game.cell_size - image_size[0]) // 2 + partial_x
|
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
|
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")
|
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
|
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
|
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")
|
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
|
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
|
y_pos = self.position_before[1] * self.game.cell_size + (self.game.cell_size - image_size[1]) // 2 + partial_y
|
||||||
self.game.render_engine.draw_image(x_pos, y_pos, image, anchor="nw", tag="unit")
|
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:
|
for cell in self.spreading_cells:
|
||||||
x_pos = cell[0] * self.game.cell_size + (self.game.cell_size - image_size[0]) // 2 + partial_x
|
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
|
y_pos = cell[1] * self.game.cell_size + (self.game.cell_size - image_size[1]) // 2 + partial_y
|
||||||
self.game.render_engine.draw_image(x_pos, y_pos, image, anchor="nw", tag="unit")
|
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")
|
||||||
|
|||||||
@@ -55,6 +55,9 @@ class Mine(Unit):
|
|||||||
# Center the mine in the cell
|
# Center the mine in the cell
|
||||||
x_pos = self.position[0] * self.game.cell_size + (self.game.cell_size - image_size[0]) // 2
|
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
|
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")
|
self.game.render_engine.draw_image(x_pos, y_pos, image, anchor="nw", tag="unit")
|
||||||
|
|
||||||
|
|||||||
@@ -67,6 +67,22 @@ class Unit(ABC):
|
|||||||
"""Handle collisions with other units. Default implementation does nothing."""
|
"""Handle collisions with other units. Default implementation does nothing."""
|
||||||
pass
|
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):
|
def die(self, score=None):
|
||||||
"""Remove unit from game and handle basic cleanup."""
|
"""Remove unit from game and handle basic cleanup."""
|
||||||
if self.id in self.game.units:
|
if self.id in self.game.units:
|
||||||
|
|||||||