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 26 NodeJs
nodejs中使用HTTP分块响应和定时器示例代码
Mar 19 NodeJs
nodejs入门教程一:概念与用法简介
Apr 24 NodeJs
nodeJS实现简单网页爬虫功能的实例(分享)
Jun 08 NodeJs
使用vs code开发Nodejs程序的使用方法
Sep 21 NodeJs
详解nodejs通过响应回写的方式渲染页面资源
Apr 07 NodeJs
NVM安装nodejs的方法实用步骤
Jan 16 NodeJs
nodejs搭建本地服务器并访问文件操作示例
May 11 NodeJs
用Nodejs实现在终端中炒股的实现
Oct 18 NodeJs
nodejs+koa2 实现模仿springMVC框架
Oct 21 NodeJs
NodeJs内存占用过高的排查实战记录
May 10 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实现采集程序原理和简单示例代码
2007/03/18 PHP
PHP IF ELSE简化/三元一次式的使用
2011/08/22 PHP
php 按指定元素值去除数组元素的实现方法
2011/11/04 PHP
浅析SVN常见问题及解决方法
2013/06/21 PHP
如何在smarty中增加类似foreach的功能自动加载数据
2013/06/26 PHP
laravel ORM关联关系中的 with和whereHas用法
2019/10/16 PHP
javascript onkeydown,onkeyup,onkeypress,onclick,ondblclick
2009/02/04 Javascript
jQuery选择器全面总结
2014/01/06 Javascript
js统计录入文本框中字符的个数并加以限制不超过多少
2014/05/23 Javascript
简介JavaScript中strike()方法的使用
2015/06/08 Javascript
jQuery根据元素值删除数组元素的方法
2015/06/24 Javascript
微信小程序 触控事件详细介绍
2016/10/17 Javascript
详解照片瀑布流效果(js,jquery分别实现与知识点总结)
2017/01/01 Javascript
node.js学习之事件模块Events的使用示例
2017/09/28 Javascript
echarts大屏字体自适应的方法步骤
2019/07/12 Javascript
vue 查看dist文件里的结构(多种方式)
2020/01/17 Javascript
通过C++学习Python
2015/01/20 Python
简单介绍Python中的len()函数的使用
2015/04/07 Python
Python中强大的命令行库click入门教程
2016/12/26 Python
Scrapy抓取京东商品、豆瓣电影及代码分享
2017/11/23 Python
Python lambda表达式用法实例分析
2018/12/25 Python
Python 获取项目根路径的代码
2019/09/27 Python
什么是python的函数体
2020/06/19 Python
python 元组和列表的区别
2020/12/30 Python
用HTML5 Canvas API中的clearRect()方法实现橡皮擦功能
2016/03/15 HTML / CSS
英国领先的奢侈品零售商之一:CRUISE
2016/12/02 全球购物
伦敦香水公司:The London Perfume Company
2019/11/13 全球购物
STP的判定过程
2012/10/01 面试题
中专毕业生自我鉴定
2013/11/21 职场文书
小学音乐教学反思
2014/02/05 职场文书
信用卡工作证明模板
2014/09/14 职场文书
乡镇党的群众路线教育实践活动领导班子对照检查材料
2014/09/25 职场文书
违纪检讨书范文
2015/01/27 职场文书
个人工作保证书
2015/02/28 职场文书
环卫工作个人总结
2015/03/04 职场文书
MySQL之MyISAM存储引擎的非聚簇索引详解
2022/03/03 MySQL