Nodejs实现多人同时在线移动鼠标的小游戏分享


Posted in NodeJs onDecember 06, 2014

最近因为项目需要,所以研究了一下nodejs的websocket实现,socket.io,这是nodejs后台应用websocket广泛使用的框架。

准备工作

1.安装socket.io,使用命令npm install socket.io
2.windows系统的话,需要vc编译环境,因为安装socket.io的时候,会编译vc代码

游戏基本原理

1.服务器监听客户端的连接
2.客户端连接成功时候,绑定页面移动鼠标事件,事件里处理发送当前坐标给服务器
3.服务器保存一个全局的坐标对象,并以客户端唯一编号为键值
4.有新连接来的时候,把坐标广播给其它客户端
5.客户端断开连接的时候,服务端删除它的坐标信息,并广播给其它客户端

开始实现服务端代码

scoket.io建立服务器监听的时候,需要依赖一个http连接,用来处理升级协议用,所以也需要一个http模块,代码如下:

var http = require('http'),

    io = require('socket.io');


var app = http.createServer().listen(9091);
var ws = io.listen(app);

然后定义一个全局的坐标对象

var postions = {};

开始监听客户端的连接,并新增广播函数(其实可用socket.io自带的广播方法io.sockets.broadcast.emit),核心代码如下:

ws.on('connection', function(client){

    // 广播函数

    var broadcast = function(msg, cl){

        for(var k in ws.sockets.sockets){

            if(ws.sockets.sockets.hasOwnProperty(k)){

                if(ws.sockets.sockets[k] && ws.sockets.sockets[k].id != cl.id){

                    ws.sockets.sockets[k].emit('position.change', msg);

                }

            }

        }

    };

    console.log('\033[92m有新的连接来:\033[39m', postions);

    // 客户端连接成功之后,就发送其它客户端的坐标信息

    client.emit('position.change', postions);

    // 接收客户端发送消息

    client.on('position.change', function(msg){

        // 目前客户端的消息就只有坐标消息

        postions[client.id] = msg;

        // 把消息广播给其它所有的客户端

        broadcast({

            type: 'position',

            postion: msg,

            id: client.id

        }, client);

    });

    // 接收客户端关闭连接消息

    client.on('close', function(){

        console.log('close!');

        // 删除客户端,并通知其它客户端

        delete postions[client.id];

        // 把消息广播给其它所有的客户端

        broadcast({

            type: 'disconnect',

            id: client.id

        }, client);

    });

    // 断开连接

    client.on('disconnect', function(){

        console.log('disconnect!');

        // 删除客户端,并通知其它客户端

        delete postions[client.id];

        // 把消息广播给其它所有的客户端

        broadcast({

            type: 'disconnect',

            id: client.id

        }, client);

    })

    // 定义客户端异常处理

    client.on('error', function(err){

        console.log('error->', err);

    })

});

分析上面的代码,关键点在于

1.新的客户端连接成功,发送其它客户端的坐标信息
2.客户端更新坐标信息的时候,通知其它客户端
3.客户端断开连接,通知其它客户端
4.广播消息类型分为修改坐标与移除坐标

编写客户端html页面

由于socket.io是自定义的框架,所以客户端需要引用socket.io.js,这个js可以从socket.io模块里查找,路径一般为node_modules\socket.io\node_modules\socket.io-client\dist,里面有合并与压缩两个版本,开发的时候可以用合并版.

完整代码如下:

<!DOCTYPE html>

<html>

<head>

    <title>socket.io 多人同时在线互动 例子</title>

    <meta charset="utf-8">

</head>

<body>
<script type="text/javascript" src="socket.io.js"></script>

<script type="text/javascript">

    var ws = io.connect('http://localhost:9091/');

    var isfirst;
    ws.on('connect', function(){

        console.log(ws);

        // 开始绑定mousemove事件

        document.onmousemove = function(ev){

            if(ws.socket.transport.isOpen){

                ws.emit('position.change', { x: ev.clientX, y: ev.clientY });

            }

        }

    })
    ws.on('position.change', function(data){

        // 开始同时在线的别的客户端

        if(!isfirst){

            isfirst = true;

            // 第一条消息是收到别个所有客户端的坐标

            for(var i in data){

                move(i, data[i]);

            }

        }else{

            // 否则,要不就是别个断开连接的消息,或者别个更新坐标的消息

            if('position' == data.type){

                move(data.id, data.postion);

            }else{

                remove(data.id);

            }

        }

    })
    ws.on('error', function(){

        console.log('error:', ws);

        ws.disconnect();

    })


    function move(id, pos){

        var ele = document.querySelector('#cursor_' + id);

        if(!ele){

            // 不存在,则创建

            ele = document.createElement('img');

            ele.id = 'cursor_' + id;

            ele.src = 'img/cursor.png';

            ele.style.position = 'absolute';

            document.body.appendChild(ele);

        }
        ele.style.left = pos.x + 'px';

        ele.style.top = pos.y + 'px';

    }
    function remove(id){

        var ele = document.querySelector('#cursor_' + id);

        ele.parentNode.removeChild(ele);

    }
</script>

</body>

</html>

页面中的img/cursor.png,可以这里找到,cursor.png,这里也有很多其它的鼠标图标,前端的原理比较简单,简单的分析如下

1.连接成功时,绑定页面mousemove事件,里面处理发送新坐标消息
2.收到消息根据消息类型,处理是修改其它客户端消息,还是移除其它客户端消息
3.定义添加其它客户端cursor图标与移除cursor图标
4.处理客户端异常消息,并添加断开连接,以让服务端移除坐标信息

运行例子

1.保存服务器代码为io_multigame.js
2.保存客户端代码为io_multigame.html
3.运行服务器代码node io_multigame.js
4.打开多个io_multigame.html页面,即可看到效果

总结

写的比较随意,参考了了不起的nodejs,这是一本好书,想了解nodejs的朋友们,可以看看这本书。

NodeJs 相关文章推荐
nodejs实用示例 缩址还原
Dec 28 NodeJs
Nodejs进程管理模块forever详解
Jun 01 NodeJs
基于NodeJS的前后端分离的思考与实践(一)全栈式开发
Sep 26 NodeJs
Nodejs极简入门教程(三):进程
Oct 27 NodeJs
Nodejs中调用系统命令、Shell脚本和Python脚本的方法和实例
Jan 01 NodeJs
Nodejs中读取中文文件编码问题、发送邮件和定时任务实例
Jan 01 NodeJs
Nodejs实现批量下载妹纸图
May 28 NodeJs
nodejs模块nodemailer基本使用-邮件发送示例(支持附件)
Mar 28 NodeJs
nodeJS实现路由功能实例代码
Jun 08 NodeJs
Nodejs之TCP服务端与客户端聊天程序详解
Jul 07 NodeJs
通过Nodejs搭建网站简单实现注册登录流程
Jun 14 NodeJs
分享五个Node.js开发的优秀实践 
Apr 07 NodeJs
Nodejs实现的一个静态服务器实例
Dec 06 #NodeJs
nodejs中简单实现Javascript Promise机制的实例
Dec 06 #NodeJs
nodejs实现的一个简单聊天室功能分享
Dec 06 #NodeJs
详谈nodejs异步编程
Dec 04 #NodeJs
nodejs下打包模块archiver详解
Dec 03 #NodeJs
nodejs中转换URL字符串与查询字符串详解
Nov 26 #NodeJs
nodejs教程之制作一个简单的文章发布系统
Nov 21 #NodeJs
You might like
php &amp;&amp; 逻辑与运算符使用说明
2010/03/04 PHP
跟我学Laravel之路由
2014/10/15 PHP
学习php设计模式 php实现原型模式(prototype)
2015/12/07 PHP
浅谈php中curl、fsockopen的应用
2016/12/10 PHP
Gird事件机制初级读本
2007/03/10 Javascript
JavaScript学习笔记记录我的旅程
2012/05/23 Javascript
node.js中的http.response.writeHead方法使用说明
2014/12/14 Javascript
jQuery简单实现input文本框内灰色提示文本效果的方法
2015/12/02 Javascript
基于javascript实现表格的简单操作
2016/05/21 Javascript
基于JavaScript实现鼠标箭头移动图片跟着移动
2016/08/30 Javascript
学习vue.js表单控件绑定操作
2016/12/05 Javascript
深入理解jQuery()方法的构建原理
2016/12/05 Javascript
VueJs单页应用实现微信网页授权及微信分享功能示例
2017/07/26 Javascript
js原生实现移动端手指滑动轮播图效果的示例
2018/01/02 Javascript
vue.js select下拉框绑定和取值方法
2018/03/03 Javascript
JavaScript实现浏览器网页自动滚动并点击的示例代码
2020/12/05 Javascript
[01:23:59]2018DOTA2亚洲邀请赛 4.1 小组赛 B组 VP vs Secret
2018/04/03 DOTA
[01:11:48]Fnatic vs IG 2018国际邀请赛小组赛BO2 第二场 8.17
2018/08/18 DOTA
Python 代码性能优化技巧分享
2012/08/07 Python
深入理解Python对Json的解析
2017/02/14 Python
Python中super函数的用法
2017/11/17 Python
对PyTorch torch.stack的实例讲解
2018/07/30 Python
python 自动轨迹绘制的实例代码
2019/07/05 Python
python 爬虫 实现增量去重和定时爬取实例
2020/02/28 Python
python 星号(*)的多种用途
2020/09/21 Python
canvas像素点操作之视频绿幕抠图
2018/09/11 HTML / CSS
市场部专员岗位职责
2013/11/30 职场文书
机械设计毕业生自荐信
2014/02/02 职场文书
行政内勤岗位职责
2014/04/07 职场文书
养成教育经验材料
2014/05/26 职场文书
实习协议书范本
2014/09/25 职场文书
学校开学标语
2014/10/06 职场文书
学前教育见习总结
2015/06/23 职场文书
初中历史教学反思
2016/02/19 职场文书
总结Python连接CS2000的详细步骤
2021/06/23 Python
MySQL创建管理子分区
2022/04/13 MySQL