Can click a player to select it. Started implementing algorithm to find paths
This commit is contained in:
parent
74f69c6f6c
commit
89df373d45
@ -1,5 +1,6 @@
|
||||
import React, {useEffect, useState} from "react";
|
||||
import {Character, PacMan} from "../game/character";
|
||||
import {findPossiblePositions} from "../utils/game";
|
||||
|
||||
/**
|
||||
* 0 = empty
|
||||
@ -23,7 +24,7 @@ const map: number[][] = [
|
||||
[1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1],
|
||||
];
|
||||
|
||||
enum TileType {
|
||||
export enum TileType {
|
||||
empty,
|
||||
wall,
|
||||
pellet,
|
||||
@ -33,15 +34,34 @@ enum TileType {
|
||||
}
|
||||
|
||||
interface BoardProps extends ComponentProps {
|
||||
characters: Character[];
|
||||
characters: Character[],
|
||||
selectedDice?: SelectedDice,
|
||||
}
|
||||
|
||||
const Board: Component<BoardProps> = ({className, characters}) => {
|
||||
const Board: Component<BoardProps> = (
|
||||
{
|
||||
className,
|
||||
characters,
|
||||
selectedDice
|
||||
}) => {
|
||||
|
||||
const [tileSize, setTileSize] = useState<number>(2);
|
||||
const [tileSize, setTileSize] = useState(2);
|
||||
const [selectedCharacter, setSelectedCharacter] = useState<Character>();
|
||||
const [possiblePositions, setPossiblePositions] = useState<CharacterPosition[]>([]);
|
||||
|
||||
function handleSelectCharacter(character: Character) {
|
||||
setSelectedCharacter(character);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
if (selectedCharacter && selectedDice) {
|
||||
const possiblePositions = findPossiblePositions(map, selectedCharacter.position, selectedDice.value);
|
||||
setPossiblePositions(possiblePositions);
|
||||
}
|
||||
}, [selectedCharacter, selectedDice]);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
for (const character of characters) { // TODO make more dynamic
|
||||
if (character instanceof PacMan) {
|
||||
character.position = {x: 3, y: 3};
|
||||
@ -68,10 +88,14 @@ const Board: Component<BoardProps> = ({className, characters}) => {
|
||||
<div key={rowIndex} className={"flex"}>
|
||||
{
|
||||
row.map((tile, colIndex) =>
|
||||
<Tile key={colIndex + rowIndex * colIndex}
|
||||
<Tile className={`${possiblePositions.find(p => p.x === colIndex && p.y === rowIndex) ? "rounded-full" : ""}`}
|
||||
characterClass={`${selectedCharacter?.isAt({x: colIndex, y: rowIndex}) ? "animate-bounce" : ""}`}
|
||||
key={colIndex + rowIndex * colIndex}
|
||||
type={tile}
|
||||
size={tileSize}
|
||||
character={characters.find(c => c.position.x === colIndex && c.position.y === rowIndex)}/>
|
||||
character={characters.find(c => c.isAt({x: colIndex, y: rowIndex}))}
|
||||
onClick={handleSelectCharacter}
|
||||
/>
|
||||
)
|
||||
}
|
||||
</div>)
|
||||
@ -86,9 +110,19 @@ interface TileProps extends ComponentProps {
|
||||
size: number,
|
||||
type?: TileType,
|
||||
character?: Character,
|
||||
onClick?: (character: Character) => void,
|
||||
characterClass?: string,
|
||||
}
|
||||
|
||||
const Tile: Component<TileProps> = ({size, type = TileType.empty, character}) => {
|
||||
const Tile: Component<TileProps> = (
|
||||
{
|
||||
size,
|
||||
type = TileType.empty,
|
||||
character,
|
||||
onClick,
|
||||
className,
|
||||
characterClass,
|
||||
}) => {
|
||||
|
||||
function setColor(): string {
|
||||
switch (type) {
|
||||
@ -108,23 +142,30 @@ const Tile: Component<TileProps> = ({size, type = TileType.empty, character}) =>
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={`${setColor()} relative`} style={{width: `${size}px`, height: `${size}px`}}>
|
||||
<div className={`${setColor()} hover:border relative max-w-[75px] max-h-[75px] ${className}`}
|
||||
style={{width: `${size}px`, height: `${size}px`}}>
|
||||
{character &&
|
||||
<div className={"inline-flex justify-center items-center w-full h-full"}>
|
||||
<CharacterComponent character={character}/>
|
||||
<CharacterComponent character={character} onClick={onClick} className={characterClass}/>
|
||||
</div>
|
||||
}
|
||||
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
interface CharacterComponentProps extends ComponentProps {
|
||||
character: Character,
|
||||
onClick?: (character: Character) => void,
|
||||
}
|
||||
|
||||
const CharacterComponent: Component<CharacterComponentProps> = ({character}) => {
|
||||
return (
|
||||
<div className={"rounded-full w-4/5 h-4/5 cursor-pointer hover:border border-black"}
|
||||
style={{backgroundColor: `${character.color}`}}/>
|
||||
);
|
||||
};
|
||||
const CharacterComponent: Component<CharacterComponentProps> = (
|
||||
{
|
||||
character,
|
||||
onClick,
|
||||
className
|
||||
}) => (
|
||||
<div className={`rounded-full w-4/5 h-4/5 cursor-pointer hover:border border-black ${className}`}
|
||||
style={{backgroundColor: `${character.color}`}}
|
||||
onClick={onClick ? () => onClick(character) : undefined}/>
|
||||
);
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, {useState} from "react";
|
||||
import React, {useEffect, useState} from "react";
|
||||
import Game from "../game/game";
|
||||
import {AllDice} from "./dice";
|
||||
import {Action} from "../websockets/actions";
|
||||
@ -20,6 +20,7 @@ export const GameComponent: Component = () => {
|
||||
}
|
||||
|
||||
function startGameLoop(): void {
|
||||
setSelectedDice(undefined);
|
||||
if (!game.isConnected()) {
|
||||
setTimeout(startGameLoop, 50);
|
||||
return;
|
||||
@ -39,7 +40,7 @@ export const GameComponent: Component = () => {
|
||||
};
|
||||
}
|
||||
|
||||
React.useEffect(() => {
|
||||
useEffect(() => {
|
||||
game = new Game();
|
||||
updateState();
|
||||
|
||||
@ -55,7 +56,7 @@ export const GameComponent: Component = () => {
|
||||
<button onClick={startGameLoop}>Roll dice</button>
|
||||
</div>
|
||||
<AllDice values={dice} onclick={handleDiceClick} selectedDiceIndex={selectedDice?.index}/>
|
||||
<GameBoard className={"mx-auto"} characters={characters}/>
|
||||
<GameBoard className={"mx-auto"} characters={characters} selectedDice={selectedDice}/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@ -10,6 +10,10 @@ export abstract class Character {
|
||||
}
|
||||
|
||||
public abstract moveTo(position: CharacterPosition): void;
|
||||
|
||||
public isAt(position: CharacterPosition): boolean {
|
||||
return this.position.x === position.x && this.position.y === position.y;
|
||||
}
|
||||
}
|
||||
|
||||
export class PacMan extends Character {
|
||||
|
46
pac-man-board-game/ClientApp/src/utils/game.ts
Normal file
46
pac-man-board-game/ClientApp/src/utils/game.ts
Normal file
@ -0,0 +1,46 @@
|
||||
import {TileType} from "../components/gameBoard";
|
||||
|
||||
/**
|
||||
* Finds all the possible positions for the character to move to
|
||||
* @param board The board the character is on
|
||||
* @param currentPos The current position of the character
|
||||
* @param steps The number of steps the character can move
|
||||
*/
|
||||
export function findPossiblePositions(board: number[][], currentPos: CharacterPosition, steps: number): CharacterPosition[] {
|
||||
const possiblePositions: CharacterPosition[] = [];
|
||||
findPossibleRecursive(board, currentPos, steps, possiblePositions);
|
||||
return possiblePositions;
|
||||
}
|
||||
|
||||
// TODO character phasing through wall next to spawn
|
||||
function findPossibleRecursive(board: number[][], currentPos: CharacterPosition, steps: number,
|
||||
possibleList: CharacterPosition[]): CharacterPosition | null {
|
||||
if (isWall(board, currentPos)) return null;
|
||||
// TODO handle teleportation
|
||||
if (steps === 0) return currentPos;
|
||||
|
||||
const result = {
|
||||
up: findPossibleRecursive(board, {x: currentPos.x, y: currentPos.y + 1}, steps - 1, possibleList),
|
||||
right: findPossibleRecursive(board, {x: currentPos.x + 1, y: currentPos.y}, steps - 1, possibleList),
|
||||
down: findPossibleRecursive(board, {x: currentPos.x, y: currentPos.y - 1}, steps - 1, possibleList),
|
||||
left: findPossibleRecursive(board, {x: currentPos.x - 1, y: currentPos.y}, steps - 1, possibleList),
|
||||
};
|
||||
|
||||
for (const [_, value] of Object.entries(result)) {
|
||||
if (value !== null && !possibleList.find(p => p.x === value.x && p.y === value.y) && !isSpawn(board, value)) {
|
||||
possibleList.push(value);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function isWall(board: number[][], currentPos: CharacterPosition): boolean {
|
||||
return board[currentPos.x][currentPos.y] === TileType.wall;
|
||||
}
|
||||
|
||||
function isSpawn(board: number[][], currentPos: CharacterPosition): boolean {
|
||||
return board[currentPos.x][currentPos.y] === TileType.pacmanSpawn ||
|
||||
board[currentPos.x][currentPos.y] === TileType.ghostSpawn;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user