fuzzyworld

dao-game / react-multiplayer / files / src / react / App-Remote.tsx

Branch react-multiplayer · default branch · all branches

App-Remote.tsx

5.2 KB · history · blame

1import * as React from 'react';
2import { useEffect, useState } from 'react';
3import { Coord } from '../game/coord';
4import { IGame, MoveResult } from '../game/game';
5import Modal from 'react-modal';
6import './App.css';
7import { Tile } from './Tile';
8import { Controls } from './Controls';
9import { delay } from '../utils/delay';
10import { Status } from './Status';
11import { PeerGame2 } from '../game/remote-game-2';
12import cursorUrl from '../../public/cursor.png';
13
14export type Props = {
15 game: PeerGame2;
16};
17
18export const AppRemote = (props: Props): React.ReactElement => {
19 const { game } = props;
20
21 const [selectedPiecePos, setSelectedPiecePos] = useState<Coord>()
22 const [validMoves, setValidMoves] = useState<Coord[]>([]);
23 const [currentPlayerId, setCurrentPlayerId] = useState<string>(game.currentPlayerId);
24 const [moveResult, setMoveResult] = useState<MoveResult>();
25 const [isModalOpen, setIsModalOpen] = useState(false);
26 const [isControlsDisabled, setIsControlsDisabled] = useState(!game.canUndoMove);
27 const [peerMousePos, setPeerMousePos] = useState<Coord>();
28
29 game.peerMousePositionCallback = (pos) => {
30 setPeerMousePos(pos);
31 }
32
33 useEffect((): void => {
34 const slowUpdate = async () => {
35 if (moveResult && moveResult.isTerminal) {
36 await delay(750);
37 setIsModalOpen(true);
38 }
39 };
40 slowUpdate();
41 }, [moveResult]);
42
43 const makeMove = async (from: Coord, to: Coord) => {
44 const result = await game.makeMove(from, to);
45 setCurrentPlayerId(game.currentPlayerId);
46 setSelectedPiecePos(undefined);
47 setValidMoves([]);
48 setMoveResult(result);
49 setIsControlsDisabled(false);
50 };
51 const undoMove = () => {
52 const move = game.undoMove();
53 console.debug({ move });
54 setCurrentPlayerId(game.currentPlayerId);
55 setSelectedPiecePos(undefined);
56 setValidMoves([]);
57 setMoveResult(undefined);
58 setIsControlsDisabled(!game.canUndoMove);
59 };
60
61 const allTiles: React.ReactElement[] = [];
62 for (let r = 0; r < game.size.row; r++) {
63 for (let c = 0; c < game.size.col; c++) {
64 const pos = new Coord(r, c);
65 const pieceClickCb = () => {
66 const isUnselectClick = selectedPiecePos !== undefined && selectedPiecePos.equals(pos);
67 if (isUnselectClick) {
68 setSelectedPiecePos(undefined);
69 setValidMoves([]);
70 } else {
71 setSelectedPiecePos(pos);
72 setValidMoves([...game.getValidMoves(pos)]);
73 }
74 };
75 const validMoveClickCb = async () => {
76 await makeMove(selectedPiecePos!, pos)
77 };
78 const tile =
79 <Tile
80 pos={pos}
81 game={game}
82 validMoves={validMoves}
83 selectedPiecePos={selectedPiecePos}
84 currentPlayerId={currentPlayerId}
85 pieceClickCb={() => pieceClickCb()}
86 validMoveClickCb={() => validMoveClickCb()}
87 />;
88 allTiles.push(tile);
89 }
90 }
91
92 const divRef = React.createRef<HTMLDivElement>();
93 return (<>
94 <div
95 ref={divRef}
96 onMouseMove={(ev) => {
97 const div = divRef.current!;
98 const xTable = ev.clientX - div.offsetLeft;
99 const yTable = ev.clientY - div.offsetTop;
100 const xRatio = xTable / div.clientWidth;
101 const yRatio = yTable / div.clientHeight;
102 game.onMouseMoveCallback(new Coord(xRatio, yRatio));
103 }}>
104 <Status
105 currentPlayerId={currentPlayerId}
106 player1Id={game.player1Id}
107 player1Name={game.player1Name}
108 player2Id={game.player2Id}
109 player2Name={game.player2Name}
110 />
111 <div className='grid-container'>
112 {allTiles}
113 </div>
114 <Controls onUndo={undoMove} isDisabled={isControlsDisabled} />
115 <div className='info'>
116 The game consists of only one simple rule and three ways to win. Rules:
117 <ul>
118 <li>Pieces move in a straight line, including diagonally, as far as possible with no jumps.</li>
119 </ul>
120 Ways to win:
121 <ol>
122 <li>Arrange your pieces in a straight line on the board (not diagonally)</li>
123 <li>Occupy four corners of the board</li>
124 <li>Form a 2x2 square anywhere on the board</li>
125 </ol>
126 </div>
127 <Modal isOpen={isModalOpen} className='modal'>
128 <h2>Game Over</h2>
129 <div>
130 {moveResult?.message}
131 </div>
132 <div>
133 <button onClick={() => location.reload()}>
134 Restart game
135 </button>
136 </div>
137 </Modal>
138 </div>
139 <div className='other-mouse'>
140 <img src={cursorUrl} />
141 </div>
142 </>);
143}