I would like to create a multiplayer HTML5 semi-real-time game using node.js and socket.io. The frame rate is 3 fps. Players use the arrow keys to move. All game objects move in straight lines (players move horizontally or vertically). Players press Page Up/Down to speed up/slow down. This is my first animated HTML5 game, and my first heavy duty JavaScript project.
I went through a tutorial called "Creating a real-time multiplayer game with WebSockets and Node.js" (click here). This tutorial displays a black square for each player with arrow key movement. Unfortunately it only works on one computer (but multiple browser tabs). You have to point your browser(s) to the public/index.html file. I would like to modify it so I can join in the game from the other computer on my LAN, by pointing my browser to 192.168.1.4:8000. Eventually I would like my brother to join in by visiting myquadrawebsite.com. I know how to do port forwarding for apache but not node.js. Here are 3 snippets of abridged, high-level code from the tutorial:
// public/index.html
<script src="http://localhost:8000/socket.io/socket.io.js"></script>
<script src="js/game.js"></script>
<script> // Initialise the game
init();
animate();
</script>
// game.js
var io = require("socket.io");
var socket, players;
function init() {
players = [];
socket = io.listen(8000);
setEventHandlers();
};
var setEventHandlers = function() {
socket.sockets.on("connection", onSocketConnection);
};
function onSocketConnection(client) {
util.log("New player has connected: "+client.id);
client.on("new player", onNewPlayer);
};
// public/js/game.js
var remotePlayers, localPlayer, socket;
function init() {
localPlayer = new Player(startX, startY);
socket = io.connect("http://localhost", {port: 8000, transports: ["websocket"]});
remotePlayers = [];
setEventHandlers();
};
var setEventHandlers = function() {
socket.on("connect", onSocketConnected);
socket.on("new player", onNewPlayer);
};
I have searched high and low for other tutorials about node.js and socket.io, but none of them have helped me so far. (My long term goal is to create an HTML5 game development framework.) If anyone can possibly point me in the right direction, I'd appreciate it. Thanks.
Unfortunately it only works on one computer (but multiple browser tabs)
This strongly suggests that you are running the server on one computer and it is not accessible from the other computer clients (the web browsers).
You should ensure that the code you use in the client uses a URL that is accessible by anybody (any client) trying to access the game e.g.
socket = io.connect("http://localhost", {port: 8000, transports: ["websocket"]});
Definitely won't work for anybody other than the person on the computer running the server.
If you update the URL to 192.168.1.4:8000 and that address is accessible to others then it is much more likely to work.
you shouldn't have to point your browser to the public, the address (depending on where you routed it (if your using express it'll just be /index.html)) http://127.0.0.1:8000 (equivalent to localhost) http://127.0.0.1:8000/index.html
I'm about halfway through my first socket.io game and i'd definitely suggest using a service like nodejitsu for deploying or even testing your game
Related
I have an animation written in Javascript. I am new to nodejs (no knowledge) and I have been finding it difficult to stream the animation in real-time to users connected to the site.
I read about socket.io and Websockets but I do not have a good approach. Currently, the animation starts with a function call and writes to a canvas.
I need to know how to stream this animation from the server-side to the client so that multiple connected users can see the same scene of the animation at the same time. A functional explanation with code will also be appreciated.
Without knowing what type of animations are used, how they're built and work, I would suggest doing the animation client-side and just send some sort of synchronization command from server to all clients using socket.io .
I also would suggest putting all users (which all should see the same animation) in to one room (see rooms).
Now you can send a synchronized command to all users, e.g. to start, continue, stop and reset the animation. On the other hand, on the server-side you could track which of the clients in the room have already loaded the animation, started, stopped and so on.
// server
io.to('some-room').emit('load', animationid);
/* ... */
socket.on('loaded', () => {
if (allClientsLoaded) {
io.to('some-room').emit('start');
}
});
socket.on('started', () => {
});
// client
socket.on('load', async (animationid) => {
await loadAnimation(animationid);
socket.emit('loaded');
});
socket.on('start', () => {
startAnimation();
});
I'm using Socket.IO to deploy a real-time drawing canvas application with Node.JS and Express but here's the problem I'm facing:
Even though I created namespaces to connect peers to namespaces according to pathnames they're visiting
(normally — /webrtc/:id), the application does a poor job of isolating two different pathnames. So it also connects two different pathnames but oddly, with a one-sided connection.
For example, if I were to go to localhost:3000/webrtc/1 on one tab and /webrtc/2 on the other, the first tab peer would transmit drawing data to the other one while the second one wouldn't.
P.S it does well within the same pathnames.
P.P.S I mean document.href.pathname by saying pathname.
Here's the source:
SERVER
var io = require('socket.io')(server);
app.get('/webrtc/:id', function(req, res, next) {
className = '/webrtc/' + req.params.id;
nsp = io.of(className);
res.render('webrtc');
nsp.on('connection', function(socket){
socket.on('drawing', (data) => nsp.emit('drawing', data));
});
})
CLIENT
var socket = io(document.location.pathname);
Tried other solutions I could find such as adding process.env.PORT and also looked at heroku's guide on socket.io.
The Phaser.io game my group is making works perfectly locally, however when we deploy to heroku there is a bug where only the first player connected will see the other players, and only for a brief moment as well. After that short period, the players freeze.
My question is, does anyone have any clue what could potentially be causing the issue? Is it something wrong with our implementation of socket.io?
Thank you in advance for your help. Extremely confused as to what is causing this issue.
Here is a deployed version: https://death-road-to-toronto.herokuapp.com/
Here is the repo if you'd like: https://github.com/Road-To-Capstone/CapstoneMultiplayer/
Here are the code snippets relevant to socket and express
Index.js
const config = require('./config');
const express = require('express');
const socketio = require('socket.io');
const http = require('http');
const app = express();
const server = http.createServer(app);
const io = socketio(server);
app.use('/', express.static(config.publicDir));
//-socket
const players = require('./players.js');
const missiles = require('./missiles.js');
const zombies = require('./zombies.js');
io.on('connection', socket => {
-------
});
//=socket
server.listen(process.env.PORT || config.port, () => {
console.log(`Listening on ${config.port}`);
});
//creating new zombie id
function newZombieId() {
let id = new Date();
return id.getTime();
}
config.js
const path = require('path');
module.exports = {
port: 3000,
publicDir: path.join(__dirname, '../public'),
game: {
start: {
x: 400,
y: 400
}
}
}
EDIT1 : I made a funny discovery while playing around with socket.io and heroku. So if I connect with another computer to the deployed version on heroku, then click on console (just to freeze the game). Anyone at that point can join and everything works perfectly, just like in the local copy.
Does anyone know why? If not what can I do as a work around? Perhaps implement a lobby system and allow all players to join and start at the same time?
Solved my problem! Going to leave my question and the solution here for prosperity, incase other people want to implement a multiplayer game using Phaser and socket.io on Heroku and also run into issues.
We added this to the index.html file </script type ="text/javascript" src="/socket.io/socket.io.js"> </script> which allows heroku to access the socket library.
It actually wasn't a setup issue with socket.io, it was our logic. When a player detects movement it instantly tries to socket.broadcast that a player moved. However, when other players first connect, they don't have time to retrieve all the players information from the server side. Thus the broadcast would cause an error where "player" is undefined. Adding a conditional statement fixed our issue.
The code in it's entirety is going to be left on github if you want to investigate further.
I am newbie about Meteor.
I am developing a realtime multiplayer game. I want to implement everything about the game but game engine states with Meteor. For example chat messages, available game rooms, invitations, online members etc. I want to make those functionalities withMeteor.
But I want to implement game states manually without Meteor with socket.io. Because, the game is real time and every 45 msec(in my architecture), game states will be streaming to the clients and I think Meteor is not for this and not flexiable. So I developed multiplayer concept and synchronising clients and server with socket.io. There is no problem about it.
I want to use Meteor and socket.io both and together. I tried to implement it. I installed socket.io with npm inside .meteor/local/build/programs/server/app under my meteor app. After that I include require statement on server side Meteor startup;
Meteor.startup(function () {
var require = Npm.require;
var sio = require('socket.io')
var socketIO = sio.listen(this.http)
socketIO.configure(function () {
socketIO.set('log level', 0);
socketIO.set('authorization', function (handshakeData, callback) {
callback(null, true); // error first callback style
});
socketIO.set("transports", ["xhr-polling"]);
socketIO.set("polling duration", 30);
});
socketIO.sockets.on('connection', function (client) {
console.log(client.id + ' is connected')
client.on('disconnect', function () {
console.log(client.id + ' is diconnected')
});
})})
And I put the connection statement on client side Meteor startup;
Meteor.startup(function () {
socket = io.connect();
socket.on('connect', function () {
console.log('connecting');
});
})
On client side, io variable is not defined error is occurred. This is seen to me that,Meteor does not import client side socket.io.js on client side. So I tried to put socket.io.js manually under clients folder to load it on client side. This is not good way I know, I should not do this. But, even I do and client loads it, there is another client side error about transport variable of io for the statement;
io.transports.push('xhr-polling');
It says that Uncaught TypeError: Cannot call method 'push' of undefined. Somehow, client side socket.io.js can not be loaded properly.
I could not find an example for usage of Meteor and socket.io together. Is there a simple way to use them both together?
Thank you!
I am trying to understand how node.js will fit in my scenario.
Currently, a mobile device sends gps coordinates to a Rails backend thru POST. The mobile device sends it every minute.
POST http://127.0.0.1:3000/location/
My RubyOnRails web app can display the history of locations on a map, no problem with this.
But my experience in nodejs is still in its infancy and I would like to understand how to display a map for real time GPS updates as they come in.
Use Socket.IO.
Most tutorials show some kind of chat application. In your case the communication is only uni-directional. And your device is not connected through WebSockets, but only POSTs new coordinates without a channel back (device doesn't subscribe to events from server).
Your web-page (showing a Google Maps control) connects to your Node.js server through socket.io and gets new coordinates pushed from your server (socket.emit). You have to remember somehow which "new-coordinate" events from devices have to be published to which listening web-clients.
And of course you need an initial list of recent coordinates for your web-page if you want to show not only new coordinates of a device. You could deliver them over sockets as well, but as you will need some kind of authentication maybe a REST call is clearer for first population of devices GPS-track.
So when a device updates its location, you only have to find connected listeners for that device and emit("new-coordinate", {lat: ..., lng: ..., deviceId: ...} events to the maps. In the web-page, you receive the events and handle them like this:
<script src="/socket.io/socket.io.js" type="text/javascript"></script>
<script type="text/javascript">
$(function () {
if (typeof io === 'undefined') {
return; // socket.io not loaded
}
var socket = io.connect();
socket.on('new-coordinate', function (data) {
console.log('arrived', data);
$(document).trigger('new-coordinate', data);
// or just directly update your map ...
});
});
</script>
Edit
As your web-page and the new-coordinate POSTs are delivered through RoR, you have to trigger the events from Ruby to node.js server-side. Basically you could call your node.js app from Ruby via REST, but there are other options like Redis pub/sub or dnode ruby.
(comment) I'd migrate the RoR app to node.js ;-) (/comment)