Spikes, better gameHandler, map width and height computed automatically & big peanut hard map
This commit is contained in:
@@ -2,10 +2,12 @@ from .stoneBlock import StoneBlock
|
||||
from .spawnPointBlock import SpawnPointBlock
|
||||
from .finishBlock import FinishBlock
|
||||
from .coinBlock import CoinBlock
|
||||
from .spikesBlock import SpikesBlock
|
||||
|
||||
BLOCKS = [
|
||||
StoneBlock,
|
||||
SpawnPointBlock,
|
||||
FinishBlock,
|
||||
CoinBlock
|
||||
CoinBlock,
|
||||
SpikesBlock,
|
||||
]
|
||||
@@ -16,8 +16,8 @@ class FinishBlock(Block):
|
||||
return False
|
||||
|
||||
def on_collision(self, gameState: GameState):
|
||||
gameState.set_stop_game(True)
|
||||
gameState.set_game_won(True)
|
||||
gameState.set_stop_game(True)
|
||||
|
||||
def to_string(self):
|
||||
return "🏁"
|
||||
@@ -0,0 +1,24 @@
|
||||
import os
|
||||
|
||||
from game.blocks.block import Block
|
||||
from game.gameState import GameState
|
||||
|
||||
class SpikesBlock(Block):
|
||||
@property
|
||||
def character(self):
|
||||
return '^'
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
return 'spikes'
|
||||
|
||||
@property
|
||||
def solid(self):
|
||||
return False
|
||||
|
||||
def on_collision(self, gameState: GameState):
|
||||
gameState.set_game_won(False)
|
||||
gameState.set_stop_game(True)
|
||||
|
||||
def to_string(self):
|
||||
return "🔥"
|
||||
+3
-2
@@ -44,10 +44,9 @@ class Game:
|
||||
if spawn_point_position is None:
|
||||
raise ValueError("No spawn point found in the map.")
|
||||
self.gameState.set_player_position(spawn_point_position)
|
||||
self._position_update()
|
||||
|
||||
while not self.gameState.stopGame:
|
||||
self._position_update() # Update the screen for example
|
||||
|
||||
if self.gameState.playerVelocity == -1 and self.waitingForInputCallback:
|
||||
self.gameState.set_player_velocity(self.waitingForInputCallback())
|
||||
self.gameState.add_move_count()
|
||||
@@ -70,6 +69,8 @@ class Game:
|
||||
|
||||
self._update_player_velocity()
|
||||
|
||||
self._position_update() # Update the screen for example
|
||||
|
||||
if self.gameStopCallback and self.gameStopCallback(self.gameState):
|
||||
self.gameState.set_stop_game(True)
|
||||
break
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
from abc import abstractmethod
|
||||
|
||||
from game.game import Game
|
||||
|
||||
|
||||
class GameHandler:
|
||||
def __init__(self, game: Game):
|
||||
self.game = game
|
||||
self.game.set_waiting_for_input_callback(self.on_input_request)
|
||||
self.game.set_position_update_callback(self.on_position_update)
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def run(self) -> None:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def on_position_update(self) -> None:
|
||||
@@ -15,3 +17,5 @@ class GameHandler:
|
||||
@abstractmethod
|
||||
def on_input_request(self) -> str:
|
||||
pass
|
||||
|
||||
|
||||
@@ -1,14 +1,48 @@
|
||||
|
||||
from time import sleep
|
||||
from game.game import Game
|
||||
from game.handlers.gameHandler import GameHandler
|
||||
|
||||
from game.handlers.gameHandler import GameHandler
|
||||
from game.game import Game
|
||||
from game.gameState import GameState
|
||||
from game.mapReader import MapReader
|
||||
from game.mapSet import MapSet
|
||||
|
||||
class UserPlayerGameHandler(GameHandler):
|
||||
KEYBOARD_INPUTS = ["w", "q", "a", "z", "e", "d", "c"]
|
||||
|
||||
def __init__(self, game: Game):
|
||||
super().__init__(game)
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.mapReader = MapReader()
|
||||
self.mapSet = MapSet(self.mapReader, self.mapReader.get_map_names())
|
||||
self.map = self._choose_map()
|
||||
self.gameState = GameState()
|
||||
self.game = Game(self.map, self.gameState)
|
||||
self.game.set_waiting_for_input_callback(self.on_input_request)
|
||||
self.game.set_position_update_callback(self.on_position_update)
|
||||
|
||||
def _choose_map(self):
|
||||
"""
|
||||
Prompt the user to choose a map from the available maps
|
||||
"""
|
||||
print("\nAvailable maps:")
|
||||
for i, map_name in enumerate(self.mapReader.get_map_names()):
|
||||
print(f"{i + 1}. {map_name.replace("_", " ").title()}")
|
||||
|
||||
while True:
|
||||
try:
|
||||
choice = int(input("Choose a map by number: ")) - 1
|
||||
if 0 <= choice < len(self.mapReader.get_map_names()):
|
||||
return self.mapSet.get_map(choice)
|
||||
else:
|
||||
print("Invalid choice. Please try again.")
|
||||
except ValueError:
|
||||
print("Invalid input. Please enter a number.")
|
||||
|
||||
def run(self) -> None:
|
||||
"""
|
||||
Run the game loop
|
||||
"""
|
||||
self.game.start_game()
|
||||
print("Game over : You " + ("Won!" if self.game.gameState.gameWon else "Lost!"))
|
||||
|
||||
def on_position_update(self) -> None:
|
||||
"""
|
||||
|
||||
+2
-2
@@ -13,11 +13,11 @@ from game.blocks.block import Block
|
||||
class Map:
|
||||
def __init__(self, map_data: dict):
|
||||
self.name = map_data.get('name', 'Unknown')
|
||||
self.width = int(map_data.get('width', 0))
|
||||
self.height = int(map_data.get('height', 0))
|
||||
self.difficulty = float(map_data.get('difficulty', 0.0))
|
||||
self.min_moves = map_data.get('min_moves', None)
|
||||
self.layout = map_data.get('layout', [])
|
||||
self.width = max(len(row) for row in self.layout) if self.layout else 0
|
||||
self.height = len(self.layout) if self.layout else 0
|
||||
|
||||
def get_block_at(self, x, y) -> Block | None:
|
||||
if 0 <= x < self.width and 0 <= y < self.height:
|
||||
|
||||
+12
-8
@@ -28,12 +28,12 @@ class MapReader:
|
||||
with open(map_path, 'rb') as f:
|
||||
config = tomllib.load(f)
|
||||
|
||||
layout = config.get('layout', '')
|
||||
|
||||
map_data = {
|
||||
'name': map_name,
|
||||
'width': config.get('width', 0),
|
||||
'height': config.get('height', 0),
|
||||
'difficulty': config.get('difficulty', 0.0),
|
||||
'layout': self._parse_layout(config.get('layout', ''))
|
||||
'layout': self._parse_layout(layout)
|
||||
}
|
||||
|
||||
if config.get('min_moves') is not None:
|
||||
@@ -48,16 +48,20 @@ class MapReader:
|
||||
|
||||
def _parse_layout(self, mapString):
|
||||
# Takes the blocks and translates their characters into the corresponding block objects.
|
||||
block_characters_mapping = self._get_block_characters_mapping()
|
||||
# Makes sure tthe width is consistent across all rows by padding with None if necessary.
|
||||
block_mapping = self._get_block_characters_mapping()
|
||||
layout = []
|
||||
for line in mapString.strip().splitlines():
|
||||
for line in mapString.splitlines():
|
||||
row = []
|
||||
for char in line:
|
||||
block_class = block_characters_mapping.get(char)
|
||||
block_class = block_mapping.get(char)
|
||||
if block_class:
|
||||
row.append(block_class())
|
||||
else:
|
||||
row.append(None)
|
||||
row.append(None) # Unknown character, treat as empty space
|
||||
layout.append(row)
|
||||
max_width = max(len(row) for row in layout)
|
||||
for row in layout:
|
||||
while len(row) < max_width:
|
||||
row.append(None) # Pad with None to ensure consistent width
|
||||
return layout
|
||||
|
||||
@@ -10,6 +10,12 @@ class MapSet:
|
||||
self.mapReader = mapReader
|
||||
self.maps = [self.mapReader.read_map(name) for name in mapNames]
|
||||
|
||||
def get_map_by_name(self, name: str):
|
||||
for map in self.maps:
|
||||
if map.name == name:
|
||||
return map
|
||||
raise ValueError(f"Map with name '{name}' not found in the MapSet.")
|
||||
|
||||
def get_map(self, index: int):
|
||||
if index < 0 or index >= len(self.maps):
|
||||
raise IndexError("Map index out of range.")
|
||||
|
||||
@@ -11,12 +11,11 @@ from game.mapSet import MapSet
|
||||
load_dotenv()
|
||||
|
||||
if __name__ == "__main__":
|
||||
mapReader = MapReader()
|
||||
mapSet = MapSet(mapReader, mapReader.get_map_names())
|
||||
map = mapSet.get_maps_by_difficulty(0, 1)[0]
|
||||
gameState = GameState()
|
||||
game = Game(map, gameState)
|
||||
gameHandler = GAME_HANDLERS["user player"](game)
|
||||
game.start_game()
|
||||
|
||||
# run_game()
|
||||
# Make the user choose the game handler
|
||||
print("Choose a game handler:")
|
||||
for i, handler_name in enumerate(GAME_HANDLERS.keys()):
|
||||
print(f"[{i + 1}] {handler_name}")
|
||||
choice = int(input("Enter the number of the game handler: ")) - 1
|
||||
handler_name = list(GAME_HANDLERS.keys())[choice]
|
||||
game_handler_class = GAME_HANDLERS[handler_name]()
|
||||
game_handler_class.run()
|
||||
@@ -0,0 +1,22 @@
|
||||
difficulty = 90
|
||||
min_moves = 42
|
||||
layout = """
|
||||
#####
|
||||
###### ########
|
||||
## ####
|
||||
### E##
|
||||
### °#####
|
||||
## ° ## ######
|
||||
#°####### ## # # ### ######
|
||||
# # ##
|
||||
## ##° ##° ^###
|
||||
# ### #### ##
|
||||
# #####^##### ##
|
||||
# ##### ####° #
|
||||
# # #
|
||||
# °# #####^^##
|
||||
## ° ###^########
|
||||
## # ##########
|
||||
#S ##^#####
|
||||
#########
|
||||
"""
|
||||
@@ -1,5 +1,3 @@
|
||||
width = 12
|
||||
height = 6
|
||||
difficulty = 10
|
||||
min_moves = 6
|
||||
layout = """\
|
||||
|
||||
Reference in New Issue
Block a user