Implement special dice usage and layout
parent
eedbf3d9f4
commit
8bbc6e1f62
|
|
@ -12,5 +12,6 @@ h1 {
|
||||||
.right-panel {
|
.right-panel {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
padding: 50px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import GameBoard from "./components/GameBoard";
|
||||||
import DiceSet from "./components/DiceSet";
|
import DiceSet from "./components/DiceSet";
|
||||||
import "./GamePage.scss";
|
import "./GamePage.scss";
|
||||||
import { PieceId } from "interface";
|
import { PieceId } from "interface";
|
||||||
|
import { DieViewProps } from "./types/DieViewProps";
|
||||||
|
|
||||||
const GamePage = () => {
|
const GamePage = () => {
|
||||||
const getRandomPieceId = () => {
|
const getRandomPieceId = () => {
|
||||||
|
|
@ -12,22 +13,80 @@ const GamePage = () => {
|
||||||
|
|
||||||
const [dice, setDice] = useState(
|
const [dice, setDice] = useState(
|
||||||
[1, 2, 3, 4].map(() => {
|
[1, 2, 3, 4].map(() => {
|
||||||
return {
|
const dieViewProps: DieViewProps = {
|
||||||
pieceId: getRandomPieceId(),
|
pieceId: getRandomPieceId(),
|
||||||
isSelected: false,
|
isSelected: false,
|
||||||
isDisabled: false,
|
isDisabled: false,
|
||||||
|
isSpecial: false,
|
||||||
|
rotation: 0,
|
||||||
|
};
|
||||||
|
return dieViewProps;
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
const [specialDice, setSpecialDice] = useState(
|
||||||
|
[
|
||||||
|
PieceId.P03,
|
||||||
|
PieceId.P08,
|
||||||
|
PieceId.P13,
|
||||||
|
PieceId.P14,
|
||||||
|
PieceId.P15,
|
||||||
|
PieceId.P19,
|
||||||
|
].map((pieceId) => {
|
||||||
|
return {
|
||||||
|
pieceId: pieceId,
|
||||||
|
isSelected: false,
|
||||||
|
isDisabled: false,
|
||||||
|
isSpecial: true,
|
||||||
rotation: 0,
|
rotation: 0,
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
const [specialDieUsedInRound, setSpecialDieUsedInRound] = useState(false);
|
||||||
|
|
||||||
|
const modifyDieState = (
|
||||||
|
matcher: (die: DieViewProps) => boolean,
|
||||||
|
newStateComputer: (die: DieViewProps) => Partial<DieViewProps>,
|
||||||
|
) => {
|
||||||
|
setDice(
|
||||||
|
dice.map((die) => {
|
||||||
|
if (!matcher(die)) return die;
|
||||||
|
return {
|
||||||
|
...die,
|
||||||
|
...newStateComputer(die),
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
setSpecialDice(
|
||||||
|
specialDice.map((die) => {
|
||||||
|
if (!matcher(die)) return die;
|
||||||
|
return {
|
||||||
|
...die,
|
||||||
|
...newStateComputer(die),
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchDie = (matcher: (die: DieViewProps) => boolean) => {
|
||||||
|
return dice.concat(specialDice).find((die) => matcher(die));
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<h1>Game Page Title</h1>
|
<h1>Game Page Title</h1>
|
||||||
<div className="game-panel">
|
<div className="game-panel">
|
||||||
<GameBoard dice={dice} setDice={setDice} />
|
<GameBoard
|
||||||
<div className="rigth-panel">
|
modifyDieState={modifyDieState}
|
||||||
<DiceSet dice={dice} setDice={setDice} />
|
fetchDie={fetchDie}
|
||||||
|
setSpecialDieUsedInRound={setSpecialDieUsedInRound}
|
||||||
|
/>
|
||||||
|
<div className="right-panel">
|
||||||
|
<DiceSet
|
||||||
|
dice={dice}
|
||||||
|
specialDice={specialDice}
|
||||||
|
modifyDieState={modifyDieState}
|
||||||
|
specialDieUsedInRound={specialDieUsedInRound}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
|
|
|
||||||
|
|
@ -1,33 +1,32 @@
|
||||||
import { Cell, CellType, directions, Exit, PieceId } from "interface";
|
import { Cell, CellType, directions, Exit } from "interface";
|
||||||
import "./BoardCell.scss";
|
import "./BoardCell.scss";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
import { DieViewProps } from "../types/DieViewProps";
|
||||||
|
|
||||||
export interface BoardCellProps {
|
export interface BoardCellProps {
|
||||||
cell: Cell;
|
cell: Cell;
|
||||||
dice: {
|
|
||||||
pieceId: PieceId;
|
|
||||||
isSelected: boolean;
|
|
||||||
isDisabled: boolean;
|
|
||||||
rotation: number;
|
|
||||||
}[];
|
|
||||||
setDice: React.Dispatch<
|
|
||||||
React.SetStateAction<
|
|
||||||
{
|
|
||||||
pieceId: PieceId;
|
|
||||||
isSelected: boolean;
|
|
||||||
isDisabled: boolean;
|
|
||||||
rotation: number;
|
|
||||||
}[]
|
|
||||||
>
|
|
||||||
>;
|
|
||||||
refreshBoardRender: () => void;
|
refreshBoardRender: () => void;
|
||||||
|
modifyDieState: (
|
||||||
|
matcher: (die: DieViewProps) => boolean,
|
||||||
|
newStateComputer: (die: DieViewProps) => Partial<DieViewProps>,
|
||||||
|
) => void;
|
||||||
|
fetchDie: (
|
||||||
|
matcher: (die: DieViewProps) => boolean,
|
||||||
|
) => DieViewProps | undefined;
|
||||||
|
setSpecialDieUsedInRound: React.Dispatch<React.SetStateAction<boolean>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const BoardCell = (props: BoardCellProps) => {
|
const BoardCell = (props: BoardCellProps) => {
|
||||||
const { cell, dice, setDice, refreshBoardRender } = props;
|
const {
|
||||||
|
cell,
|
||||||
|
refreshBoardRender,
|
||||||
|
modifyDieState,
|
||||||
|
fetchDie,
|
||||||
|
setSpecialDieUsedInRound,
|
||||||
|
} = props;
|
||||||
const [pieceRotationAngle, setPieceRotationAngle] = useState(0);
|
const [pieceRotationAngle, setPieceRotationAngle] = useState(0);
|
||||||
const handleBoardCellClick = () => {
|
const handleBoardCellClick = () => {
|
||||||
const selectedDie = dice.find((die) => die.isSelected);
|
const selectedDie = fetchDie((die) => die.isSelected);
|
||||||
if (!selectedDie) return;
|
if (!selectedDie) return;
|
||||||
try {
|
try {
|
||||||
cell.placePiece(
|
cell.placePiece(
|
||||||
|
|
@ -38,17 +37,17 @@ const BoardCell = (props: BoardCellProps) => {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setDice(
|
modifyDieState(
|
||||||
dice.map((die) => {
|
(die) => die === selectedDie,
|
||||||
return die !== selectedDie
|
() => {
|
||||||
? die
|
return {
|
||||||
: {
|
isSelected: false,
|
||||||
...selectedDie,
|
isDisabled: true,
|
||||||
isSelected: false,
|
};
|
||||||
isDisabled: true,
|
},
|
||||||
};
|
|
||||||
}),
|
|
||||||
);
|
);
|
||||||
|
if (selectedDie.isSpecial) setSpecialDieUsedInRound(true);
|
||||||
|
// Set rotation to the piece in the board, not the die
|
||||||
setPieceRotationAngle(selectedDie.rotation);
|
setPieceRotationAngle(selectedDie.rotation);
|
||||||
refreshBoardRender();
|
refreshBoardRender();
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,8 @@
|
||||||
.dice-set-actions {
|
.dice-set-actions {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
padding: 50px 50px 0;
|
|
||||||
width: max-content;
|
width: max-content;
|
||||||
margin: auto;
|
margin: auto auto 50px auto;
|
||||||
|
|
||||||
img {
|
img {
|
||||||
border: 3px solid green;
|
border: 3px solid green;
|
||||||
|
|
@ -24,5 +23,14 @@
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(2, auto);
|
grid-template-columns: repeat(2, auto);
|
||||||
gap: 20px;
|
gap: 20px;
|
||||||
padding: 50px;
|
margin: 0 0 50px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.special-dice-set {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, auto);
|
||||||
|
margin: 0 0 50px 0;
|
||||||
|
column-gap: 12%;
|
||||||
|
row-gap: 20px;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
@ -1,55 +1,42 @@
|
||||||
import { PieceId } from "interface";
|
|
||||||
import "./DiceSet.scss";
|
import "./DiceSet.scss";
|
||||||
import Die from "./Die";
|
import Die from "./Die";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
import { DieViewProps } from "../types/DieViewProps";
|
||||||
|
|
||||||
export interface DiceSetProps {
|
export interface DiceSetProps {
|
||||||
dice: {
|
dice: DieViewProps[];
|
||||||
pieceId: PieceId;
|
specialDice: DieViewProps[];
|
||||||
isSelected: boolean;
|
modifyDieState: (
|
||||||
isDisabled: boolean;
|
matcher: (die: DieViewProps) => boolean,
|
||||||
rotation: number;
|
newStateComputer: (die: DieViewProps) => Partial<DieViewProps>,
|
||||||
}[];
|
) => void;
|
||||||
setDice: React.Dispatch<
|
specialDieUsedInRound: boolean;
|
||||||
React.SetStateAction<
|
|
||||||
{
|
|
||||||
pieceId: PieceId;
|
|
||||||
isSelected: boolean;
|
|
||||||
isDisabled: boolean;
|
|
||||||
rotation: number;
|
|
||||||
}[]
|
|
||||||
>
|
|
||||||
>;
|
|
||||||
}
|
}
|
||||||
const DiceSet = (props: DiceSetProps) => {
|
const DiceSet = (props: DiceSetProps) => {
|
||||||
const { dice, setDice } = props;
|
const { dice, specialDice, modifyDieState, specialDieUsedInRound } = props;
|
||||||
const handleDieClick = (die: {
|
const handleDieClick = (clickedDie: DieViewProps) => {
|
||||||
pieceId: PieceId;
|
if (clickedDie.isDisabled) return;
|
||||||
isSelected: boolean;
|
const isSpecialDie = clickedDie.isSpecial;
|
||||||
isDisabled: boolean;
|
if (isSpecialDie && specialDieUsedInRound) return;
|
||||||
rotation: number;
|
modifyDieState(
|
||||||
}) => {
|
() => true,
|
||||||
if (die.isDisabled) return;
|
(die) => {
|
||||||
const newDiceState = dice.map((oldDie) => {
|
return {
|
||||||
const isSelected = die === oldDie;
|
isSelected: die === clickedDie,
|
||||||
return {
|
};
|
||||||
...oldDie,
|
},
|
||||||
isSelected: isSelected,
|
);
|
||||||
};
|
|
||||||
});
|
|
||||||
setDice(newDiceState);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleRotateButton = (rotation: number) => {
|
const handleRotateButton = (rotation: number) => {
|
||||||
const newDiceState = dice.map((die) => {
|
modifyDieState(
|
||||||
if (!die.isSelected) return die;
|
(die) => die.isSelected,
|
||||||
const rotationAngle = (die.rotation + rotation + 360) % 360;
|
(die) => {
|
||||||
return {
|
return {
|
||||||
...die,
|
rotation: (die.rotation + rotation + 360) % 360,
|
||||||
rotation: rotationAngle,
|
};
|
||||||
};
|
},
|
||||||
});
|
);
|
||||||
setDice(newDiceState);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
@ -70,6 +57,11 @@ const DiceSet = (props: DiceSetProps) => {
|
||||||
<Die die={die} handleDieClick={handleDieClick} />
|
<Die die={die} handleDieClick={handleDieClick} />
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
<div className="special-dice-set">
|
||||||
|
{specialDice.map((die) => (
|
||||||
|
<Die die={die} handleDieClick={handleDieClick} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -30,3 +30,8 @@
|
||||||
|
|
||||||
transition: transform 0.5s cubic-bezier(.47,1.64,.41,.8);
|
transition: transform 0.5s cubic-bezier(.47,1.64,.41,.8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.special-dice-set .dice {
|
||||||
|
height: 80px;
|
||||||
|
width: 80px;
|
||||||
|
}
|
||||||
|
|
@ -1,19 +1,9 @@
|
||||||
import { PieceId } from "interface";
|
|
||||||
import "./Die.scss";
|
import "./Die.scss";
|
||||||
|
import { DieViewProps } from "../types/DieViewProps";
|
||||||
|
|
||||||
interface DieProps {
|
interface DieProps {
|
||||||
die: {
|
die: DieViewProps;
|
||||||
pieceId: PieceId;
|
handleDieClick: (die: DieViewProps) => void;
|
||||||
isSelected: boolean;
|
|
||||||
isDisabled: boolean;
|
|
||||||
rotation: number;
|
|
||||||
};
|
|
||||||
handleDieClick: (die: {
|
|
||||||
pieceId: PieceId;
|
|
||||||
isSelected: boolean;
|
|
||||||
isDisabled: boolean;
|
|
||||||
rotation: number;
|
|
||||||
}) => void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const Die = (props: DieProps) => {
|
const Die = (props: DieProps) => {
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,18 @@
|
||||||
import { buildBoard, PieceId } from "interface";
|
import { buildBoard } from "interface";
|
||||||
import "./GameBoard.scss";
|
import "./GameBoard.scss";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import BoardCell from "./BoardCell";
|
import BoardCell from "./BoardCell";
|
||||||
|
import { DieViewProps } from "../types/DieViewProps";
|
||||||
|
|
||||||
export interface GameBoardProps {
|
export interface GameBoardProps {
|
||||||
dice: {
|
modifyDieState: (
|
||||||
pieceId: PieceId;
|
matcher: (die: DieViewProps) => boolean,
|
||||||
isSelected: boolean;
|
newStateComputer: (die: DieViewProps) => Partial<DieViewProps>,
|
||||||
isDisabled: boolean;
|
) => void;
|
||||||
rotation: number;
|
fetchDie: (
|
||||||
}[];
|
matcher: (die: DieViewProps) => boolean,
|
||||||
setDice: React.Dispatch<
|
) => DieViewProps | undefined;
|
||||||
React.SetStateAction<
|
setSpecialDieUsedInRound: React.Dispatch<React.SetStateAction<boolean>>;
|
||||||
{
|
|
||||||
pieceId: PieceId;
|
|
||||||
isSelected: boolean;
|
|
||||||
isDisabled: boolean;
|
|
||||||
rotation: number;
|
|
||||||
}[]
|
|
||||||
>
|
|
||||||
>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const GameBoard = (props: GameBoardProps) => {
|
const GameBoard = (props: GameBoardProps) => {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
import { PieceId } from "interface";
|
||||||
|
|
||||||
|
export interface DieViewProps {
|
||||||
|
pieceId: PieceId;
|
||||||
|
isSelected: boolean;
|
||||||
|
isDisabled: boolean;
|
||||||
|
isSpecial: boolean;
|
||||||
|
rotation: number;
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue