Add Mice! game and associated tools
- Created gameinfo.xml for the Mice! game, detailing its description, release date, developer, and genre. - Added mice.sh script to activate the conda environment and run the game. - Implemented colorize_assets.py as a placeholder for future asset colorization functionality. - Developed convert_audio.py to convert audio files to 8-bit unsigned format at 22100 Hz. - Introduced maze.py for generating mazes using Depth First Search (DFS) with a graphical interface. - Created resize_assets.py to resize PNG assets to 18x18 pixels and center them on a 20x20 canvas.
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Audio conversion script to convert audio files to u8 22100 Hz format
|
||||
"""
|
||||
|
||||
from pydub import AudioSegment
|
||||
import os
|
||||
import sys
|
||||
import argparse
|
||||
|
||||
def convert_audio(input_path, output_path=None):
|
||||
"""Convert audio file to u8 format at 22100 Hz"""
|
||||
|
||||
# Generate output path if not provided
|
||||
if output_path is None:
|
||||
base_name = os.path.splitext(input_path)[0]
|
||||
output_path = f"{base_name}_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}")
|
||||
|
||||
def main():
|
||||
"""Main function to handle command line arguments"""
|
||||
parser = argparse.ArgumentParser(description='Convert audio files to u8 22100 Hz format')
|
||||
parser.add_argument('input_file', help='Input audio file path')
|
||||
parser.add_argument('-o', '--output', help='Output file path (optional)')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
convert_audio(args.input_file, args.output)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
# DFS: Depth First Search
|
||||
import random
|
||||
import tkinter as tk
|
||||
import json
|
||||
import time
|
||||
|
||||
class MazeGenerator:
|
||||
def __init__(self, width=10, height=10):
|
||||
self.width = width * 2 + 1 # Considera le pareti nel calcolo della larghezza
|
||||
self.height = height * 2 + 1 # Considera le pareti nel calcolo dell'altezza
|
||||
self.generate_maze()
|
||||
self.window = tk.Tk()
|
||||
self.window.title("Maze")
|
||||
self.canvas = tk.Canvas(self.window, width=self.width*10, height=self.height*10)
|
||||
self.canvas.pack()
|
||||
self.arrival_point = (self.width - 2, self.height - 2) # Aggiorna il punto di arrivo
|
||||
self.backtrack = []
|
||||
|
||||
def generate_maze(self):
|
||||
# Inizializza il labirinto con muri (True)
|
||||
self.maze = [[True for _ in range(self.width)] for _ in range(self.height)]
|
||||
|
||||
# Definisci le direzioni (N, S, E, W)
|
||||
self.directions = [(-2, 0), (2, 0), (0, -2), (0, 2)]
|
||||
|
||||
# Punto di partenza
|
||||
start_x, start_y = (1, 1)
|
||||
self.maze[start_y][start_x] = False
|
||||
self.stack = [(start_x, start_y)]
|
||||
|
||||
def stack_iteration(self):
|
||||
if not self.stack: # Check if the stack is empty
|
||||
return
|
||||
|
||||
current_x, current_y = self.stack[-1]
|
||||
|
||||
# Function to get the unvisited neighbors
|
||||
def get_unvisited_neighbors(x, y):
|
||||
time.sleep(0.005)
|
||||
neighbors = []
|
||||
if not (self.arrival_point == (x,y)):
|
||||
for dx, dy in self.directions:
|
||||
nx, ny = x + dx, y + dy
|
||||
if 1 <= nx < self.width - 1 and 1 <= ny < self.height - 1 and self.maze[ny][nx]:
|
||||
neighbors.append((nx, ny))
|
||||
return neighbors
|
||||
|
||||
neighbors = get_unvisited_neighbors(current_x, current_y)
|
||||
|
||||
if neighbors:
|
||||
# Choose a random unvisited neighbor
|
||||
chosen_x, chosen_y = random.choice(neighbors)
|
||||
|
||||
# Remove the wall between the current cell and the chosen cell
|
||||
self.maze[(current_y + chosen_y) // 2][(current_x + chosen_x) // 2] = False
|
||||
|
||||
# Mark the chosen cell as visited
|
||||
self.maze[chosen_y][chosen_x] = False
|
||||
|
||||
# Push the chosen cell to the stack
|
||||
self.stack.append((chosen_x, chosen_y))
|
||||
else:
|
||||
# Backtrack if no unvisited neighbors are found
|
||||
self.backtrack.append(self.stack.pop())
|
||||
|
||||
def update_maze(self):
|
||||
self.stack_iteration()
|
||||
self.draw_maze()
|
||||
if self.stack: # Continue updating only if there are cells left to visit
|
||||
self.window.after(10, self.update_maze)
|
||||
else:
|
||||
self.add_random_passages()
|
||||
self.draw_maze()
|
||||
with open('maze.json', 'w') as json_file:
|
||||
json.dump(self.maze, json_file)
|
||||
|
||||
def add_random_passages(self):
|
||||
# Aggiungi passaggi casuali tra i corridoi
|
||||
for _ in range(30):
|
||||
x = random.randrange(1, self.width - 1, 2)
|
||||
y = random.randrange(1, self.height - 1, 2)
|
||||
print(x, y)
|
||||
self.maze[y][x] = False
|
||||
|
||||
def draw_maze(self):
|
||||
self.canvas.delete("all")
|
||||
for i in range(self.height):
|
||||
for j in range(self.width):
|
||||
color = "black" if self.maze[i][j] else "white"
|
||||
# if (i, j) in self.backtrack:
|
||||
# color="yellow"
|
||||
if (i, j) == self.arrival_point:
|
||||
color = "green" # Color the arrival point green
|
||||
elif (i, j) == (1 ,1):
|
||||
color = "red" # Color the arrival point green
|
||||
elif self.stack and (j, i) == self.stack[-1]:
|
||||
color = "blue" # Color the current position blue
|
||||
self.canvas.create_rectangle(j*10, i*10, (j+1)*10, (i+1)*10, fill=color)
|
||||
|
||||
|
||||
def run(self):
|
||||
self.update_maze()
|
||||
|
||||
self.window.mainloop()
|
||||
|
||||
# Crea e avvia il generatore di labirinti
|
||||
generator = MazeGenerator(15, 8)
|
||||
generator.run()
|
||||
@@ -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()
|
||||
Reference in New Issue
Block a user