Fixed bug in teleportation, moved some state and functions

This commit is contained in:
martin 2023-05-28 23:54:34 +02:00
parent ee00611c33
commit 3d95ff71d6
7 changed files with 43 additions and 34 deletions

@ -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);