Fixed bug in teleportation, moved some state and functions
This commit is contained in:
parent
ee00611c33
commit
3d95ff71d6
pac-man-board-game/ClientApp
@ -1,14 +1,14 @@
|
|||||||
import React, {useEffect, useState} from "react";
|
import React, {useEffect, useState} from "react";
|
||||||
import {Character, PacMan} from "../game/character";
|
import {Character, PacMan} from "../game/character";
|
||||||
import findPossiblePositions from "../game/possibleMovesAlgorithm";
|
import findPossiblePositions from "../game/possibleMovesAlgorithm";
|
||||||
import {testMap} from "../game/map";
|
|
||||||
import {Direction} from "../game/direction";
|
import {Direction} from "../game/direction";
|
||||||
import {GameTile} from "./gameTile";
|
import {GameTile} from "./gameTile";
|
||||||
|
|
||||||
interface BoardProps extends ComponentProps {
|
interface BoardProps extends ComponentProps {
|
||||||
characters: Character[],
|
characters: Character[],
|
||||||
selectedDice?: SelectedDice,
|
selectedDice?: SelectedDice,
|
||||||
onMove?: (character: Character) => void
|
onMove?: (character: Character) => void,
|
||||||
|
map: GameMap
|
||||||
}
|
}
|
||||||
|
|
||||||
const Board: Component<BoardProps> = (
|
const Board: Component<BoardProps> = (
|
||||||
@ -16,10 +16,10 @@ const Board: Component<BoardProps> = (
|
|||||||
className,
|
className,
|
||||||
characters,
|
characters,
|
||||||
selectedDice,
|
selectedDice,
|
||||||
onMove
|
onMove,
|
||||||
|
map
|
||||||
}) => {
|
}) => {
|
||||||
|
|
||||||
const [tileSize, setTileSize] = useState(2);
|
|
||||||
const [selectedCharacter, setSelectedCharacter] = useState<Character>();
|
const [selectedCharacter, setSelectedCharacter] = useState<Character>();
|
||||||
const [possiblePositions, setPossiblePositions] = useState<Path[]>([]); // TODO reset when other client moves a character
|
const [possiblePositions, setPossiblePositions] = useState<Path[]>([]); // TODO reset when other client moves a character
|
||||||
const [hoveredPosition, setHoveredPosition] = useState<Path>();
|
const [hoveredPosition, setHoveredPosition] = useState<Path>();
|
||||||
@ -43,7 +43,7 @@ const Board: Component<BoardProps> = (
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (selectedCharacter && selectedDice) {
|
if (selectedCharacter && selectedDice) {
|
||||||
const possiblePaths = findPossiblePositions(testMap, selectedCharacter, selectedDice.value);
|
const possiblePaths = findPossiblePositions(map, selectedCharacter, selectedDice.value);
|
||||||
setPossiblePositions(possiblePaths);
|
setPossiblePositions(possiblePaths);
|
||||||
} else {
|
} else {
|
||||||
setPossiblePositions([]);
|
setPossiblePositions([]);
|
||||||
@ -59,29 +59,18 @@ const Board: Component<BoardProps> = (
|
|||||||
character.position = {end: {x: 7, y: 3}, direction: Direction.up};
|
character.position = {end: {x: 7, y: 3}, direction: Direction.up};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleResize(): void {
|
|
||||||
const newSize = Math.floor(window.innerWidth / 12);
|
|
||||||
setTileSize(newSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
handleResize();
|
|
||||||
|
|
||||||
window.addEventListener("resize", handleResize);
|
|
||||||
return () => window.removeEventListener("resize", handleResize);
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`w-fit ${className}`}>
|
<div className={`w-fit ${className}`}>
|
||||||
{
|
{
|
||||||
testMap.map((row, rowIndex) =>
|
map.map((row, rowIndex) =>
|
||||||
<div key={rowIndex} className={"flex"}>
|
<div key={rowIndex} className={"flex"}>
|
||||||
{
|
{
|
||||||
row.map((tile, colIndex) =>
|
row.map((tile, colIndex) =>
|
||||||
<GameTile
|
<GameTile
|
||||||
key={colIndex + rowIndex * colIndex}
|
key={colIndex + rowIndex * colIndex}
|
||||||
type={tile}
|
type={tile}
|
||||||
size={tileSize}
|
|
||||||
possiblePath={possiblePositions.find(p => p.end.x === colIndex && p.end.y === rowIndex)}
|
possiblePath={possiblePositions.find(p => p.end.x === colIndex && p.end.y === rowIndex)}
|
||||||
character={characters.find(c => c.isAt({x: colIndex, y: rowIndex}))}
|
character={characters.find(c => c.isAt({x: colIndex, y: rowIndex}))}
|
||||||
isSelected={selectedCharacter?.isAt({x: colIndex, y: rowIndex})}
|
isSelected={selectedCharacter?.isAt({x: colIndex, y: rowIndex})}
|
||||||
|
@ -4,6 +4,7 @@ import {Action} from "../websockets/actions";
|
|||||||
import GameBoard from "./gameBoard";
|
import GameBoard from "./gameBoard";
|
||||||
import {Character, Ghost, PacMan} from "../game/character";
|
import {Character, Ghost, PacMan} from "../game/character";
|
||||||
import WebSocketService from "../websockets/WebSocketService";
|
import WebSocketService from "../websockets/WebSocketService";
|
||||||
|
import {testMap} from "../game/map";
|
||||||
|
|
||||||
const wsService = new WebSocketService("wss://localhost:3000/api/game");
|
const wsService = new WebSocketService("wss://localhost:3000/api/game");
|
||||||
|
|
||||||
@ -64,7 +65,7 @@ export const GameComponent: Component = () => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
wsService.onReceive = doAction;
|
wsService.onReceive = doAction;
|
||||||
wsService.open();
|
wsService.open();
|
||||||
|
|
||||||
startGameLoop();
|
startGameLoop();
|
||||||
return () => wsService.close();
|
return () => wsService.close();
|
||||||
}, []);
|
}, []);
|
||||||
@ -77,7 +78,7 @@ export const GameComponent: Component = () => {
|
|||||||
</div>
|
</div>
|
||||||
<AllDice values={dice} onclick={handleDiceClick} selectedDiceIndex={selectedDice?.index}/>
|
<AllDice values={dice} onclick={handleDiceClick} selectedDiceIndex={selectedDice?.index}/>
|
||||||
<GameBoard className={"mx-auto my-2"} characters={characters.current} selectedDice={selectedDice}
|
<GameBoard className={"mx-auto my-2"} characters={characters.current} selectedDice={selectedDice}
|
||||||
onMove={onCharacterMove}/>
|
onMove={onCharacterMove} map={testMap}/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React from "react";
|
import React, {useEffect, useState} from "react";
|
||||||
import {TileType} from "../game/tileType";
|
import {TileType} from "../game/tileType";
|
||||||
import {Character, Dummy} from "../game/character";
|
import {Character, Dummy} from "../game/character";
|
||||||
import {Direction} from "../game/direction";
|
import {Direction} from "../game/direction";
|
||||||
@ -6,7 +6,6 @@ import {Direction} from "../game/direction";
|
|||||||
interface TileWithCharacterProps extends ComponentProps {
|
interface TileWithCharacterProps extends ComponentProps {
|
||||||
possiblePath?: Path,
|
possiblePath?: Path,
|
||||||
character?: Character,
|
character?: Character,
|
||||||
size: number,
|
|
||||||
type?: TileType,
|
type?: TileType,
|
||||||
handleMoveCharacter?: (path: Path) => void,
|
handleMoveCharacter?: (path: Path) => void,
|
||||||
handleSelectCharacter?: (character: Character) => void,
|
handleSelectCharacter?: (character: Character) => void,
|
||||||
@ -20,7 +19,6 @@ export const GameTile: Component<TileWithCharacterProps> = (
|
|||||||
{
|
{
|
||||||
possiblePath,
|
possiblePath,
|
||||||
character,
|
character,
|
||||||
size,
|
|
||||||
type,
|
type,
|
||||||
handleMoveCharacter,
|
handleMoveCharacter,
|
||||||
handleSelectCharacter,
|
handleSelectCharacter,
|
||||||
@ -32,7 +30,6 @@ export const GameTile: Component<TileWithCharacterProps> = (
|
|||||||
return (
|
return (
|
||||||
<Tile className={`${possiblePath?.end ? "border-4 border-white" : ""}`}
|
<Tile className={`${possiblePath?.end ? "border-4 border-white" : ""}`}
|
||||||
type={type}
|
type={type}
|
||||||
size={size}
|
|
||||||
onClick={possiblePath ? () => handleMoveCharacter?.(possiblePath) : undefined}
|
onClick={possiblePath ? () => handleMoveCharacter?.(possiblePath) : undefined}
|
||||||
onMouseEnter={possiblePath ? () => handleStartShowPath?.(possiblePath) : undefined}
|
onMouseEnter={possiblePath ? () => handleStartShowPath?.(possiblePath) : undefined}
|
||||||
onMouseLeave={handleStopShowPath}>
|
onMouseLeave={handleStopShowPath}>
|
||||||
@ -42,12 +39,10 @@ export const GameTile: Component<TileWithCharacterProps> = (
|
|||||||
<CharacterComponent
|
<CharacterComponent
|
||||||
character={character}
|
character={character}
|
||||||
onClick={handleSelectCharacter}
|
onClick={handleSelectCharacter}
|
||||||
className={`${isSelected ? "animate-bounce" : ""}`}/>
|
className={isSelected ? "animate-bounce" : ""}/>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
{showPath &&
|
{showPath && <PathSymbol/>}
|
||||||
<PathSymbol/>
|
|
||||||
}
|
|
||||||
<AddDummy path={possiblePath}/>
|
<AddDummy path={possiblePath}/>
|
||||||
</>
|
</>
|
||||||
</Tile>
|
</Tile>
|
||||||
@ -61,7 +56,6 @@ const PathSymbol: Component = () => ( // TODO sometimes shows up when it shouldn
|
|||||||
);
|
);
|
||||||
|
|
||||||
interface TileProps extends ChildProps {
|
interface TileProps extends ChildProps {
|
||||||
size: number,
|
|
||||||
type?: TileType,
|
type?: TileType,
|
||||||
onClick?: () => void,
|
onClick?: () => void,
|
||||||
onMouseEnter?: () => void,
|
onMouseEnter?: () => void,
|
||||||
@ -73,7 +67,6 @@ interface TileProps extends ChildProps {
|
|||||||
|
|
||||||
const Tile: Component<TileProps> = (
|
const Tile: Component<TileProps> = (
|
||||||
{
|
{
|
||||||
size,
|
|
||||||
type = TileType.empty,
|
type = TileType.empty,
|
||||||
onClick,
|
onClick,
|
||||||
onMouseEnter,
|
onMouseEnter,
|
||||||
@ -82,6 +75,8 @@ const Tile: Component<TileProps> = (
|
|||||||
children
|
children
|
||||||
}) => {
|
}) => {
|
||||||
|
|
||||||
|
const [tileSize, setTileSize] = useState(2);
|
||||||
|
|
||||||
function setColor(): string {
|
function setColor(): string {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case TileType.empty:
|
case TileType.empty:
|
||||||
@ -99,9 +94,22 @@ const Tile: Component<TileProps> = (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
|
||||||
|
function handleResize(): void {
|
||||||
|
const newSize = Math.floor(window.innerWidth / 12);
|
||||||
|
setTileSize(newSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleResize();
|
||||||
|
|
||||||
|
window.addEventListener("resize", handleResize);
|
||||||
|
return () => window.removeEventListener("resize", handleResize);
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`${setColor()} hover:border relative max-w-[75px] max-h-[75px] ${className}`}
|
<div className={`${setColor()} hover:border relative max-w-[75px] max-h-[75px] ${className}`}
|
||||||
style={{width: `${size}px`, height: `${size}px`}}
|
style={{width: `${tileSize}px`, height: `${tileSize}px`}}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
onMouseEnter={onMouseEnter}
|
onMouseEnter={onMouseEnter}
|
||||||
onMouseLeave={onMouseLeave}>
|
onMouseLeave={onMouseLeave}>
|
||||||
|
@ -20,6 +20,7 @@ export abstract class Character {
|
|||||||
public follow(path: Path): void {
|
public follow(path: Path): void {
|
||||||
this.position.end = path.end;
|
this.position.end = path.end;
|
||||||
this.position.direction = path.direction;
|
this.position.direction = path.direction;
|
||||||
|
this.position.path = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
public isAt(position: Position): boolean {
|
public isAt(position: Position): boolean {
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
import {EnumType} from "typescript";
|
|
||||||
|
|
||||||
export enum Direction {
|
export enum Direction {
|
||||||
left,
|
left,
|
||||||
up,
|
up,
|
||||||
|
@ -51,7 +51,7 @@ function findPossibleRecursive(board: GameMap, currentPos: Path, steps: number,
|
|||||||
function addToPath(currentPos: Path): void {
|
function addToPath(currentPos: Path): void {
|
||||||
if (!currentPos.path) {
|
if (!currentPos.path) {
|
||||||
currentPos.path = [];
|
currentPos.path = [];
|
||||||
} else if(!currentPos.path.includes(currentPos.end)) {
|
} else if (!currentPos.path.includes(currentPos.end)) {
|
||||||
currentPos.path = [...currentPos.path, currentPos.end];
|
currentPos.path = [...currentPos.path, currentPos.end];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -112,7 +112,9 @@ function addTeleportationTiles(board: GameMap, currentPath: Path, steps: number,
|
|||||||
const possiblePositions = findTeleportationTiles(board);
|
const possiblePositions = findTeleportationTiles(board);
|
||||||
const paths: Path[] = [];
|
const paths: Path[] = [];
|
||||||
for (const pos of possiblePositions) {
|
for (const pos of possiblePositions) {
|
||||||
if (pos.end.x !== Math.max(currentPath.end.x, 0) || pos.end.y !== Math.max(currentPath.end.y, 0)) {
|
if (pos.end.x !== interval(0, board.length - 1, currentPath.end.x) ||
|
||||||
|
pos.end.y !== interval(0, board.length - 1, currentPath.end.y)) {
|
||||||
|
|
||||||
pos.path = currentPath.path;
|
pos.path = currentPath.path;
|
||||||
paths.push(...findPossibleRecursive(board, pos, steps, isPacMan));
|
paths.push(...findPossibleRecursive(board, pos, steps, isPacMan));
|
||||||
}
|
}
|
||||||
@ -120,6 +122,10 @@ function addTeleportationTiles(board: GameMap, currentPath: Path, steps: number,
|
|||||||
return paths;
|
return paths;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function interval(lower: number, upper: number, value: number): number {
|
||||||
|
return Math.max(Math.min(value, upper), lower);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds all the teleportation tiles on the board
|
* Finds all the teleportation tiles on the board
|
||||||
* @param board The board the character is on
|
* @param board The board the character is on
|
||||||
|
@ -131,6 +131,12 @@ test("Pac-Man rolls six from position [7,1] (right), path to [9,5] should be fiv
|
|||||||
expect(result[0].path?.length).toBe(5);
|
expect(result[0].path?.length).toBe(5);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("Pac-Man rolls 5 from position [9,3] (down), should return 5", () => {
|
||||||
|
pacMan.follow({end: {x: 9, y: 3}, direction: Direction.down});
|
||||||
|
const result = possibleMovesAlgorithm(testMap, pacMan, 5);
|
||||||
|
expect(result.length).toBe(5);
|
||||||
|
});
|
||||||
|
|
||||||
function arrayEquals<T extends any[]>(result: T, expected: T, message?: string): void {
|
function arrayEquals<T extends any[]>(result: T, expected: T, message?: string): void {
|
||||||
for (const item of expected) {
|
for (const item of expected) {
|
||||||
expect(result, message).toContainEqual(item);
|
expect(result, message).toContainEqual(item);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user