diff --git a/backend/controllers/roomController.js b/backend/controllers/roomController.js
index 80a36ac..8a5bf2a 100644
--- a/backend/controllers/roomController.js
+++ b/backend/controllers/roomController.js
@@ -23,14 +23,8 @@ const createNewRoom = data => {
return room;
};
-const findPlayer = async sessionID => {
- const player = await Room.findOne({ 'players.sessionID': sessionID }).exec();
- console.log(player);
- return await Room.findOne({ 'players.sessionID': sessionID }).exec();
-};
-
Room.watch().on('change', async data => {
sendToPlayersData(await getRoom(data.documentKey._id));
});
-module.exports = { getRoom, getRooms, updateRoom, getJoinableRoom, createNewRoom, findPlayer };
+module.exports = { getRoom, getRooms, updateRoom, getJoinableRoom, createNewRoom };
diff --git a/backend/handlers/gameHandler.js b/backend/handlers/gameHandler.js
index a13ff04..9ef9315 100644
--- a/backend/handlers/gameHandler.js
+++ b/backend/handlers/gameHandler.js
@@ -1,6 +1,5 @@
const { getRoom, updateRoom } = require('../controllers/roomController');
const { sendToPlayersRolledNumber } = require('../socket/emits');
-const { getPawnPositionAfterMove } = require('../utils/functions');
const { rollDice, isMoveValid } = require('./handlersFunctions');
module.exports = socket => {
@@ -10,7 +9,7 @@ module.exports = socket => {
const room = await getRoom(req.session.roomId);
const pawn = room.getPawn(pawnId);
if (isMoveValid(req.session, pawn, room)) {
- const newPositionOfMovedPawn = getPawnPositionAfterMove(room.rolledNumber, pawn);
+ const newPositionOfMovedPawn = pawn.getPositionAfterMove(room.rolledNumber);
room.changePositionOfPawn(pawn, newPositionOfMovedPawn);
room.beatPawns(newPositionOfMovedPawn, req.session.color);
room.changeMovingPlayer();
diff --git a/backend/handlers/roomHandler.js b/backend/handlers/roomHandler.js
index bee90de..f99324c 100644
--- a/backend/handlers/roomHandler.js
+++ b/backend/handlers/roomHandler.js
@@ -1,5 +1,5 @@
const { getRooms, getRoom, updateRoom, createNewRoom } = require('../controllers/roomController');
-const { sendToOnePlayerRooms, sendToOnePlayerData, sendToPlayersData } = require('../socket/emits');
+const { sendToOnePlayerRooms, sendToOnePlayerData } = require('../socket/emits');
module.exports = socket => {
const req = socket.request;
diff --git a/backend/models/pawn.js b/backend/models/pawn.js
index 3df2429..2680cad 100644
--- a/backend/models/pawn.js
+++ b/backend/models/pawn.js
@@ -2,8 +2,6 @@ const mongoose = require('mongoose');
const Schema = mongoose.Schema;
-const { getPawnPositionAfterMove } = require('../utils/functions');
-
const PawnSchema = new Schema({
color: String,
basePos: Number,
@@ -15,10 +13,70 @@ PawnSchema.methods.canMove = function (rolledNumber) {
return true;
}
// (if player's pawn is near finish line) if the move does not go beyond the win line
- if (this.position !== getPawnPositionAfterMove(rolledNumber, this) && this.position !== this.basePos) {
+ if (this.position !== this.getPositionAfterMove(rolledNumber) && this.position !== this.basePos) {
return true;
}
return false;
};
+PawnSchema.methods.getPositionAfterMove = function (rolledNumber) {
+ const { position, color } = this;
+ switch (color) {
+ case 'red':
+ if (position + rolledNumber <= 73) {
+ if (position >= 0 && position <= 3) {
+ return 16;
+ } else if (position <= 66 && position + rolledNumber >= 67) {
+ return position + rolledNumber + 1;
+ } else {
+ return position + rolledNumber;
+ }
+ } else {
+ return position;
+ }
+ case 'blue':
+ if (position + rolledNumber <= 79) {
+ if (position >= 4 && position <= 7) {
+ return 55;
+ } else if (position <= 67 && position + rolledNumber > 67) {
+ return position + rolledNumber - 52;
+ } else if (position <= 53 && position + rolledNumber >= 54) {
+ return position + rolledNumber + 20;
+ } else {
+ return position + rolledNumber;
+ }
+ } else {
+ return position;
+ }
+ case 'green':
+ if (position + rolledNumber <= 85) {
+ if (position >= 8 && position <= 11) {
+ return 42;
+ } else if (position <= 67 && position + rolledNumber > 67) {
+ return position + rolledNumber - 52;
+ } else if (position <= 40 && position + rolledNumber >= 41) {
+ return position + rolledNumber + 39;
+ } else {
+ return position + rolledNumber;
+ }
+ } else {
+ return position;
+ }
+ case 'yellow':
+ if (position + rolledNumber <= 85) {
+ if (position >= 12 && position <= 15) {
+ return 29;
+ } else if (position <= 67 && position + rolledNumber > 67) {
+ return position + rolledNumber - 52;
+ } else if (position <= 27 && position + rolledNumber >= 28) {
+ return position + rolledNumber + 58;
+ } else {
+ return position + rolledNumber;
+ }
+ } else {
+ return position;
+ }
+ }
+};
+
module.exports = PawnSchema;
diff --git a/backend/models/room.js b/backend/models/room.js
index 2c7ca34..8c3f25a 100644
--- a/backend/models/room.js
+++ b/backend/models/room.js
@@ -1,6 +1,5 @@
const mongoose = require('mongoose');
const { colors } = require('../utils/constants');
-const { getPawnPositionAfterMove, getStartPositions } = require('../utils/functions');
const { makeRandomMove } = require('../handlers/handlersFunctions');
const PawnSchema = require('./pawn');
const PlayerSchema = require('./player');
@@ -16,7 +15,23 @@ const RoomSchema = new mongoose.Schema({
timeoutID: Number,
rolledNumber: Number,
players: [PlayerSchema],
- pawns: { type: [PawnSchema], default: getStartPositions() },
+ pawns: {
+ type: [PawnSchema],
+ default: () => {
+ const startPositions = [];
+ for (let i = 0; i < 16; i++) {
+ let pawn = {};
+ pawn.basePos = i;
+ pawn.position = i;
+ if (i < 4) pawn.color = colors[0];
+ else if (i < 8) pawn.color = colors[1];
+ else if (i < 12) pawn.color = colors[2];
+ else if (i < 16) pawn.color = colors[3];
+ startPositions.push(pawn);
+ }
+ return startPositions;
+ },
+ },
});
RoomSchema.methods.beatPawns = function (position, attackingPawnColor) {
@@ -44,7 +59,7 @@ RoomSchema.methods.changeMovingPlayer = function () {
};
RoomSchema.methods.movePawn = function (pawn) {
- const newPositionOfMovedPawn = getPawnPositionAfterMove(this.rolledNumber, pawn);
+ const newPositionOfMovedPawn = pawn.getPositionAfterMove(this.rolledNumber);
this.changePositionOfPawn(pawn, newPositionOfMovedPawn);
this.beatPawns(newPositionOfMovedPawn, pawn.color);
};
diff --git a/src/App.js b/src/App.js
index 770998b..6853ef8 100644
--- a/src/App.js
+++ b/src/App.js
@@ -2,7 +2,7 @@ import React, { useEffect, useState, createContext } from 'react';
import { io } from 'socket.io-client';
import { BrowserRouter as Router, Route, Redirect, Switch } from 'react-router-dom';
import ReactLoading from 'react-loading';
-import Gameboard from './components/Gameboard';
+import Gameboard from './components/Gameboard/Gameboard';
import LoginPage from './components/LoginPage/LoginPage';
export const PlayerDataContext = createContext();
diff --git a/src/components/game-board-components/Dice.jsx b/src/components/Gameboard/Dice/Dice.jsx
similarity index 62%
rename from src/components/game-board-components/Dice.jsx
rename to src/components/Gameboard/Dice/Dice.jsx
index b18131e..98a0751 100644
--- a/src/components/game-board-components/Dice.jsx
+++ b/src/components/Gameboard/Dice/Dice.jsx
@@ -1,24 +1,28 @@
-import React, { useState, useEffect, useContext } from 'react';
-import { SocketContext } from '../../App';
-import one from '../../images/dice/1.png';
-import two from '../../images/dice/2.png';
-import three from '../../images/dice/3.png';
-import four from '../../images/dice/4.png';
-import five from '../../images/dice/5.png';
-import six from '../../images/dice/6.png';
-import roll from '../../images/dice/roll.png';
+import React, { useEffect, useContext } from 'react';
+import { SocketContext } from '../../../App';
+import one from '../../../images/dice/1.png';
+import two from '../../../images/dice/2.png';
+import three from '../../../images/dice/3.png';
+import four from '../../../images/dice/4.png';
+import five from '../../../images/dice/5.png';
+import six from '../../../images/dice/6.png';
+import roll from '../../../images/dice/roll.png';
const Dice = ({ rolledNumberCallback, rolledNumber, nowMoving, color, movingPlayer }) => {
const socket = useContext(SocketContext);
- const [images] = useState([one, two, three, four, five, six, roll]);
+
+ const images = [one, two, three, four, five, six, roll];
+
const handleRoll = () => {
socket.emit('game:roll');
};
+
useEffect(() => {
socket.on('game:roll', number => {
rolledNumberCallback(number);
});
}, []);
+
return (
{movingPlayer === color ? (
diff --git a/src/components/Gameboard.jsx b/src/components/Gameboard/Gameboard.jsx
similarity index 88%
rename from src/components/Gameboard.jsx
rename to src/components/Gameboard/Gameboard.jsx
index e0764d9..45f7ae8 100644
--- a/src/components/Gameboard.jsx
+++ b/src/components/Gameboard/Gameboard.jsx
@@ -1,17 +1,16 @@
-import React, { useState, useEffect, useContext, useCallback } from 'react';
+import React, { useState, useEffect, useContext } from 'react';
import ReactLoading from 'react-loading';
-import { PlayerDataContext, SocketContext } from '../App';
-import Map from './game-board-components/Map';
-import Navbar from './Navbar';
+import { PlayerDataContext, SocketContext } from '../../App';
+import Map from './Map/Map';
+import Navbar from '../Navbar/Navbar';
const Gameboard = () => {
- // Context data
const socket = useContext(SocketContext);
const context = useContext(PlayerDataContext);
- // Render data
+
const [pawns, setPawns] = useState([]);
const [players, setPlayers] = useState([]);
- // Game logic data
+
const [rolledNumber, setRolledNumber] = useState(null);
const [time, setTime] = useState();
const [isReady, setIsReady] = useState();
@@ -19,7 +18,8 @@ const Gameboard = () => {
const [started, setStarted] = useState(false);
const [movingPlayer, setMovingPlayer] = useState('red');
- const checkWin = useCallback(() => {
+
+ const checkWin = () => {
// Player wins when all pawns with same color are inside end base
if (pawns.filter(pawn => pawn.color === 'red' && pawn.position === 73).length === 4) {
alert('Red Won');
@@ -30,7 +30,8 @@ const Gameboard = () => {
} else if (pawns.filter(pawn => pawn.color === 'yellow' && pawn.position === 91).length === 4) {
alert('Yellow Won');
}
- }, [pawns]);
+ };
+
useEffect(() => {
socket.emit('room:data', context.roomId);
socket.on('room:data', data => {
@@ -59,9 +60,8 @@ const Gameboard = () => {
setTime(data.nextMoveTime);
setStarted(data.started);
});
- }, []);
+ }, [socket]);
- // Callback to handle dice rolling between dice and map component
const rolledNumberCallback = number => {
setRolledNumber(number);
};
diff --git a/src/components/Gameboard/Map/Map.jsx b/src/components/Gameboard/Map/Map.jsx
new file mode 100644
index 0000000..1af250e
--- /dev/null
+++ b/src/components/Gameboard/Map/Map.jsx
@@ -0,0 +1,111 @@
+import React, { useEffect, useRef, useState, useContext } from 'react';
+import { PlayerDataContext, SocketContext } from '../../../App';
+
+import mapImage from '../../../images/map.jpg';
+import positions from '../positions';
+import pawnImages from '../../../constants/pawnImages';
+import canPawnMove from './canPawnMove';
+import getPositionAfterMove from './getPositionAfterMove';
+
+const Map = ({ pawns, nowMoving, rolledNumber }) => {
+ const player = useContext(PlayerDataContext);
+ const socket = useContext(SocketContext);
+ const canvasRef = useRef(null);
+
+ const [hintPawn, setHintPawn] = useState();
+
+ const paintPawn = (context, x, y, color) => {
+ const touchableArea = new Path2D();
+ touchableArea.arc(x, y, 12, 0, 2 * Math.PI);
+ const image = new Image();
+ image.src = pawnImages[color];
+ image.onload = function () {
+ context.drawImage(image, x - 17, y - 14, 35, 30);
+ };
+ return touchableArea;
+ };
+
+ const handleCanvasClick = event => {
+ if (hintPawn) {
+ const canvas = canvasRef.current;
+ const ctx = canvas.getContext('2d');
+ const rect = canvas.getBoundingClientRect(),
+ cursorX = event.clientX - rect.left,
+ cursorY = event.clientY - rect.top;
+ for (const pawn of pawns) {
+ if (ctx.isPointInPath(pawn.touchableArea, cursorX, cursorY)) {
+ socket.emit('game:move', pawn._id);
+ }
+ }
+ setHintPawn(null);
+ }
+ };
+
+ const handleMouseMove = event => {
+ if (nowMoving && rolledNumber) {
+ const canvas = canvasRef.current;
+ const ctx = canvas.getContext('2d');
+ const rect = canvas.getBoundingClientRect(),
+ x = event.clientX - rect.left,
+ y = event.clientY - rect.top;
+ canvas.style.cursor = 'default';
+ for (const pawn of pawns) {
+ if (pawn.touchableArea) {
+ if (
+ ctx.isPointInPath(pawn.touchableArea, x, y) &&
+ player.color === pawn.color &&
+ canPawnMove(pawn, rolledNumber)
+ ) {
+ const pawnPosition = getPositionAfterMove(pawn, rolledNumber);
+ if (pawnPosition) {
+ canvas.style.cursor = 'pointer';
+ setHintPawn({ id: pawn._id, position: pawnPosition, color: 'grey' });
+ break;
+ }
+ } else {
+ setHintPawn(null);
+ }
+ } else {
+ setHintPawn(null);
+ }
+ }
+ } else {
+ setHintPawn(null);
+ }
+ };
+ const rerenderCanvas = () => {
+ const canvas = canvasRef.current;
+ const ctx = canvas.getContext('2d');
+ const image = new Image();
+ image.src = mapImage;
+ image.onload = function () {
+ ctx.drawImage(image, 0, 0);
+ pawns.forEach((pawn, index) => {
+ pawns[index].touchableArea = paintPawn(
+ ctx,
+ positions[pawn.position].x,
+ positions[pawn.position].y,
+ pawn.color
+ );
+ });
+ if (hintPawn) {
+ paintPawn(ctx, positions[hintPawn.position].x, positions[hintPawn.position].y, hintPawn.color);
+ }
+ };
+ };
+ useEffect(() => {
+ rerenderCanvas();
+ }, [hintPawn, pawns, rerenderCanvas]);
+
+ return (
+
+ );
+};
+export default Map;
diff --git a/src/components/Gameboard/Map/canPawnMove.js b/src/components/Gameboard/Map/canPawnMove.js
new file mode 100644
index 0000000..1a5de63
--- /dev/null
+++ b/src/components/Gameboard/Map/canPawnMove.js
@@ -0,0 +1,26 @@
+export default (pawn, rolledNumber) => {
+ // If is in base
+ if ((rolledNumber === 1 || rolledNumber === 6) && pawn.position === pawn.basePos) {
+ return true;
+ // Other situations: pawn is on map or pawn is in end positions
+ } else if (pawn.position !== pawn.basePos) {
+ switch (pawn.color) {
+ case 'red':
+ if (pawn.position + rolledNumber <= 73) return true;
+ break;
+ case 'blue':
+ if (pawn.position + rolledNumber <= 79) return true;
+ break;
+ case 'green':
+ if (pawn.position + rolledNumber <= 85) return true;
+ break;
+ case 'yellow':
+ if (pawn.position + rolledNumber <= 91) return true;
+ break;
+ default:
+ return false;
+ }
+ } else {
+ return false;
+ }
+};
diff --git a/backend/utils/functions.js b/src/components/Gameboard/Map/getPositionAfterMove.js
similarity index 79%
rename from backend/utils/functions.js
rename to src/components/Gameboard/Map/getPositionAfterMove.js
index 81f5522..6b403ca 100644
--- a/backend/utils/functions.js
+++ b/src/components/Gameboard/Map/getPositionAfterMove.js
@@ -1,19 +1,4 @@
-const { colors } = require('./constants');
-function getStartPositions() {
- const startPositions = [];
- for (let i = 0; i < 16; i++) {
- let pawn = {};
- pawn.basePos = i;
- pawn.position = i;
- if (i < 4) pawn.color = colors[0];
- else if (i < 8) pawn.color = colors[1];
- else if (i < 12) pawn.color = colors[2];
- else if (i < 16) pawn.color = colors[3];
- startPositions.push(pawn);
- }
- return startPositions;
-}
-function getPawnPositionAfterMove(rolledNumber, pawn) {
+export default (pawn, rolledNumber) => {
const { position, color } = pawn;
switch (color) {
case 'red':
@@ -71,5 +56,4 @@ function getPawnPositionAfterMove(rolledNumber, pawn) {
return position;
}
}
-}
-module.exports = { getStartPositions, getPawnPositionAfterMove };
+};
diff --git a/src/components/game-board-components/positions.js b/src/components/Gameboard/positions.js
similarity index 100%
rename from src/components/game-board-components/positions.js
rename to src/components/Gameboard/positions.js
diff --git a/src/components/LoginPage/AddServer/AddServer.jsx b/src/components/LoginPage/AddServer/AddServer.jsx
index 054bf54..4333c50 100644
--- a/src/components/LoginPage/AddServer/AddServer.jsx
+++ b/src/components/LoginPage/AddServer/AddServer.jsx
@@ -10,7 +10,6 @@ const AddServer = () => {
useEffect(() => {
socket.on('room:created', () => {
- console.log('ewa');
socket.emit('room:rooms');
});
}, []);
diff --git a/src/components/LoginPage/NameInput/NameInput.jsx b/src/components/LoginPage/NameInput/NameInput.jsx
index e1212e4..307518a 100644
--- a/src/components/LoginPage/NameInput/NameInput.jsx
+++ b/src/components/LoginPage/NameInput/NameInput.jsx
@@ -1,13 +1,14 @@
import React, { useState, useContext, useEffect } from 'react';
import { SocketContext } from '../../../App';
+import useInput from '../../../hooks/useInput';
import './NameInput.css';
const NameInput = ({ isRoomPrivate, roomId }) => {
const socket = useContext(SocketContext);
- const [nickname, setNickname] = useState('');
- const [password, setPassword] = useState('');
+ const nickname = useInput('');
+ const password = useInput('');
const [isPasswordWrong, setIsPasswordWrong] = useState(false);
const handleButtonClick = () => {
- socket.emit('player:login', { name: nickname, password: password, roomId: roomId });
+ socket.emit('player:login', { name: nickname.value, password: password.value, roomId: roomId });
};
useEffect(() => {
socket.on('error:wrongPassword', () => {
@@ -28,12 +29,12 @@ const NameInput = ({ isRoomPrivate, roomId }) => {
return (
- {joining ? (
-
- ) : null}
+ {joining ?
: null}
);
};
diff --git a/src/components/navbar-components/AnimatedOverlay.jsx b/src/components/Navbar/NameContainer/AnimatedOverlay/AnimatedOverlay.jsx
similarity index 67%
rename from src/components/navbar-components/AnimatedOverlay.jsx
rename to src/components/Navbar/NameContainer/AnimatedOverlay/AnimatedOverlay.jsx
index 5fc82fa..ba0558a 100644
--- a/src/components/navbar-components/AnimatedOverlay.jsx
+++ b/src/components/Navbar/NameContainer/AnimatedOverlay/AnimatedOverlay.jsx
@@ -1,13 +1,9 @@
-import React, { useState, useEffect } from 'react';
+import React, { useMemo } from 'react';
import { CSSTransition } from 'react-transition-group';
import './TimerAnimation.js';
const AnimatedOverlay = ({ time }) => {
- const [animationDelay, setAnimationDelay] = useState();
-
- useEffect(() => {
- setAnimationDelay(15 - Math.ceil((time - Date.now()) / 1000));
- }, [time]);
+ const animationDelay = useMemo(() => 15 - Math.ceil((time - Date.now()) / 1000), [time]);
return (
{
return (
diff --git a/src/components/Navbar.css b/src/components/Navbar/Navbar.css
similarity index 100%
rename from src/components/Navbar.css
rename to src/components/Navbar/Navbar.css
diff --git a/src/components/Navbar.jsx b/src/components/Navbar/Navbar.jsx
similarity index 82%
rename from src/components/Navbar.jsx
rename to src/components/Navbar/Navbar.jsx
index 0c67c8a..1b05d12 100644
--- a/src/components/Navbar.jsx
+++ b/src/components/Navbar/Navbar.jsx
@@ -1,10 +1,10 @@
import React from 'react';
-import Dice from './game-board-components/Dice';
-import NameContainer from './navbar-components/NameContainer';
-import ReadyButton from './navbar-components/ReadyButton';
+import Dice from '../Gameboard/Dice/Dice';
+import NameContainer from './NameContainer/NameContainer';
+import ReadyButton from './ReadyButton/ReadyButton';
import './Navbar.css';
import { useContext } from 'react';
-import { PlayerDataContext } from '../App';
+import { PlayerDataContext } from '../../App';
const Navbar = ({ players, started, time, isReady, rolledNumber, nowMoving, rolledNumberCallback, movingPlayer }) => {
const context = useContext(PlayerDataContext);
const colors = ['red', 'blue', 'green', 'yellow'];
diff --git a/src/components/navbar-components/ReadyButton.jsx b/src/components/Navbar/ReadyButton/ReadyButton.jsx
similarity index 77%
rename from src/components/navbar-components/ReadyButton.jsx
rename to src/components/Navbar/ReadyButton/ReadyButton.jsx
index 6addc94..6249a9e 100644
--- a/src/components/navbar-components/ReadyButton.jsx
+++ b/src/components/Navbar/ReadyButton/ReadyButton.jsx
@@ -1,19 +1,17 @@
import React, { useState, useContext, useEffect } from 'react';
-import { SocketContext } from '../../App';
+import { SocketContext } from '../../../App';
import Switch from '@material-ui/core/Switch';
import '../Navbar.css';
-import './TimerAnimation';
+import '../NameContainer/AnimatedOverlay/TimerAnimation';
const ReadyButton = ({ isReady }) => {
const socket = useContext(SocketContext);
- const [checked, setChecked] = useState();
+ const [checked, setChecked] = useState(isReady);
+
const handleCheckboxChange = () => {
socket.emit('player:ready');
setChecked(!checked);
};
- useEffect(() => {
- setChecked(isReady);
- });
return (
diff --git a/src/components/game-board-components/Map.jsx b/src/components/game-board-components/Map.jsx
deleted file mode 100644
index 0d93155..0000000
--- a/src/components/game-board-components/Map.jsx
+++ /dev/null
@@ -1,230 +0,0 @@
-import React, { useEffect, useRef, useState, useContext, useCallback } from 'react';
-import { PlayerDataContext, SocketContext } from '../../App';
-import positions from './positions';
-import bluePawn from '../../images/pawns/blue-pawn.png';
-import greenPawn from '../../images/pawns/green-pawn.png';
-import yellowPawn from '../../images/pawns/yellow-pawn.png';
-import redPawn from '../../images/pawns/red-pawn.png';
-import greyPawn from '../../images/pawns/grey-pawn.png';
-const Map = ({ pawns, nowMoving, rolledNumber }) => {
- const context = useContext(PlayerDataContext);
- const socket = useContext(SocketContext);
- const [hintPawn, setHintPawn] = useState();
- const paintPawn = (context, x, y, color) => {
- const circle = new Path2D();
- circle.arc(x, y, 12, 0, 2 * Math.PI);
- const image = new Image();
- switch (color) {
- case 'green':
- image.src = greenPawn;
- break;
- case 'blue':
- image.src = bluePawn;
- break;
- case 'red':
- image.src = redPawn;
- break;
- case 'yellow':
- image.src = yellowPawn;
- break;
- case 'grey':
- image.src = greyPawn;
- break;
- }
- context.drawImage(image, x - 17, y - 14, 35, 30);
- return circle;
- };
-
- const canvasRef = useRef(null);
-
- // Return true when pawn can move
- const checkIfPawnCanMove = useCallback(
- pawn => {
- // If is in base
- if ((rolledNumber === 1 || rolledNumber === 6) && pawn.position === pawn.basePos) {
- return true;
- // Other situations: pawn is on map or pawn is in end positions
- } else if (pawn.position !== pawn.basePos) {
- switch (pawn.color) {
- case 'red':
- if (pawn.position + rolledNumber <= 73) return true;
- break;
- case 'blue':
- if (pawn.position + rolledNumber <= 79) return true;
- break;
- case 'green':
- if (pawn.position + rolledNumber <= 85) return true;
- break;
- case 'yellow':
- if (pawn.position + rolledNumber <= 91) return true;
- break;
- default:
- return false;
- }
- } else {
- return false;
- }
- },
- [rolledNumber]
- );
-
- const handleCanvasClick = event => {
- // If hint pawn exist it means that pawn can move
- if (hintPawn) {
- const canvas = canvasRef.current;
- const ctx = canvas.getContext('2d');
- const rect = canvas.getBoundingClientRect(),
- x = event.clientX - rect.left,
- y = event.clientY - rect.top;
- for (const pawn of pawns) {
- if (ctx.isPointInPath(pawn.circle, x, y)) {
- socket.emit('game:move', pawn._id);
- }
- }
- setHintPawn(null);
- }
- };
- const getHintPawnPosition = pawn => {
- // Based on color (because specific color have specific base and end positions)
- let { position } = pawn;
- switch (context.color) {
- case 'red':
- // When in base
- if (position >= 0 && position <= 3) {
- return 16;
- // Next to end
- } else if (position <= 66 && position + rolledNumber >= 67) {
- return position + rolledNumber + 1; // 1 is difference between last position on map and first on end
- // Normal move
- } else {
- return position + rolledNumber;
- }
- case 'blue':
- // When in base
- if (position >= 4 && position <= 7) {
- return 55;
- // Next to red base
- } else if (position <= 67 && position + rolledNumber > 67) {
- return position + rolledNumber - 52;
- // Next to base
- } else if (position <= 53 && position + rolledNumber >= 54) {
- return position + rolledNumber + 20;
- // Normal move
- } else {
- return position + rolledNumber;
- }
- case 'green':
- // When in base
- if (position >= 8 && position <= 11) {
- return 42;
- // Next to red base
- } else if (position <= 67 && position + rolledNumber > 67) {
- return position + rolledNumber - 52;
- // Next to base
- } else if (position <= 40 && position + rolledNumber >= 41) {
- return position + rolledNumber + 39;
- // Normal move
- } else {
- return position + rolledNumber;
- }
- case 'yellow':
- // When in base
- if (position >= 12 && position <= 15) {
- return 29;
- // Next to red base
- } else if (position <= 67 && position + rolledNumber > 67) {
- return position + rolledNumber - 52;
- // Next to base
- } else if (position <= 27 && position + rolledNumber >= 28) {
- return position + rolledNumber + 58;
- // Normal move
- } else {
- return position + rolledNumber;
- }
- default:
- return position;
- }
- };
- const handleMouseMove = event => {
- if (nowMoving && rolledNumber) {
- const canvas = canvasRef.current;
- const ctx = canvas.getContext('2d');
- // Gets x and y cords of mouse on canvas
- const rect = canvas.getBoundingClientRect(),
- x = event.clientX - rect.left,
- y = event.clientY - rect.top;
- canvas.style.cursor = 'default';
- for (const pawn of pawns) {
- if (pawn.circle) {
- /*
- This condition checks if mouse location is:
- 1) on pawn
- 2) is color of pawn same as player's
- 3) if pawn can move
- And then sets cursor to pointer and paints hint pawn - where will be pawn after click
- */
- if (
- ctx.isPointInPath(pawn.circle, x, y) &&
- context.color === pawn.color &&
- checkIfPawnCanMove(pawn)
- ) {
- const pawnPosition = getHintPawnPosition(pawn);
- // Checks if pawn can make a move
- if (pawnPosition) {
- canvas.style.cursor = 'pointer';
- setHintPawn({ id: pawn._id, position: pawnPosition, color: 'grey' });
- break;
- }
- } else {
- setHintPawn(null);
- }
- }
- }
- }
- };
- const rerenderCanvas = useCallback(() => {
- const canvas = canvasRef.current;
- const ctx = canvas.getContext('2d');
- const image = new Image();
- image.src = 'https://img-9gag-fun.9cache.com/photo/a8GdpYZ_460s.jpg';
- image.onload = function () {
- ctx.drawImage(image, 0, 0);
- pawns.forEach((pawn, index) => {
- pawns[index].circle = paintPawn(
- ctx,
- positions[pawn.position].x,
- positions[pawn.position].y,
- pawn.color
- );
- });
- if (hintPawn) {
- paintPawn(ctx, positions[hintPawn.position].x, positions[hintPawn.position].y, hintPawn.color);
- }
- };
- }, [checkIfPawnCanMove, context.color, hintPawn, nowMoving, pawns, rolledNumber]);
-
- // Rerender canvas when pawns have changed
- useEffect(() => {
- rerenderCanvas();
- }, [hintPawn, pawns, rerenderCanvas]);
-
- useEffect(() => {
- socket.on('game:move', () => {
- setHintPawn(null);
- });
- socket.on('game:roll', () => {
- setHintPawn(null);
- });
- }, [socket]);
- return (
-
- );
-};
-export default Map;
diff --git a/src/constants/pawnImages.js b/src/constants/pawnImages.js
new file mode 100644
index 0000000..e568106
--- /dev/null
+++ b/src/constants/pawnImages.js
@@ -0,0 +1,13 @@
+import bluePawn from '../images/pawns/blue-pawn.png';
+import greenPawn from '../images/pawns/green-pawn.png';
+import redPawn from '../images/pawns/red-pawn.png';
+import yellowPawn from '../images/pawns/yellow-pawn.png';
+import greyPawn from '../images/pawns/grey-pawn.png';
+
+export default {
+ green: greenPawn,
+ blue: bluePawn,
+ red: redPawn,
+ yellow: yellowPawn,
+ grey: greyPawn,
+};
diff --git a/src/constants/positions.js b/src/constants/positions.js
new file mode 100644
index 0000000..c437f9f
--- /dev/null
+++ b/src/constants/positions.js
@@ -0,0 +1,117 @@
+const positions = [
+ // Red base
+ { x: 67, y: 67 }, // 0
+ { x: 67, y: 116 },
+ { x: 117, y: 67 },
+ { x: 117, y: 116 },
+ // Blue base
+ { x: 67, y: 343 },
+ { x: 67, y: 392 },
+ { x: 117, y: 343 },
+ { x: 117, y: 392 },
+ // Green base
+ { x: 343, y: 343 },
+ { x: 392, y: 392 },
+ { x: 392, y: 343 }, // 10
+ { x: 343, y: 392 },
+ // Yellow base
+ { x: 343, y: 67 },
+ { x: 392, y: 116 },
+ { x: 392, y: 67 },
+ { x: 343, y: 116 },
+ // Map - starting from red field
+ { x: 45, y: 200 },
+ { x: 76, y: 200 },
+ { x: 107, y: 200 },
+ { x: 138, y: 200 },
+ { x: 169, y: 200 }, // 20
+
+ { x: 200, y: 169 },
+ { x: 200, y: 138 },
+ { x: 200, y: 107 },
+ { x: 200, y: 76 },
+ { x: 200, y: 45 },
+ { x: 200, y: 14 },
+ // Top
+ { x: 230, y: 14 },
+ { x: 261, y: 14 },
+ { x: 261, y: 45 },
+ { x: 261, y: 76 }, // 30
+ { x: 261, y: 107 },
+ { x: 261, y: 138 },
+ { x: 261, y: 169 },
+
+ { x: 291, y: 200 },
+ { x: 321, y: 200 },
+ { x: 352, y: 200 },
+ { x: 383, y: 200 },
+ { x: 414, y: 200 },
+ { x: 445, y: 200 },
+ // Right
+ { x: 445, y: 230 }, // 40
+
+ { x: 445, y: 261 },
+ { x: 414, y: 261 },
+ { x: 383, y: 261 },
+ { x: 352, y: 261 },
+ { x: 321, y: 261 },
+ { x: 291, y: 261 },
+
+ { x: 261, y: 291 },
+ { x: 261, y: 322 },
+ { x: 261, y: 353 },
+ { x: 261, y: 384 }, // 50
+ { x: 261, y: 414 },
+ { x: 261, y: 445 },
+ // Bottom
+ { x: 230, y: 445 },
+
+ { x: 200, y: 445 },
+ { x: 200, y: 414 },
+ { x: 200, y: 384 },
+ { x: 200, y: 353 },
+ { x: 200, y: 322 },
+ { x: 200, y: 291 },
+
+ { x: 169, y: 261 }, // 60
+ { x: 138, y: 261 },
+ { x: 107, y: 261 },
+ { x: 76, y: 261 },
+ { x: 45, y: 261 },
+
+ { x: 15, y: 261 },
+ // Left
+ { x: 15, y: 231 }, // 66
+ // One behind red base
+ { x: 15, y: 200 }, //67
+ // Red end
+ { x: 45, y: 231 }, // 68
+ { x: 76, y: 231 },
+ { x: 107, y: 231 },
+ { x: 138, y: 231 },
+ { x: 169, y: 231 },
+ { x: 200, y: 231 }, // 73
+ // Blue end
+ { x: 231, y: 414 }, // 74
+ { x: 231, y: 384 },
+ { x: 231, y: 353 },
+ { x: 231, y: 322 },
+ { x: 231, y: 291 },
+ { x: 231, y: 260 }, // 79
+ // Green end
+ { x: 414, y: 231 }, // 80
+ { x: 383, y: 231 },
+ { x: 352, y: 231 },
+ { x: 321, y: 231 },
+ { x: 290, y: 231 },
+ { x: 259, y: 231 }, // 85
+ // Yellow base
+ { x: 230, y: 45 }, // 86
+ { x: 230, y: 76 },
+ { x: 230, y: 107 },
+ { x: 230, y: 138 },
+ { x: 230, y: 169 },
+ { x: 230, y: 200 }, // 91
+];
+
+export default positions;
diff --git a/src/hooks/useInput.js b/src/hooks/useInput.js
new file mode 100644
index 0000000..1144f96
--- /dev/null
+++ b/src/hooks/useInput.js
@@ -0,0 +1,11 @@
+import { useState } from 'react';
+export default function useInput({ initialValue }) {
+ const [value, setValue] = useState(initialValue);
+ const handleChange = e => {
+ setValue(e.target.value);
+ };
+ return {
+ value,
+ onChange: handleChange,
+ };
+}
diff --git a/src/images/map.jpg b/src/images/map.jpg
new file mode 100644
index 0000000..8c158fd
Binary files /dev/null and b/src/images/map.jpg differ