使用HTML5,WebSockets,nodejs和socket.io构建实时游戏

jopen 12年前

    想象一下在网络上玩游戏只需要简单地登录,不需要本地安装,不需要任何许可证,在浏览器或者手机中的多人游戏可以断线重连--这基本上就是“云游戏”了。好吧,这听起来挺俗套了,但是我们接下来就能见识到这些了,而且比我们想象的更好更快!

    我们先列出一些概念建立真正有潜在意义的东西我们想要做是:

  • 发布常见的浏览器上展现的游戏

  • 在不同浏览器(桌面版或者移动版)上控制游戏

  • 管理控制器与游戏之间的通知

  • 确保不需要任何的安装,即使作为浏览器插件

  • 估计涉及到的延时

初始调查研究以及选择

    Nodejs 拥有高并发特性,是个 JavaScript 框架,因此是基于函数式或者事件编程的。这听起来很棒,但是有较陡的学习曲线。socket.io 实现的 WebSockets 运行得很好,便于管理。

    EventMachine 同时也管理着使用事件触发的 I/O 的高并发,对于高并发这应该是一个理想的选择,但怎么才能让 WebSockets 更容易管理呢?

    简单地根据一些关于 nodejs 和我们调查研究的新玩意儿判断,我们选择了 nodejs。

    以下是我们用到的一些节点模块:

  • Socket.IO - 很明显的 WebSockets 选择
  • Express - 这是我们对用户界面的选择。我们本可以使用 Rails 程序,但是杀鸡焉用牛刀?
  • Jade - HTML 模版
  • Redis - 数据分发

就此行动

    我们需要构建的是一个能够给我们想要数据并且很有趣的东西,所以,我们决定开发一个叫 “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上构建一个多人游戏。这将带来规模以及延时的限制。

    原文地址 , OSChina.net原创编译