我們先列出一些概念,以建立真正有潛在意義的東西。我們想要做的是:
發布常見的浏覽器上展現的游戲
在不同浏覽器(桌面版或者移動版)上控制游戲
管理控制器與游戲之間的通知
確保不需要任何的安裝,即使作為浏覽器插件
估計涉及到的延時
初始調查研究以及選擇
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
我們建立服務器節點並可如下配置:
01
HOST =
"localhost"
,
02
PORT =
"3001"
03
04
var
express = require(
'express'
)
05
, app = express.createServer()
06
, redis = require(
'redis'
)
07
, io = require(
'socket.io'
).listen(app);
08
09
const DB = redis.createClient();
10
io.set(
'log level'
, 1);
// reduce logging
11
12
app.use(express.bodyParser());
13
app.use(express.static(__dirname +
'/public'
));
14
app.set(
'view engine'
,
'jade'
);
15
16
app.listen(PORT);
我們還需要保持 Redis PubSub通道是打開的,我們可以這樣做:
01
io.sockets.on(
'connection'
,
function
(socket) {
02
const subscribe = redis.createClient();
03
const publish = redis.createClient();
04
05
socket.on(
'publish'
,
function
(channel, data) {
06
publish.publish(channel, data);
07
});
08
09
socket.on(
'psubscribe'
,
function
(channel) {
10
subscribe.psubscribe(channel);
11
});
12
13
subscribe.on(
"pmessage"
,
function
(pattern, channel, message) {
14
socket.emit(
'message'
, { channel: channel, data: message });
15
});
16
});
創建一個新的舞池
為了創建一個新的舞池,我們需要調用 '/games/new' 這個鏈接來顯示,這將創建一個舞池,並准備好客戶端代碼並偵聽“新加舞者”或者“動作改變”的事件。
開始游戲
為了使卡通人物出現在舞池中,用戶需要鍵入由移動浏覽器生成的唯一舞池的 URL,然後將出現一個輸入你的昵稱的界面,這樣你便能在舞池中定義自我了。
正式開玩
一旦你加入游戲後,你講看到你的卡通人物出現在舞池中。
同時,你將在你的移動浏覽器中看到四個控制鍵。你可以點擊任何一個使得你的卡通人物在舞池中舞蹈。
這是客戶端如何用JS進行動作控制的:
1
$(
"#subscribe"
).submit(
function
() {
2
socket.emit(
'psubscribe'
, $(
'#subscribe #channel'
).val());
3
return
false
;
4
});
5
6
$(
".action"
).click(
function
() {
7
socket.emit(
'publish'
,
'game.#{gameid}.action.'
+ $(
this
).data(
'action'
),
8
JSON.stringify({ nick:
"#{nick}"
, ts: Date.now() })
9
);
WebSockets 將為特定游戲發布出控制事件,當 nodejs 接受到事件以後,將通過 Redis PubSub 分發出去。只要有監聽器連接著,他們就都會收到事件通知。由於監聽器本身就是WebSockets,他們將會在網頁上接收到推送的通知。
性能 - 延時與並發
我們在各種類型的網絡環境中進行了測試,如 WiFi,3G 甚至是 Edge 網絡。最壞的場景情況是 Edge 網絡,我們發現有 200ms 的延時--這可能還是還是可以接受的。
當我們測試並發的時候,我們能輕松地達到一百個舞者同舞的規模,現在最大的問題就是我必須為每一個用戶打開一個 redis 客戶端。所以我需要解決這個問題,其他的問題便是服務器端的 “Too many files open” 異常。這不是一個與節點相關的問題而是與配置有關的問題。
Github repos
已將該游戲更新到了github http://github.com/joshsoftware/tapit 。
至此我們還要做些什麼?
這只是個開始,我們接下來要在web上構建一個多人游戲。這將帶來規模以及延時的限制。