Tweak frontend and game logic

This commit is contained in:
Eden Kirin
2023-03-26 00:37:58 +01:00
parent 3ac07f3072
commit f54344a17f
5 changed files with 88 additions and 26 deletions

View File

@ -14,7 +14,6 @@
<body> <body>
<div class="container-fluid"> <div class="container-fluid">
<h1>FairHopper WS Client</h1> <h1>FairHopper WS Client</h1>
<div class="row"> <div class="row">
<div class="col-10"> <div class="col-10">
<div class="board-container"> <div class="board-container">
@ -23,7 +22,7 @@
</div> </div>
<div class="col-2"> <div class="col-2">
<h3>Players</h3> <h3>Players</h3>
<ul id="players-content"></ul> <ul class="players" id="players-content"></ul>
</div> </div>
</div> </div>
</div> </div>
@ -46,8 +45,12 @@
document.getElementById("board-content").innerHTML = html; document.getElementById("board-content").innerHTML = html;
} }
function renderCellContent(x, y, content) { function findCell(position) {
const cell = document.getElementById(`cell-${x}-${y}`); return document.getElementById(`cell-${position.x}-${position.y}`);
}
function renderCellContent(position, content) {
const cell = findCell(position);
if (cell) { if (cell) {
cell.innerText = content; cell.innerText = content;
} }
@ -56,7 +59,10 @@
function renderPlayerList(players) { function renderPlayerList(players) {
const html = players.map((player) => { const html = players.map((player) => {
return ` return `
<li>${player.name} (${player.move_count})</li> <li class="${player.reached_destination ? "text-success" : ""}">
${player.name} (${player.move_count})
${player.reached_destination ? "✅" : ""}
</li>
`; `;
}).join(""); }).join("");
document.getElementById("players-content").innerHTML = html; document.getElementById("players-content").innerHTML = html;
@ -64,7 +70,20 @@
function renderPlayers(players) { function renderPlayers(players) {
players.forEach(player => { players.forEach(player => {
renderCellContent(player.position.x, player.position.y, "😎"); const cell = findCell(player.position);
if (cell) {
const playerIcon = "😎";
const html = `
<div class="player-tooltip">${player.name}</div>
${playerIcon}
`;
cell.innerHTML = html;
}
//renderCellContent(player.position.x, player.position.y, "😎");
}); });
} }
@ -79,12 +98,12 @@
function renderObstacles(layers) { function renderObstacles(layers) {
const objects = getLayerObjectsOfType(layers, "OBSTACLE"); const objects = getLayerObjectsOfType(layers, "OBSTACLE");
objects.forEach(obj => { objects.forEach(obj => {
renderCellContent(obj.position.x, obj.position.y, "🔥"); renderCellContent(obj.position, "🔥");
}); });
} }
function renderDestination(position) { function renderDestination(position) {
renderCellContent(position.x, position.y, "🏠"); renderCellContent(position, "🏠");
} }
window.onload = function () { window.onload = function () {

View File

@ -17,4 +17,32 @@ body {
flex: 1; flex: 1;
text-align: center; text-align: center;
background-color: beige; background-color: beige;
position: relative;
}
ul.players {
list-style-type: none;
padding-left: 0;
}
.player-tooltip {
position: absolute;
top: -25px;
font-size: 8pt;
padding: 2px 10px;
color: white;
background-color: darkred;
border-radius: 5px;
z-index: 1000;
}
.player-tooltip::after {
content: " ";
position: absolute;
top: 100%; /* At the bottom of the tooltip */
left: 50%;
margin-left: -5px;
border-width: 5px;
border-style: solid;
border-color: darkred transparent transparent transparent;
} }

View File

@ -69,14 +69,8 @@ class GameEngine:
return player return player
async def move_player( def _move_position(self, position: Position, direction: Direction) -> Position:
self, player: Player, direction: Direction new_position = Position(position.x, position.y)
) -> PlayerMoveResult:
player.reset_timeout()
new_position = Position(player.position.x, player.position.y)
logging.info(f"Player {player} move to {direction}")
if direction == Direction.LEFT: if direction == Direction.LEFT:
new_position.x -= 1 new_position.x -= 1
elif direction == Direction.RIGHT: elif direction == Direction.RIGHT:
@ -87,39 +81,56 @@ class GameEngine:
new_position.y += 1 new_position.y += 1
else: else:
raise ValueError(f"Unhandled direction: {direction}") raise ValueError(f"Unhandled direction: {direction}")
return new_position
async def move_player(
self, player: Player, direction: Direction
) -> PlayerMoveResult:
player.reset_timeout()
# player will not be able to move once they reach the destination
if player.reached_destination:
return PlayerMoveResult.DESTINATION_REACHED
logging.info(f"Player {player} move to {direction}")
new_position = self._move_position(player.position, direction)
player.move_attempt_count += 1 player.move_attempt_count += 1
if not self.position_in_board_bounds(new_position): if not self._position_in_board_bounds(new_position):
raise PositionOutOfBounds() raise PositionOutOfBounds()
if self.colided_with_obstacle(new_position): if self._colided_with_obstacle(new_position):
raise Collision() raise Collision()
player.position = new_position player.position = new_position
player.move_count += 1 player.move_count += 1
if self._is_player_on_destination(player):
player.reached_destination = True
logging.info(f"Player {player} reached destination!")
if self.ws_server: if self.ws_server:
await self.ws_server.send_game_state() await self.ws_server.send_game_state()
if self.is_player_on_destination(player):
logging.info(f"Player {player} reached destination!")
return PlayerMoveResult.DESTINATION_REACHED
self.__debug_print_board() self.__debug_print_board()
if player.reached_destination:
return PlayerMoveResult.DESTINATION_REACHED
await asyncio.sleep(settings.game.MOVE_DELAY) await asyncio.sleep(settings.game.MOVE_DELAY)
return PlayerMoveResult.OK return PlayerMoveResult.OK
def is_player_on_destination(self, player: Player) -> bool: def _is_player_on_destination(self, player: Player) -> bool:
return player.position == self.board.destination.position return player.position == self.board.destination.position
def position_in_board_bounds(self, position: Position) -> bool: def _position_in_board_bounds(self, position: Position) -> bool:
return ( return (
0 <= position.x < self.board.width and 0 <= position.y < self.board.height 0 <= position.x < self.board.width and 0 <= position.y < self.board.height
) )
def colided_with_obstacle(self, position: Position) -> bool: def _colided_with_obstacle(self, position: Position) -> bool:
return self.board.get_object_at_position(position) is not None return self.board.get_object_at_position(position) is not None
def get_board_layout(self) -> BoardLayout: def get_board_layout(self) -> BoardLayout:

View File

@ -22,6 +22,7 @@ class Player:
) )
active: bool = True active: bool = True
can_be_deactivated: bool = True can_be_deactivated: bool = True
reached_destination: bool = False
def reset_timeout(self) -> None: def reset_timeout(self) -> None:
self.last_seen = datetime.datetime.now() self.last_seen = datetime.datetime.now()

View File

@ -15,9 +15,12 @@ class LayerDto(BaseModel):
name: str name: str
objects: list[LayerObjectDto] objects: list[LayerObjectDto]
class GameStatePlayerDto(PlayerDto):
reached_destination: bool
class GameStateDto(BaseModel): class GameStateDto(BaseModel):
board: BoardDto board: BoardDto
destination: DestinationDto destination: DestinationDto
players: list[PlayerDto] players: list[GameStatePlayerDto]
layers: list[LayerDto] layers: list[LayerDto]