Aggiungi file di configurazione per i binding dei tasti e implementa la gestione degli input nel gioco
This commit is contained in:
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"quit": ["Q", 12],
|
||||||
|
"new_rat": ["Return", 13],
|
||||||
|
"kill_rat": ["D"],
|
||||||
|
"toggle_audio": ["M"],
|
||||||
|
"toggle_full_screen": ["F"],
|
||||||
|
"scroll_up": ["Up", 8],
|
||||||
|
"scroll_down": ["Down", 9],
|
||||||
|
"scroll_left": ["Left", 10],
|
||||||
|
"scroll_right": ["Right", 11],
|
||||||
|
"spawn_bomb": ["Space", 1],
|
||||||
|
"pause": ["P", 16]
|
||||||
|
}
|
||||||
+15
-18
@@ -5,37 +5,34 @@ import random
|
|||||||
|
|
||||||
class KeyBindings:
|
class KeyBindings:
|
||||||
def key_pressed(self, key, coords=None):
|
def key_pressed(self, key, coords=None):
|
||||||
|
if key in self.keybindings["quit"]:
|
||||||
#print(key)
|
|
||||||
if key == "Q" or key == 12:
|
|
||||||
self.engine.close()
|
self.engine.close()
|
||||||
elif key == "Return" or key == 13:
|
elif key in self.keybindings["new_rat"]:
|
||||||
self.new_rat()
|
self.new_rat()
|
||||||
elif key == "D":
|
elif key in self.keybindings["kill_rat"]:
|
||||||
if self.units:
|
if self.units:
|
||||||
self.units[random.choice(list(self.units.keys()))].die(score=5)
|
self.units[random.choice(list(self.units.keys()))].die(score=5)
|
||||||
elif key == "M":
|
elif key in self.keybindings["toggle_audio"]:
|
||||||
self.audio = not self.audio
|
self.audio = not self.audio
|
||||||
elif key == "F":
|
elif key in self.keybindings["toggle_full_screen"]:
|
||||||
self.full_screen = not self.full_screen
|
self.full_screen = not self.full_screen
|
||||||
self.engine.full_screen(self.full_screen)
|
self.engine.full_screen(self.full_screen)
|
||||||
elif key == "Up" or key == 8:
|
elif key in self.keybindings["scroll_up"]:
|
||||||
self.start_scrolling("Up")
|
self.start_scrolling("Up")
|
||||||
elif key == "Down" or key == 9:
|
elif key in self.keybindings["scroll_down"]:
|
||||||
self.start_scrolling("Down")
|
self.start_scrolling("Down")
|
||||||
elif key == "Left" or key == 10:
|
elif key in self.keybindings["scroll_left"]:
|
||||||
self.start_scrolling("Left")
|
self.start_scrolling("Left")
|
||||||
elif key == "Right" or key == 11:
|
elif key in self.keybindings["scroll_right"]:
|
||||||
self.start_scrolling("Right")
|
self.start_scrolling("Right")
|
||||||
elif key == "Space" or key == 1:
|
elif key in self.keybindings["spawn_bomb"]:
|
||||||
self.play_sound("PUTDOWN.WAV")
|
self.play_sound("PUTDOWN.WAV", tag="effects")
|
||||||
self.spawn_bomb(self.pointer)
|
self.spawn_bomb(self.pointer)
|
||||||
elif key == "P" or key == 16:
|
elif key in self.keybindings["pause"]:
|
||||||
self.pause = not self.pause
|
self.pause = not self.pause
|
||||||
# elif key == "mouse":
|
|
||||||
# adjusted_coords = (coords[0]//self.cell_size*2, coords[1]//self.cell_size*2)
|
def quit_game(self):
|
||||||
# self.pointer = adjusted_coords
|
self.engine.close()
|
||||||
# self.scroll_cursor()
|
|
||||||
def key_released(self, key):
|
def key_released(self, key):
|
||||||
if key in ["Up", "Down", "Left", "Right", 8, 9, 10, 11]:
|
if key in ["Up", "Down", "Left", "Right", 8, 9, 10, 11]:
|
||||||
self.stop_scrolling()
|
self.stop_scrolling()
|
||||||
|
|||||||
+32
-19
@@ -7,7 +7,7 @@ from ctypes import *
|
|||||||
from PIL import Image
|
from PIL import Image
|
||||||
from sdl2 import SDL_AudioSpec
|
from sdl2 import SDL_AudioSpec
|
||||||
|
|
||||||
import random
|
|
||||||
class GameWindow:
|
class GameWindow:
|
||||||
def __init__(self, width, height, cell_size, title="Default", key_callback=None):
|
def __init__(self, width, height, cell_size, title="Default", key_callback=None):
|
||||||
|
|
||||||
@@ -23,6 +23,7 @@ class GameWindow:
|
|||||||
self.h_offset = self.h_start_offset
|
self.h_offset = self.h_start_offset
|
||||||
self.max_w_offset = self.target_size[0] - self.width
|
self.max_w_offset = self.target_size[0] - self.width
|
||||||
self.max_h_offset = self.target_size[1] - self.height
|
self.max_h_offset = self.target_size[1] - self.height
|
||||||
|
self.scale = self.target_size[1] // self.cell_size
|
||||||
print(f"Screen size: {self.width}x{self.height}")
|
print(f"Screen size: {self.width}x{self.height}")
|
||||||
sdl2.ext.init(joystick=True)
|
sdl2.ext.init(joystick=True)
|
||||||
sdl2.SDL_Init(sdl2.SDL_INIT_AUDIO)
|
sdl2.SDL_Init(sdl2.SDL_INIT_AUDIO)
|
||||||
@@ -37,11 +38,12 @@ class GameWindow:
|
|||||||
self.running = True
|
self.running = True
|
||||||
self.key_down, self.key_up, self.axis_scroll = key_callback
|
self.key_down, self.key_up, self.axis_scroll = key_callback
|
||||||
self.performance = 0
|
self.performance = 0
|
||||||
self.audio_devs = []
|
self.audio_devs = {}
|
||||||
#for i in range(5):
|
self.button_cursor = [0, 0]
|
||||||
# self.audio_devs.append((True, sdl2.SDL_OpenAudioDevice(None, 0, SDL_AudioSpec(freq=22050, aformat=sdl2.AUDIO_U8, channels=1, samples=2048), None, 0)))
|
self.buttons = {}
|
||||||
|
self.audio_devs["base"] = sdl2.SDL_OpenAudioDevice(None, 0, SDL_AudioSpec(freq=22050, aformat=sdl2.AUDIO_U8, channels=1, samples=2048), None, 0)
|
||||||
self.audio_dev = sdl2.SDL_OpenAudioDevice(None, 0, SDL_AudioSpec(freq=22050, aformat=sdl2.AUDIO_U8, channels=1, samples=2048), None, 0)
|
self.audio_devs["effects"] = sdl2.SDL_OpenAudioDevice(None, 0, SDL_AudioSpec(freq=22050, aformat=sdl2.AUDIO_U8, channels=1, samples=2048), None, 0)
|
||||||
|
self.audio_devs["music"] = sdl2.SDL_OpenAudioDevice(None, 0, SDL_AudioSpec(freq=22050, aformat=sdl2.AUDIO_U8, channels=1, samples=2048), None, 0)
|
||||||
def create_texture(self, tiles: list):
|
def create_texture(self, tiles: list):
|
||||||
bg_surface = sdl2.SDL_CreateRGBSurface(0, self.width, self.height, 32, 0, 0, 0, 0)
|
bg_surface = sdl2.SDL_CreateRGBSurface(0, self.width, self.height, 32, 0, 0, 0, 0)
|
||||||
for tile in tiles:
|
for tile in tiles:
|
||||||
@@ -97,8 +99,8 @@ class GameWindow:
|
|||||||
sprite.position = (x+self.w_offset, y+self.h_offset)
|
sprite.position = (x+self.w_offset, y+self.h_offset)
|
||||||
self.renderer.copy(sprite, dstrect=sprite.position)
|
self.renderer.copy(sprite, dstrect=sprite.position)
|
||||||
|
|
||||||
|
|
||||||
def draw_rectangle(self, x, y, width, height, tag, outline="red", filling=None):
|
def draw_rectangle(self, x, y, width, height, tag, outline="red", filling=None):
|
||||||
x, y = x + self.w_offset, y + self.h_offset
|
|
||||||
if filling:
|
if filling:
|
||||||
self.renderer.fill((x, y, width, height), sdl2.ext.Color(*filling))
|
self.renderer.fill((x, y, width, height), sdl2.ext.Color(*filling))
|
||||||
else:
|
else:
|
||||||
@@ -113,8 +115,8 @@ class GameWindow:
|
|||||||
def delete_tag(self, tag):
|
def delete_tag(self, tag):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def win_screen(self, text, **kwargs):
|
def dialog(self, text, **kwargs):
|
||||||
self.draw_rectangle(50 - self.w_offset, 50 - self.h_offset,
|
self.draw_rectangle(50, 50,
|
||||||
self.target_size[0] - 100, self.target_size[1] - 100, "win", filling=(255, 255, 255))
|
self.target_size[0] - 100, self.target_size[1] - 100, "win", filling=(255, 255, 255))
|
||||||
self.draw_text(text, self.fonts[self.target_size[1]//20], "center", sdl2.ext.Color(0, 0, 0))
|
self.draw_text(text, self.fonts[self.target_size[1]//20], "center", sdl2.ext.Color(0, 0, 0))
|
||||||
if image := kwargs.get("image"):
|
if image := kwargs.get("image"):
|
||||||
@@ -133,11 +135,7 @@ class GameWindow:
|
|||||||
sprite_score.position = (self.target_size[0] // 2 - 50-sprite_score.size[0] // 4,
|
sprite_score.position = (self.target_size[0] // 2 - 50-sprite_score.size[0] // 4,
|
||||||
self.target_size[1] // 2 + 60 + 20 * (i + 1))
|
self.target_size[1] // 2 + 60 + 20 * (i + 1))
|
||||||
self.renderer.copy(sprite_score, dstrect=sprite_score.position)
|
self.renderer.copy(sprite_score, dstrect=sprite_score.position)
|
||||||
def pause_screen(self, text):
|
|
||||||
self.draw_rectangle(50 - self.w_offset, 50 - self.h_offset,
|
|
||||||
self.target_size[0] - 100, self.target_size[1] - 100, "pause", filling=(255, 255, 255))
|
|
||||||
self.draw_text(text, self.fonts[self.target_size[1]//20], "center", sdl2.ext.Color(0, 0, 0))
|
|
||||||
|
|
||||||
def get_image_size(self, image):
|
def get_image_size(self, image):
|
||||||
return image.size
|
return image.size
|
||||||
|
|
||||||
@@ -159,6 +157,9 @@ class GameWindow:
|
|||||||
def is_in_visible_area(self, x, y):
|
def is_in_visible_area(self, x, y):
|
||||||
return -self.w_offset -self.cell_size <= x <= self.width - self.w_offset and -self.h_offset -self.cell_size <= y <= self.height - self.h_offset
|
return -self.w_offset -self.cell_size <= x <= self.width - self.w_offset and -self.h_offset -self.cell_size <= y <= self.height - self.h_offset
|
||||||
|
|
||||||
|
def get_perf_counter(self):
|
||||||
|
return sdl2.SDL_GetPerformanceCounter()
|
||||||
|
|
||||||
def mainloop(self, **kwargs):
|
def mainloop(self, **kwargs):
|
||||||
while self.running:
|
while self.running:
|
||||||
performance_start = sdl2.SDL_GetPerformanceCounter()
|
performance_start = sdl2.SDL_GetPerformanceCounter()
|
||||||
@@ -228,7 +229,7 @@ class GameWindow:
|
|||||||
self.w_offset = x
|
self.w_offset = x
|
||||||
self.h_offset = y
|
self.h_offset = y
|
||||||
|
|
||||||
def play_sound(self, sound_file):
|
def play_sound(self, sound_file, tag="base"):
|
||||||
print(sound_file)
|
print(sound_file)
|
||||||
sound_file = os.path.join("sound", sound_file)
|
sound_file = os.path.join("sound", sound_file)
|
||||||
rw = sdl2.SDL_RWFromFile(byteify(sound_file, "utf-8"), b"rb")
|
rw = sdl2.SDL_RWFromFile(byteify(sound_file, "utf-8"), b"rb")
|
||||||
@@ -237,12 +238,12 @@ class GameWindow:
|
|||||||
|
|
||||||
_buf = POINTER(sdl2.Uint8)()
|
_buf = POINTER(sdl2.Uint8)()
|
||||||
_length = sdl2.Uint32()
|
_length = sdl2.Uint32()
|
||||||
spec = SDL_AudioSpec(freq=22050, aformat=sdl2.AUDIO_U8, channels=1, samples=2048)
|
|
||||||
|
|
||||||
|
spec = SDL_AudioSpec(freq=22050, aformat=sdl2.AUDIO_U8, channels=1, samples=2048)
|
||||||
if sdl2.SDL_LoadWAV_RW(rw, 1, byref(spec), byref(_buf), byref(_length)) == None:
|
if sdl2.SDL_LoadWAV_RW(rw, 1, byref(spec), byref(_buf), byref(_length)) == None:
|
||||||
raise RuntimeError("Failed to load WAV")
|
raise RuntimeError("Failed to load WAV")
|
||||||
devid = self.audio_dev
|
devid = self.audio_devs[tag]
|
||||||
sdl2.SDL_ClearQueuedAudio(devid)
|
# Clear any queued audio
|
||||||
sdl2.SDL_ClearQueuedAudio(devid)
|
sdl2.SDL_ClearQueuedAudio(devid)
|
||||||
|
|
||||||
# Start playing audio
|
# Start playing audio
|
||||||
@@ -255,4 +256,16 @@ class GameWindow:
|
|||||||
sdl2.SDL_PauseAudioDevice(dev[1], 1)
|
sdl2.SDL_PauseAudioDevice(dev[1], 1)
|
||||||
sdl2.SDL_ClearQueuedAudio(dev[1])
|
sdl2.SDL_ClearQueuedAudio(dev[1])
|
||||||
|
|
||||||
|
def start_dialog(self, **kwargs):
|
||||||
|
self.dialog("Welcome to the Mice!", **kwargs)
|
||||||
|
center = self.get_view_center()
|
||||||
|
self.draw_button(center[0], center[1] + 10 * self.scale, "Start", 120, 50, (0, 0))
|
||||||
|
|
||||||
|
def draw_button(self, x, y, text, width, height, coords):
|
||||||
|
if self.button_cursor[0] == coords[0] and self.button_cursor[1] == coords[1]:
|
||||||
|
color = (0, 0, 255)
|
||||||
|
self.draw_rectangle(x, y, width, height, "button", outline8u=color)
|
||||||
|
self.draw_text(text, self.fonts[20], (x + 10, y + 10), (0,0,0))
|
||||||
|
|
||||||
|
def get_view_center(self):
|
||||||
|
return self.w_offset + self.width // 2, self.h_offset + self.height // 2
|
||||||
@@ -7,6 +7,7 @@ from engine import maze, sdl2 as engine, controls
|
|||||||
import os
|
import os
|
||||||
import datetime
|
import datetime
|
||||||
import subprocess
|
import subprocess
|
||||||
|
import json
|
||||||
|
|
||||||
class MiceMaze(controls.KeyBindings):
|
class MiceMaze(controls.KeyBindings):
|
||||||
def __init__(self, maze_file):
|
def __init__(self, maze_file):
|
||||||
@@ -27,13 +28,19 @@ class MiceMaze(controls.KeyBindings):
|
|||||||
self.scrolling_direction = None
|
self.scrolling_direction = None
|
||||||
self.pause = False
|
self.pause = False
|
||||||
self.game_end = (False, None)
|
self.game_end = (False, None)
|
||||||
|
self.dialog = "start_menu"
|
||||||
self.scrolling = False
|
self.scrolling = False
|
||||||
self.sounds = {}
|
self.sounds = {}
|
||||||
|
self.start_game()
|
||||||
|
self.background_texture = None
|
||||||
|
keybindings_file, = "keybinding_game.json",
|
||||||
|
with open(os.path.join("conf", keybindings_file)) as f:
|
||||||
|
self.keybindings = json.load(f)
|
||||||
|
|
||||||
|
def start_game(self):
|
||||||
for _ in range(5):
|
for _ in range(5):
|
||||||
self.new_rat()
|
self.new_rat()
|
||||||
self.background_texture = None
|
|
||||||
|
|
||||||
|
|
||||||
def count_rats(self):
|
def count_rats(self):
|
||||||
count = 0
|
count = 0
|
||||||
for unit in self.units.values():
|
for unit in self.units.values():
|
||||||
@@ -78,9 +85,9 @@ class MiceMaze(controls.KeyBindings):
|
|||||||
def game_over(self):
|
def game_over(self):
|
||||||
if self.game_end[0]:
|
if self.game_end[0]:
|
||||||
if not self.game_end[1]:
|
if not self.game_end[1]:
|
||||||
self.engine.win_screen("Game Over: Mice are too many!", image=self.assets["BMP_WEWIN"])
|
self.engine.dialog("Game Over: Mice are too many!", image=self.assets["BMP_WEWIN"])
|
||||||
else:
|
else:
|
||||||
self.engine.win_screen(f"You Win! Points: {self.points}", image=self.assets["BMP_WEWIN"], scores=self.read_score())
|
self.engine.dialog(f"You Win! Points: {self.points}", image=self.assets["BMP_WEWIN"], scores=self.read_score())
|
||||||
|
|
||||||
|
|
||||||
return True
|
return True
|
||||||
@@ -106,7 +113,9 @@ class MiceMaze(controls.KeyBindings):
|
|||||||
|
|
||||||
def update_maze(self):
|
def update_maze(self):
|
||||||
if self.pause:
|
if self.pause:
|
||||||
self.engine.pause_screen("Paused")
|
if self.dialog != "start_menu":
|
||||||
|
self.engine.dialog("Pause")
|
||||||
|
self.engine.start_dialog(image=self.assets["BMP_WEWIN"])
|
||||||
return
|
return
|
||||||
if self.game_over():
|
if self.game_over():
|
||||||
return
|
return
|
||||||
@@ -128,7 +137,6 @@ class MiceMaze(controls.KeyBindings):
|
|||||||
|
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
self.draw_maze()
|
|
||||||
self.engine.mainloop(update=self.update_maze, bg_update=self.draw_maze)
|
self.engine.mainloop(update=self.update_maze, bg_update=self.draw_maze)
|
||||||
|
|
||||||
def scroll_cursor(self, x=0, y=0):
|
def scroll_cursor(self, x=0, y=0):
|
||||||
|
|||||||
Executable → Regular
BIN
Binary file not shown.
Executable → Regular
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
+2
-1
@@ -103,7 +103,9 @@ class Rat(Unit):
|
|||||||
self.game.spawn_unit(Point, unit.position_before, value=score)
|
self.game.spawn_unit(Point, unit.position_before, value=score)
|
||||||
|
|
||||||
def draw(self):
|
def draw(self):
|
||||||
|
start_perf = self.game.engine.get_perf_counter()
|
||||||
direction = self.calculate_rat_direction()
|
direction = self.calculate_rat_direction()
|
||||||
|
|
||||||
sex = self.sex if self.age > AGE_THRESHOLD else "BABY"
|
sex = self.sex if self.age > AGE_THRESHOLD else "BABY"
|
||||||
image = self.game.rat_assets[sex][direction]
|
image = self.game.rat_assets[sex][direction]
|
||||||
image_size = self.game.engine.get_image_size(image)
|
image_size = self.game.engine.get_image_size(image)
|
||||||
@@ -117,7 +119,6 @@ class Rat(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.engine.draw_image(x_pos, y_pos, image, anchor="nw", tag="unit")
|
self.game.engine.draw_image(x_pos, y_pos, image, anchor="nw", tag="unit")
|
||||||
self.bbox = (x_pos, y_pos, x_pos + image_size[0], y_pos + image_size[1])
|
self.bbox = (x_pos, y_pos, x_pos + image_size[0], y_pos + image_size[1])
|
||||||
#self.game.engine.draw_rectangle(self.bbox[0], self.bbox[1], self.bbox[2] - self.bbox[0], self.bbox[3] - self.bbox[1], "unit")
|
#self.game.engine.draw_rectangle(self.bbox[0], self.bbox[1], self.bbox[2] - self.bbox[0], self.bbox[3] - self.bbox[1], "unit")
|
||||||
|
|||||||
@@ -1,15 +1,12 @@
|
|||||||
<game>
|
<game>
|
||||||
<path>./dRally.sh</path>
|
<path>/roms/tools/mice/rats</path>
|
||||||
<name>Death Rally</name>
|
<name>Mice!</name>
|
||||||
<desc>Death Rally is a strategic top-down racing game where players start with a modest budget and car, competing across 19 tracks in races against increasingly challenging opponents to earn money for upgrades. With choices of six car models and enhancements in engi>
|
<desc>Mice! is a strategic game where players must kill rats with bombs before they reproduce and become too numerous. The game is a clone of the classic game Rats! for Windows 95. <image>./drally/cover.png</image>
|
||||||
|
<releasedate>20241225T000000</releasedate>
|
||||||
In addition to race earnings, players can score bonuses for achievements like wiping out all competition, completing races unscathed, or fulfilling sponsor missions. Bonuses vary based on the chosen car, with the ultimate goal being to top the championship table and defeat the Adve>
|
<developer>Matteo Benedetto</developer>
|
||||||
<image>./drally/cover.png</image>
|
<publisher>Check Mate Corp.</publisher>
|
||||||
<releasedate>19960101T000000</releasedate>
|
<genre>Casual</genre>
|
||||||
<developer>Remedy Entertainment Ltd.</developer>
|
<players>1</players>
|
||||||
<publisher>Apogee Software</publisher>
|
|
||||||
<genre>Simulation-Race 3rd Pers. view-Race, Driving</genre>
|
|
||||||
<players>1-4</players>
|
|
||||||
<playcount>1</playcount>
|
<playcount>1</playcount>
|
||||||
<lastplayed>20240915T212155</lastplayed>
|
<lastplayed>20240915T212155</lastplayed>
|
||||||
</game>
|
</game>
|
||||||
Reference in New Issue
Block a user