Replaced the canvas map with a react component
This commit is contained in:
parent
046617ae20
commit
74f69c6f6c
130
pac-man-board-game/ClientApp/src/components/gameBoard.tsx
Normal file
130
pac-man-board-game/ClientApp/src/components/gameBoard.tsx
Normal file
@ -0,0 +1,130 @@
|
||||
import React, {useEffect, useState} from "react";
|
||||
import {Character, PacMan} from "../game/character";
|
||||
|
||||
/**
|
||||
* 0 = empty
|
||||
* 1 = wall
|
||||
* 2 = pellet
|
||||
* 3 = power pellet
|
||||
* 4 = ghost spawn
|
||||
* 5 = pacman spawn
|
||||
*/
|
||||
const map: number[][] = [
|
||||
[1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1],
|
||||
[1, 2, 0, 0, 0, 2, 0, 0, 0, 2, 1],
|
||||
[1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1],
|
||||
[1, 0, 1, 5, 1, 0, 1, 4, 1, 0, 1],
|
||||
[1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1],
|
||||
[0, 2, 0, 0, 0, 3, 0, 0, 0, 2, 0],
|
||||
[1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1],
|
||||
[1, 0, 1, 4, 1, 0, 1, 5, 1, 0, 1],
|
||||
[1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1],
|
||||
[1, 2, 0, 0, 0, 2, 0, 0, 0, 2, 1],
|
||||
[1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1],
|
||||
];
|
||||
|
||||
enum TileType {
|
||||
empty,
|
||||
wall,
|
||||
pellet,
|
||||
powerPellet,
|
||||
ghostSpawn,
|
||||
pacmanSpawn,
|
||||
}
|
||||
|
||||
interface BoardProps extends ComponentProps {
|
||||
characters: Character[];
|
||||
}
|
||||
|
||||
const Board: Component<BoardProps> = ({className, characters}) => {
|
||||
|
||||
const [tileSize, setTileSize] = useState<number>(2);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
for (const character of characters) { // TODO make more dynamic
|
||||
if (character instanceof PacMan) {
|
||||
character.position = {x: 3, y: 3};
|
||||
} else {
|
||||
character.position = {x: 7, y: 3};
|
||||
}
|
||||
}
|
||||
|
||||
function handleResize(): void {
|
||||
const newSize = Math.floor(window.innerWidth / 12);
|
||||
setTileSize(newSize);
|
||||
}
|
||||
|
||||
handleResize();
|
||||
|
||||
window.addEventListener("resize", handleResize);
|
||||
return () => window.removeEventListener("resize", handleResize);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className={`w-fit ${className}`}>
|
||||
{
|
||||
map.map((row, rowIndex) =>
|
||||
<div key={rowIndex} className={"flex"}>
|
||||
{
|
||||
row.map((tile, colIndex) =>
|
||||
<Tile key={colIndex + rowIndex * colIndex}
|
||||
type={tile}
|
||||
size={tileSize}
|
||||
character={characters.find(c => c.position.x === colIndex && c.position.y === rowIndex)}/>
|
||||
)
|
||||
}
|
||||
</div>)
|
||||
}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Board;
|
||||
|
||||
interface TileProps extends ComponentProps {
|
||||
size: number,
|
||||
type?: TileType,
|
||||
character?: Character,
|
||||
}
|
||||
|
||||
const Tile: Component<TileProps> = ({size, type = TileType.empty, character}) => {
|
||||
|
||||
function setColor(): string {
|
||||
switch (type) {
|
||||
case TileType.empty:
|
||||
return "bg-black";
|
||||
case TileType.wall:
|
||||
return "bg-blue-500";
|
||||
case TileType.pellet:
|
||||
return "bg-yellow-500";
|
||||
case TileType.powerPellet:
|
||||
return "bg-orange-500";
|
||||
case TileType.ghostSpawn:
|
||||
return "bg-red-500";
|
||||
case TileType.pacmanSpawn:
|
||||
return "bg-green-500";
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={`${setColor()} relative`} style={{width: `${size}px`, height: `${size}px`}}>
|
||||
{character &&
|
||||
<div className={"inline-flex justify-center items-center w-full h-full"}>
|
||||
<CharacterComponent character={character}/>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
interface CharacterComponentProps extends ComponentProps {
|
||||
character: Character,
|
||||
}
|
||||
|
||||
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}`}}/>
|
||||
);
|
||||
};
|
@ -1,23 +0,0 @@
|
||||
import React, {useEffect, useRef} from "react";
|
||||
import TileMap from "../game/tileMap";
|
||||
|
||||
const tileMap = new TileMap();
|
||||
|
||||
const GameCanvas: Component = ({className}) => {
|
||||
|
||||
const canvasRef = useRef<HTMLCanvasElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const context = canvasRef.current?.getContext("2d");
|
||||
if (!context) return;
|
||||
context.canvas.height = context.canvas.width;
|
||||
|
||||
tileMap.draw(context);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<canvas ref={canvasRef} className={`shadow-lg w-3/4 aspect-square ${className}`}></canvas>
|
||||
);
|
||||
};
|
||||
|
||||
export default GameCanvas;
|
@ -1,10 +1,14 @@
|
||||
import React, {useState} from "react";
|
||||
import GameCanvas from "../components/gameCanvas";
|
||||
import Game from "../game/game";
|
||||
import {AllDice} from "./dice";
|
||||
import {Action} from "../websockets/actions";
|
||||
import GameBoard from "./gameBoard";
|
||||
import {Ghost, PacMan} from "../game/character";
|
||||
|
||||
let game: Game;
|
||||
|
||||
const characters = [new PacMan("yellow"), new Ghost("purple")];
|
||||
|
||||
export const GameComponent: Component = () => {
|
||||
|
||||
const [dice, setDice] = useState<number[]>();
|
||||
@ -51,7 +55,7 @@ export const GameComponent: Component = () => {
|
||||
<button onClick={startGameLoop}>Roll dice</button>
|
||||
</div>
|
||||
<AllDice values={dice} onclick={handleDiceClick} selectedDiceIndex={selectedDice?.index}/>
|
||||
<GameCanvas className={"mx-auto"}/>
|
||||
<GameBoard className={"mx-auto"} characters={characters}/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@ -1,10 +1,10 @@
|
||||
type CharacterColor = "red" | "blue" | "yellow" | "green";
|
||||
type CharacterColor = "red" | "blue" | "yellow" | "green" | "purple";
|
||||
|
||||
export abstract class Character {
|
||||
public color: CharacterColor;
|
||||
public position: CharacterPosition;
|
||||
|
||||
public constructor(color: CharacterColor, startPosition: CharacterPosition) {
|
||||
public constructor(color: CharacterColor, startPosition: CharacterPosition = {x: 0, y: 0}) {
|
||||
this.color = color;
|
||||
this.position = startPosition;
|
||||
}
|
||||
|
@ -1,93 +0,0 @@
|
||||
import {Character, Ghost, PacMan} from "./character";
|
||||
|
||||
export default class TileMap {
|
||||
|
||||
/**
|
||||
* 0 = empty
|
||||
* 1 = wall
|
||||
* 2 = pellet
|
||||
* 3 = power pellet
|
||||
* 4 = ghost spawn
|
||||
* 5 = pacman spawn
|
||||
*/
|
||||
private map: number[][] = [
|
||||
[1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1],
|
||||
[1, 2, 0, 0, 0, 2, 0, 0, 0, 2, 1],
|
||||
[1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1],
|
||||
[1, 0, 1, 5, 1, 0, 1, 4, 1, 0, 1],
|
||||
[1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1],
|
||||
[0, 2, 0, 0, 0, 3, 0, 0, 0, 2, 0],
|
||||
[1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1],
|
||||
[1, 0, 1, 4, 1, 0, 1, 5, 1, 0, 1],
|
||||
[1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1],
|
||||
[1, 2, 0, 0, 0, 2, 0, 0, 0, 2, 1],
|
||||
[1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1],
|
||||
];
|
||||
|
||||
public characters: Character[] = [];
|
||||
|
||||
public constructor() {
|
||||
this.characters.push(new PacMan("yellow", {x: 3, y: 3}), new Ghost("blue", {x: 7, y: 3}));
|
||||
}
|
||||
|
||||
public draw(ctx: CanvasRenderingContext2D): void {
|
||||
this.drawMap(ctx);
|
||||
this.drawCharacters(ctx);
|
||||
}
|
||||
|
||||
private drawMap(context: CanvasRenderingContext2D): void {
|
||||
const tileSize = this.getTileSize(context);
|
||||
|
||||
for (let row = 0; row < this.map.length; row++) {
|
||||
for (let col = 0; col < this.map[row].length; col++) {
|
||||
|
||||
const tile = this.map[row][col];
|
||||
switch (tile) {
|
||||
case 0:
|
||||
this.drawTile(context, col * tileSize, row * tileSize, tileSize, "black");
|
||||
break;
|
||||
case 1:
|
||||
this.drawTile(context, col * tileSize, row * tileSize, tileSize, "blue");
|
||||
break;
|
||||
case 2:
|
||||
this.drawTile(context, col * tileSize, row * tileSize, tileSize, "yellow");
|
||||
break;
|
||||
case 3:
|
||||
this.drawTile(context, col * tileSize, row * tileSize, tileSize, "orange");
|
||||
break;
|
||||
case 4:
|
||||
this.drawTile(context, col * tileSize, row * tileSize, tileSize, "red");
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private drawTile(context: CanvasRenderingContext2D, x: number, y: number, tileSize: number, color: string): void {
|
||||
context.fillStyle = color;
|
||||
context.fillRect(x, y, tileSize, tileSize);
|
||||
}
|
||||
|
||||
private drawCharacters(ctx: CanvasRenderingContext2D): void {
|
||||
for (const character of this.characters) {
|
||||
this.drawCircle(ctx, character);
|
||||
}
|
||||
}
|
||||
|
||||
private drawCircle(ctx: CanvasRenderingContext2D, character: Character): void {
|
||||
const tileSize = this.getTileSize(ctx);
|
||||
const x = character.position.x * tileSize;
|
||||
const y = character.position.y * tileSize;
|
||||
ctx.fillStyle = character.color;
|
||||
ctx.beginPath();
|
||||
ctx.arc(x + tileSize / 2, y + tileSize / 2, tileSize / 2, tileSize / 2, 0.34 * Math.PI);
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
private getTileSize(context: CanvasRenderingContext2D): number {
|
||||
const canvasSize = context.canvas.width;
|
||||
return canvasSize / this.map[0].length;
|
||||
}
|
||||
}
|
@ -36,6 +36,8 @@
|
||||
<TypeScriptCompile Remove="ClientApp\src\components\Home.tsx" />
|
||||
<TypeScriptCompile Remove="ClientApp\src\pages\FetchData.tsx" />
|
||||
<TypeScriptCompile Remove="ClientApp\src\classes\tileMap.ts" />
|
||||
<TypeScriptCompile Remove="ClientApp\src\game\tileMap.ts" />
|
||||
<TypeScriptCompile Remove="ClientApp\src\components\gameCanvas.tsx" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="DebugEnsureNodeEnv" BeforeTargets="Build" Condition=" '$(Configuration)' == 'Debug' And !Exists('$(SpaRoot)node_modules') ">
|
||||
|
Loading…
x
Reference in New Issue
Block a user