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中实现sleep功能实例
Mar 24 NodeJs
浅谈NodeJS中require路径问题
May 07 NodeJs
Nodejs如何搭建Web服务器
Mar 28 NodeJs
详解nodejs爬虫程序解决gbk等中文编码问题
Apr 06 NodeJs
nodejs爬虫遇到的乱码问题汇总
Apr 07 NodeJs
NodeJs的fs读写删除移动监听
Apr 28 NodeJs
nodejs 最新版安装npm 的使用详解
Jan 18 NodeJs
Nodejs 发布自己的npm包并制作成命令行工具的实例讲解
May 15 NodeJs
nodejs对项目下所有空文件夹创建gitkeep的方法
Aug 02 NodeJs
图解NodeJS实现登录注册功能
Sep 16 NodeJs
ubuntu系统下使用pm2设置nodejs开机自启动的方法
May 12 NodeJs
node快速搭建后台的实现步骤
Feb 18 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
SONY ICF-SW07收音机电路分析
2021/03/02 无线电
php array_push()数组函数:将一个或多个单元压入数组的末尾(入栈)
2011/07/12 PHP
如何使用PHP实现javascript的escape和unescape函数
2013/06/29 PHP
php遍历、读取文件夹中图片并分页显示图片的方法
2016/11/15 PHP
jQuery 树形结构的选择器
2010/02/15 Javascript
Angular的模块化(代码分享)
2016/12/26 Javascript
简单实现js悬浮导航效果
2017/02/05 Javascript
强大的JavaScript响应式图表Chartist.js的使用
2017/09/13 Javascript
详解webpack提取第三方库的正确姿势
2017/12/22 Javascript
JS插件clipboard.js实现一键复制粘贴功能
2020/12/04 Javascript
解决Angular2 router.navigate刷新页面的问题
2018/08/31 Javascript
vue2 设置router-view默认路径的实例
2018/09/20 Javascript
Vue利用Blob下载原生二进制数组文件
2019/09/25 Javascript
vue实现计算器功能
2020/02/22 Javascript
在vue中实现嵌套页面(iframe)
2020/07/30 Javascript
vue-cli3项目打包后自动化部署到服务器的方法
2020/09/16 Javascript
Python中Iterator迭代器的使用杂谈
2016/06/20 Python
Python三级目录展示的实现方法
2016/09/28 Python
通过Python爬虫代理IP快速增加博客阅读量
2016/12/14 Python
python多线程socket编程之多客户端接入
2017/09/12 Python
Python中defaultdict与lambda表达式用法实例小结
2018/04/09 Python
python实现简单的文字识别
2018/11/27 Python
使用Python快速制作可视化报表的方法
2019/02/03 Python
通过案例解析python鸭子类型相关原理
2020/10/10 Python
Python3爬虫ChromeDriver的安装实例
2021/02/06 Python
手对手的教你用canvas画一个简单的海报的方法示例
2018/12/10 HTML / CSS
佳能英国官方网站:Canon UK
2017/08/08 全球购物
到底Java是如何传递参数的?是by value或by reference?
2012/07/13 面试题
2014两会学习心得:榜样精神伴我行
2014/03/17 职场文书
老师对学生的寄语
2014/04/09 职场文书
2014年创先争优活动总结
2014/05/04 职场文书
2014教师研修学习体会
2014/07/08 职场文书
工作检讨书范文
2015/01/23 职场文书
2015年事业单位工作总结
2015/04/27 职场文书
每日六道java新手入门面试题,通往自由的道路
2021/06/30 Java/Android
叶县这家生产军用电台的兵工厂,人称“四机部”,走出一上将
2022/02/18 无线电