I am a beginner at multiplayer game development. I am trying to code a multiplayer game running on node.js socket.io html5. I have already the players which are created on server's side. Now I have a problem with creating the balls on server's side. Here's my scenario:
- Server creates an amount of balls
- Then it emits to all connected users
- Each user receives the balls
- Then the server tries to move the balls
- On each movement the server emits the new coordinates x,y of each ball to clients
- Client receives the balls and tries to draw them in the main loop
I can get the balls on each client's side but the balls are not changing their coordinates which means they are not updating the new values that the server had emitted before. Below is my code. If anyone could see it and tells me where I make mistake I would be so thankful.
the html code: simpleChat.html
<style>
#myCanvas {
border: 1px solid red;
background-color:pink;
}
</style>
<script src="jeu.js"></script>
<script src="/socket.io/socket.io.js"></script>
<script>
var username = prompt("What's your name?");
var conversation, data, datasend, users;
var socket = io.connect();
// on connection to server, ask for user's name with an anonymous callback
socket.on('connect', function(){
// call the server-side function 'adduser' and send one parameter (value of prompt)
socket.emit('adduser', username);
});
// listener, whenever the server emits 'updatechat', this updates the chat body
socket.on('updatechat', function (username, data) {
var chatMessage = "<b>" + username + ":</b> " + data + "<br>";
conversation.innerHTML += chatMessage;
});
// just one player moved
socket.on('updatepos', function (newPos) {
console.log('client: '+newPos.user +' has to update pos to ['+newPos.x+','+newPos.y+']');
updatePlayerNewPos(newPos);
});
// listener, whenever the server emits 'updateusers', this updates the username list
socket.on('updateusers', function(listOfUsers) {
users.innerHTML = "";
for(var name in listOfUsers) {
var userLineOfHTML = '<div>' + name + '</div>';
users.innerHTML += userLineOfHTML;
}
});
// update the whole list of players, useful when a player
// connects or disconnects, we must update the whole list
socket.on('updatePlayers', function(listOfplayers) {
updatePlayers(listOfplayers);
});
// on load of page
window.addEventListener("load", function(){
// get handles on various GUI components
conversation = document.querySelector("#conversation");
data = document.querySelector("#data");
datasend = document.querySelector("#datasend");
users = document.querySelector("#users");
// Listener for send button
datasend.addEventListener("click", function(evt) {
sendMessage();
});
// detect if enter key pressed in the input field
data.addEventListener("keypress", function(evt) {
// if pressed ENTER, then send
if(evt.keyCode === 13) {
this.blur();
sendMessage();
}
});
// sends the chat message to the server
function sendMessage() {
var message = data.value;
data.value = "";
// tell server to execute 'sendchat' and send along one parameter
socket.emit('sendchat', message);
}
});
</script>
<body onload="init();">
<p>
<canvas width = 600 height = 400 id="myCanvas"></canvas>
<p>
<div style="float:left;width:100px;border-right:1px solid black;height:300px;padding:10px;overflow:scroll-y;">
<b>USERS</b>
<div id="users"></div>
</div>
<div style="float:left;width:300px;height:250px;overflow:scroll-y;padding:10px;">
<div id="conversation"></div>
<input id="data" style="width:200px;" />
<input type="button" id="datasend" value="send" />
</div>
</body>
server's side server.js => in command prompt: node server.js
// We need to use the express framework: have a real web servler that knows how to send mime types etc.
var express = require('express');
// Init globals variables for each module required
var app = express()
, http = require('http')
, server = http.createServer(app)
, io = require('socket.io').listen(server);
// launch the http server on given port
server.listen(8082);
// Indicate where static files are located. Without this, no external js file, no css...
app.use(express.static(__dirname + '/'));
// routing
app.get('/', function (req, res) {
res.sendFile(__dirname + '/simpleChat.html');
});
// usernames which are currently connected to the chat
var usernames = {};
var listOfPlayers = {};
var canvas_d = {};
var oldTime = 0;
var joueurs = new Array();
var currentP = {};
var width = 600, height = 400;
var ballArray=[],ballArrayColor=[];
//var ballPos={};
function Balle(x, y, vx, vy, diameter, ballcol) {
this.x = x;
this.y = y;
this.vx = vx;
this.vy = vy;
this.rayon = diameter / 2;
this.bcolor=ballcol;
/*
this.draw = function (ballcol) {
ctx.beginPath();
ctx.arc(this.x, this.y, this.rayon, 0, 2 * Math.PI);
ctx.fillStyle = ballcol;
ctx.fill();
// console.log(ballcol);
};*/
/*
this.move = function () {
this.x += this.vx;
this.y += this.vy;
};*/
}
function createBalls(numberOfBalls) {
for (var i = 0; i < numberOfBalls; i++) {
var balcolor = getRandomColor();
// Create a ball with random position and speed
var ball = new Balle(width * Math.random(),
height * Math.random(),
(10 * Math.random()) - 5,
(10 * Math.random()) - 5,
15, balcolor); // radius, change if ou like.
// Add it to the array
//ballArray[i] = ball;
ballArray.push(ball);
ballArrayColor[i] = balcolor;
//console.log(i, balcolor);
}
}
function getRandomColor() {
var letters = '0123456789ABCDEF';
var color = '#';
for (var i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
}
function getMax(arr) {
var maxX = 0;
var maxY = 0;
for (var i in arr) {
if (i !== null) {
console.log('i not null kaj getMax');
if (maxX <= arr[i].x) {
maxX = arr[i].x + arr[i].width;
if (maxX >= (canvas_d.width - arr[i].width)) {
maxX = arr[i].x;
if (maxY <= arr[i].y) {
maxY = arr[i].y + arr[i].height;
}
}
}
} else {
maxX = arr[i].x;
maxY = arr[i].y;
}
}
return {'maxX': maxX + 0.5, 'maxY': maxY + 0.5};
}
function checkCollisionWithAnotherPlayer(arr, usr, currentP) {
for (var name in arr) {
console.log('other player: ' + name);
if (usr !== name) {
if ((arr[usr].x < (arr[name].x + arr[name].width))
&& ((arr[usr].x + arr[usr].width) > arr[name].x)
&& ((arr[usr].y + arr[usr].height) > arr[name].y)
&& (arr[usr].y < (arr[name].y + arr[name].height))) {
console.log('collision');
listOfPlayers[usr].x = currentP.x;
listOfPlayers[usr].y = currentP.y;
}
}
}
}
io.sockets.on('connection', function (socket) {
// when the client emits 'sendchat', this listens and executes
socket.on('sendchat', function (data) {
// we tell the client to execute 'updatechat' with 2 parameters
io.sockets.emit('updatechat', socket.username, data);
});
socket.on('canvas', function (d) {
canvas_d.width = d.width;
canvas_d.height = d.height;
});
// when the client emits 'sendupdate', this listens and executes
socket.on('sendupdate', function (input) {
console.log('socket on sendupdate from ' + input.user);
currentP = {'x': listOfPlayers[input.user].x, 'y': listOfPlayers[input.user].y};
oldTime = input.lastMove;
var now = Date.now();
console.log('now ' + now);
//calculating delta time
var delta = (now - oldTime) / 1000;
console.log('delta ' + delta);
listOfPlayers[input.user].speedX = listOfPlayers[input.user].speedY = 0;
if (input.inputStates.left) {
listOfPlayers[input.user].speedX = -listOfPlayers[input.user].v;
} else if (input.inputStates.up) {
listOfPlayers[input.user].speedY = -listOfPlayers[input.user].v;
} else if (input.inputStates.right) {
listOfPlayers[input.user].speedX = listOfPlayers[input.user].v;
} else if (input.inputStates.down) {
listOfPlayers[input.user].speedY = listOfPlayers[input.user].v;
}
listOfPlayers[input.user].x += delta * listOfPlayers[input.user].speedX;
listOfPlayers[input.user].y += delta * listOfPlayers[input.user].speedY;
//player restriction
if (listOfPlayers[input.user].x < 0)
listOfPlayers[input.user].x = 0;
//up wall
if (listOfPlayers[input.user].y < 0)
listOfPlayers[input.user].y = 0;
//down wall
if (listOfPlayers[input.user].y + listOfPlayers[input.user].height > canvas_d.height)
listOfPlayers[input.user].y -= delta * listOfPlayers[input.user].speedY;
//right wall
if (listOfPlayers[input.user].x + listOfPlayers[input.user].width > canvas_d.width)
listOfPlayers[input.user].x -= delta * listOfPlayers[input.user].speedX;
//collision detection with other players
checkCollisionWithAnotherPlayer(listOfPlayers, input.user, currentP);
console.log('socket emits to all players the updated position of player: ' + input.user + ' to position: ' + listOfPlayers[input.user].x + ' , ' + listOfPlayers[input.user].y);
var newPos = {'user': input.user, 'x': listOfPlayers[input.user].x, 'y': listOfPlayers[input.user].y};
io.sockets.emit('updatepos', newPos);
});
//when client emits 'drawBalls' the server will try to move each ball
socket.on('drawBalls',function(){
for(var i=0;i<ballArray;i++){
ballArray[i].x += ballArray[i].vx+10;
ballArray[i].y += ballArray[i].vy+10;
}
var ballPosit={
'balls':ballArray,
'colors':ballArrayColor
};
socket.emit('updateBallPos',ballPosit);
});
// when the client emits 'adduser', this listens and executes
socket.on('adduser', function (username) {
// we store the username in the socket session for this client
// the 'socket' variable is unique for each client connected,
// so we can use it as a sort of HTTP session
socket.username = username;
// add the client's username to the global list
// similar to usernames.michel = 'michel', usernames.toto = 'toto'
usernames[username] = username;
// echo to the current client that he is connecter
socket.emit('updatechat', 'SERVER', 'you have connected');
// echo to all client except current, that a new person has connected
socket.broadcast.emit('updatechat', 'SERVER', username + ' has connected');
// tell all clients to update the list of users on the GUI
io.sockets.emit('updateusers', usernames);
// Create a new player and store his position too... for that
// we have an object that is a "list of players" in that form
// listOfPlayer = {'michel':{'x':0, 'y':0, 'v':0},
// john:{'x':10, 'y':10, 'v':0}}
// for this example we have x, y and v for speed... ?
var player = {'x': 10, 'y': 10, 'v': 200, 'height': 100, 'width': 100, 'lastUpdate': null, 'name': username};
var newPlayer;
newPlayer = getMax(listOfPlayers);
player.x = newPlayer.maxX;
player.y = newPlayer.maxY;
console.log(newPlayer.maxX + ' - ' + newPlayer.maxY);
joueurs.push(player.username);
listOfPlayers[username] = player;
io.sockets.emit('updatePlayers', listOfPlayers);
//creation of balls
if(joueurs.length===1){
createBalls(2);
}
console.log('taille of joueurs; '+joueurs.length);
var ballPos={
'balls':ballArray,
'colors':ballArrayColor,
'user':username
};
// socket.emit('createBalls',ballPos);
});
// when the user disconnects.. perform this
socket.on('disconnect', function () {
var index = joueurs.indexOf(socket.username);
joueurs.splice(index, 1);
// remove the username from global usernames list
delete usernames[socket.username];
// update list of users in chat, client-side
io.sockets.emit('updateusers', usernames);
// Remove the player too
delete listOfPlayers[socket.username];
io.sockets.emit('updatePlayers', listOfPlayers);
// echo globally that this client has left
socket.broadcast.emit('updatechat', 'SERVER', socket.username + ' has disconnected');
});
});
client's side. jeu.js
var canvas, ctx, w, h;
var ballArray = [], ballArrayColor = [];
// for time based animation
// vars for handling inputs
var inputStates = {};
// Autres joueurs
var allPlayers = {};
var now;
function init() {
console.log("init");
canvas = document.querySelector("#myCanvas");
// often useful
w = canvas.width;
h = canvas.height;
ctx = canvas.getContext('2d');
var canvasDimension = {'width': w, 'height': h};
socket.emit('canvas', canvasDimension);
// Les écouteurs
//canvas.addEventListener("mousedown", traiteMouseDown);
//canvas.addEventListener("mousemove", traiteMouseMove);
//createBalls(2);
socket.on('createBalls',function(data){
ballArray=data.balls;
ballArrayColor=data.colors;
});
window.addEventListener('keydown', movePlayer, false);
anime();
}
function movePlayer(evt) {
inputStates.left = false;
inputStates.up = false;
inputStates.right = false;
inputStates.down = false;
if (evt.keyCode === 37) {
inputStates.left = true;
} else if (evt.keyCode === 38) {
evt.preventDefault();
inputStates.up = true;
} else if (evt.keyCode === 39) {
inputStates.right = true;
} else if (evt.keyCode === 40) {
evt.preventDefault();
inputStates.down = true;
}
now = Date.now();
var input = {'user': username, 'inputStates': inputStates, 'lastMove': now};
console.log('player' + username + ' wants to move with inputStates: ' + inputStates.up + ' ; ' + inputStates.down + ' ; ' + inputStates.left + ' ; ' + inputStates.right);
socket.emit('sendupdate', input);
}
function updatePlayerNewPos(newPos) {
for (var i in allPlayers) {
if (i === newPos.user) {
allPlayers[i].x = newPos.x;
allPlayers[i].y = newPos.y;
console.log('I have just moved!-> ' + newPos.x + ' ; ' + newPos.y);
}
}
}
// Mise à jour du tableau quand un joueur arrive
// ou se deconnecte
function updatePlayers(listOfPlayers) {
allPlayers = listOfPlayers;
}
function drawPlayer(joueur) {
// save the context
ctx.save();
// draw a red rectangle
// head
ctx.fillStyle = 'yellow';
ctx.fillRect(joueur.x, joueur.y, 100, 100);
ctx.fillStyle = "grey";
ctx.fillRect(joueur.x, joueur.y, 100, 10);
//eyebrows
ctx.fillStyle = 'black';
ctx.fillRect(joueur.x + 5, joueur.y + 15, 20, 5);
ctx.fillRect(joueur.x + 75, joueur.y + 15, 20, 5);
// eyes
ctx.fillStyle = 'lightblue';
ctx.fillRect(joueur.x + 10, joueur.y + 25, 10, 10);
ctx.fillRect(joueur.x + 80, joueur.y + 25, 10, 10);
// interior of eye
ctx.fillStyle = 'blue';
ctx.fillRect(joueur.x + 13, joueur.y + 27, 5, 5);
ctx.fillRect(joueur.x + 83, joueur.y + 27, 5, 5);
// Nose
ctx.fillStyle = 'brown';
ctx.fillRect(joueur.x + 50, joueur.y + 35, 8, 15);
//Moustaches
ctx.fillStyle = 'grey';
ctx.fillRect(joueur.x + 43, joueur.y + 63, 25, 5);
// Mouth
ctx.fillStyle = 'red';
ctx.fillRect(joueur.x + 35, joueur.y + 70, 40, 20);
//teeth
ctx.fillStyle = 'white';
ctx.fillRect(joueur.x + 38, joueur.y + 73, 10, 15);
ctx.fillRect(joueur.x + 50, joueur.y + 73, 10, 15);
ctx.fillRect(joueur.x + 62, joueur.y + 73, 10, 15);
// ctx.strokeText(joueur.name,joueur.x+50,joueur.y+50);
ctx.restore();
}
function drawAllPlayers() {
for (var name in allPlayers) {
drawPlayer(allPlayers[name]);
}
}
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
function anime() {
if (username !== undefined) {
// 1 On efface l'écran
ctx.clearRect(0, 0, canvas.width, canvas.height);
// 2 On dessine des objets
drawAllPlayers();
socket.on('updateBallPos',function(data){
console.log('=== updating the pos of balls');
ballArray=[];
ballArrayColor=[];
ballArray=data.balls;
ballArrayColor=data.colors;
});
//drawing the balls
for (var i = 0; i < ballArray.length; i++) {
var balle = ballArray[i];
var bc = ballArrayColor[i];
console.log(balle.x, balle.y, bc);
// 1) Move the ball
// balle.move();
// 2) collision test with walls
//collisionTestWithWalls(balle);
// 3) draw the ball
// balle.draw(bc);
ctx.beginPath();
ctx.arc(balle.x, balle.y, balle.rayon, 0, 2 * Math.PI);
ctx.fillStyle = bc;
ctx.fill();
}
socket.emit('drawBalls','balls are drawn');
}/*
socket.on('updateBallPos',function(data){
console.log('=== updating the pos of balls');
ballArray=[];
ballArrayColor=[];
ballArray=data.balls;
ballArrayColor=data.colors;
});
for (var i = 0; i < ballArray.length; i++) {
var balle = ballArray[i];
var bc = ballArrayColor[i];
console.log(balle.x, balle.y, bc);
// 1) Move the ball
// balle.move();
// 2) collision test with walls
//collisionTestWithWalls(balle);
// 3) draw the ball
// balle.draw(bc);
ctx.beginPath();
ctx.arc(balle.x, balle.y, balle.rayon, 0, 2 * Math.PI);
ctx.fillStyle = bc;
ctx.fill();
}
socket.emit('drawBalls','balls are drawn');
*/
//collisionTestBetweenBalls();
// 4 On rappelle la fonction d'animation à 60 im/s
requestAnimationFrame(anime);
}
via P Richmond
No comments:
Post a Comment