想象一下在网络上玩游戏只需要简单地登录,不需要本地安装,不需要任何许可证,在浏览器或者手机中的多人游戏可以断线重连--这基本上就是“云游戏”了。好吧,这听起来挺俗套了,但是我们接下来就能见识到这些了,而且比我们想象的更好更快!
我们先列出一些概念,以建立真正有潜在意义的东西。我们想要做的是:
发布常见的浏览器上展现的游戏
在不同浏览器(桌面版或者移动版)上控制游戏
管理控制器与游戏之间的通知
确保不需要任何的安装,即使作为浏览器插件
估计涉及到的延时
初始调查研究以及选择
Nodejs 拥有高并发特性,是个 JavaScript 框架,因此是基于函数式或者事件编程的。这听起来很棒,但是有较陡的学习曲线。socket.io 实现的 WebSockets 运行得很好,便于管理。
EventMachine 同时也管理着使用事件触发的 I/O 的高并发,对于高并发这应该是一个理想的选择,但怎么才能让 WebSockets 更容易管理呢?
简单地根据一些关于 nodejs 和我们调查研究的新玩意儿判断,我们选择了 nodejs。
以下是我们用到的一些节点模块:
就此行动
我们需要构建的是一个能够给我们想要数据并且很有趣的东西,所以,我们决定开发一个叫 “Tapit” 的游戏。
Tapit 是一个舞池,在这里你能通过点击一个唯一的URL然后输入你的昵称加入游戏,随后你可以看到代表你的卡通人物出现在舞池中,在你的移动浏览器中也会出现控制器 - 有4个动作可以改变图像令你的卡通人物舞动起来。这便是创建了一个“集中交互式游戏”,玩家能在舞池前看到他的卡通人物在舞蹈,并播放着他的调调!这是一个很有潜力的简单应用。
所以,我们开始建立服务器节点以及节点模块,并且在服务器上安装了 Redis 以最大程度利用 Redis 的分发优势。
需要安装节点,npm 以及节点模块,可以阅读以下链接:nodejs and npm。
配置 socket.io,express 以及 redis
我们建立服务器节点并可如下配置:
HOST = "localhost", PORT = "3001" var express = require('express') , app = express.createServer() , redis = require('redis') , io = require('socket.io').listen(app); const DB = redis.createClient(); io.set('log level', 1); // reduce logging app.use(express.bodyParser()); app.use(express.static(__dirname + '/public')); app.set('view engine', 'jade'); app.listen(PORT);
我们还需要保持 Redis PubSub通道是打开的,我们可以这样做:
io.sockets.on('connection', function(socket) { const subscribe = redis.createClient(); const publish = redis.createClient(); socket.on('publish', function(channel, data) { publish.publish(channel, data); }); socket.on('psubscribe', function(channel) { subscribe.psubscribe(channel); }); subscribe.on("pmessage", function(pattern, channel, message) { socket.emit('message', { channel: channel, data: message }); }); });
创建一个新的舞池
为了创建一个新的舞池,我们需要调用 '/games/new' 这个链接来显示,这将创建一个舞池,并准备好客户端代码并侦听“新加舞者”或者“动作改变”的事件。
开始游戏
为了使卡通人物出现在舞池中,用户需要键入由移动浏览器生成的唯一舞池的 URL,然后将出现一个输入你的昵称的界面,这样你便能在舞池中定义自我了。
正式开玩
一旦你加入游戏后,你讲看到你的卡通人物出现在舞池中。
同时,你将在你的移动浏览器中看到四个控制键。你可以点击任何一个使得你的卡通人物在舞池中舞蹈。
这是客户端如何用JS进行动作控制的:
$("#subscribe").submit(function() { socket.emit('psubscribe', $('#subscribe #channel').val()); return false; }); $(".action").click(function() { socket.emit('publish', 'game.#{gameid}.action.' + $(this).data('action'), JSON.stringify({ nick: "#{nick}", ts: Date.now() }) );
WebSockets 将为特定游戏发布出控制事件,当 nodejs 接受到事件以后,将通过 Redis PubSub 分发出去。只要有监听器连接着,他们就都会收到事件通知。由于监听器本身就是WebSockets,他们将会在网页上接收到推送的通知。
性能 - 延时与并发
我们在各种类型的网络环境中进行了测试,如 WiFi,3G 甚至是 Edge 网络。最坏的场景情况是 Edge 网络,我们发现有 200ms 的延时--这可能还是还是可以接受的。
当我们测试并发的时候,我们能轻松地达到一百个舞者同舞的规模,现在最大的问题就是我必须为每一个用户打开一个 redis 客户端。所以我需要解决这个问题,其他的问题便是服务器端的 “Too many files open” 异常。这不是一个与节点相关的问题而是与配置有关的问题。
Github repos
已将该游戏更新到了github http://github.com/joshsoftware/tapit 。
至此我们还要做些什么?
这只是个开始,我们接下来要在web上构建一个多人游戏。这将带来规模以及延时的限制。