diff --git a/README.md b/README.md index a71453b..4bb9ca7 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,13 @@ # Online multiplayer Ludo -WORK IN PROGRESS ... ## About **Ludo** is a strategy board game for two to four players, in which the players race their four tokens from start to finish according to the rolls of a single die. Like other cross and circle games, Ludo is derived from the Indian game Pachisi, but simpler. The game and its variations are popular in many countries and under various names. [Read more](https://en.wikipedia.org/wiki/Ludo_(board_game)) +## Interface +![Interface](https://github.com/Wenszel/mern-ludo/blob/main/src/images/readme1.png?raw=true) + ## Installation -Play this game [here]() +Play this game [here](https://smaga-wiktor-ludo.herokuapp.com) ``` npm i npm start @@ -18,12 +20,15 @@ node server.js ### Backend - Node.js - Express -- express-session -- MongoDB +- Express-session +- MongoDB, Mongoose - MongoDB sessions store -- Maybe Redis in future ### Frontend - React - Axios - Material UI -- Canvas \ No newline at end of file +- Canvas +## ToDo +- Redis +- SocketIO +- Add more game logic \ No newline at end of file diff --git a/backend/routes/game.js b/backend/routes/game.js index fdb7ca3..16e4d08 100644 --- a/backend/routes/game.js +++ b/backend/routes/game.js @@ -32,7 +32,7 @@ router.post('/move', function (req, res){ doc.players[index+1].nowMoving = true; } // Updating timer - doc.nextMoveTime = Date.now()+30000; + doc.nextMoveTime = Date.now()+15000; RoomModel.findOneAndUpdate({_id: req.session.roomId}, doc, function(err, doc){ res.send("Correctly Moved!"); }); diff --git a/backend/routes/player.js b/backend/routes/player.js index 912e0ce..6cd61d6 100644 --- a/backend/routes/player.js +++ b/backend/routes/player.js @@ -18,7 +18,8 @@ var changeReadyState = (req, res, exit) =>{ } if(updatedPlayers.filter(player => player.ready).length >= 2){ updatedDoc.started = true; - updatedDoc.nextMoveTime = Date.now()+30000; + updatedDoc.players = updatedDoc.players.map(player => player.ready === true); + updatedDoc.nextMoveTime = Date.now() + 15000; updatedDoc.players[0].nowMoving = true; } diff --git a/backend/routes/room.js b/backend/routes/room.js index e949c22..591194b 100644 --- a/backend/routes/room.js +++ b/backend/routes/room.js @@ -58,7 +58,8 @@ router.post('/add', function (req, res) { if (players.length === 4) { updateObj.full = true; // Room is full updateObj.started = true; // Game started - updateObj.nextMoveTime = Date.now()+30000; + updateObj.nextMoveTime = Date.now() + 15000; + updateObj.players = updateObj.players.map(player => player.ready === true); updateObj.players[0].nowMoving = true; //First joined player moving updateObj.pawns = getStartPositions(); } @@ -100,7 +101,7 @@ router.get('/', function(req,res){ }else{ doc.players[index + 1].nowMoving = true; } - doc.nextMoveTime = Date.now()+30000; + doc.nextMoveTime = Date.now()+15000; RoomModel.findOneAndUpdate({_id: req.session.roomId}, doc, function(err, docs){ if(err){ res.status(500).send(err) diff --git a/backend/server.js b/backend/server.js index d97192c..3456c07 100644 --- a/backend/server.js +++ b/backend/server.js @@ -2,20 +2,17 @@ const express = require("express"); const cors = require('cors'); const cookieParser = require('cookie-parser') const session = require('express-session') -const bodyParser = require('body-parser'); const app = express(); app.use(cookieParser()); -app.use(bodyParser.urlencoded({ +app.use(express.urlencoded({ extended: true })); -app.use(bodyParser.json()); +app.use(express.json()); app.set('trust proxy', 1) app.use(cors({ origin: [ - 'localhost:3001', 'http://localhost:3001', - 'https://localhost:3001' ], credentials: true, })) diff --git a/src/App.js b/src/App.js index 8b5b0b3..4adf78d 100644 --- a/src/App.js +++ b/src/App.js @@ -16,12 +16,9 @@ function App() { useEffect(() => { axios.get('http://localhost:3000/player', { withCredentials:true, - mode: 'cors' }) - .then( response => { + .then(response => { setPlayerData(response.data) - console.log(response.data); - response.data.roomId!=null ? setRedirect(true) : setRedirect(false); }); },[]); @@ -29,15 +26,13 @@ function App() { const handleExit = e => { e.preventDefault(); window.addEventListener('unload', () => { - axios.post('http://localhost:3000/player/exit', {withCredentials:true, mode: 'cors'}) + axios.post('http://localhost:3000/player/exit', {withCredentials:true, }) }); } const idCallback = () => { axios.get('http://localhost:3000/player/', { withCredentials:true, - mode: 'cors', - headers: { "Content-Type": "application/json" }, }) .then(response => { setPlayerData(response.data); diff --git a/src/components/Gameboard.jsx b/src/components/Gameboard.jsx index ef1e460..63c4965 100644 --- a/src/components/Gameboard.jsx +++ b/src/components/Gameboard.jsx @@ -20,7 +20,6 @@ const Gameboard = () => { const fetchData = () => { axios.get('http://localhost:3000/room/',{ withCredentials:true, - mode: 'cors', }).then((response)=>{ // Filling navbar with empty player nick container while(response.data.players.length !== 4){ @@ -36,6 +35,7 @@ const Gameboard = () => { setNowMoving(false); } } + checkWin(); setPlayers(response.data.players); setPawns(response.data.pawns); setTime(response.data.nextMoveTime); @@ -43,6 +43,7 @@ const Gameboard = () => { }) } 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") }else if(pawns.filter(pawn => pawn.color === 'blue' && pawn.position === 79).length === 4){ diff --git a/src/components/Navbar.css b/src/components/Navbar.css deleted file mode 100644 index dea4d6d..0000000 --- a/src/components/Navbar.css +++ /dev/null @@ -1,7 +0,0 @@ -.navbar-container{ - display: flex; - flex-direction: row; -} -.navbar-container>div{ - margin-right: 10px; -} \ No newline at end of file diff --git a/src/components/Navbar.jsx b/src/components/Navbar.jsx index 23fe5d2..47e5975 100644 --- a/src/components/Navbar.jsx +++ b/src/components/Navbar.jsx @@ -1,7 +1,7 @@ import React from 'react'; import NameContainer from './navbar-components/NameContainer' import ReadyButton from './navbar-components/ReadyButton' -import './Navbar.css'; + const Navbar = ({ players, started, time }) => { return(
diff --git a/src/components/game-board-components/Dice.jsx b/src/components/game-board-components/Dice.jsx index 35fe412..3c1a893 100644 --- a/src/components/game-board-components/Dice.jsx +++ b/src/components/game-board-components/Dice.jsx @@ -8,7 +8,7 @@ import five from '../../images/dice/5.png'; import six from '../../images/dice/6.png'; const Dice = ({ rolledNumberCallback, nowMoving }) => { - const [rolledNumber, setRolledNumber] = useState() + const [rolledNumber, setRolledNumber] = useState(); const [images] = useState([one, two, three, four, five, six]); const handleRoll = () => { axios.get('http://localhost:3000/game/roll').then(response => { @@ -19,8 +19,8 @@ const Dice = ({ rolledNumberCallback, nowMoving }) => { }) } return( -
- {rolledNumber ? : nowMoving ? : null } +
+ {rolledNumber ? : nowMoving ? : null}
) } diff --git a/src/components/game-board-components/Map.css b/src/components/game-board-components/Map.css deleted file mode 100644 index a9f9175..0000000 --- a/src/components/game-board-components/Map.css +++ /dev/null @@ -1,3 +0,0 @@ -.canvas-container{ - margin: 10px; -} \ No newline at end of file diff --git a/src/components/game-board-components/Map.jsx b/src/components/game-board-components/Map.jsx index 90f88cb..199e281 100644 --- a/src/components/game-board-components/Map.jsx +++ b/src/components/game-board-components/Map.jsx @@ -2,7 +2,6 @@ import React, { useEffect, useRef, useState, useContext } from 'react'; import { PlayerDataContext } from '../../App'; import axios from 'axios'; import positions from './positions'; -import './Map.css'; const Map = ({ pawns, nowMoving, rolledNumber }) => { const context = useContext(PlayerDataContext); @@ -44,8 +43,8 @@ const Map = ({ pawns, nowMoving, rolledNumber }) => { }else{ return false; } - } + const handleCanvasClick = event => { // If hint pawn exist it means that pawn can move if(hintPawn){ @@ -56,10 +55,8 @@ const Map = ({ pawns, nowMoving, rolledNumber }) => { y = event.clientY - rect.top; for(const pawn of pawns){ if (ctx.isPointInPath(pawn.circle, x, y)) { - axios.post('http://localhost:3000/game/move', {pawnId: pawn._id, position: hintPawn.position}, - { - withCredentials: true, - }).then(() => { + axios.post('http://localhost:3000/game/move', {pawnId: pawn._id, position: hintPawn.position}, {withCredentials: true}) + .then(() => { setHintPawn(null); }); @@ -125,7 +122,6 @@ const Map = ({ pawns, nowMoving, rolledNumber }) => { return position + rolledNumber; } } - }; const handleMouseMove = event => { if(nowMoving && rolledNumber){ diff --git a/src/components/navbar-components/NameContainer.css b/src/components/navbar-components/NameContainer.css deleted file mode 100644 index 4973b6f..0000000 --- a/src/components/navbar-components/NameContainer.css +++ /dev/null @@ -1,21 +0,0 @@ -.name-container{ - width: 100px; - height: 50px; - border-radius: 5px; - color: white; - font-weight: bold; - display: flex; - text-align: center; - justify-content: center; - align-items: center; -} -.timer{ - background-color: darkblue; - color: white; - position: relative; - top: -20px; - left: 15px; - width: 30px; - height: 20px; - border-radius: 5px; -} \ No newline at end of file diff --git a/src/components/navbar-components/NameContainer.jsx b/src/components/navbar-components/NameContainer.jsx index d5fc5f0..80f2415 100644 --- a/src/components/navbar-components/NameContainer.jsx +++ b/src/components/navbar-components/NameContainer.jsx @@ -1,5 +1,5 @@ import React from 'react'; -import './NameContainer.css'; + const NameContainer = ( {player, time} ) => { const getRemainingTime = () => { return Math.round((time - Date.now())/1000)+1; @@ -11,7 +11,6 @@ const NameContainer = ( {player, time} ) => { {player.nowMoving ?
{getRemainingTime()}
: null}
) - } export default NameContainer; \ No newline at end of file diff --git a/src/images/readme1.png b/src/images/readme1.png new file mode 100644 index 0000000..b9bbbc0 Binary files /dev/null and b/src/images/readme1.png differ diff --git a/src/index.css b/src/index.css index 0587192..7725404 100644 --- a/src/index.css +++ b/src/index.css @@ -3,4 +3,40 @@ body{ display: flex; flex-direction: column; align-items: center; +} +.canvas-container{ + margin: 10px; +} +.dice-container{ + position: absolute; + top: 30%; + left: 20%; +} +.navbar-container{ + display: flex; + flex-direction: row; +} +.navbar-container>div{ + margin-right: 10px; +} +.name-container{ + width: 100px; + height: 50px; + border-radius: 5px; + color: white; + font-weight: bold; + display: flex; + text-align: center; + justify-content: center; + align-items: center; +} +.timer{ + background-color: darkblue; + color: white; + position: relative; + top: -20px; + left: 15px; + width: 30px; + height: 20px; + border-radius: 5px; } \ No newline at end of file