Injustice - Developers Among Us (SciFiDevCon 2024)
Node.js multiplayer HTML5 game
1. Hello I’m Jafar
Multiplayer Worlds
with
Node.js + HTML
http://jaf.ar.com
2. Inspired By
RED INTERACTIVE
http://FF0000
2009 - I Love Flash
2010 - Steve Jobs Hates Flash
2011 - Flash dies slow death... :(
3. My Website is....
Not perfect....
Probably really hackable...
Still using globals....
Chat room needs filters...
Server not authoritave
4. OH NO BUGS IN CHROME!
Works well in Chrome 19 !
Download Chrome Canary
Worked well in Chrome 16
Chrome updates to 17...
...bugs come back
(image flicker)
Might be a cache issue....
Might be a Mac thing...
Maybe Wifi on Mac thing
http://www.eclipse.org/forums/index.php/mv/tree/262108/#page_top
5. MICROSOFT SAYS
NO WEBSOCKETS
So Screw IE9 or Lower
and Opera and Safari
Although Socket.io does
work on browsers without
web sockets
(too choppy)
Microsoft Changes Their Mind
IE10 pretty good....
6. STACK
Node.js - server
Socket.IO - cross browser sockets
Now.js - namespace, easy chat rooms
Express - static files, pages
jQuery - front end stuff
8. JUST USE HTML DIV’s
Canvas too slow for a large map
Because when you draw on canvas you must also clear
each move and each pixel
3000 x 3000 = 9 Million px/sec
3000px
3000px 1920 x 1024
“Tip: DOM is usually always faster than canvas....”
http://craftyjs.com/demos/tutorial/tutorial.html
9. Where is My Player?
in relation to the DOM Window
var PosX = $('#myPlayer').offset().left - $(window).scrollLeft();
#myPlayer .player .player
.player
.player .player
if( PosX < 50 || PosX > (winW - 50) ) //within 50px of window
window.scrollBy(x,y); //scroll the window to keep player in view
10. var players = {};
id, x, y, direction, moving, floor, skin
CLIENT
//KEY DOWN
function kdRight(){
now.pullPlayers(now.core.clientId,player.x, player.y, 0,1,floor_y,skin_num);
}
SERVER
//PULL PLAYERS
everyone.now.pullPlayers = function(id,x,y,dir,mov,flo,skin){
actors[id] = {x:x, y:y, dir:dir, mov:mov,flo:flo,skin:skin};
var playerUpdate = {};
playerUpdate = {id:id,x:x,y:y,dir:dir,mov:mov,flo:flo,skin:skin};
everyone.now.showPlayers(playerUpdate);
};
CLIENT
//SHOW PLAYERS
now.showPlayers = function(plyr) {
players[plyr.id] = {x:plyr.x, y:plyr.y, dir:plyr.dir, mov:plyr.mov,flo:plyr.flo,skin:plyr.skin};
}
>>>> LOOP THE PLAYERS OBJECT
11. Animation Loop
//MOVE PLAYERS
function movePlayers(){
//FOR LOOP
for(var i in players) {
//REMOVE
$(".player[rel='" + i + "']").remove();
//ADD
$('#Players').append('<div class="player" rel="' + i + '"></div>');
>>>>IF MOVING (next page)
>>>>ELSE STANDING STILL (next page)
}
}
12. //MOVING
if(players[i].mov == 1) {
//LEFT
if(players[i].dir == 1) {
players[i].x--;
$(".player[rel='"+ i +"']").css('left', players[i].x );
$(".player[rel='"+ i +"']").css('top', players[i].y );
$(".player[rel='"+ i +"']").css('background-image',img_walk_l);
//RIGHT
} else if(players[i].dir == 0){
players[i].x ++;
$(".player[rel='"+ i +"']").css('left', players[i].x );
$(".player[rel='"+ i +"']").css('top', players[i].y );
$(".player[rel='"+ i +"']").css('background-image',img_walk_r);
} else {
$(".player[rel='"+ i +"']").css('left', players[i].x );
$(".player[rel='"+ i +"']").css('top', players[i].y );
$(".player[rel='"+ i +"']").css('background-image',img_front);
}
//STANDING STILL
} else {
//LEFT
if(players[i].dir == 1) {
$(".player[rel='"+ i +"']").css('background-image',img_l);
$(".player[rel='"+ i +"']").css('left', players[i].x );
$(".player[rel='"+ i +"']").css('top', players[i].y );
//RIGHT
} else if (players[i].dir == 0){
$(".player[rel='"+ i +"']").css('background-image',img_r);
$(".player[rel='"+ i +"']").css('left', players[i].x );
$(".player[rel='"+ i +"']").css('top', players[i].y );
//BACK
} else if (players[i].dir == 'b'){
$(".player[rel='"+ i +"']").css('background-image',img_back);
$(".player[rel='"+ i +"']").css('left', players[i].x );
$(".player[rel='"+ i +"']").css('top', players[i].y );
//FRONT
} else {
$(".player[rel='"+ i +"']").css('background-image',img_front);
$(".player[rel='"+ i +"']").css('left', players[i].x );
$(".player[rel='"+ i +"']").css('top', players[i].y );
}
//END MOV
}
13. Wait What About My Player
//GLOBALS
--movement
--leftKey
--rightKey
//MY PLAYER
function myPlayer() {
if ( movement && leftKey ) {
player.x --;
$('#player').css('left',player.x );
} else if ( movement && rightKey ) {
player.x ++;
$('#player').css('left',player.x );
} else {
$('#player').css('left',player.x );
}
//END FUNC
}
14. GRAVITY LOOP
We use the global object “players{}”
//GRAVITY
function gravity() {
//MY PLAYER
if ( player.y !== floor_y ) {
player.y ++;
player.y ++;
$('#player').css('top',player.y );
}
//FOR LOOP
for (var i in players) {
//IN THE AIR
if( i === now.core.clientId && players[i].y !== floor_y ) {
players[i].y++;
players[i].y++;
$(".player[rel='"+ i +"']").css('top', players[i].y );
} else if ( i !== now.core.clientId && players[i].y !== players[i].flo) {
players[i].y++;
players[i].y++;
$(".player[rel='"+ i +"']").css('top', players[i].y );
} else {
//do nothing
}
}
}