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>
var socket = io();
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);
pid = id;
gameState = state;
cube_width = c_width;
cube_height = c_height;
speed = sp;
cube_speed = sp;
score = score;
fn($(window).width(), $(window).height());
});
@ -39,12 +40,17 @@
gameState = state;
});
socket.on('shootball', function(y){
if(ball_owner == 1) leftY = y;
if(ball_owner == 2) rightY = y;
shootBall(false);
socket.on('scoreChange', function(val){
score = val;
});
// 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 **/
socket.on('countdown', function(i){
text = 'Starting in ' + i;
@ -74,11 +80,20 @@
rightV = val;
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){
console.log(arg);
(arg);
});
/** Initialize Canvas **/
var c = document.getElementById("test");
@ -86,7 +101,6 @@
c.width = $(window).width();
c.height = $(window).height();
var leftY = 0;
var rightY = 0;
var leftV = 0;
@ -94,6 +108,7 @@
var leftColor = 'red';
var rightColor = 'blue';
var gameState = 0; // 0 == Waiting for Players, 1 == Countdown, 2 == inGame, 3 == ??Win??
var score = [0,0];
/** FPS Vars **/
var lastCalledTime,
@ -108,7 +123,7 @@
/** Prop-Config **/
var cube_width = 50,
cube_height = 200,
speed = 7,
cube_speed = 7,
ball_size = 15,
ball_speed = 8,
ballX = cube_width+ball_size,
@ -167,35 +182,38 @@
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){
ctx.fillStyle = 'black';
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){
var specstr = "Spectator-Mode"
ctx.fillStyle = 'black';
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 **/
/** Note: Get position by multiplying it with the "Render-Delta" - for same speed on every system **/
leftY -= leftV*Math.round((1*delta)*60*speed);
rightY -= rightV*Math.round((1*delta)*60*speed);
// console.log(leftV*delta*60*cube_speed);
// leftY -= leftV*delta*60*cube_speed;
// rightY -= rightV*delta*60*cube_speed;
// NOTE Server is calcualating Position -> Client is only drawing
ctx.fillStyle = leftColor;
@ -203,61 +221,66 @@
ctx.fillStyle = rightColor;
ctx.fillRect(width-cube_width, rightY, cube_width, cube_height);
/** Move Ball with Paddle if owned by owner (@roundstart) **/
if(ball_owner == 1){
ballX = cube_width+ball_size,
ballY = leftY+cube_height/2;
}
else if(ball_owner == 2){
ballX = width-cube_width-ball_size,
ballY = rightY+cube_height/2;
}
/** ############ **/
/** Ball Physics **/
/** ############ **/
/** Collide with right Paddle or get point and respawn **/
if(ballX > width - cube_width){
if(ballY < rightY || ballY > rightY+cube_height){
console.log('Point for Left');
ball_VX = 0;
ball_VY = 0;
ball_owner = 1;
} else {
var intersect = ((rightY+cube_height/2)-ballY)/(cube_height/2);
console.log(intersect);
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){
console.log('Point for Right');
ball_VX = 0;
ball_VY = 0;
ball_owner = 2;
} else {
var intersect = ((leftY+cube_height/2)-ballY)/(cube_height/2);
console.log(intersect);
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;
}
// /** Move Ball with Paddle if owned by owner (@roundstart) **/
// if(ball_owner == 1){
// ballX = cube_width+ball_size,
// ballY = leftY+cube_height/2;
// }
// else if(ball_owner == 2){
// ballX = width-cube_width-ball_size,
// ballY = rightY+cube_height/2;
// }
//
// /** ############ **/
// /** Ball Physics **/
// /** ############ **/
//
// /** Collide with right Paddle or get point and respawn **/
// if(ballX > width - cube_width){
// if(ballY < rightY || ballY > rightY+cube_height){
// console.log('Point for Left');
// ball_VX = 0;
// ball_VY = 0;
// ball_owner = 1;
// } else {
// var intersect = ((rightY+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 < leftY || ballY > leftY+cube_height){
// console.log('Point for Right');
// ball_VX = 0;
// ball_VY = 0;
// ball_owner = 2;
// } else {
// var intersect = ((leftY+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);
// }
/** Draw Ball **/
ctx.fillStyle = 'black';
ballX += Math.round((1*delta)*60)*ball_VX;
ballY += Math.round((1*delta)*60)*ball_VY;
// ballX += Math.round((1*delta)*60)*ball_VX;
// ballY += Math.round((1*delta)*60)*ball_VY;
ctx.beginPath();
ctx.arc(ballX, ballY, ball_size, 0, 2*Math.PI);
ctx.fill();
@ -299,7 +322,7 @@
case 37 :
case 39 :
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){
console.log(leftY);
var time = Date.now();
if(pos == 1){
leftV = val;
if(!localcoop)
socket.emit('vchange', pos, val, leftY);
socket.emit('vchange', pos, val, leftY, time);
}
if(pos == 2){
rightV = val;
if(!localcoop)
socket.emit('vchange', pos, val, rightY);
socket.emit('vchange', pos, val, rightY, time);
}
}
function shootBall(sync = true) {
/** TODO Tewak and Add MAX_Speed **/
if(ball_owner == 1){
ball_VX = ball_speed;
if(!localcoop && sync)
socket.emit('ballshoot', leftY);
}
else if(ball_owner == 2){
ball_VX = -ball_speed;
if(!localcoop && sync)
socket.emit('ballshoot', rightY);
}
ball_owner = 0;
function shootBall() {
// console.log('### Ball shoot event ###');
// /** TODO Tewak and Add MAX_Speed **/
// if(ball_owner == 1){
// ball_VX = ball_speed;
// console.log('owner: left - at:' + leftY);
//
// }
// else if(ball_owner == 2){
// ball_VX = -ball_speed;
// console.log('owner: right - at:' + rightY);
// if(!localcoop)
// socket.emit('ballshoot', rightY);
// }
// ball_owner = 0;
}
function animloop() {

254
index.js
View file

@ -6,33 +6,52 @@ app.get('/', function(req, res){
res.sendFile(__dirname + '/index.html');
});
var sockets = [];
var gameState = 0;
var width, height;
var startinterval;
/** Parameters **/
var clients = [], // List of all conected clients
players = [], // Store Player 1 and Player 2 in Array {Player1 == players[0]}
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 **/
var cube_width = 50,
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 **/
/** ########## **/
io.on('connection', function(socket){
var id = sockets.length + 1;
if(sockets.length == 1)
if(sockets[0].id == 2) id = 1;
var clientkey = sockets.push(new Client(id, socket)) - 1;
/** Set ID for User **/
var id = clients.length + 1;
if(clients.length == 1)
if(clients[0].id == 2) id = 1;
var clientkey = clients.push(new Client(id, socket)) - 1;
console.log('Client connected. ID=' + id);
/** ######### **/
/** HANDSHAKE **/
/** ######### **/
socket.emit('handshake', id, gameState, cube_width, cube_height, speed, function(w, h){ // Callback function for 1st Client to set screen size //
sockets[clientkey].width = w;
sockets[clientkey].height = h;
if(sockets.length > 1 && gameState == 0) setUp(socket);
socket.emit('handshake', id, gameState, cube_width, cube_height, cube_speed, score, function(w, h){ // Callback function for 1st Client to set screen size //
clients[clientkey].width = w;
clients[clientkey].height = h;
if(clients.length > 1 && gameState == 0) setUp(socket);
});
if(gameState > 0) socket.emit('size', width, height);
@ -43,18 +62,60 @@ if(gameState > 0) socket.emit('size', width, height);
fn(Date.now());
});
/** #### **/
/** ######### **/
/** Ballshoot **/
/** ### **/
/** ######### **/
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 **/
/** ############## **/
socket.on('vchange', function(pos, val, y){
socket.broadcast.emit('changeV', pos, val, y);
socket.on('vchange', function(pos, val, y, timestamp){
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(){
var index;
sockets.forEach(function(sock, ind){
clients.forEach(function(sock, ind){
if (sock.socket == socket){
index = ind;
return;
}
});
var oldid = sockets[index].id;
sockets.splice(index, 1);
var oldid = clients[index].id;
clients.splice(index, 1);
console.log('Client disconnected. ID=' + (oldid+1));
if(sockets.length == 1){
sockets[0].socket.emit('test', 'player_left'); //TODO win-event
if(clients.length == 1){
clients[0].socket.emit('test', 'player_left'); //TODO win-event
console.log('Only one Player left. Sending win-event');
// Debug Restart:
gameState = 0;
@ -80,7 +141,7 @@ if(gameState > 0) socket.emit('size', width, height);
broadcastGameState(socket);
return;
}
else if(sockets.length == 0){
else if(clients.length == 0){
console.log('All Players left. Reseting lobby...');
gameState = 0;
id = 0;
@ -88,10 +149,10 @@ if(gameState > 0) socket.emit('size', width, height);
}
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){
case 1 : sockets[key].id = 1; sockets[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 1 : clients[key].id = 1; clients[key].socket.emit('handshake', 1); console.log('New Player 1 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;
}
@ -103,16 +164,20 @@ http.listen(3000, function(){
console.log('listening on *:3000');
});
/** Sync all settings to client and start the game **/
function setUp(socket){
gameState = 1;
broadcastGameState(socket);
console.log('Starting SetUp...');
/** Select smalest screensize and set for all clients **/
sockets.forEach(function(sock){
clients.forEach(function(sock){
broadcastGameState(socket);
if(sock.id == 1)
sockets.forEach(function(sock2){
if(sock.id == 1){
players[0] = new Player(sock.id, sock.socket);
clients.forEach(function(sock2){
if(sock2.id == 2){
players[1] = new Player(sock2.id, sock2.socket);
if(sock.width < sock2.width)
width = sock.width;
else
@ -123,7 +188,10 @@ function setUp(socket){
height = sock2.height;
}
});
}
});
if(calcPos == null) // Start tick Server only once
tickServer();
socket.emit('size', width, height);
socket.broadcast.emit('size', width, height);
var i = 5;
@ -132,6 +200,7 @@ function setUp(socket){
socket.emit('countdown', i);
socket.broadcast.emit('countdown', i);
if(i == 0){
resetPlayers();
clearInterval(startinterval);
gameState = 2;
broadcastGameState(socket);
@ -141,14 +210,139 @@ function setUp(socket){
}, 1000);
}
/** Broadcast GameState to all clients **/
function broadcastGameState(socket){
socket.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){
this.id = id;
this.socket = socket;
this.width = 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;
}