mine implementation
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 273 B |
@@ -9,5 +9,6 @@
|
|||||||
"scroll_left": ["Left", 10],
|
"scroll_left": ["Left", 10],
|
||||||
"scroll_right": ["Right", 11],
|
"scroll_right": ["Right", 11],
|
||||||
"spawn_bomb": ["Space", 1],
|
"spawn_bomb": ["Space", 1],
|
||||||
|
"spawn_mine": ["Left Ctrl", "Control_R", 17],
|
||||||
"pause": ["P", 16]
|
"pause": ["P", 16]
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Audio conversion script to convert mine.wav to u8 22100 Hz format
|
||||||
|
"""
|
||||||
|
|
||||||
|
from pydub import AudioSegment
|
||||||
|
import os
|
||||||
|
|
||||||
|
def convert_mine_wav():
|
||||||
|
"""Convert mine.wav to u8 format at 22100 Hz"""
|
||||||
|
|
||||||
|
# Input and output paths
|
||||||
|
input_path = "sound/mine.wav"
|
||||||
|
output_path = "sound/mine_converted.wav"
|
||||||
|
|
||||||
|
if not os.path.exists(input_path):
|
||||||
|
print(f"Error: {input_path} not found!")
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Load the audio file
|
||||||
|
print(f"Loading {input_path}...")
|
||||||
|
audio = AudioSegment.from_wav(input_path)
|
||||||
|
|
||||||
|
# Print current format info
|
||||||
|
print(f"Original format:")
|
||||||
|
print(f" Sample rate: {audio.frame_rate} Hz")
|
||||||
|
print(f" Channels: {audio.channels}")
|
||||||
|
print(f" Sample width: {audio.sample_width} bytes ({audio.sample_width * 8} bits)")
|
||||||
|
print(f" Duration: {len(audio)} ms")
|
||||||
|
|
||||||
|
# Convert to mono if stereo
|
||||||
|
if audio.channels > 1:
|
||||||
|
print("Converting to mono...")
|
||||||
|
audio = audio.set_channels(1)
|
||||||
|
|
||||||
|
# Convert to 22100 Hz sample rate
|
||||||
|
print("Converting sample rate to 22100 Hz...")
|
||||||
|
audio = audio.set_frame_rate(22100)
|
||||||
|
|
||||||
|
# Convert to 8-bit unsigned (u8)
|
||||||
|
print("Converting to 8-bit unsigned format...")
|
||||||
|
audio = audio.set_sample_width(1) # 1 byte = 8 bits
|
||||||
|
|
||||||
|
# Export the converted audio
|
||||||
|
print(f"Saving to {output_path}...")
|
||||||
|
audio.export(output_path, format="wav")
|
||||||
|
|
||||||
|
# Print new format info
|
||||||
|
converted_audio = AudioSegment.from_wav(output_path)
|
||||||
|
print(f"\nConverted format:")
|
||||||
|
print(f" Sample rate: {converted_audio.frame_rate} Hz")
|
||||||
|
print(f" Channels: {converted_audio.channels}")
|
||||||
|
print(f" Sample width: {converted_audio.sample_width} bytes ({converted_audio.sample_width * 8} bits)")
|
||||||
|
print(f" Duration: {len(converted_audio)} ms")
|
||||||
|
|
||||||
|
print(f"\nConversion complete! Output saved as: {output_path}")
|
||||||
|
|
||||||
|
# Optionally replace the original file
|
||||||
|
replace = input("\nReplace original mine.wav with converted version? (y/n): ").lower()
|
||||||
|
if replace == 'y':
|
||||||
|
import shutil
|
||||||
|
# Backup original
|
||||||
|
backup_path = "sound/mine_original.wav"
|
||||||
|
shutil.copy2(input_path, backup_path)
|
||||||
|
print(f"Original file backed up as: {backup_path}")
|
||||||
|
|
||||||
|
# Replace original
|
||||||
|
shutil.copy2(output_path, input_path)
|
||||||
|
os.remove(output_path)
|
||||||
|
print(f"Original file replaced with converted version.")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error during conversion: {e}")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
convert_mine_wav()
|
||||||
+2
-1
@@ -27,8 +27,9 @@ class KeyBindings:
|
|||||||
elif key in keybindings.get("scroll_right", []):
|
elif key in keybindings.get("scroll_right", []):
|
||||||
self.start_scrolling("Right")
|
self.start_scrolling("Right")
|
||||||
elif key in keybindings.get("spawn_bomb", []):
|
elif key in keybindings.get("spawn_bomb", []):
|
||||||
self.render_engine.play_sound("PUTDOWN.WAV")
|
|
||||||
self.spawn_bomb(self.pointer)
|
self.spawn_bomb(self.pointer)
|
||||||
|
elif key in keybindings.get("spawn_mine", []):
|
||||||
|
self.spawn_mine(self.pointer)
|
||||||
elif key in keybindings.get("pause", []):
|
elif key in keybindings.get("pause", []):
|
||||||
self.game_status = "paused" if self.game_status == "game" else "game"
|
self.game_status = "paused" if self.game_status == "game" else "game"
|
||||||
elif key in keybindings.get("start_game", []):
|
elif key in keybindings.get("start_game", []):
|
||||||
|
|||||||
+3
-1
@@ -2,6 +2,7 @@ import os
|
|||||||
|
|
||||||
class Graphics():
|
class Graphics():
|
||||||
def load_assets(self):
|
def load_assets(self):
|
||||||
|
print("Loading graphics assets...")
|
||||||
self.tunnel = self.render_engine.load_image("Rat/BMP_TUNNEL.png", surface=True)
|
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.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 = {}
|
||||||
@@ -18,6 +19,7 @@ class Graphics():
|
|||||||
self.assets[file[:-4]] = self.render_engine.load_image(f"Rat/{file}")
|
self.assets[file[:-4]] = self.render_engine.load_image(f"Rat/{file}")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# ==================== RENDERING ====================
|
# ==================== RENDERING ====================
|
||||||
|
|
||||||
def draw_maze(self):
|
def draw_maze(self):
|
||||||
@@ -65,7 +67,7 @@ class Graphics():
|
|||||||
self.blood_stains[position] = new_blood_surface
|
self.blood_stains[position] = new_blood_surface
|
||||||
|
|
||||||
# Regenerate background to include the updated blood stain
|
# Regenerate background to include the updated blood stain
|
||||||
self.regenerate_background()
|
self.background_texture = None
|
||||||
|
|
||||||
def scroll_cursor(self, x=0, y=0):
|
def scroll_cursor(self, x=0, y=0):
|
||||||
if self.pointer[0] + x > self.map.width or self.pointer[1] + y > self.map.height:
|
if self.pointer[0] + x > self.map.width or self.pointer[1] + y > self.map.height:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import random
|
import random
|
||||||
import uuid
|
import uuid
|
||||||
from units import rat, bomb
|
from units import rat, bomb, mine
|
||||||
|
|
||||||
class UnitManager:
|
class UnitManager:
|
||||||
def count_rats(self):
|
def count_rats(self):
|
||||||
@@ -17,8 +17,15 @@ class UnitManager:
|
|||||||
self.spawn_unit(rat_class, position)
|
self.spawn_unit(rat_class, position)
|
||||||
|
|
||||||
def spawn_bomb(self, position):
|
def spawn_bomb(self, position):
|
||||||
|
self.render_engine.play_sound("PUTDOWN.WAV")
|
||||||
self.spawn_unit(bomb.Timer, position)
|
self.spawn_unit(bomb.Timer, position)
|
||||||
|
|
||||||
|
def spawn_mine(self, position):
|
||||||
|
if self.map.is_wall(position[0], position[1]):
|
||||||
|
return
|
||||||
|
self.render_engine.play_sound("PUTDOWN.WAV")
|
||||||
|
self.spawn_unit(mine.Mine, position)
|
||||||
|
|
||||||
def spawn_unit(self, unit, position, **kwargs):
|
def spawn_unit(self, unit, position, **kwargs):
|
||||||
id = uuid.uuid4()
|
id = uuid.uuid4()
|
||||||
self.units[id] = unit(self, position, id, **kwargs)
|
self.units[id] = unit(self, position, id, **kwargs)
|
||||||
|
|||||||
@@ -96,14 +96,14 @@ class MiceMaze(
|
|||||||
|
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
count_rats = self.count_rats()
|
||||||
if self.count_rats() > 200:
|
if count_rats > 200:
|
||||||
self.render_engine.stop_sound()
|
self.render_engine.stop_sound()
|
||||||
self.render_engine.play_sound("WEWIN.WAV")
|
self.render_engine.play_sound("WEWIN.WAV")
|
||||||
self.game_end = (True, False)
|
self.game_end = (True, False)
|
||||||
self.game_status = "paused"
|
self.game_status = "paused"
|
||||||
return True
|
return True
|
||||||
if not len(self.units):
|
if not count_rats:
|
||||||
self.render_engine.stop_sound()
|
self.render_engine.stop_sound()
|
||||||
self.render_engine.play_sound("VICTORY.WAV")
|
self.render_engine.play_sound("VICTORY.WAV")
|
||||||
self.render_engine.play_sound("WELLDONE.WAV", tag="effects")
|
self.render_engine.play_sound("WELLDONE.WAV", tag="effects")
|
||||||
|
|||||||
@@ -0,0 +1,123 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Script to resize PNG asset files to 18x18 pixels and center them on a 20x20 canvas.
|
||||||
|
Saves the result back to the same file.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import glob
|
||||||
|
from PIL import Image, ImageOps
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
def resize_and_center_image(image_path, target_size=(18, 18), canvas_size=(20, 20)):
|
||||||
|
"""
|
||||||
|
Resize an image to target_size and center it on a canvas of canvas_size.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
image_path (str): Path to the image file
|
||||||
|
target_size (tuple): Size to resize the image to (width, height)
|
||||||
|
canvas_size (tuple): Size of the final canvas (width, height)
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# Open the image
|
||||||
|
with Image.open(image_path) as img:
|
||||||
|
# Convert to RGBA to handle transparency
|
||||||
|
img = img.convert("RGBA")
|
||||||
|
|
||||||
|
# Resize the image to target size using high-quality resampling
|
||||||
|
resized_img = img.resize(target_size, Image.Resampling.LANCZOS)
|
||||||
|
|
||||||
|
# Create a new transparent canvas
|
||||||
|
canvas = Image.new("RGBA", canvas_size, (0, 0, 0, 0))
|
||||||
|
|
||||||
|
# Calculate position to center the resized image
|
||||||
|
x_offset = (canvas_size[0] - target_size[0]) // 2
|
||||||
|
y_offset = (canvas_size[1] - target_size[1]) // 2
|
||||||
|
|
||||||
|
# Paste the resized image onto the canvas
|
||||||
|
canvas.paste(resized_img, (x_offset, y_offset), resized_img)
|
||||||
|
|
||||||
|
# Save back to the same file
|
||||||
|
canvas.save(image_path, "PNG", optimize=True)
|
||||||
|
|
||||||
|
print(f"✓ Processed: {os.path.basename(image_path)}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"✗ Error processing {image_path}: {str(e)}")
|
||||||
|
|
||||||
|
def process_directory(directory_path, file_pattern="*.png"):
|
||||||
|
"""
|
||||||
|
Process all PNG files in a directory.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
directory_path (str): Path to the directory containing PNG files
|
||||||
|
file_pattern (str): Pattern to match files (default: "*.png")
|
||||||
|
"""
|
||||||
|
if not os.path.exists(directory_path):
|
||||||
|
print(f"Error: Directory '{directory_path}' does not exist.")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Find all PNG files matching the pattern
|
||||||
|
search_pattern = os.path.join(directory_path, file_pattern)
|
||||||
|
png_files = glob.glob(search_pattern)
|
||||||
|
|
||||||
|
if not png_files:
|
||||||
|
print(f"No PNG files found in '{directory_path}' matching pattern '{file_pattern}'")
|
||||||
|
return
|
||||||
|
|
||||||
|
print(f"Found {len(png_files)} PNG files to process...")
|
||||||
|
|
||||||
|
# Process each file
|
||||||
|
for png_file in png_files:
|
||||||
|
resize_and_center_image(png_file)
|
||||||
|
|
||||||
|
print(f"\nCompleted processing {len(png_files)} files.")
|
||||||
|
|
||||||
|
def process_single_file(file_path):
|
||||||
|
"""
|
||||||
|
Process a single PNG file.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
file_path (str): Path to the PNG file
|
||||||
|
"""
|
||||||
|
if not os.path.exists(file_path):
|
||||||
|
print(f"Error: File '{file_path}' does not exist.")
|
||||||
|
return
|
||||||
|
|
||||||
|
if not file_path.lower().endswith('.png'):
|
||||||
|
print(f"Error: File '{file_path}' is not a PNG file.")
|
||||||
|
return
|
||||||
|
|
||||||
|
print(f"Processing single file: {os.path.basename(file_path)}")
|
||||||
|
resize_and_center_image(file_path)
|
||||||
|
print("Processing complete.")
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description="Resize PNG assets to 18x18px and center on 20x20px canvas")
|
||||||
|
parser.add_argument("path", help="Path to PNG file or directory containing PNG files")
|
||||||
|
parser.add_argument("--pattern", default="*.png", help="File pattern to match (default: *.png)")
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
if os.path.isfile(args.path):
|
||||||
|
process_single_file(args.path)
|
||||||
|
elif os.path.isdir(args.path):
|
||||||
|
process_directory(args.path, args.pattern)
|
||||||
|
else:
|
||||||
|
print(f"Error: '{args.path}' is not a valid file or directory.")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
# If run without arguments, process the assets/Rat directory by default
|
||||||
|
import sys
|
||||||
|
if len(sys.argv) == 1:
|
||||||
|
# Default to processing the assets/Rat directory
|
||||||
|
script_dir = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
assets_dir = os.path.join(script_dir, "assets", "Rat")
|
||||||
|
if os.path.exists(assets_dir):
|
||||||
|
print("No arguments provided. Processing assets/Rat directory by default...")
|
||||||
|
process_directory(assets_dir)
|
||||||
|
else:
|
||||||
|
print("assets/Rat directory not found. Please provide a path as argument.")
|
||||||
|
print("Usage: python resize_assets.py <path_to_file_or_directory>")
|
||||||
|
else:
|
||||||
|
main()
|
||||||
Binary file not shown.
Binary file not shown.
@@ -6,3 +6,4 @@ from .unit import Unit
|
|||||||
from .rat import Rat, Male, Female
|
from .rat import Rat, Male, Female
|
||||||
from .bomb import Bomb, Timer, Explosion
|
from .bomb import Bomb, Timer, Explosion
|
||||||
from .points import Point
|
from .points import Point
|
||||||
|
from .mine import Mine
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
from .unit import Unit
|
||||||
|
from .bomb import Explosion
|
||||||
|
class Mine(Unit):
|
||||||
|
def __init__(self, game, position=(0,0), id=None):
|
||||||
|
super().__init__(game, position, id)
|
||||||
|
self.speed = 1.0 # Mine doesn't move but needs speed for consistency
|
||||||
|
self.armed = True # Mine is active and ready to explode
|
||||||
|
|
||||||
|
def move(self):
|
||||||
|
"""Mines don't move, but we need to check for collision with rats each frame."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def collisions(self):
|
||||||
|
"""Check if a rat steps on the mine (has position_before on mine's position)."""
|
||||||
|
if not self.armed:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Check for rats that have position_before on this mine's position
|
||||||
|
for rat_unit in self.game.unit_positions_before.get(self.position, []):
|
||||||
|
if hasattr(rat_unit, 'sex'): # Check if it's a rat (rats have sex attribute)
|
||||||
|
# Mine explodes and kills the rat
|
||||||
|
self.explode(rat_unit)
|
||||||
|
break
|
||||||
|
|
||||||
|
def explode(self, victim_rat):
|
||||||
|
"""Mine explodes, killing the rat and destroying itself."""
|
||||||
|
if not self.armed:
|
||||||
|
return
|
||||||
|
|
||||||
|
print("MINE EXPLOSION!")
|
||||||
|
self.game.render_engine.play_sound("BOMB.WAV")
|
||||||
|
|
||||||
|
# Kill the rat that stepped on the mine
|
||||||
|
if victim_rat.id in self.game.units:
|
||||||
|
victim_rat.die(score=5)
|
||||||
|
|
||||||
|
# Remove the mine from the game
|
||||||
|
self.die()
|
||||||
|
|
||||||
|
def draw(self):
|
||||||
|
"""Draw the mine using the mine asset."""
|
||||||
|
if not self.armed:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Use mine asset
|
||||||
|
image = self.game.assets["mine"]
|
||||||
|
image_size = self.game.render_engine.get_image_size(image)
|
||||||
|
|
||||||
|
# Center the mine in the cell
|
||||||
|
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
|
||||||
|
|
||||||
|
self.game.render_engine.draw_image(x_pos, y_pos, image, anchor="nw", tag="unit")
|
||||||
|
|
||||||
|
def die(self, score=None):
|
||||||
|
"""Remove mine from game and disarm it."""
|
||||||
|
self.armed = False
|
||||||
|
Explosion(self.game, self.position).draw()
|
||||||
|
super().die(score)
|
||||||
Reference in New Issue
Block a user