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的10个性能优化技巧
Jul 15 NodeJs
轻松创建nodejs服务器(1):一个简单nodejs服务器例子
Dec 18 NodeJs
NodeJS学习笔记之FS文件模块
Jan 13 NodeJs
nodejs URL模块操作URL相关方法介绍
Mar 03 NodeJs
nodejs实现遍历文件夹并统计文件大小
May 28 NodeJs
深入浅析NodeJs并发异步的回调处理
Dec 21 NodeJs
angular2+nodejs实现图片上传功能
Mar 27 NodeJs
nodejs入门教程五:连接数据库的方法分析
Apr 24 NodeJs
NodeJs安装npm包一直失败的解决方法
Apr 28 NodeJs
nodejs超出最大的调用栈错误问题
Dec 27 NodeJs
原生nodejs使用websocket代码分享
Apr 07 NodeJs
NodeJS http模块用法示例【创建web服务器/客户端】
Nov 05 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 strtok()函数的优点分析
2010/03/02 PHP
php输入流php://input使用示例(php发送图片流到服务器)
2013/12/25 PHP
js宝典学习笔记(上)
2007/01/10 Javascript
jQuery解决iframe高度自适应代码
2009/12/20 Javascript
javaScript 关闭浏览器 (不弹出提示框)
2010/01/31 Javascript
浅谈Unicode与JavaScript的发展史
2015/01/19 Javascript
js操作滚动条事件实例
2015/01/29 Javascript
SuperSlide标签切换、焦点图多种组合插件
2015/03/14 Javascript
jquery插件autocomplete用法示例
2016/07/01 Javascript
HTML中setCapture、releaseCapture 使用方法浅析
2016/09/25 Javascript
javascript中对象的定义、使用以及对象和原型链操作小结
2016/12/14 Javascript
默认浏览器设置及vue自动打开页面的方法
2018/09/21 Javascript
jQuery插件实现非常实用的tab栏切换功能【案例】
2019/02/18 jQuery
Webpack4+Babel7+ES6兼容IE8的实现
2019/04/10 Javascript
详细讲解如何创建, 发布自己的 Vue UI 组件库
2019/05/29 Javascript
vue 地区选择器v-distpicker的常用功能
2019/07/23 Javascript
如何在wxml中直接写js代码(wxs)
2019/11/14 Javascript
vue 实现用户登录方式的切换功能
2020/04/14 Javascript
[57:16]2014 DOTA2华西杯精英邀请赛 5 25 LGD VS VG第二场
2014/05/26 DOTA
在Python中用has_key()方法查找键是否存在的教程
2015/05/21 Python
在Python的Flask框架中验证注册用户的Email的方法
2015/09/02 Python
Python处理菜单消息操作示例【基于win32ui模块】
2018/05/09 Python
Python操作mongodb的9个步骤
2018/06/04 Python
Python的argparse库使用详解
2018/10/09 Python
对python数据切割归并算法的实例讲解
2018/12/12 Python
在python中使用with打开多个文件的方法
2019/01/07 Python
python上传时包含boundary时的解决方法
2020/04/08 Python
css3进行截取替代js的substring
2013/09/02 HTML / CSS
英国最好的温室之家:Greenhouses Direct
2019/07/13 全球购物
男女钓鱼靴和甲板鞋:XTRATUF
2021/01/09 全球购物
毕业生在校学习的自我评价分享
2013/10/08 职场文书
仲裁协议书
2014/09/26 职场文书
英文诗歌翻译方法(赏析)
2019/08/16 职场文书
pytorch 如何把图像数据集进行划分成train,test和val
2021/05/31 Python
css中有哪些方式可以隐藏页面元素及区别
2022/06/16 HTML / CSS
mysql序号rownum行号实现方式
2022/12/24 MySQL