I am writing a multi-player game using processing.js, node.js and socket.io.
Question #1:
In the client, I use p5.js to create a class Ball.
I want the server to send parameter to create an array using that class (balls.push(new Ball(x, y));), so every client can have a bunch of balls moving on the canvas.
I know I should use socket.io to emit the parameter to the client but i have no clue.
Normally the array is created inside the setup function inside p5...so how could socket do that?
Question #2:
How could the client send the mouseX and mouseY to the server? And then how could the server send back others' mouseX and mouseY to every client?
I try to make p5.js into normal js like this:
(function () {
"use strict";
function sketchProc(processing) {
var p=processing,
var ...,
var ...;
function ball(){...}
p.setup=function(){}
p.draw=function(){}
}
var canvas = document.getElementById("canvas1"),
p = new Processing(canvas, sketchProc);
}());
But i don't know if this helps...
The balls should be passed to the client only in the connection event. That's where node's beauty lies, code sharing.
To create a socket server, you can use either node's native Net module or Socket.io
On the server:
var server = net.createServer();
server.listen(PORT, HOST);
server.on('connection', function(socket) {
socket.write({ type: "BallsArray", data: BallsArray });
});
On the client, you use WebSockets with Socket.io:
var client = io.connect('http://localhost:3000');
var BallsArray = null;
client.on('message', function(msg) {
if(msg.type == "BallsArray")
BallsArray = msg.data;
});
Related
I am trying to add a notification system. If a user logs in and performs an action a notification should be sent to another user if he is logged in. I have made my application in node.js using express. I know that I have to use socket but how the event needs to be handled? If someone could let me know any reference or sample which I can follow for this task?
I just did something similar and handled it like this:
io.js - central node.js file where I handle new connnections and store io
var io = require('socket.io')();
io.on('connection', function(socket){
console.log("Socket established with id: " + socket.id);
socket.on('disconnect', function () {
console.log("Socket disconnected: " + socket.id);
});
});
module.exports = io;
someroute.js - somewhere in the node.js server application I want to emit messages
var appRoot = require('app-root-path');
var io = require(appRoot + '/server/io');
/*your code, somwhere you will call the
* function below whenever you want to emit
* the 'user_did_action' event:
*/
if(user.didNewStuff()){
emitUserAction(user);
}
var emitUserAction = function(user){
io.sockets.emit('user_did_action', user);
};
client_javascript.js - some client js (in my case angular, but it doesent matter), import the socket.io lib, then access somewhere in the client like this:
/*connect to the server*/
var socket = io.connect();
/*do something wen the event 'user_did_action'
* is received, just invoke the callback
*
*in the function param data, you will have the same
*data you emitted earlier in the server,
*in this example the user object!*/
socket.on('user_did_action', myFunctionToHandleTheEvent(data));
I create a server with Node.js:
var net = require('net');
var PORT = 8181;
var server = net.createServer(
function(socket) {
console.log(this.address());
socket.on('data', function(data) {
var msg = data.toString().replace(/\n$/, '');
console.log('got: ' + msg);
});
process.stdin.on('readable',
function() {
var chunk = process.stdin.read();
if (chunk !== null) {
socket.write(chunk);
}
}
)
socket.write('heyyo\n');
}
)
Now, when multiple connections are coming in, this server sends out the typed in line only to the first connection.
I have two questions:
what is a standard way to handle this, i.e. to store the incoming sockets into an array?
exactly what happens that causes the readable event not to reach the other connections' callback function?
I would highly recommend using a library like socket.io. It makes handling connect/disconnect as well as placing sockets in rooms very simple. Additionally you can get the full list of available rooms and connected sockets through the adapter class it offers. A functional example is available in the docs.
This must have been asked already a thousand times, but I do not find any of the answers satisfying, so I'll try having another go, being as clear as possible.
I am starting out with a clean Express; the one that is usually done via the following terminal commands:
user$ express
user$ npm install
then I proceed installing socket.io, this way:
user$ npm install socket.io --save
on my main.js file I then have the following:
//app.js
var express = require('express'),
http = require('http'),
path = require('path'),
io = require('socket.io'),
routes = require('./routes');
var app = express();
I start my socket.io server by attaching it to my express one:
//app.js
var server = http.createServer(app).listen(app.get('port'), function(){
console.log('express server started!');
});
var sIo = io.listen(server);
What I do now is to set the usual routes for Express to work with:
//app.js
app.get('/', routes.index);
app.get('/send/:recipient/:text', routes.sendMessage);
Now, Since I like to keep things organized, I want to put my socket.io code in another file, so instead of using the usual code:
//app.js
sIo.sockets.on('connection', function(socket){
console.log('got a connection');
});
I use the following to be able to access both the socket and the sIo object (as that object contains all the connections infos (important)):
//app.js
sIo.sockets.on('connection', function(socket){
routes.connection(sIo, socket);
});
// index.js (./routes)
exports.connection = function(sIo, socket){
console.log('got a connection.');
};
This way I can do all my socket.io jobs in here. I know that I can access all my clients information now from the sIo object, but of course, they do not contain any information about their session data.
My questions now are the following:
Suppose a user makes an HTTP request to send a message and the handler in my routes is like this:
exports.sendMessage = function(req, res){
//do stuff here
};
How can I get this to "fire" something in my socket.io to send a message? I do not want to know all the underlying work that needs to be done, like keeping track of messages, users, etc. I only want to understand how to "fire" socket.io to do something.
How can I make sure that socket.io sends the message only to a person in particular and be 100% sure that nobody else gets it? From what I can see, there is no way to get the session infos from the sIo object.
Thanks in advance.
question one: The cleanest way to separate the two would probably be to use an EventEmitter. You create an EventEmitter that emits when an http message comes in. You can pass session information along with the event to tie it back to the user who sent the message if necessary.
// index.js (./routes)
var EventEmitter = require('events').EventEmitter;
module.exports.messageEmitter = messageEmitter = new EventEmitter();
module.exports.sendMessage = function(req, res) {
messageEmitter.emit('private_message', req.params.recipient, req.params.text);
};
question 2: You can access the socket when the initial connection is made. An example mostly borrowed from this answer:
var connect = require('connect'),
userMap = {};
routes.messageEmitter.on('private_message', function(recipient, text) {
userMap[recipient].emit('private_message', text);
});
io.on('connection', function(socket_client) {
var cookie_string = socket_client.request.headers.cookie;
var parsed_cookies = connect.utils.parseCookie(cookie_string);
var connect_sid = parsed_cookies['connect.sid'];
if (connect_sid) {
session_store.get(connect_sid, function (error, session) {
userMap[session.username] = socket_client;
});
}
socket_client.on('private_message', function(username, message) {
userMap[username].emit(private_message, message)
});
});
So we're just creating a map between a session's username and a socket connection. Now whenever you need to send a message you can easily lookup what socket is associated with that user and send a message to them using their socket. Just make sure to handle disconnects, and reconnects and connecting in multiple tabs, etc.
I have built something like what you are saying. If a user can make a socket request, it pushes the message via the socket, and then the server does a broadcast or emit of it. But, if a user can't connect to the socket, it then does the http post, like what you are saying by calling the sendMessage. What I have done, rather than having sendMessage shoot off a socket is that I also have my clients doing an ajax request every 5 seconds or so. That will bring back new messages, and if any of the messages were not received via socket.io, I then add them to my clientside array. This acts as sort of a safety net, so I don't have to always fully trust socket.io.
see below in pseudo code
client
if canSendSocketMessage()
sendSocketMessage(message)
else
sendAjaxMessage(message)
setInterval( ->
// ajax call
getNewMessages()
), 5000
server
socket stuff
socket.on 'message' ->
saveMessage()
socket.emit(message)
ajax endpoints
app.post 'sendMessage'
saveMessage()
app.get 'getNewMessages'
res.send getNewMessages()
in socket.io 0.6, i have following example code:
var io = require('/usr/lib/node_modules/socket.io');
var server = http.createServer(function(req,res){
var path = url.parse(req.url).pathname;
switch( path ){
....
//core codes
socket.broadcast(data);
}
}).listen(8080);
// ... ...
var socket = io.listen(server);
and everything going ok.
But now i have renew the socket.io to 0.7 and have changed the socket.broadcast to socket.sockets.broadcast.send(data) ;
Got an exception : can not call send of 'undefined'?
Who can tell me how can i send data to everybody without listening on a certain event?
Maybe here is a way:
clients = new Array();
socket.on('connection',function(socket){ clients.push(socket);}
// ...
for(s in clients) s.send(data);
// ...
does it really needed to do like this way?
Thanks!
In socket.io 0.7 you do:
io.sockets.send() // broadcasts to all connected users
io.sockets.json.send() // broadcasts JSON to all connected users
io.sockets.emit('eventname') // broadcasts and emit
or to namespaces
io.of('/namespace').send('msg'); // broadcast to all connect users in /namespace
you can just do
var io = require('socket.io').listen(80);
io.sockets.on('connection', function (socket) {
socket.broadcast.emit('user connected');
});
Use
sioServer.sockets.on('connection', function (client) {
client.broadcast.send('Hello, Everybody else!');
});
to broadcast to every other connected client (that is except the broadcasting client himself) and use
sioServer.sockets.on('connection', function (client) {
sioServer.sockets.send('Hello, Everybody!');
});
to broadcast to everybody (including client himself).
I'm writing a two player card game, (say it's regular poker for simplicity) in Node.js and Express js. There's a couple of things I'm having trouble with. First, how do I make sure that there are only 2 players that can access an instance of the game, and is it possible to have them reconnect if they lose the connection? Second, how do send a message from the server to the client? I can send it within the "socket.on" listener call, but within the normal scope of the program I can't get it to work.
var socket = io.listen(app);
socket.on('connection', function(client){
player++;
if(player <= 2) {
var messageout = "player " + player + " connected";
client.broadcast(messageout);
client.on('message', function(data){console.log(data); })
client.on('disconnect', function(){console.log('disconnected');})
}
else {
socket.end;
}
});
I'm having trouble conceptually what's going on here and how to approach the problem. For example, do I do it all with sockets? Or do I return a web page with the updated state of the game (cards, bets, etc.) every turn?
First, how do I make sure that there
are only 2 players that can access an
instance of the game?
Create an array of instance objects.
When a new player joins either create a new instance and set them as player1, or add them to an existing instance as player two.
var instances = [];
function Instance () {
return {
name = 'game' + instances.length + 1,
gameVariables = defaults,
player1 = null,
player2 = null,
player1UUID = UUID(),
player2UUID = UUID()
}
}
Is it possible to have them reconnect
if they lose the connection?
If you send each player a UUID when they initially connect you can have them use it to authenticate when they reconnect.
How do I send a message from the
server to the client?
client.send({ gameState: gameState() });
of if you've saved the client into an object: instances[ 'game1' ].player1.send( data );
I do it all with sockets?
I would deal with all dynamic interactions with web sockets.
Do I return a web page with the updated state of the game (cards, bets, etc.) every turn?
I wouldn't send html over web sockets. Instead send json and use a client side template to render it.
Try now.
// server
var nowjs = require("now")
var everyone = nowjs.initialize(app);
everyone.connected(function() {
if (users.length < 2) {
users.push(this);
}
});
everyone.now.sendMessage = function(message, cb) {
gameLogic(message);
users.forEach(function(user) {
user.update(gameLogic.getState());
});
};
//client
$("#action").click(function() {
now.sendMessage($(this).data("action"));
});
now.update = function(data) {
// update UI
};