前几天看了关于websocket的相关教程,觉的在做多人联网游戏方面,socket还是很有用的。所以这两天稍微研究了一些。做了一个简单的火箭车游戏的demo。用了加深对soecket应用的了解。
环境
这里我使用了node来作为服务器端。主要用到的库是express 和 socket.io.两者都可以通过npm install来安装。因为我们要做游戏,所以我这里用了自己封装的一个简单web canvas引擎:Hamster。客户端主要使用jqeury和Hamster。
搭建开发目录
整个项目的目录结构如下图所示:
- app
- client
- public
- resource
- js
- index.html
- public
- server.js
根目录下的server.js是我们的服务器脚本。客户端的逻辑写在client/public/下面的js文件夹中。resource为所有的图片资源。client下的index.html为游戏入口文件。
搭建服务
ok,安装相关的依赖之后我们就可以开始写服务端的逻辑了。
打开server.js,代码如下:
1 | var express = require("express"); |
记得在client下的index.html写点什么。然后命令行通过node server.js来启动服务。浏览器打开127.0.0.1:3000这个时候应该可以看见你写下的那什么了。其实这段代码也挺好理解的。首先启动一个express的app服务,再用socket来监听这个服务。然后使用app.use()函数来确定服务端的路由。最后是设置服务启动监听的端口。
客户端
1 |
|
这里我先把整个的html文件贴了出来。主要是一些html的标签的设置与样式的设置。这里我们稍微注意下js文件加入的顺序。socket.io.js和jqeury我们放在最前面,因为后面很多的操作都要基于这两者,config和Hamster是引擎的配置文件和库文件。这里要放在我们用户代码之前。最后只要注意下。id 为main的canvas为我们的游戏主场景。
登陆以及获取PassCode
还记得我们以前玩那种局域网游戏,在你创建完了服务器主机之后,小伙伴们都会想你询问你的ip地址,或者设置的密码以便加入游戏。这里我们也采用类似的方法。只是不是通过ip地址来加入。我们在玩家创建房间之后,服务端来随机生成一个PassCode,然后玩家通过输入passcode来进入游戏。只有两个输入相同的passcode的玩家才能进入游戏场景。
然后我们先开始写客户端生成passcode的代码。
打开main.js,这里我们创建游戏房间以及其他的一些dom操作用到了jqeury库。首先我们创建一个Login的类,用它来管理整个玩家的创建房间与加入游戏房间的逻辑。
1 | $(function(){ |
首先我们先写一个链接成功的反馈。我们的服务在前一部分已经成功启动了。现在我们需要看我们的客户端的socket链接是否成功。这里我们用socket.on(“connect”,callback)来做检测。如果链接是成功的。则反馈一些相对应的dom文本。接下来是关于建立游戏房间的逻辑。我们需要在输入框中输入一个id,然后点击build来创建房间。如果通过验证,会像服务端发送一个login的消息。这个消息还传送了一个叫做nickName的参数。其实这个游戏中,并没有使用nickname这个参数。因为我们的passcode仅仅只是自动返回随机数。如果你像做一个验证更加完美,或者安全度更高的多人游戏,可以把这个nickname和passcode的生成做一下算法的关联。这里我就不说太多了。
正如你所看到的。socket.emit()这个函数是向服务端发送消息。而socket.on是接受来自服务端的消息。socket通信的一个很大的特点是客户度啊与服务端是一直链接着的。不管是服务端还是客户端,都可以即时的相应到来自对方发送过来的消息。也正是这个特点,才使即时联网的游戏更加流畅。
既然发送了消息,那么我们服务端就要响应来自客户端的消息。
这里我们打开server.js
1 |
|
这里的io.on是整个socket的启动,当有新的客户端链接进来的,就开始执行其中的逻辑。参数socket代表的是当前链接的信息,有点像js中的this。
然后我们开始通过socket.on(“login”)来接收来自客户端的login消息。如果有这养的消息传进来。我们就开始执行下部分的逻辑。这里你可以尝试着打印下参数中的nickname,看和你所输入的nickname是不是吻合的。接着我们把生成的passcode来push到passcodelist中去做统一的管理,因为我们后面还得通过验证passcode来加入游戏。
后面我们发现了一个不同的消息传送的方式。socket.broadcast.emit()这个是socket广播消息的函数。用来向所有的已经链接到了服务端的所有客户端发布消息。这里当我们的服务器收到来自客户端的disconnect消息之后,他便向所有的客户端广播。refresh消息来告诉客户端,有玩家离线了。最前面的if语句是用来做一个小小的游戏人数控制用的。因为目前我们只做双人游戏。所以暂时只允许两名玩家加入游戏。
ok,接下来又得写客户端的逻辑了。当我们受到来自服务端的loginSuccess消息之后,我们得做点什么。
打开main.js,加入
1 |
|
这样我们在前端的页面中显示这个passcode了。
有了创建的逻辑之后,我们开始写用户加入游戏房间的逻辑。
继续在main.js中加入:
1 |
|
这个逻辑很简单,我就不多说了,就是输入passcode,然后发送消息到服务端。
我们要在服务端接收这个消息,并且去验证这个passcode是否是正确的。
ok,打开server.js,往下加入。
1 |
|
我们首先验证passcode是不是正确的。如果正确,就可以开始向客户端发送成功的消息,并且分配1p和2p的游戏位置给两个玩家。然后在控制台作出相应的输出。当玩家数量到可以开始游戏了之后,向客户端发送gameStart消息。
游戏逻辑以及数据交换
回到客户端,我们这里拿到了gameStart消息之后,意味着游戏可以开始了。
打开main.js,我们开始要写游戏逻辑了。
这里首先说明下。因为这个只是基于socket学习的demo,我不打算把这个游戏逻辑设计得有多么的复杂。只是为了简短的实现联机游戏的基本功能。如果想让这个游戏更加具有游戏性,完全可以自己来做一些修改添加。
1 |
|
这里我就不详细一段一段的说明了,前面主要是各种游戏元素的添加,加入键盘的keyUp事件,当按下w松开的时候,会触发小车前进的动作。当玩家player1的小车前进了之后,将自己的坐标通过soket.emit(“position1”)发送到服务端,服务端在得到player1的数据之后会向player2玩家发送消息“position1Fresh”,这样player2拿到这个消息中player1的位置之后,在自己的屏幕上更新player1的位置,这样就像是player1在player2的客户端进行了移动。
最后加上游戏结束时的消息响应,客户端的逻辑基本就结束了。
回到server.js ,加入对player1和player2的消息的响应,以及结束条件的判定。整个游戏基本就完成了。
1 |
|
结尾
最后放一张游戏的截图。
注意,这里使用的游戏素材请注意版权,不要做学习之外的用途。
整个项目的源码放在了github上。