var app = require('express')(); var http = require('http').Server(app); var io = require('socket.io')(http); app.get('/', function(req, res){ res.sendFile(__dirname + '/index.html'); }); /** 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, 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){ /** 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, 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); /** #### **/ /** Ping **/ /** ### **/ socket.on('appping', function(fn){ fn(Date.now()); }); /** ######### **/ /** Ballshoot **/ /** ######### **/ socket.on('ballshoot', function(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, timestamp){ players[pos-1].vY = val; // NOTE Interpolation not needed // 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; // } // 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); }); /** ########## **/ /** DISCONNECT **/ /** ########## **/ socket.on('disconnect', function(){ var index; clients.forEach(function(sock, ind){ if (sock.socket == socket){ index = ind; return; } }); var oldid = clients[index].id; clients.splice(index, 1); console.log('Client disconnected. ID=' + (oldid+1)); if(clients.length == 1){ clients[0].socket.emit('debug', 'player_left'); //TODO win-event console.log('Only one Player left. Sending win-event'); // Debug Restart: gameState = 0; clearInterval(startinterval); broadcastGameState(socket); return; } else if(clients.length == 0){ console.log('All Players left. Reseting lobby...'); gameState = 0; id = 0; return; } var key = 0; if(clients[0].id == 1 || clients[0].id == 2) key = 1; switch(oldid){ 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; } }); }); 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 **/ clients.forEach(function(sock){ broadcastGameState(socket); 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 width = sock2.width; if(sock.height < sock2.height) height = sock.height; else 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; startinterval = setInterval(function(){ i--; socket.emit('countdown', i); socket.broadcast.emit('countdown', i); if(i == 0){ resetPlayers(); clearInterval(startinterval); gameState = 2; broadcastGameState(socket); socket.emit('gamestate'); socket.broadcast.emit('gamestate'); } }, 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('paddlepos', player.id, player.vY, player.y); player.socket.broadcast.emit('paddlepos', 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); } } /** 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('score', score); players[0].socket.broadcast.emit('score', 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; }