edited css and readme
This commit is contained in:
parent
7304922e86
commit
c8773ed546
17
README.md
17
README.md
@ -1,11 +1,13 @@
|
|||||||
# Online multiplayer Ludo
|
# Online multiplayer Ludo
|
||||||
WORK IN PROGRESS ...
|
|
||||||
## About
|
## 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))
|
**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
|
||||||
|

|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
Play this game [here]()
|
Play this game [here](https://smaga-wiktor-ludo.herokuapp.com)
|
||||||
```
|
```
|
||||||
npm i
|
npm i
|
||||||
npm start
|
npm start
|
||||||
@ -18,12 +20,15 @@ node server.js
|
|||||||
### Backend
|
### Backend
|
||||||
- Node.js
|
- Node.js
|
||||||
- Express
|
- Express
|
||||||
- express-session
|
- Express-session
|
||||||
- MongoDB
|
- MongoDB, Mongoose
|
||||||
- MongoDB sessions store
|
- MongoDB sessions store
|
||||||
- Maybe Redis in future
|
|
||||||
### Frontend
|
### Frontend
|
||||||
- React
|
- React
|
||||||
- Axios
|
- Axios
|
||||||
- Material UI
|
- Material UI
|
||||||
- Canvas
|
- Canvas
|
||||||
|
## ToDo
|
||||||
|
- Redis
|
||||||
|
- SocketIO
|
||||||
|
- Add more game logic
|
||||||
@ -32,7 +32,7 @@ router.post('/move', function (req, res){
|
|||||||
doc.players[index+1].nowMoving = true;
|
doc.players[index+1].nowMoving = true;
|
||||||
}
|
}
|
||||||
// Updating timer
|
// Updating timer
|
||||||
doc.nextMoveTime = Date.now()+30000;
|
doc.nextMoveTime = Date.now()+15000;
|
||||||
RoomModel.findOneAndUpdate({_id: req.session.roomId}, doc, function(err, doc){
|
RoomModel.findOneAndUpdate({_id: req.session.roomId}, doc, function(err, doc){
|
||||||
res.send("Correctly Moved!");
|
res.send("Correctly Moved!");
|
||||||
});
|
});
|
||||||
|
|||||||
@ -18,7 +18,8 @@ var changeReadyState = (req, res, exit) =>{
|
|||||||
}
|
}
|
||||||
if(updatedPlayers.filter(player => player.ready).length >= 2){
|
if(updatedPlayers.filter(player => player.ready).length >= 2){
|
||||||
updatedDoc.started = true;
|
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;
|
updatedDoc.players[0].nowMoving = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -58,7 +58,8 @@ router.post('/add', function (req, res) {
|
|||||||
if (players.length === 4) {
|
if (players.length === 4) {
|
||||||
updateObj.full = true; // Room is full
|
updateObj.full = true; // Room is full
|
||||||
updateObj.started = true; // Game started
|
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.players[0].nowMoving = true; //First joined player moving
|
||||||
updateObj.pawns = getStartPositions();
|
updateObj.pawns = getStartPositions();
|
||||||
}
|
}
|
||||||
@ -100,7 +101,7 @@ router.get('/', function(req,res){
|
|||||||
}else{
|
}else{
|
||||||
doc.players[index + 1].nowMoving = true;
|
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){
|
RoomModel.findOneAndUpdate({_id: req.session.roomId}, doc, function(err, docs){
|
||||||
if(err){
|
if(err){
|
||||||
res.status(500).send(err)
|
res.status(500).send(err)
|
||||||
|
|||||||
@ -2,20 +2,17 @@ const express = require("express");
|
|||||||
const cors = require('cors');
|
const cors = require('cors');
|
||||||
const cookieParser = require('cookie-parser')
|
const cookieParser = require('cookie-parser')
|
||||||
const session = require('express-session')
|
const session = require('express-session')
|
||||||
const bodyParser = require('body-parser');
|
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
app.use(cookieParser());
|
app.use(cookieParser());
|
||||||
app.use(bodyParser.urlencoded({
|
app.use(express.urlencoded({
|
||||||
extended: true
|
extended: true
|
||||||
}));
|
}));
|
||||||
app.use(bodyParser.json());
|
app.use(express.json());
|
||||||
app.set('trust proxy', 1)
|
app.set('trust proxy', 1)
|
||||||
app.use(cors({
|
app.use(cors({
|
||||||
origin: [
|
origin: [
|
||||||
'localhost:3001',
|
|
||||||
'http://localhost:3001',
|
'http://localhost:3001',
|
||||||
'https://localhost:3001'
|
|
||||||
],
|
],
|
||||||
credentials: true,
|
credentials: true,
|
||||||
}))
|
}))
|
||||||
|
|||||||
@ -16,12 +16,9 @@ function App() {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
axios.get('http://localhost:3000/player', {
|
axios.get('http://localhost:3000/player', {
|
||||||
withCredentials:true,
|
withCredentials:true,
|
||||||
mode: 'cors'
|
|
||||||
})
|
})
|
||||||
.then( response => {
|
.then(response => {
|
||||||
setPlayerData(response.data)
|
setPlayerData(response.data)
|
||||||
console.log(response.data);
|
|
||||||
|
|
||||||
response.data.roomId!=null ? setRedirect(true) : setRedirect(false);
|
response.data.roomId!=null ? setRedirect(true) : setRedirect(false);
|
||||||
});
|
});
|
||||||
},[]);
|
},[]);
|
||||||
@ -29,15 +26,13 @@ function App() {
|
|||||||
const handleExit = e => {
|
const handleExit = e => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
window.addEventListener('unload', () => {
|
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 = () => {
|
const idCallback = () => {
|
||||||
axios.get('http://localhost:3000/player/', {
|
axios.get('http://localhost:3000/player/', {
|
||||||
withCredentials:true,
|
withCredentials:true,
|
||||||
mode: 'cors',
|
|
||||||
headers: { "Content-Type": "application/json" },
|
|
||||||
})
|
})
|
||||||
.then(response => {
|
.then(response => {
|
||||||
setPlayerData(response.data);
|
setPlayerData(response.data);
|
||||||
|
|||||||
@ -20,7 +20,6 @@ const Gameboard = () => {
|
|||||||
const fetchData = () => {
|
const fetchData = () => {
|
||||||
axios.get('http://localhost:3000/room/',{
|
axios.get('http://localhost:3000/room/',{
|
||||||
withCredentials:true,
|
withCredentials:true,
|
||||||
mode: 'cors',
|
|
||||||
}).then((response)=>{
|
}).then((response)=>{
|
||||||
// Filling navbar with empty player nick container
|
// Filling navbar with empty player nick container
|
||||||
while(response.data.players.length !== 4){
|
while(response.data.players.length !== 4){
|
||||||
@ -36,6 +35,7 @@ const Gameboard = () => {
|
|||||||
setNowMoving(false);
|
setNowMoving(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
checkWin();
|
||||||
setPlayers(response.data.players);
|
setPlayers(response.data.players);
|
||||||
setPawns(response.data.pawns);
|
setPawns(response.data.pawns);
|
||||||
setTime(response.data.nextMoveTime);
|
setTime(response.data.nextMoveTime);
|
||||||
@ -43,6 +43,7 @@ const Gameboard = () => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
const checkWin = () => {
|
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){
|
if(pawns.filter(pawn => pawn.color === 'red' && pawn.position === 73).length === 4){
|
||||||
alert("Red Won")
|
alert("Red Won")
|
||||||
}else if(pawns.filter(pawn => pawn.color === 'blue' && pawn.position === 79).length === 4){
|
}else if(pawns.filter(pawn => pawn.color === 'blue' && pawn.position === 79).length === 4){
|
||||||
|
|||||||
@ -1,7 +0,0 @@
|
|||||||
.navbar-container{
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
}
|
|
||||||
.navbar-container>div{
|
|
||||||
margin-right: 10px;
|
|
||||||
}
|
|
||||||
@ -1,7 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import NameContainer from './navbar-components/NameContainer'
|
import NameContainer from './navbar-components/NameContainer'
|
||||||
import ReadyButton from './navbar-components/ReadyButton'
|
import ReadyButton from './navbar-components/ReadyButton'
|
||||||
import './Navbar.css';
|
|
||||||
const Navbar = ({ players, started, time }) => {
|
const Navbar = ({ players, started, time }) => {
|
||||||
return(
|
return(
|
||||||
<div className = "navbar-container">
|
<div className = "navbar-container">
|
||||||
|
|||||||
@ -8,7 +8,7 @@ import five from '../../images/dice/5.png';
|
|||||||
import six from '../../images/dice/6.png';
|
import six from '../../images/dice/6.png';
|
||||||
|
|
||||||
const Dice = ({ rolledNumberCallback, nowMoving }) => {
|
const Dice = ({ rolledNumberCallback, nowMoving }) => {
|
||||||
const [rolledNumber, setRolledNumber] = useState()
|
const [rolledNumber, setRolledNumber] = useState();
|
||||||
const [images] = useState([one, two, three, four, five, six]);
|
const [images] = useState([one, two, three, four, five, six]);
|
||||||
const handleRoll = () => {
|
const handleRoll = () => {
|
||||||
axios.get('http://localhost:3000/game/roll').then(response => {
|
axios.get('http://localhost:3000/game/roll').then(response => {
|
||||||
@ -19,8 +19,8 @@ const Dice = ({ rolledNumberCallback, nowMoving }) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
return(
|
return(
|
||||||
<div>
|
<div className="dice-container">
|
||||||
{rolledNumber ? <img src={images[rolledNumber - 1]} width="100" height="100"/> : nowMoving ? <button onClick={handleRoll}>Roll</button> : null }
|
{rolledNumber ? <img src={images[rolledNumber - 1]} width="100" height="100"/> : nowMoving ? <button onClick={handleRoll}> Roll </button> : null}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,3 +0,0 @@
|
|||||||
.canvas-container{
|
|
||||||
margin: 10px;
|
|
||||||
}
|
|
||||||
@ -2,7 +2,6 @@ import React, { useEffect, useRef, useState, useContext } from 'react';
|
|||||||
import { PlayerDataContext } from '../../App';
|
import { PlayerDataContext } from '../../App';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import positions from './positions';
|
import positions from './positions';
|
||||||
import './Map.css';
|
|
||||||
|
|
||||||
const Map = ({ pawns, nowMoving, rolledNumber }) => {
|
const Map = ({ pawns, nowMoving, rolledNumber }) => {
|
||||||
const context = useContext(PlayerDataContext);
|
const context = useContext(PlayerDataContext);
|
||||||
@ -44,8 +43,8 @@ const Map = ({ pawns, nowMoving, rolledNumber }) => {
|
|||||||
}else{
|
}else{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleCanvasClick = event => {
|
const handleCanvasClick = event => {
|
||||||
// If hint pawn exist it means that pawn can move
|
// If hint pawn exist it means that pawn can move
|
||||||
if(hintPawn){
|
if(hintPawn){
|
||||||
@ -56,10 +55,8 @@ const Map = ({ pawns, nowMoving, rolledNumber }) => {
|
|||||||
y = event.clientY - rect.top;
|
y = event.clientY - rect.top;
|
||||||
for(const pawn of pawns){
|
for(const pawn of pawns){
|
||||||
if (ctx.isPointInPath(pawn.circle, x, y)) {
|
if (ctx.isPointInPath(pawn.circle, x, y)) {
|
||||||
axios.post('http://localhost:3000/game/move', {pawnId: pawn._id, position: hintPawn.position},
|
axios.post('http://localhost:3000/game/move', {pawnId: pawn._id, position: hintPawn.position}, {withCredentials: true})
|
||||||
{
|
.then(() => {
|
||||||
withCredentials: true,
|
|
||||||
}).then(() => {
|
|
||||||
setHintPawn(null);
|
setHintPawn(null);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -125,7 +122,6 @@ const Map = ({ pawns, nowMoving, rolledNumber }) => {
|
|||||||
return position + rolledNumber;
|
return position + rolledNumber;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
const handleMouseMove = event => {
|
const handleMouseMove = event => {
|
||||||
if(nowMoving && rolledNumber){
|
if(nowMoving && rolledNumber){
|
||||||
|
|||||||
@ -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;
|
|
||||||
}
|
|
||||||
@ -1,5 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import './NameContainer.css';
|
|
||||||
const NameContainer = ( {player, time} ) => {
|
const NameContainer = ( {player, time} ) => {
|
||||||
const getRemainingTime = () => {
|
const getRemainingTime = () => {
|
||||||
return Math.round((time - Date.now())/1000)+1;
|
return Math.round((time - Date.now())/1000)+1;
|
||||||
@ -11,7 +11,6 @@ const NameContainer = ( {player, time} ) => {
|
|||||||
{player.nowMoving ? <div className="timer"> {getRemainingTime()} </div> : null}
|
{player.nowMoving ? <div className="timer"> {getRemainingTime()} </div> : null}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default NameContainer;
|
export default NameContainer;
|
||||||
BIN
src/images/readme1.png
Normal file
BIN
src/images/readme1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 124 KiB |
@ -3,4 +3,40 @@ body{
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
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;
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue
Block a user