I have been making a small multiplayer game using socket.io
, and when I use a local websocket (http://127.0.0.1:8080
), and I open multiple clients on my computer, there is 0 lag between devices (I can see realtime changes of other players per tab). However, I decided to test it out across multiple devices, and so I used ngrok
to expose my local web server to the internet, and now when I open multiple clients (accessible through theajuppal.com/archipelago.io), the other clients do not load smoothly, the position of other players is updated choppily. Is this an issue with ngrok
? Or is my application too demanding on the server?
Live demo here
tl;dr
I am sending and receiving multiple events per second, every time I iterate over my main loop (update
) with requestAnimationFrame
, I request an updated list of the players from the server. Would that be enough to cause the lag I am seeing? Or is it an issue with ngrok
?
There is a lot of code but I will attach it below:
app.js
canvas = document.getElementById("canvas")
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
ctx = canvas.getContext('2d');
var socket = io.connect('ws://127.0.0.1:8080');
var paused = false;
socket.on('disconnect', function () {
$("#coords").css({transition: "5000ms"});
$("#coords").css({opacity: 0});
$("#foo").css({backgroundColor: "white"});
$("#label")[0].innerHTML = "Server has disconnected.<br>Please reload the page.<br>If the problem persists, please contact the admin at aj8uppal@gmail.com.";
$("#label").css({opacity: 1});
paused = true;
$("#foo")[0].appendChild(labelText);
});
socket.on('connect', function(){
// alert("we back");
});
var startTime;
var tiles;
var started = false;
$(document).ready(function() {
$("body").animate({scrollTop: 0}, 500);
});
keysPressed = {}
$("#playbutton").on("click", function(){
lastElementTop = $("canvas").position().top ;
stopAlert = true;
$(".site-wrapper").css({"box-shadow": "inset 0 0 200px rgba(17, 51, 80, 0)"})
setTimeout(function(){
$("body").animate({scrollTop: lastElementTop}, 1000);
}, 10);
setTimeout(function(){
$("body").animate({scrollTop: lastElementTop}, 1000);
}, 10000000000);
started = false;
SHIP_WIDTH = 20
SHIP_HEIGHT = 70
SHIP_COLOR = "rgb("+Math.floor(Math.random()*255)+", "+Math.floor(Math.random()*255)+", "+Math.floor(Math.random()*255)+")";
SHIP_SPEED = 10;
SHIP_ROTATE_SPEED = 3;
BOARD_WIDTH = 12800;
BOARD_HEIGHT = 6200;
OFFSET_X = canvas.width/2-SHIP_WIDTH/2;
OFFSET_Y = canvas.height/2-SHIP_HEIGHT/2;
// ABS_X = BOARD_WIDTH/2;
// ABS_Y = BOARD_HEIGHT/2;
ABS_X = Math.floor(Math.random()*BOARD_WIDTH-OFFSET_X-SHIP_WIDTH);
ABS_Y = Math.floor(Math.random()*BOARD_HEIGHT-OFFSET_Y-SHIP_HEIGHT);
mouseX = -1;
mouseY = -1;
velX = 0;
velY = 0;
desired_angle = 0;
prev_angle = 0;
ID = -1;
ship = {absx: ABS_X, absy: ABS_Y, width: SHIP_WIDTH, height: SHIP_HEIGHT, color: SHIP_COLOR, angle: 0, id: -1}
players = [ship];
socket.on("sendingData", function(newPlayers){
players = newPlayers;
});
socket.emit("connected", {absx: ABS_X, absy: ABS_Y, color: SHIP_COLOR, angle: 0});
socket.on("sendInitialData", function(data){
ID = data.id;
ship.id=ID;
board = data.board;
setTimeout(function(){
init();
}, 100);
});
});
function init(){
$("#coords").css({top: $("canvas").position().top+50, left: 75});
$("#coords")[0].innerHTML = ABS_X+":"+ABS_Y;
$("#coords").css({opacity: 1});
started = true;
(function animloop(){
requestAnimationFrame(animloop);
update();
})();
}
function Tile(x_pos, y_pos, width, height, color){
this.x_pos = (x_pos*100)-Math.floor(ship.absx);
this.y_pos = (y_pos*100)-Math.floor(ship.absy);
this.width = width;
this.height = height;
this.color = color;
this.getData = function(){
return {x: this.x_pos, y: this.y_pos, width: this.width, height: this.height, color: this.color};
};
this.update = function(){
updateTile(this.getData());
};
}
function update(){
if(!paused){
ctx.clearRect(0, 0, canvas.width, canvas.height);
socket.emit("requestData", {player: ship});
// socket.emit("availableTiles", {width: canvas.width, height: canvas.height, board: board, ship: ship})
ctx.fillStyle = "rgba(0, 0, 0, 0.25)";
ctx.beginPath();
ctx.fillRect(-ship.absx, -ship.absy, 12800, 6200);
ctx.strokeStyle = "rgb(0, 0, 0)";
ctx.stroke();
for(var y = 0; y < board.length; y++){
for(var x = 0; x < board[y].length; x++){
tile = board[y][x];
if(tile == 1){
if( ((x+1)*100)-Math.floor(ship.absx) > 0 && (x*100)-Math.floor(ship.absx) < canvas.width &&
((y+1)*100)-Math.floor(ship.absy) > 0 && (y*100)-Math.floor(ship.absy) < canvas.height){
updateTile({x: (x*100)-Math.floor(ship.absx), y: (y*100)-Math.floor(ship.absy), width: 100, height: 100, color: "#8c8c8c"});
}
}
}
}
if(mouseX != -1 && mouseY != -1){
dx = mouseX - (OFFSET_X-ship.width/2);
dy = mouseY - (OFFSET_Y-ship.height/2);
angle = Math.atan2(dy, dx);
velX = (Math.abs(dx)/(canvas.width/2)) * SHIP_SPEED * Math.cos(angle);
velY = (Math.abs(dy)/(canvas.height/2)) * SHIP_SPEED * Math.sin(angle);
}
if(ship.absx <= BOARD_WIDTH-OFFSET_X && ship.absx >= -OFFSET_X){
ship.absx+=velX;
}
if(ship.absy <= BOARD_HEIGHT-OFFSET_Y && ship.absy >= -OFFSET_Y){
ship.absy+=velY;
}
if(ship.absx < -OFFSET_X){
ship.absx = -OFFSET_X;
}
if(ship.absy < -OFFSET_Y){
ship.absy = -OFFSET_Y;
}
if(ship.absx > BOARD_WIDTH-OFFSET_X){
ship.absx = BOARD_WIDTH-OFFSET_X
}
if(ship.absy > BOARD_HEIGHT-OFFSET_Y){
ship.absy = BOARD_HEIGHT-OFFSET_Y;
}
for(var p = 0; p < players.length; p++){
if(players[p].id == ship.id){
// debugger;
updateShip(players[p]);
}else{
updatePlayer(players[p]);
}
}
}
}
function updatePlayer(player){
ctx.save();
ctx.translate(OFFSET_X+(player.absx-ship.absx), OFFSET_Y+(player.absy-ship.absy));
ctx.rotate((Math.PI/180)*(player.angle-90));
ctx.fillStyle = player.color;
ctx.fillRect(-player.width/2, -player.height/2, player.width, player.height);
ctx.restore();
}
function updateShip(player){
ctx.save();
ctx.translate(OFFSET_X, OFFSET_Y);
player.angle = desired_angle;
ctx.rotate((Math.PI/180)*(player.angle-90));
ctx.fillStyle = player.color;
ctx.fillRect(-player.width/2, -player.height/2, player.width, player.height);
ctx.restore();
}
function updateTile(tile){
ctx.fillStyle = tile.color;
ctx.fillRect(tile.x, tile.y, tile.width, tile.height);
}
$(document).keydown(function(e){
// console.log("hi");
keysPressed[e.keyCode] = true;
if([32, 37, 38, 39, 40].indexOf(e.keyCode) > -1){
e.preventDefault();
}
});
$(document).keyup(function(e){
keysPressed[e.keyCode] = false;
});
$(document).mousemove(function(e){
mouseX = e.clientX;
mouseY = e.clientY;
if(started){
difX = (OFFSET_X-ship.width/2)-e.clientX;
difY = (OFFSET_Y+ship.height/2)-e.clientY;
result = 180*Math.atan2(difY, difX)/Math.PI;
prev_angle = desired_angle;
desired_angle = result;
ship.angle = desired_angle;
if(result < 0){
result+=360;
}
}
});
stopAlert = false;
$("#alert").on("click", function(){
if($("#alert")[0].innerHTML == "Alert!"){
doAlert("alert");
$("#alert")[0].innerHTML = "Stop alert!";
}else{
stopAlert = true;
$("#alert")[0].innerHTML = "Alert!";
}
});
function doAlert(state){
if(stopAlert){
stopAlert = false;
$(".site-wrapper").css({"box-shadow": "inset 0 0 200px rgb(17, 51, 80)"})
return;
}
if(state == "alert"){
$(".site-wrapper").css({"box-shadow": "inset 0 0 200px #D65653"})
setTimeout(function(){
doAlert("calm");
}, 500);
}else{
$(".site-wrapper").css({"box-shadow": "inset 0 0 200px rgb(17, 51, 80)"})
setTimeout(function(){
doAlert("alert");
}, 500);
}
}
server.js
var config = require('./config');
var app = require('http').createServer();
var io = require('socket.io')(app);
var fs = require('fs');
count = 0;
players = [];
board = [];
for(var y = 0; y < 62; y++){
sub = []
for(var x = 0; x < 128; x++){
sub.push(Math.random() < 0.1 ? 1 : 0);
}
board.push(sub);
}
app.listen(config.serverPort);
console.log("Starting server on port " + config.serverPort);
io.on('connection', function(socket) {
socket.on("connected", function(data){
players.push({x: data.x, y: data.y, color: data.color, angle: 0, id: count});
socket.emit("sendInitialData", {id: count, board: board});
count+=1;
console.log(count);
});
socket.on("requestData", function(data){
socket.emit("sendingData", players);
players[data.player.id] = data.player;
});
});
index.html
<!DOCTYPE HTML>
<html>
<head>
<link href="css/bootstrap.min.css" rel="stylesheet">
<link href="css/cover.css" rel="stylesheet">
<script src="js/socket.io.min.js"></script>
<script src="js/modernizr.min.js"></script>
<script src="js/jquery.min.js"></script>
<script src="js/bootstrap.min.js"></script>
</head>
<body>
<div class="site-wrapper">
<div class="site-wrapper-inner">
<div class="cover-container">
<div class="masthead clearfix">
<div class="inner">
<h3 class="masthead-brand">Archipegalo.io</h3>
<nav>
<ul class="nav masthead-nav">
<li><a href="http://facebook.com">Share on Facebook</a></li>
<li><a href="http://twitter.com">Post in Twitter</a></li>
</ul>
</nav>
</div>
</div>
<div class="inner cover">
<form class="form-signin">
<h1 class="cover-heading">Welcome to Archipegalo.</h1>
<p class="lead">Pillage and loot your friends (and enemies) in this highly addicting MMO.</p>
<input type="name" id="inputName" class="form-control" placeholder="Enter your name" required="true" autofocus>
<button id="playbutton" class="btn btn-lg btn-primary btn-block" type="submit">Play!</button>
<!-- <button id="alert" class="btn btn-lg btn-primary btn-block" type="button">Alert!</button>-->
</form>
</div>
<div class="mastfoot">
<div class="inner">
<p>Made by A.J. Uppal</p>
</div>
</div>
</div>
</div>
</div>
<div id="foo" style="display: table; position: absolute; width: 100%; height: 100%; transition: 5000ms;"><span id="label" style="display: table-cell; vertical-align: middle; color: black; font-size: 24px; opacity: 0; transition: 5000ms">Game Over</span></div>
<canvas id="canvas"></canvas>
<div id="coords" style="position: absolute; opacity: 0"></div>
<script>
$("#coords").css({top: $("canvas").position().top+50, left: $("canvas").width()-75});
</script>
</body>
<script src="main2.js"></script>
</html>
via ᴬᴶ ᵁᴾᴾᴬᴸ
No comments:
Post a Comment