技术开发 频道

全程指导:Node JS实战之制作涂鸦游戏

  【IT168技术】Node.js目前无论是在前端还是后端开发中,已经越来越受到广大开发者的关注,相关使用Node.js进行开发的案例也越来越多。

  Node是一个Javascript运行环境(runtime)。实际上它是对GoogleV8引擎(应用于Google Chrome浏览器)进行了封装。V8引 擎执行Javascript的速度非常快,性能非常好。Node对一些特殊用例进行了优化,提供了替代的API,使得V8在非浏览器环境下运行得更好。例 如,在服务器环境中,处理二进制数据通常是必不可少的,但Javascript对此支持不足,因此,V8.Node增加了Buffer类,方便并且高效地 处理二进制数据。因此,Node不仅仅简单的使用了V8,还对其进行了优化,使其在各环境下更加给力。

  在本文中,将带领读者通过实战制作一个能供多人在线涂鸦画画的游戏,让读者体会Node.js的特殊魅力,这个游戏的特点是多人在浏览这个页面时,大家都可以在页面上自由涂鸦,而且大家是互相看到其涂鸦的效果的。Node.js由于可以让开发者编写服务端运行的Javascript,因此能同时处理大量的连接,特别适合比如聊天,网络游戏等需要对即时性要求高的。本文要求读者有一定的Javascript和其他编程语言的基本知识。

  安装node.js

  首先,我们从nodejs.org下载node.js,这十分简单,特别是在windows下,直接安装installer的安装包setup运行就可以了,如果在linux等其他操作系统上运行,可以在终端中运行一系列的命令,如下:

  echo 'export PATH=$HOME/local/bin:$PATH' >> ~/.bashrc
. ~/.bashrc
mkdir ~
/local
mkdir ~
/node-latest-install
cd ~
/node-latest-install
curl http:
//nodejs.org/dist/node-latest.tar.gz | tar xz --strip-components=1
.
/configure --prefix=~/local
make install # ok, fine, this step probably takes more than
30 seconds...
curl http:
//npmjs.org/install.sh | sh

  在安装完毕node.js后,我们需要安装node.js中的模块包,因为在程序中我们要用到网络相关的一系列功能,而幸运的是,node.js都帮我们封装了大量而丰富的相关的各种函数和方法,这些都可以通过npm模块管理器去下载这些模块包,本文中,需要使用的是socket.io和node-static两个模块,其中node-static模块是专门针对HTML,CSS和js而用到的。我们在命令行中,输入如下命令,就可以马上完成安装了。

  npm install socket.io node-static

  如何运行程序

  本文的示例代码在如下地址可以下载:http://demo.tutorialzine.com/2012/08/nodejs-drawing-game/node-drawing-game.zip

  ,可以将下载后的代码解压缩,然后打开node.js的命令行,进入该目录,然后执行:

  node app.js

  然后打开浏览器,输入http://localhost:8080,马上就可以感受这个游戏了!

 
${PageNumber}

  编写HTML页面部分

  接下来,我们首先编写页面部分的HTML代码。首先,在页面中,我们使用HTML5的canvas去绘画游戏的背景界面,并且使用div来设定每一个游戏绘画者的鼠标的指针,这个指针的形状使用的是一个.pointer的css样式,并且使用绝对定位。详细的css文件,请参考assets/css/styles.css文件。下面是

  index.html的代码,如下:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Node.js Multiplayer Drawing Game | Tutorialzine Demo</title>

<!-- The stylesheets -->
<link rel="stylesheet" href="assets/css/styles.css" />

<!--[if lt IE 9]>
<script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
</head>

<body>
<div id="cursors">
<!-- The mouse pointers will be created here -->
</div>

<canvas id="paper" width="1900" height="1000">
Your browser needs
to support canvas for this to work!
</canvas>

<hgroup id="instructions">
<h1>Draw anywhere!</h1>
<h2>You will see everyone else who's doing the same.</h2>
<h3>Tip: if the stage gets dirty, simply reload the page</h3>
</hgroup>

<!-- JavaScript includes. Notice that socket.io.js is served by node.js -->
<script src="/socket.io/socket.io.js"></script>
<script src="http://code.jquery.com/jquery-1.8.0.min.js"></script>
<script src="assets/js/script.js"></script>

</body>
</html>

  可以看到,上面的canvas画布的尺寸有点大,有的用户的屏幕大小关系可能看不完整,但这个没关系,开发者可以去调节其大小。此外在页面中也包括了socket.io.js这个文件了,但在下载的代码文件中其实读者是找不到这个文件的,因为其实这个其实是服务端生成的文件而已,这个有点象著名的AJAX框架DWR的原理一样。下图就是运行index.html后的效果:

Node JS实战之制作涂鸦游戏

${PageNumber}

  客户端的代码

  跟我们平时在Javascript中进行调用不同,这次node.js需要在客户端和服务端同时都运用上Javascript。在下面提到的代码中,使用了socket.io去连接服务端,并且当发生了相关事件后,就通知用户。事件的传递都是以消息的形式进行的,并且统一交由node.js处理。事件消息中包含了鼠标的坐标,每一个操作者的唯一的id,以及判断用户当前是否正在绘画。

$(function(){
// 判断浏览器是否支持canvas功能
if(!('getContext' in document.createElement('canvas'))){
alert('Sorry, it looks like your browser does not support canvas!');
return false;
}
// web服务器地址,端口在app.js中设置
var url
= 'http://localhost:8080';
var doc = $(document),
win
= $(window),
canvas
= $('#paper'),
ctx = canvas[0].getContext('2d'),
instructions = $('#instructions');
// 产生一个唯一的用户id
var id
= Math.round($.now()*Math.random());
// 判断是否正在绘图
var drawing
= false;
var clients
= {};
var cursors
= {};
var socket
= io.connect(url);
socket.on(
'moving', function (data) {
if(! (data.id in clients)){
// 发现一个新的用户加入了游戏在线绘画,给新用户一个可以绘画的画笔光标
cursors[data.id]
= $('<div class="cursor">').appendTo('#cursors');
}
// 移动光标
cursors[data.id].css({
'left' : data.x,
'top' : data.y
});
// 判断用户是否还在绘画
if(data.drawing && clients[data.id]){
// 在画布中画线条,其中clients[data.id]数组中包含了用户之前的光标的位置
drawLine(clients[data.id].x, clients[data.id].y, data.x, data.y);
}
// 保存当前光标状态
clients[data.id]
= data;
clients[data.id].updated
= $.now();
});
var prev
= {};
canvas.on(
'mousedown',function(e){
e.preventDefault();
drawing
= true;
prev.x
= e.pageX;
prev.y
= e.pageY;
// 隐藏操作指引
instructions.fadeOut();
});
//当光标移开时,设置停止绘画标记
doc.bind(
'mouseup mouseleave',function(){
drawing = false;
});
//获取当前时间
var lastEmit
= $.now();
doc.on(
'mousemove',function(e){

//30秒后通过socket发送广播消息
if($.now() - lastEmit > 30){
socket.emit(
'mousemove',{
'x': e.pageX,
'y': e.pageY,
'drawing': drawing,
'id': id
});
lastEmit
= $.now();
}
// 如果在绘画中的状态的话,则允许用户继续绘画
if(drawing){
drawLine(prev.x, prev.y, e.pageX, e.pageY);
prev.x
= e.pageX;
prev.y
= e.pageY;
}
});
// 对超过10秒依然不绘画的用户进行移除
setInterval(
function(){
for(ident in clients){
if($.now() - clients[ident].updated > 10000){
//删除该不活跃的用户
cursors[ident].remove();
delete clients[ident];
delete cursors[ident];
}
}
},
10000);
//标准画线的方法
function drawLine(fromx, fromy, tox, toy){
ctx.moveTo(fromx, fromy);
ctx.lineTo(tox, toy);
ctx.stroke();
}
});

  在上面的代码中,使用了socket.emit方法去发送消息给node.js,因为要求多个用户同时各自在绘画图时,都要把其当前光标状态等广播给其他人,因此会带来大量的数据包,所以这里每30秒才将用户的绘画状态包装成消息体的形式发送出去,并且对超过10秒不进行绘画的用户进行清除。

${PageNumber}

  服务端代码的编写

  现在我们进入服务端代码的编写,读者可能会以为,会否服务端代码会比客户端的代码多很都长,但在nodejs的世界,却正好相反,服务端的代码更加简单,这都得益于nodejs对各种常用的功能进行的封装,服务端的app.js代码如下:

// 包含http模块
var app
= require('http').createServer(handler),
io = require('socket.io').listen(app),
static = require('node-static'); // 引入node-static模块专门处理相关的html和js等
// 创建一个web服务器,并在8080端口监听
var fileServer
= new static.Server('./');

app.listen(
8080);

function handler (request, response) {

request.addListener(
'end', function () {
fileServer.serve(request, response); });
}

// 如果需要看调试信息删除这行
io.set(
'log level', 1);

// 监听客户端的请求
io.sockets.on(
'connection', function (socket) {

// 开始监听鼠标的移动事件
socket.on(
'mousemove', function (data) {

// 广播消息到各客户端
socket.broadcast.emit(
'moving', data);
});
});

  就这么简单!我们的服务端程序就编写完毕了,现在可以按前文说到的方法进行运行了。

  小结

  在本文中,简单为大家介绍了如何使用node.js开发一个多人同时在线涂鸦的小游戏,可以看到,由于node.js的特点,使得编写该类型的程序变得十分简单,node.js还有大量特性需要开发者去挖掘和学习,敬请期待itpub的相关文章介绍。

0
相关文章