added timer

This commit is contained in:
Wenszel 2021-04-25 21:20:14 +02:00
parent 3c78b0cf8b
commit b9c6db9586
10 changed files with 83 additions and 37 deletions

View File

@ -23,5 +23,9 @@ router.get('/roll', function (req, res){
res.send({number: Math.ceil(Math.random() * 6)}); res.send({number: Math.ceil(Math.random() * 6)});
}); });
router.post('/move', function (req, res){
});
module.exports = router; module.exports = router;

View File

@ -18,6 +18,7 @@ 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()+15;
updatedDoc.players[0].nowMoving = true; updatedDoc.players[0].nowMoving = true;
} }

View File

@ -57,6 +57,7 @@ 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()+15;
updateObj.players[0].nowMoving = true; //First joined player moving updateObj.players[0].nowMoving = true; //First joined player moving
updateObj.pawns = getStartPositions(); updateObj.pawns = getStartPositions();
} }

View File

@ -6,7 +6,7 @@ var RoomSchema = new Schema({
createDate: Date, createDate: Date,
started: Boolean, started: Boolean,
full: Boolean, full: Boolean,
timer: Number, nextMoveTime: Number,
players: [{ players: [{
name: String, name: String,
color: String, color: String,

View File

@ -1,4 +1,4 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState, createContext } from 'react';
import axios from 'axios'; import axios from 'axios';
import { Beforeunload } from 'react-beforeunload'; import { Beforeunload } from 'react-beforeunload';
@ -7,10 +7,10 @@ import { BrowserRouter as Router , Route , Redirect, Switch } from 'react-router
import Gameboard from './components/Gameboard' import Gameboard from './components/Gameboard'
import NameInput from './components/NameInput'; import NameInput from './components/NameInput';
function App() { export const PlayerDataContext = createContext();
const [id, setId] = useState(''); function App() {
const [color, setColor] = useState(''); const [playerData, setPlayerData] = useState();
const [redirect, setRedirect] = useState(); const [redirect, setRedirect] = useState();
useEffect(() => { useEffect(() => {
@ -19,11 +19,12 @@ function App() {
mode: 'cors' mode: 'cors'
}) })
.then( response => { .then( response => {
setId(response.data.playerId); setPlayerData(response.data)
setColor(response.data.color); console.log(response.data);
response.data.roomId!=null ? setRedirect(true) : setRedirect(false); response.data.roomId!=null ? setRedirect(true) : setRedirect(false);
}); });
},[id]) },[]);
const handleExit = e => { const handleExit = e => {
e.preventDefault(); e.preventDefault();
@ -32,16 +33,16 @@ function App() {
}); });
} }
const idCallback = (id)=>{ const idCallback = () => {
axios.get('http://localhost:3000/player/', { axios.get('http://localhost:3000/player/', {
withCredentials:true, withCredentials:true,
mode: 'cors', mode: 'cors',
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
}) })
.then(response => { .then(response => {
setId(response.data.playerId); setPlayerData(response.data);
setColor(response.data.color); console.log(response.data);
setRedirect(true) setRedirect(true);
}) })
} }
@ -57,7 +58,9 @@ function App() {
</Route> </Route>
<Route path="/game"> <Route path="/game">
<Beforeunload onBeforeunload={handleExit}> <Beforeunload onBeforeunload={handleExit}>
<Gameboard id={id} color={color}/> <PlayerDataContext.Provider value={playerData}>
<Gameboard/>
</PlayerDataContext.Provider>
</Beforeunload> </Beforeunload>
</Route> </Route>
</Switch> </Switch>

View File

@ -1,26 +1,33 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect, useContext } from 'react';
import { PlayerDataContext } from '../App'
import axios from 'axios'; import axios from 'axios';
import Map from './game-board-components/Map' import Map from './game-board-components/Map'
import Dice from './game-board-components/Dice' import Dice from './game-board-components/Dice'
import Navbar from './Navbar' import Navbar from './Navbar'
const Gameboard = ({id, color}) => { const Gameboard = () => {
// Context data
const context = useContext(PlayerDataContext);
const [id, setId] = useState();
// Render data
const [pawns, setPawns] = useState([]); const [pawns, setPawns] = useState([]);
const [players, setPlayers] = useState([]); const [players, setPlayers] = useState([]);
// Game logic data
const [rolledNumber, setRolledNumber] = useState(''); const [rolledNumber, setRolledNumber] = useState('');
const [time, setTime] = useState();
const [nowMoving, setNowMoving] = useState(false); const [nowMoving, setNowMoving] = useState(false);
const [started, setStarted] = useState(false); const [started, setStarted] = useState(false);
//fetching players data to display them in navbar // Fetching game data
const fetchData = () => { const fetchData = () => {
axios.get('http://localhost:3000/room/',{ axios.get('http://localhost:3000/room/',{
withCredentials:true, withCredentials:true,
mode: 'cors', mode: 'cors',
}).then((response)=>{ }).then((response)=>{
// Filling navbar with empty player nick container
while(response.data.players.length !== 4){ while(response.data.players.length !== 4){
response.data.players.push({ response.data.players.push({name: "...",});
name: "...", };
}) // Checks if client is currently moving player by session ID
}
if(id===response.data.players.find(player => player.nowMoving === true)?._id){ if(id===response.data.players.find(player => player.nowMoving === true)?._id){
setNowMoving(true); setNowMoving(true);
}else{ }else{
@ -28,10 +35,12 @@ const Gameboard = ({id, color}) => {
} }
setPlayers(response.data.players); setPlayers(response.data.players);
setPawns(response.data.pawns); setPawns(response.data.pawns);
setTime(response.data.nextMoveTime);
setStarted(response.data.started); setStarted(response.data.started);
}) })
} }
useEffect(() => { useEffect(() => {
setId(context.playerId);
//sending ajax every 1 sec //sending ajax every 1 sec
const interval = setInterval(fetchData, 1000); const interval = setInterval(fetchData, 1000);
return () => clearInterval(interval); return () => clearInterval(interval);
@ -43,9 +52,9 @@ const Gameboard = ({id, color}) => {
return ( return (
<> <>
<Navbar players={players} started={started}/> <Navbar players={players} started={started} time={time}/>
{nowMoving ? <Dice nowMoving={nowMoving} rolledNumberCallback={rolledNumberCallback}/> : null} {nowMoving ? <Dice nowMoving={nowMoving} rolledNumberCallback={rolledNumberCallback}/> : null}
<Map pawns={pawns} nowMoving={nowMoving} color={color} rolledNumber={rolledNumber}/> <Map pawns={pawns} nowMoving={nowMoving} rolledNumber={rolledNumber}/>
</> </>
) )

View File

@ -2,11 +2,11 @@ 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'; import './Navbar.css';
const Navbar = ( { players, started }) => { const Navbar = ({ players, started, time }) => {
return( return(
<div className = "navbar-container"> <div className = "navbar-container">
{players.map((player, index) => {players.map((player, index) =>
<NameContainer key={index} player = {player}/> <NameContainer key = {index} player = {player} time = {time}/>
)} )}
{started ? null : <ReadyButton/>} {started ? null : <ReadyButton/>}
</div> </div>

View File

@ -1,9 +1,14 @@
import React, { useEffect, useRef, useState } from 'react'; import React, { useEffect, useRef, useState, useContext } from 'react';
import { PlayerDataContext } from '../../App';
import axios from 'axios';
import positions from './positions'; import positions from './positions';
import './Map.css'; import './Map.css';
const Map = ({ pawns, nowMoving, color, rolledNumber }) => { const Map = ({ pawns, nowMoving, rolledNumber }) => {
const context = useContext(PlayerDataContext);
const [color, setColor] = useState();
const [hintPawn, setHintPawn] = useState(); const [hintPawn, setHintPawn] = useState();
const paintPawn = (context, x, y, color) =>{ const paintPawn = (context, x, y, color) =>{
const circle = new Path2D(); const circle = new Path2D();
circle.arc(x, y, 12, 0, 2 * Math.PI); circle.arc(x, y, 12, 0, 2 * Math.PI);
@ -26,6 +31,11 @@ const Map = ({ pawns, nowMoving, color, rolledNumber }) => {
y = event.clientY - rect.top; y = event.clientY - rect.top;
for(const pawn of pawns){ for(const pawn of pawns){
if (context.isPointInPath(pawn.circle, x, y)) { if (context.isPointInPath(pawn.circle, x, y)) {
axios.post('http://localhost:3000/game/move', {
withCredentials: true,
mode: 'cors',
data: {_id: pawn._id}
});
setHintPawn(null); setHintPawn(null);
} }
} }
@ -65,6 +75,7 @@ const Map = ({ pawns, nowMoving, color, rolledNumber }) => {
if(nowMoving && rolledNumber){ if(nowMoving && rolledNumber){
const canvas = canvasRef.current; const canvas = canvasRef.current;
const context = canvas.getContext('2d'); const context = canvas.getContext('2d');
// Gets x and y cords of mouse on canvas
const rect = canvas.getBoundingClientRect(), const rect = canvas.getBoundingClientRect(),
x = event.clientX - rect.left, x = event.clientX - rect.left,
y = event.clientY - rect.top; y = event.clientY - rect.top;
@ -81,7 +92,7 @@ const Map = ({ pawns, nowMoving, color, rolledNumber }) => {
if (context.isPointInPath(pawn.circle, x, y) && pawn.color === color && (pawn.position>15 || rolledNumber === 1 || rolledNumber === 6)) { if (context.isPointInPath(pawn.circle, x, y) && pawn.color === color && (pawn.position>15 || rolledNumber === 1 || rolledNumber === 6)) {
canvas.style.cursor = "pointer"; canvas.style.cursor = "pointer";
const pawnPosition = getHintPawnPosition(pawn); const pawnPosition = getHintPawnPosition(pawn);
setHintPawn({x: positions[pawnPosition].x, y: positions[pawnPosition].y, color: 'grey'}); setHintPawn({id: pawn._id, x: positions[pawnPosition].x, y: positions[pawnPosition].y, color: 'grey'});
break; break;
}else{ }else{
setHintPawn(null); setHintPawn(null);
@ -91,10 +102,10 @@ const Map = ({ pawns, nowMoving, color, rolledNumber }) => {
} }
}; };
const rerenderCanvas = () => { const rerenderCanvas = () => {
const canvas = canvasRef.current const canvas = canvasRef.current;
const context = canvas.getContext('2d') const context = canvas.getContext('2d');
var image = new Image(); var image = new Image();
image.src = 'https://img-9gag-fun.9cache.com/photo/a8GdpYZ_460s.jpg' image.src = 'https://img-9gag-fun.9cache.com/photo/a8GdpYZ_460s.jpg';
image.onload = function() { image.onload = function() {
context.drawImage(image, 0 , 0); context.drawImage(image, 0 , 0);
pawns.forEach( (pawn, index) => { pawns.forEach( (pawn, index) => {
@ -107,8 +118,10 @@ const Map = ({ pawns, nowMoving, color, rolledNumber }) => {
} }
// Rerender canvas when pawns have changed // Rerender canvas when pawns have changed
useEffect(() => { useEffect(() => {
setColor(context.color);
rerenderCanvas(); rerenderCanvas();
}, [pawns]); }, [pawns]);
return( return(
<canvas <canvas
className="canvas-container" className="canvas-container"
@ -120,4 +133,4 @@ const Map = ({ pawns, nowMoving, color, rolledNumber }) => {
/> />
) )
} }
export default Map export default Map;

View File

@ -5,6 +5,17 @@
color: white; color: white;
font-weight: bold; font-weight: bold;
display: flex; display: flex;
text-align: center;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
} }
.timer{
background-color: darkblue;
color: white;
position: relative;
top: -20px;
left: 15px;
width: 30px;
height: 20px;
border-radius: 5px;
}

View File

@ -1,10 +1,14 @@
import React from 'react'; import React from 'react';
import './NameContainer.css' import './NameContainer.css';
const NameContainer = ( {player} ) => { const NameContainer = ( {player, time} ) => {
const getRemainingTime = () => {
return Math.floor((time - Date.now())/1000);
}
return ( return (
<div className="name-container" <div className="name-container"
style={ player.ready ? { backgroundColor: player.color} : { backgroundColor: 'grey'} }> style={ player.ready ? { backgroundColor: player.color} : { backgroundColor: 'grey'} }>
{player.name} {player.name}
{player.nowMoving ? <div className="timer"> {getRemainingTime()} </div> : null}
</div> </div>
) )