Reputation: 1
I've been working on a simple multiplayer pong game for the browser using javascript but can't for the life of me figure out how to start the game for all players without everything getting desynced.
I really do not want to save the balls' position every millisecond to firebase as it would probably just be inefficient and waste space.
I did however sync up the players movements by saving their corresponding Y value to firebase and that works fine.
I am hosting this on github pages so I cannot use something like socket.io or websockets for this (atleast I think I can't) so I am resorting to firebase.
I have tried setting a 'ready' boolean to each player after they have loaded the pong game and only starting it once both players are ready but that still doesn't work to sync the ball up.
Here is my code that handles multiplayer and the pong game, anything below //GAME CODE
is pong, anything above is firebase related
function handleMultiplayer(gameref) {
const ready = ref(database, "public/ongoingGames/pong/" + gameref.key + "/players/plr" + currentPlayer + "/ready")
const yRef = ref(database, "public/ongoingGames/pong/" + gameref.key + "/players/plr" + currentPlayer + "/y")
const otherPlayer = currentPlayer === 1 ? 2 : 1
const otherPlayerYRef = ref(database, "public/ongoingGames/pong/" + gameref.key + "/players/plr" + otherPlayer + "/y")
const otherPlayerReadyRef = ref(database, "public/ongoingGames/pong/" + gameref.key + "/players/plr" + otherPlayer + "/ready")
let interval = setInterval(() => {
if (currentPlayer == 1) {
set(yRef, player1Y)
}
if (currentPlayer == 2) {
set(yRef, player2Y)
}
}, 10);
onDisconnect(gameref).remove().then(() => {
//stops it spamming the yref
clearInterval(interval)
})
//when the other player moves up or down set their current Y value in game
onValue(otherPlayerYRef, snapshot => {
const data = snapshot.val()
if (otherPlayer === 1) {
player1Y = data
}
if (otherPlayer === 2) {
player2Y = data
}
})
let currentPlayerReady
onValue(gameref, (snapshot) => {
const data = snapshot.val()
if (!data) { location.reload() }
// if 2 players are in the game, start it and make the canvas visible
if (Object.keys(data.players).length == maxPlayers) {
// this only triggers once as shown by the if statement
if (canvas.style.display != "flex") {
canvas.style.display = "flex"
matchmaking.remove()
document.getElementById("canvasContainer").style.display = "block"
document.getElementById("name1").textContent = data.players.plr1.name + " score : "
document.getElementById("name2").textContent = data.players.plr2.name + " score : "
//delay to make sure the player has loaded in
setTimeout(() => {
set(ready, true)
currentPlayerReady = true
}, 2000);
setInterval(interval)
}
}
})
// wait for condition to turn true
function waitFor(conditionFunction) {
const poll = resolve => {
if (conditionFunction()) resolve();
else setTimeout(_ => poll(resolve), 400);
}
return new Promise(poll);
}
// trigger once the other players ready value has changed
onValue(otherPlayerReadyRef, async (snapshot) => {
const otherPlayerReady = snapshot.val()
console.log("A")
await waitFor(_ => currentPlayerReady === true)
await waitFor(_ => otherPlayerReady === true)
//calls when both players are ready, starts game
console.log("B")
//GAME CODE
// i'll be honest I used AI to generate the code below this comment as a test for multiplayer, it works fine
let dx = 2;
let dy = -2;
let player1UpPressed = false;
let player1DownPressed = false;
let player2UpPressed = false;
let player2DownPressed = false;
let player1Score = 0;
let player2Score = 0;
function drawPaddle(y1, y2) {
ctx.fillStyle = '#000'; // Set fill style for paddles
ctx.fillRect(0, y1, paddleWidth, paddleHeight); // Draw paddle for player 1
ctx.fillRect(canvas.width - paddleWidth, y2, paddleWidth, paddleHeight); // Draw paddle for player 2
}
function drawBall() {
ctx.beginPath();
ctx.arc(ballX, ballY, ballRadius, 0, Math.PI * 2);
ctx.fillStyle = '#0095DD';
ctx.fill();
ctx.closePath();
}
function drawScores() {
let player1Text = document.getElementById("name1").textContent;
let player2Text = document.getElementById("name2").textContent;
// Extract the player names
let playerName1 = player1Text.substring(0, player1Text.indexOf(':') + 1);
let playerName2 = player2Text.substring(0, player2Text.indexOf(':') + 1);
// Update only the score values
document.getElementById("name1").textContent = playerName1 + " " + player1Score;
document.getElementById("name2").textContent = playerName2 + " " + player2Score;
}
function updatePaddlePositions() {
if (currentPlayer === 1) {
if (player1UpPressed && player1Y > 0) {
player1Y -= 5;
}
if (player1DownPressed && player1Y < canvas.height - paddleHeight) {
player1Y += 5;
}
} else if (currentPlayer === 2) {
if (player2UpPressed && player2Y > 0) {
player2Y -= 5;
}
if (player2DownPressed && player2Y < canvas.height - paddleHeight) {
player2Y += 5;
}
}
}
function updateScores() {
// Check if the ball went past the paddles
if (ballX - ballRadius <= 0) {
player2Score++; // Player 2 scored
resetBall();
} else if (ballX + ballRadius >= canvas.width) {
player1Score++; // Player 1 scored
resetBall();
}
}
function resetBall() {
ballX = canvas.width / 2;
ballY = canvas.height / 2;
dx = -dx; // Change ball direction
}
function draw() {
// Draw trail effect by filling canvas with transparent color
ctx.fillStyle = 'rgba(255, 255, 255, 0.4)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Draw paddles and ball
drawPaddle(player1Y, player2Y);
drawBall();
drawScores(); // Draw scores
// Bounce the ball off the walls
if (ballY + dy > canvas.height - ballRadius || ballY + dy < ballRadius) {
dy = -dy;
}
// Bounce the ball off the paddles
if (
(ballX - ballRadius <= paddleWidth && ballY >= player1Y && ballY <= player1Y + paddleHeight) ||
(ballX + ballRadius >= canvas.width - paddleWidth && ballY >= player2Y && ballY <= player2Y + paddleHeight)
) {
dx = -dx;
}
// Update ball position
ballX += dx;
ballY += dy;
// Update paddle positions
updatePaddlePositions();
// Update scores
updateScores();
}
document.addEventListener('keydown', function (e) {
if (e.key === 'w') {
if (currentPlayer === 1) {
player1UpPressed = true;
} else if (currentPlayer === 2) {
player2UpPressed = true;
}
} else if (e.key === 's') {
if (currentPlayer === 1) {
player1DownPressed = true;
} else if (currentPlayer === 2) {
player2DownPressed = true;
}
}
});
document.addEventListener('keyup', function (e) {
if (e.key === 'w') {
if (currentPlayer === 1) {
player1UpPressed = false;
} else if (currentPlayer === 2) {
player2UpPressed = false;
}
} else if (e.key === 's') {
if (currentPlayer === 1) {
player1DownPressed = false;
} else if (currentPlayer === 2) {
player2DownPressed = false;
}
}
});
setInterval(draw, 10);
})
}
Upvotes: 0
Views: 99