From 44192ea3fef4e7d61454de38920c8469e422beb7 Mon Sep 17 00:00:00 2001 From: Martin Berg Alstad <600878@stud.hvl.no> Date: Sun, 21 May 2023 19:18:21 +0200 Subject: [PATCH] Added movement to characters, and remove used dice --- .../ClientApp/src/components/gameBoard.tsx | 29 ++++++++++++---- .../src/components/gameComponent.tsx | 34 ++++++++++++++++--- .../ClientApp/src/game/character.ts | 2 ++ pac-man-board-game/ClientApp/src/game/game.ts | 13 ------- .../src/game/possibleMovesAlgorithm.ts | 16 ++++----- .../ClientApp/src/types/types.d.ts | 2 +- .../ClientApp/src/websockets/actions.ts | 2 +- .../Controllers/GameController.cs | 7 ++-- pac-man-board-game/Game/Actions.cs | 3 +- 9 files changed, 68 insertions(+), 40 deletions(-) diff --git a/pac-man-board-game/ClientApp/src/components/gameBoard.tsx b/pac-man-board-game/ClientApp/src/components/gameBoard.tsx index dec0813..4dc653c 100644 --- a/pac-man-board-game/ClientApp/src/components/gameBoard.tsx +++ b/pac-man-board-game/ClientApp/src/components/gameBoard.tsx @@ -28,13 +28,15 @@ const map: number[][] = [ interface BoardProps extends ComponentProps { characters: Character[], selectedDice?: SelectedDice, + onMove?: (character: Character) => void } const Board: Component = ( { className, characters, - selectedDice + selectedDice, + onMove }) => { const [tileSize, setTileSize] = useState(2); @@ -45,6 +47,14 @@ const Board: Component = ( setSelectedCharacter(character); } + function handleMoveCharacter(position: CharacterPosition): void { + if (selectedCharacter) { + selectedCharacter.moveTo(position); + onMove?.(selectedCharacter); + setSelectedCharacter(undefined); + } + } + useEffect(() => { if (selectedCharacter && selectedDice) { const possiblePositions = findPossiblePositions(map, selectedCharacter.position, selectedDice.value); @@ -89,7 +99,9 @@ const Board: Component = ( type={tile} size={tileSize} character={characters.find(c => c.isAt({x: colIndex, y: rowIndex}))} - onClick={handleSelectCharacter} + onCharacterClick={handleSelectCharacter} + onClick={possiblePositions.find(p => p.x === colIndex && p.y === rowIndex) ? + () => handleMoveCharacter({x: colIndex, y: rowIndex}) : undefined} /> ) } @@ -104,8 +116,9 @@ export default Board; interface TileProps extends ComponentProps { size: number, type?: TileType, + onClick?: () => void, character?: Character, - onClick?: (character: Character) => void, + onCharacterClick?: (character: Character) => void, characterClass?: string, } @@ -113,10 +126,11 @@ const Tile: Component = ( { size, type = TileType.empty, - character, onClick, - className, + character, + onCharacterClick, characterClass, + className, }) => { function setColor(): string { @@ -138,10 +152,11 @@ const Tile: Component = ( return (
+ style={{width: `${size}px`, height: `${size}px`}} + onClick={onClick}> {character &&
- +
} diff --git a/pac-man-board-game/ClientApp/src/components/gameComponent.tsx b/pac-man-board-game/ClientApp/src/components/gameComponent.tsx index 73fb0be..0b078c8 100644 --- a/pac-man-board-game/ClientApp/src/components/gameComponent.tsx +++ b/pac-man-board-game/ClientApp/src/components/gameComponent.tsx @@ -1,15 +1,15 @@ -import React, {useEffect, useState} from "react"; +import React, {useEffect, useRef, useState} from "react"; import Game from "../game/game"; import {AllDice} from "./dice"; import {Action} from "../websockets/actions"; import GameBoard from "./gameBoard"; -import {Ghost, PacMan} from "../game/character"; +import {Character, Ghost, PacMan} from "../game/character"; let game: Game; -const characters = [new PacMan("yellow"), new Ghost("purple")]; - export const GameComponent: Component = () => { + // Better for testing than outside of the component + const characters = useRef([new PacMan("yellow"), new Ghost("purple")]); const [dice, setDice] = useState(); const [selectedDice, setSelectedDice] = useState(); @@ -36,10 +36,33 @@ export const GameComponent: Component = () => { case Action.rollDice: setDice(parsed.Data as number[]); // Updates the state of other players break; + case Action.moveCharacter: + setDice(parsed.Data?.dice as number[]); + const character = parsed.Data?.character as Character; + characters.current.find(c => c.color === character.color)?.moveTo(character.position); + break; } }; } + function onCharacterMove(character: Character): void { + if (dice && selectedDice) { + // Remove the dice that was used from the list of dice + + dice.splice(selectedDice.index, 1); + setDice([...dice]); + } + setSelectedDice(undefined); + const data: ActionMessage = { + Action: Action.moveCharacter, + Data: { + dice: dice?.length ?? 0 > 0 ? dice : null, + character: character + } + }; + game.wsService.send(data); + } + useEffect(() => { game = new Game(); updateState(); @@ -56,7 +79,8 @@ export const GameComponent: Component = () => {
- + ); }; diff --git a/pac-man-board-game/ClientApp/src/game/character.ts b/pac-man-board-game/ClientApp/src/game/character.ts index 75d4950..b89f4a2 100644 --- a/pac-man-board-game/ClientApp/src/game/character.ts +++ b/pac-man-board-game/ClientApp/src/game/character.ts @@ -18,12 +18,14 @@ export abstract class Character { export class PacMan extends Character { moveTo(position: CharacterPosition): void { + this.position = position; } } export class Ghost extends Character { moveTo(position: CharacterPosition): void { + this.position = position; } } diff --git a/pac-man-board-game/ClientApp/src/game/game.ts b/pac-man-board-game/ClientApp/src/game/game.ts index e4b66e9..298cf25 100644 --- a/pac-man-board-game/ClientApp/src/game/game.ts +++ b/pac-man-board-game/ClientApp/src/game/game.ts @@ -23,11 +23,6 @@ export default class Game { const dice = result.Data; setDice(dice); // Updates the state of the current player - // Choose a dice - - // Choose a character to move - // this.chooseCharacter(); - // Use the remaining dice to move pac-man if the player moved a ghost or vice versa // Check if the game is over @@ -66,14 +61,6 @@ export default class Game { return result; } - private movePacMan(steps: number): void { - throw new Error("Not implemented"); - } - - private moveGhost(steps: number): void { - throw new Error("Not implemented"); - } - private isGameOver(): boolean { throw new Error("Not implemented"); } diff --git a/pac-man-board-game/ClientApp/src/game/possibleMovesAlgorithm.ts b/pac-man-board-game/ClientApp/src/game/possibleMovesAlgorithm.ts index 9822f0e..e51ef19 100644 --- a/pac-man-board-game/ClientApp/src/game/possibleMovesAlgorithm.ts +++ b/pac-man-board-game/ClientApp/src/game/possibleMovesAlgorithm.ts @@ -14,18 +14,16 @@ export default function findPossiblePositions(board: number[][], currentPos: Cha function findPossibleRecursive(board: number[][], currentPos: CharacterPosition, steps: number, possibleList: CharacterPosition[], visitedTiles: CharacterPosition[]): CharacterPosition | null { - if (isOutsideBoard(currentPos)) { + if (isOutsideBoard(currentPos, board.length)) { addTeleportationTiles(board, currentPos, steps, possibleList, visitedTiles); } else if (visitedTiles.find(tile => tile.x === currentPos.x && tile.y === currentPos.y)) { return null; - } else { - if (isWall(board, currentPos)) { - return null; - } + } else if (isWall(board, currentPos)) { + return null; } visitedTiles.push(currentPos); if (steps === 0) return currentPos; - + const nextStep = steps - 1; const result = { up: findPossibleRecursive(board, {x: currentPos.x, y: currentPos.y + 1}, nextStep, possibleList, visitedTiles), @@ -52,7 +50,7 @@ function addTeleportationTiles(board: number[][], currentPos: CharacterPosition, function pushToList(board: number[][], list: CharacterPosition[], newEntries: (CharacterPosition | null)[]): void { for (const entry of newEntries) { - if (entry !== null && !list.find(p => p.x === entry.x && p.y === entry.y) && !isSpawn(board, entry)) { + if (entry !== null && !list.find(p => p.x === entry.x && p.y === entry.y) && !isOutsideBoard(entry, board.length) && !isSpawn(board, entry)) { list.push(entry); } } @@ -77,8 +75,8 @@ function findTeleportationTiles(board: number[][]): CharacterPosition[] { return possiblePositions; } -function isOutsideBoard(currentPos: CharacterPosition): boolean { - return currentPos.x < 0 || currentPos.y < 0; +function isOutsideBoard(currentPos: CharacterPosition, boardSize: number): boolean { + return currentPos.x < 0 || currentPos.x >= boardSize || currentPos.y < 0 || currentPos.y >= boardSize; } function isWall(board: number[][], currentPos: CharacterPosition): boolean { diff --git a/pac-man-board-game/ClientApp/src/types/types.d.ts b/pac-man-board-game/ClientApp/src/types/types.d.ts index 29626c3..1b7acb4 100644 --- a/pac-man-board-game/ClientApp/src/types/types.d.ts +++ b/pac-man-board-game/ClientApp/src/types/types.d.ts @@ -4,7 +4,7 @@ type Setter = React.Dispatch>; type WebSocketData = string | ArrayBufferLike | Blob | ArrayBufferView; -type ActionMessage = { +type ActionMessage = { Action: import("../websockets/actions").Action, Data?: T } diff --git a/pac-man-board-game/ClientApp/src/websockets/actions.ts b/pac-man-board-game/ClientApp/src/websockets/actions.ts index f076022..22e5723 100644 --- a/pac-man-board-game/ClientApp/src/websockets/actions.ts +++ b/pac-man-board-game/ClientApp/src/websockets/actions.ts @@ -1,4 +1,4 @@ export enum Action { rollDice, - pickDice, + moveCharacter, } \ No newline at end of file diff --git a/pac-man-board-game/Controllers/GameController.cs b/pac-man-board-game/Controllers/GameController.cs index a5466ab..d08c603 100644 --- a/pac-man-board-game/Controllers/GameController.cs +++ b/pac-man-board-game/Controllers/GameController.cs @@ -24,7 +24,7 @@ public class GameController : GenericController protected override ArraySegment Run(WebSocketReceiveResult result, byte[] data) { - var stringResult = data.GetString(data.Length); + var stringResult = data.GetString(result.Count); Logger.Log(LogLevel.Information, "Received: {}", stringResult); var action = ActionMessage.FromJson(stringResult); @@ -39,12 +39,13 @@ public class GameController : GenericController { case GameAction.RollDice: var rolls = _diceCup.Roll(); - Logger.Log(LogLevel.Information, "Rolled {}", string.Join(", ", rolls)); + Logger.Log(LogLevel.Information, "Rolled [{}]", string.Join(", ", rolls)); message.Data = rolls; break; default: - throw new ArgumentOutOfRangeException(nameof(message), "Action not allowed"); + Logger.Log(LogLevel.Information, "Sending message to all clients"); + break; } } } \ No newline at end of file diff --git a/pac-man-board-game/Game/Actions.cs b/pac-man-board-game/Game/Actions.cs index be5d0e8..0bf0cd9 100644 --- a/pac-man-board-game/Game/Actions.cs +++ b/pac-man-board-game/Game/Actions.cs @@ -4,7 +4,8 @@ namespace pacMan.Game; public enum GameAction { - RollDice + RollDice, + MoveCharacter, } public class ActionMessage