Archived
1
0
Fork 0

Handle all Physics serverside

This commit is contained in:
Simon Giesel 2017-01-21 18:58:44 +01:00
parent 0f344b7b63
commit 8cf7f9336c
2 changed files with 343 additions and 124 deletions

View file

@ -17,13 +17,14 @@
<script> <script>
var socket = io(); var socket = io();
var pid; var pid;
socket.on('handshake', function(id, state, c_width, c_height, sp, fn){ socket.on('handshake', function(id, state, c_width, c_height, sp, score, fn){
$('id').text(id); $('id').text(id);
pid = id; pid = id;
gameState = state; gameState = state;
cube_width = c_width; cube_width = c_width;
cube_height = c_height; cube_height = c_height;
speed = sp; cube_speed = sp;
score = score;
fn($(window).width(), $(window).height()); fn($(window).width(), $(window).height());
}); });
@ -39,12 +40,17 @@
gameState = state; gameState = state;
}); });
socket.on('shootball', function(y){ socket.on('scoreChange', function(val){
if(ball_owner == 1) leftY = y; score = val;
if(ball_owner == 2) rightY = y;
shootBall(false);
}); });
// Obsolete
// socket.on('shootball', function(y){
// if(ball_owner == 1) leftY = y;
// if(ball_owner == 2) rightY = y;
// shootBall();
// });
/** Make Countdown serversided No cheating possible **/ /** Make Countdown serversided No cheating possible **/
socket.on('countdown', function(i){ socket.on('countdown', function(i){
text = 'Starting in ' + i; text = 'Starting in ' + i;
@ -74,11 +80,20 @@
rightV = val; rightV = val;
rightY = y; rightY = y;
} }
console.log(leftY); (leftY);
});
socket.on('ballpos', function(data){
ballX = data['x'];
ballY = data['y'];
ball_VX = data['vx'];
ball_VY = data['vy'];
ball_speed = data['speed'];
ball_owner = data['owner'];
}); });
socket.on('test', function(arg){ socket.on('test', function(arg){
console.log(arg); (arg);
}); });
/** Initialize Canvas **/ /** Initialize Canvas **/
var c = document.getElementById("test"); var c = document.getElementById("test");
@ -86,7 +101,6 @@
c.width = $(window).width(); c.width = $(window).width();
c.height = $(window).height(); c.height = $(window).height();
var leftY = 0; var leftY = 0;
var rightY = 0; var rightY = 0;
var leftV = 0; var leftV = 0;
@ -94,6 +108,7 @@
var leftColor = 'red'; var leftColor = 'red';
var rightColor = 'blue'; var rightColor = 'blue';
var gameState = 0; // 0 == Waiting for Players, 1 == Countdown, 2 == inGame, 3 == ??Win?? var gameState = 0; // 0 == Waiting for Players, 1 == Countdown, 2 == inGame, 3 == ??Win??
var score = [0,0];
/** FPS Vars **/ /** FPS Vars **/
var lastCalledTime, var lastCalledTime,
@ -108,7 +123,7 @@
/** Prop-Config **/ /** Prop-Config **/
var cube_width = 50, var cube_width = 50,
cube_height = 200, cube_height = 200,
speed = 7, cube_speed = 7,
ball_size = 15, ball_size = 15,
ball_speed = 8, ball_speed = 8,
ballX = cube_width+ball_size, ballX = cube_width+ball_size,
@ -167,35 +182,38 @@
ctx.fillRect(0, 0, width, height); ctx.fillRect(0, 0, width, height);
/** Points **/
var scoretxt = score[0] + ' : ' + score[1];
ctx.fillStyle = 'black';
ctx.font = '40px monospace';
ctx.textAlign = 'center';
ctx.fillText(scoretxt, width/2, 70);
if(gameState < 2){ if(gameState < 2){
ctx.fillStyle = 'black'; ctx.fillStyle = 'black';
ctx.font = '30px monospace'; ctx.font = '30px monospace';
ctx.fillText(text, width/2-text.length*8, height/2-30); ctx.textAlign = 'center';
ctx.fillText(text, width/2, height/2-30);
} }
if(gameState == 2 && pid > 2){ if(gameState == 2 && pid > 2){
var specstr = "Spectator-Mode" var specstr = "Spectator-Mode"
ctx.fillStyle = 'black'; ctx.fillStyle = 'black';
ctx.font = '15px monospace'; ctx.font = '15px monospace';
ctx.fillText(specstr, width/2-specstr.length*8, 50); ctx.textAlign = 'center';
ctx.fillText(specstr, width/2, 25);
} }
if(leftY > height-cube_height || leftY < 0)
leftV = 0;
if(rightY > height-cube_height || rightY < 0)
rightV = 0;
if(leftY < 0 ) leftY = 0;
if(rightY < 0 ) rightY = 0;
if(leftY > height-cube_height) leftY = height-cube_height;
if(rightY > height-cube_height) rightY = height-cube_height;
/** Draw Cube **/ /** Draw Cube **/
/** Note: Get position by multiplying it with the "Render-Delta" - for same speed on every system **/ /** Note: Get position by multiplying it with the "Render-Delta" - for same speed on every system **/
// console.log(leftV*delta*60*cube_speed);
leftY -= leftV*Math.round((1*delta)*60*speed); // leftY -= leftV*delta*60*cube_speed;
rightY -= rightV*Math.round((1*delta)*60*speed); // rightY -= rightV*delta*60*cube_speed;
// NOTE Server is calcualating Position -> Client is only drawing
ctx.fillStyle = leftColor; ctx.fillStyle = leftColor;
@ -203,61 +221,66 @@
ctx.fillStyle = rightColor; ctx.fillStyle = rightColor;
ctx.fillRect(width-cube_width, rightY, cube_width, cube_height); ctx.fillRect(width-cube_width, rightY, cube_width, cube_height);
/** Move Ball with Paddle if owned by owner (@roundstart) **/ // /** Move Ball with Paddle if owned by owner (@roundstart) **/
if(ball_owner == 1){ // if(ball_owner == 1){
ballX = cube_width+ball_size, // ballX = cube_width+ball_size,
ballY = leftY+cube_height/2; // ballY = leftY+cube_height/2;
} // }
else if(ball_owner == 2){ // else if(ball_owner == 2){
ballX = width-cube_width-ball_size, // ballX = width-cube_width-ball_size,
ballY = rightY+cube_height/2; // ballY = rightY+cube_height/2;
} // }
//
/** ############ **/ // /** ############ **/
/** Ball Physics **/ // /** Ball Physics **/
/** ############ **/ // /** ############ **/
//
/** Collide with right Paddle or get point and respawn **/ // /** Collide with right Paddle or get point and respawn **/
if(ballX > width - cube_width){ // if(ballX > width - cube_width){
if(ballY < rightY || ballY > rightY+cube_height){ // if(ballY < rightY || ballY > rightY+cube_height){
console.log('Point for Left'); // console.log('Point for Left');
ball_VX = 0; // ball_VX = 0;
ball_VY = 0; // ball_VY = 0;
ball_owner = 1; // ball_owner = 1;
} else { // } else {
var intersect = ((rightY+cube_height/2)-ballY)/(cube_height/2); // var intersect = ((rightY+cube_height/2)-ballY)/(cube_height/2);
console.log(intersect); // console.log('Intersect with right at:');
ball_VX = -ball_speed*Math.cos(intersect*ball_maxAngle); // console.log(intersect);
ball_VY = -ball_speed*Math.sin(intersect*ball_maxAngle); // console.log('###########################');
} // ball_VX = -ball_speed*Math.cos(intersect*ball_maxAngle);
} // ball_VY = -ball_speed*Math.sin(intersect*ball_maxAngle);
// }
/** Collide with left Paddle or get point and respawn **/ // }
if(ballX < cube_width){ //
if(ballY < leftY || ballY > leftY+cube_height){ // /** Collide with left Paddle or get point and respawn **/
console.log('Point for Right'); // if(ballX < cube_width){
ball_VX = 0; // if(ballY < leftY || ballY > leftY+cube_height){
ball_VY = 0; // console.log('Point for Right');
ball_owner = 2; // ball_VX = 0;
} else { // ball_VY = 0;
var intersect = ((leftY+cube_height/2)-ballY)/(cube_height/2); // ball_owner = 2;
console.log(intersect); // } else {
ball_VX = ball_speed*Math.cos(intersect*ball_maxAngle); // var intersect = ((leftY+cube_height/2)-ballY)/(cube_height/2);
ball_VY = ball_speed*Math.sin(intersect*ball_maxAngle); // console.log('Intersect with left at:');
} // console.log(intersect);
} // console.log('###########################');
// ball_VX = ball_speed*Math.cos(intersect*ball_maxAngle);
/** TODO INCREASE SPEED ON PADDLE HIT (weiter außen = schneller) **/ // ball_VY = ball_speed*Math.sin(intersect*ball_maxAngle);
// }
/** Collide with walls **/ // }
if(ballY <= 0 || ballY >= height-ball_size){ //
ball_VY = -ball_VY; // /** TODO INCREASE SPEED ON PADDLE HIT (weiter außen = schneller) **/
} //
// /** Collide with walls **/
// if(ballY <= 0 || ballY >= height-ball_size){
// ball_VY = -ball_VY;
// console.log(ballX + ' : ' + ballY);
// }
/** Draw Ball **/ /** Draw Ball **/
ctx.fillStyle = 'black'; ctx.fillStyle = 'black';
ballX += Math.round((1*delta)*60)*ball_VX; // ballX += Math.round((1*delta)*60)*ball_VX;
ballY += Math.round((1*delta)*60)*ball_VY; // ballY += Math.round((1*delta)*60)*ball_VY;
ctx.beginPath(); ctx.beginPath();
ctx.arc(ballX, ballY, ball_size, 0, 2*Math.PI); ctx.arc(ballX, ballY, ball_size, 0, 2*Math.PI);
ctx.fill(); ctx.fill();
@ -299,7 +322,7 @@
case 37 : case 37 :
case 39 : case 39 :
case 65 : case 65 :
case 68 : if(ball_owner != pid)break; shootBall(); break; case 68 : if(ball_owner != pid)break; if(ball_owner == 1) socket.emit('ballshoot', leftY); else if(ball_owner == 2) socket.emit('ballshoot', rightY); break;
} }
} }
}); });
@ -343,32 +366,34 @@
function setV(pos, val){ function setV(pos, val){
console.log(leftY); var time = Date.now();
if(pos == 1){ if(pos == 1){
leftV = val; leftV = val;
if(!localcoop) if(!localcoop)
socket.emit('vchange', pos, val, leftY); socket.emit('vchange', pos, val, leftY, time);
} }
if(pos == 2){ if(pos == 2){
rightV = val; rightV = val;
if(!localcoop) if(!localcoop)
socket.emit('vchange', pos, val, rightY); socket.emit('vchange', pos, val, rightY, time);
} }
} }
function shootBall(sync = true) { function shootBall() {
/** TODO Tewak and Add MAX_Speed **/ // console.log('### Ball shoot event ###');
if(ball_owner == 1){ // /** TODO Tewak and Add MAX_Speed **/
ball_VX = ball_speed; // if(ball_owner == 1){
if(!localcoop && sync) // ball_VX = ball_speed;
socket.emit('ballshoot', leftY); // console.log('owner: left - at:' + leftY);
} //
else if(ball_owner == 2){ // }
ball_VX = -ball_speed; // else if(ball_owner == 2){
if(!localcoop && sync) // ball_VX = -ball_speed;
socket.emit('ballshoot', rightY); // console.log('owner: right - at:' + rightY);
} // if(!localcoop)
ball_owner = 0; // socket.emit('ballshoot', rightY);
// }
// ball_owner = 0;
} }
function animloop() { function animloop() {

254
index.js
View file

@ -6,33 +6,52 @@ app.get('/', function(req, res){
res.sendFile(__dirname + '/index.html'); res.sendFile(__dirname + '/index.html');
}); });
var sockets = []; /** Parameters **/
var gameState = 0; var clients = [], // List of all conected clients
var width, height; players = [], // Store Player 1 and Player 2 in Array {Player1 == players[0]}
var startinterval; gameState = 0, // Game-Controler Variable
width, height, // Final Width + Height of Game-Window
startinterval, // Interval for Counting down (cancelable)
calcPos,
score = [0,0];
/** Game-Config **/ /** Game-Config **/
var cube_width = 50, var cube_width = 50,
cube_height = 200, cube_height = 200,
speed = 7; cube_speed = 7; // Depending on 'tickrate' [cube_speed*tickrate == acutal Speed]
/** Networking-Config **/
var tickrate = 20;
/** Ball-Config **/
var ball_size = 15,
ball_speed = 15,
ballX = cube_width+ball_size,
ballY = cube_height/2,
ball_owner = 1,
ball_VX = 0,
ball_VY = 0,
ball_maxAngle = 5*Math.PI/12;
/** ########## **/ /** ########## **/
/** CONNECTION **/ /** CONNECTION **/
/** ########## **/ /** ########## **/
io.on('connection', function(socket){ io.on('connection', function(socket){
var id = sockets.length + 1; /** Set ID for User **/
if(sockets.length == 1) var id = clients.length + 1;
if(sockets[0].id == 2) id = 1; if(clients.length == 1)
var clientkey = sockets.push(new Client(id, socket)) - 1; if(clients[0].id == 2) id = 1;
var clientkey = clients.push(new Client(id, socket)) - 1;
console.log('Client connected. ID=' + id); console.log('Client connected. ID=' + id);
/** ######### **/ /** ######### **/
/** HANDSHAKE **/ /** HANDSHAKE **/
/** ######### **/ /** ######### **/
socket.emit('handshake', id, gameState, cube_width, cube_height, speed, function(w, h){ // Callback function for 1st Client to set screen size // socket.emit('handshake', id, gameState, cube_width, cube_height, cube_speed, score, function(w, h){ // Callback function for 1st Client to set screen size //
sockets[clientkey].width = w; clients[clientkey].width = w;
sockets[clientkey].height = h; clients[clientkey].height = h;
if(sockets.length > 1 && gameState == 0) setUp(socket); if(clients.length > 1 && gameState == 0) setUp(socket);
}); });
if(gameState > 0) socket.emit('size', width, height); if(gameState > 0) socket.emit('size', width, height);
@ -43,18 +62,60 @@ if(gameState > 0) socket.emit('size', width, height);
fn(Date.now()); fn(Date.now());
}); });
/** #### **/ /** ######### **/
/** Ballshoot **/ /** Ballshoot **/
/** ### **/ /** ######### **/
socket.on('ballshoot', function(y){ socket.on('ballshoot', function(y){
socket.broadcast.emit('shootball', y); // shottball event obsolet
// socket.emit('shootball', y);
// socket.broadcast.emit('shootball', y);
console.log('### Ball shoot event ###');
if(ball_owner == 1){
ball_VX = ball_speed;
console.log('owner: left - at:' + players[0].y);
}
else if(ball_owner == 2){
ball_VX = -ball_speed;
console.log('owner: right - at:' + players[1].y);
}
ball_owner = 0;
}); });
/** ################ **/ /** ################ **/
/** Paddel V-Change **/ /** Paddel V-Change **/
/** ############## **/ /** ############## **/
socket.on('vchange', function(pos, val, y){ socket.on('vchange', function(pos, val, y, timestamp){
socket.broadcast.emit('changeV', pos, val, y); var timediff = Date.now()-timestamp;
// console.log('INTERPOLATING...');
// var diff = ((players[pos-1].speed/tickrate)*timediff);
// if(players[pos-1].vY == 0){ // Lag from Sender (accel)
// if(val > 0)
// players[pos-1].y -= diff;
// if(val < 0)
// players[pos-1].y += diff;
// }
// if(players[pos-1].vY == 1){
// if(val == 0)
// players[pos-1].y += diff;
// }
// if(players[pos-1].vY == -1){
// if(val == 0)
// players[pos-1].y -= diff;
// }
players[pos-1].vY = val;
// console.log('Diff:' + diff);
// console.log('Got: ' + y + ' @ ' + timestamp);
// console.log('Expected:' + players[pos-1].y + ' @ ' + Date.now());
socket.emit('changeV', pos, val, players[pos-1].y);
socket.broadcast.emit('changeV', pos, val, players[pos-1].y);
}); });
/** ########## **/ /** ########## **/
@ -62,17 +123,17 @@ if(gameState > 0) socket.emit('size', width, height);
/** ########## **/ /** ########## **/
socket.on('disconnect', function(){ socket.on('disconnect', function(){
var index; var index;
sockets.forEach(function(sock, ind){ clients.forEach(function(sock, ind){
if (sock.socket == socket){ if (sock.socket == socket){
index = ind; index = ind;
return; return;
} }
}); });
var oldid = sockets[index].id; var oldid = clients[index].id;
sockets.splice(index, 1); clients.splice(index, 1);
console.log('Client disconnected. ID=' + (oldid+1)); console.log('Client disconnected. ID=' + (oldid+1));
if(sockets.length == 1){ if(clients.length == 1){
sockets[0].socket.emit('test', 'player_left'); //TODO win-event clients[0].socket.emit('test', 'player_left'); //TODO win-event
console.log('Only one Player left. Sending win-event'); console.log('Only one Player left. Sending win-event');
// Debug Restart: // Debug Restart:
gameState = 0; gameState = 0;
@ -80,7 +141,7 @@ if(gameState > 0) socket.emit('size', width, height);
broadcastGameState(socket); broadcastGameState(socket);
return; return;
} }
else if(sockets.length == 0){ else if(clients.length == 0){
console.log('All Players left. Reseting lobby...'); console.log('All Players left. Reseting lobby...');
gameState = 0; gameState = 0;
id = 0; id = 0;
@ -88,10 +149,10 @@ if(gameState > 0) socket.emit('size', width, height);
} }
var key = 0; var key = 0;
if(sockets[0].id == 1 || sockets[0].id == 2) key = 1; if(clients[0].id == 1 || clients[0].id == 2) key = 1;
switch(oldid){ switch(oldid){
case 1 : sockets[key].id = 1; sockets[key].socket.emit('handshake', 1); console.log('New Player 1 selected.'); setUp(); break; case 1 : clients[key].id = 1; clients[key].socket.emit('handshake', 1); console.log('New Player 1 selected.'); setUp(); break;
case 2 : sockets[key].id = 2; sockets[key].socket.emit('handshake', 2); console.log('New Player 2 selected.'); setUp(); break; case 2 : clients[key].id = 2; clients[key].socket.emit('handshake', 2); console.log('New Player 2 selected.'); setUp(); break;
default : console.log('Spectator left. Nothing need to select new Players.'); break; default : console.log('Spectator left. Nothing need to select new Players.'); break;
} }
@ -103,16 +164,20 @@ http.listen(3000, function(){
console.log('listening on *:3000'); console.log('listening on *:3000');
}); });
/** Sync all settings to client and start the game **/
function setUp(socket){ function setUp(socket){
gameState = 1; gameState = 1;
broadcastGameState(socket); broadcastGameState(socket);
console.log('Starting SetUp...'); console.log('Starting SetUp...');
/** Select smalest screensize and set for all clients **/ /** Select smalest screensize and set for all clients **/
sockets.forEach(function(sock){ clients.forEach(function(sock){
broadcastGameState(socket); broadcastGameState(socket);
if(sock.id == 1) if(sock.id == 1){
sockets.forEach(function(sock2){ players[0] = new Player(sock.id, sock.socket);
clients.forEach(function(sock2){
if(sock2.id == 2){ if(sock2.id == 2){
players[1] = new Player(sock2.id, sock2.socket);
if(sock.width < sock2.width) if(sock.width < sock2.width)
width = sock.width; width = sock.width;
else else
@ -123,7 +188,10 @@ function setUp(socket){
height = sock2.height; height = sock2.height;
} }
}); });
}
}); });
if(calcPos == null) // Start tick Server only once
tickServer();
socket.emit('size', width, height); socket.emit('size', width, height);
socket.broadcast.emit('size', width, height); socket.broadcast.emit('size', width, height);
var i = 5; var i = 5;
@ -132,6 +200,7 @@ function setUp(socket){
socket.emit('countdown', i); socket.emit('countdown', i);
socket.broadcast.emit('countdown', i); socket.broadcast.emit('countdown', i);
if(i == 0){ if(i == 0){
resetPlayers();
clearInterval(startinterval); clearInterval(startinterval);
gameState = 2; gameState = 2;
broadcastGameState(socket); broadcastGameState(socket);
@ -141,14 +210,139 @@ function setUp(socket){
}, 1000); }, 1000);
} }
/** Broadcast GameState to all clients **/
function broadcastGameState(socket){ function broadcastGameState(socket){
socket.emit('gamestate', gameState); socket.emit('gamestate', gameState);
socket.broadcast.emit('gamestate', gameState); socket.broadcast.emit('gamestate', gameState);
} }
function tickServer(){
calcPos = setInterval(function(){
calculatePlayerPosition();
calculateBallPosition();
}, tickrate);
}
function calculatePlayerPosition(){
players.forEach(function(player){
player.y -= player.vY*player.speed;
if(player.y > height-player.height || player.y < 0) player.vY = 0;
if(player.y < 0) player.y = 0;
if(player.y > height-player.height) player.y = height-player.height;
player.socket.emit('changeV', player.id, player.vY, player.y);
player.socket.broadcast.emit('changeV', player.id, player.vY, player.y);
});
}
function calculateBallPosition(){
/** Move Ball with Paddle if owned by owner (@roundstart) **/
if(ball_owner == 1){
ballX = cube_width+ball_size,
ballY = players[0].y+cube_height/2;
}
else if(ball_owner == 2){
ballX = width-cube_width-ball_size,
ballY = players[1].y+cube_height/2;
}
/** ############ **/
/** Ball Physics **/
/** ############ **/
ballX += ball_VX;
ballY += ball_VY;
/** Collide with right Paddle or get point and respawn **/
if(ballX > width - cube_width){
if(ballY < players[1].y || ballY > players[1].y+cube_height){
console.log('Point for Left');
changeScore(1, score[0]+1);
ball_VX = 0;
ball_VY = 0;
ball_owner = 1;
} else {
var intersect = ((players[1].y+cube_height/2)-ballY)/(cube_height/2);
console.log('Intersect with right at:');
console.log(intersect);
console.log('###########################');
ball_VX = -ball_speed*Math.cos(intersect*ball_maxAngle);
ball_VY = -ball_speed*Math.sin(intersect*ball_maxAngle);
}
}
/** Collide with left Paddle or get point and respawn **/
if(ballX < cube_width){
if(ballY < players[0].y || ballY > players[0].y+cube_height){
console.log('Point for Right');
changeScore(2, score[1]+1);
ball_VX = 0;
ball_VY = 0;
ball_owner = 2;
} else {
var intersect = ((players[0].y+cube_height/2)-ballY)/(cube_height/2);
console.log('Intersect with left at:');
console.log(intersect);
console.log('###########################');
ball_VX = ball_speed*Math.cos(intersect*ball_maxAngle);
ball_VY = ball_speed*Math.sin(intersect*ball_maxAngle);
}
}
/** TODO INCREASE SPEED ON PADDLE HIT (weiter außen = schneller) **/
/** Collide with walls **/
if(ballY <= 0 || ballY >= height-ball_size){
ball_VY = -ball_VY;
console.log(ballX + ' : ' + ballY);
}
var data = {
x : ballX,
y : ballY,
vx : ball_VX,
vy : ball_VY,
speed : ball_speed,
owner : ball_owner
};
players[0].socket.emit('ballpos', data);
players[0].socket.broadcast.emit('ballpos', data);
}
function changeScore(id, val){
score[id-1] = val;
players[0].socket.emit('scoreChange', score);
players[0].socket.broadcast.emit('scoreChange', score);
}
function resetPlayers(){
players.forEach(function(player){
player.speed = cube_speed;
player.width = cube_width;
player.height = cube_height;
player.y = 0;
player.vY = 0;
changeScore(player.id-1, 0);
});
}
function resetServer(){
// TODO
}
function Client(id, socket){ function Client(id, socket){
this.id = id; this.id = id;
this.socket = socket; this.socket = socket;
this.width = 0; this.width = 0;
this.height = 0; this.height = 0;
} }
function Player(id, socket){
this.id = id;
this.socket = socket;
this.speed = cube_speed;
this.width = cube_width;
this.height = cube_height;
this.y = 0;
this.vY = 0;
}