147 lines
6.7 KiB
Python
147 lines
6.7 KiB
Python
"""
|
|
Represents the main game class.
|
|
This class is responsible for managing the game's logic.
|
|
It offers to set a callback function that will be called when waiting for a player input.
|
|
It provides the gameState object to access the current state of the game.
|
|
It provides the Map object to access the map.
|
|
It provides some stopGame conditions to stop the game like the max number of moves or the player score.
|
|
It provides public methods to start, stop and reset the game.
|
|
It provides public methods to change the current map.
|
|
"""
|
|
|
|
from game.blocks.block import Block
|
|
from game.gameState import GameState
|
|
from game.map import Map
|
|
from colorama import Style
|
|
|
|
|
|
class Game:
|
|
def __init__(self, map: Map, gameState: GameState):
|
|
self.map = map
|
|
self.gameState = gameState
|
|
self.waitingForInputCallback = None
|
|
|
|
def set_waiting_for_input_callback(self, callback):
|
|
self.waitingForInputCallback = callback
|
|
|
|
def set_position_update_callback(self, callback):
|
|
self.positionUpdateCallback = callback
|
|
|
|
def _position_update(self):
|
|
if self.positionUpdateCallback:
|
|
self.positionUpdateCallback()
|
|
|
|
def start_game(self):
|
|
self.gameState.set_stop_game(False)
|
|
|
|
# Spawn the player at the spawn point
|
|
spawn_point_position = self.map.get_first_block_type_position('spawn_point')
|
|
if spawn_point_position is None:
|
|
raise ValueError("No spawn point found in the map.")
|
|
self.gameState.set_player_position(spawn_point_position)
|
|
|
|
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()
|
|
|
|
# Try to move the player according to his velocity
|
|
velocity_position = self.get_position_at_velocity()
|
|
block_at_velocity = None
|
|
if velocity_position is not None:
|
|
block_at_velocity = self.map.get_block_at(velocity_position[0], velocity_position[1])
|
|
if not block_at_velocity or not block_at_velocity.solid: # Empty space or non-solid block → Move the player to the new position
|
|
if velocity_position:
|
|
self.gameState.set_player_position(velocity_position)
|
|
if block_at_velocity:
|
|
block_at_velocity.on_collision(self.gameState) # Do something when the player is on the block, like add score or stop the game
|
|
# Check if the player is on a solid block
|
|
player_position = self.gameState.get_player_position()
|
|
block_at_player_position = self.map.get_block_at(player_position[0], player_position[1] + 1)
|
|
if block_at_player_position and block_at_player_position.solid:
|
|
self.gameState.set_player_velocity(-1) # Stop the player from falling
|
|
|
|
self._update_player_velocity()
|
|
|
|
|
|
def _update_player_velocity(self):
|
|
current_velocity = self.gameState.playerVelocity
|
|
if current_velocity == -1: # If no velocity, then the player is not moving, so we don't need to update the velocity
|
|
return
|
|
|
|
if current_velocity == "down": # Falling straight down → Still falling except if the player is on a block
|
|
if not self._get_block_at_velocity() == None and self._get_block_at_velocity().solid: # If block at where the player is going is solid, then the player will stop falling
|
|
self.gameState.set_player_velocity(-1)
|
|
return
|
|
|
|
if current_velocity is "up": # Going up → Going down
|
|
self.gameState.set_player_velocity("down")
|
|
return
|
|
|
|
if current_velocity in ["left_down", "right_down"]:
|
|
self.gameState.set_player_velocity("down")
|
|
return
|
|
|
|
if current_velocity in ["left", "right"]:
|
|
self.gameState.set_player_velocity(current_velocity + "_down")
|
|
block_at_velocity = self._get_block_at_velocity()
|
|
if not block_at_velocity == None and block_at_velocity.solid: # If block at where the player is going is solid, then the player will fall down
|
|
self.gameState.set_player_velocity("down")
|
|
return
|
|
|
|
if current_velocity in ["left_up", "right_up"]:
|
|
self.gameState.set_player_velocity(current_velocity.replace("_up", "_down"))
|
|
block_at_velocity = self._get_block_at_velocity()
|
|
if not block_at_velocity == None and block_at_velocity.solid: # If block at where the player is going is solid, then the player will fall down
|
|
self.gameState.set_player_velocity("down")
|
|
return
|
|
|
|
def get_position_at_velocity(self) -> tuple | None:
|
|
player_position = self.gameState.get_player_position()
|
|
current_velocity = self.gameState.playerVelocity
|
|
|
|
if current_velocity == -1:
|
|
return None
|
|
|
|
if current_velocity == "down":
|
|
return (player_position[0], player_position[1] + 1)
|
|
|
|
if current_velocity == "left_down":
|
|
return (player_position[0] - 1, player_position[1] + 1)
|
|
|
|
if current_velocity == "right_down":
|
|
return (player_position[0] + 1, player_position[1] + 1)
|
|
|
|
if current_velocity == "left":
|
|
return (player_position[0] - 1, player_position[1])
|
|
|
|
if current_velocity == "right":
|
|
return (player_position[0] + 1, player_position[1])
|
|
|
|
if current_velocity == "left_up":
|
|
return (player_position[0] - 1, player_position[1] - 1)
|
|
|
|
if current_velocity == "right_up":
|
|
return (player_position[0] + 1, player_position[1] - 1)
|
|
|
|
return None
|
|
|
|
def _get_block_at_velocity(self) -> Block | None:
|
|
position_at_velocity = self.get_position_at_velocity()
|
|
if position_at_velocity is None:
|
|
return None
|
|
return self.map.get_block_at(position_at_velocity[0], position_at_velocity[1])
|
|
|
|
def stop_game(self):
|
|
self.gameState.set_stop_game(True)
|
|
|
|
def to_string(self):
|
|
"""
|
|
Returns a string representation of the game state and map with player position.
|
|
"""
|
|
player_position = self.gameState.get_player_position()
|
|
map_string_dict = self.map.to_string_dict()
|
|
map_string_dict[player_position[1]][player_position[0]] = f'{Style.BRIGHT}🦧'
|
|
return '\n'.join([''.join(character + Style.RESET_ALL for character in row) for row in map_string_dict]) |