博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Cocos Creator 实现画板(你画我猜)
阅读量:6605 次
发布时间:2019-06-24

本文共 6952 字,大约阅读时间需要 23 分钟。

前言

本例是基于cocos官方推荐raphael实现的。其中画板与看板的同步处理我采用的是在画板画完一条线之后看板再同步数据来显示画线过程。

一、实现效果如下:

二、画板核心代码

1、初始化画板参数

onLoad: function () {        // 初始化参数        this.lineWidth = 5;        this.strokeColor = cc.color(0, 0, 0);        this.isClearMode = false;        this.group = this.addComponent('R.group');        // 绑定触摸通知事件通知        cc.eventManager.addListener({            event: cc.EventListener.TOUCH_ONE_BY_ONE,            onTouchBegan: this.onTouchBegan.bind(this),            onTouchMoved: this.onTouchMoved.bind(this),            onTouchEnded: this.onTouchEnded.bind(this),        }, this.node);    },复制代码

需要注意的事项:

① 本例使用的是 raphael 库的 group 的概念来处理的画板中的线

2、触摸开始事件回调处理

onTouchBegan: function (touch, event) {        // 初始一条线的数据        this.dataDict = {};        this.dataDict.dataEvent = 'draw';        // 获取开始时间点        this.dataDict.startTime = new Date().getTime();        // 获取触摸点数据        var touchLoc = touch.getLocation();        touchLoc = this.node.parent.convertToNodeSpaceAR(touchLoc);        // 从group获取一条Path实例        var path = this.group.addPath();        path.fillColor = 'none';        // 判断是否是橡皮擦状态        if (this.isClearMode) {            path.lineWidth = 15;            path.strokeColor = cc.color(255, 255, 255);        } else {            path.lineWidth = this.lineWidth;            path.strokeColor = this.strokeColor;        }        this.dataDict.strokeColor = path.strokeColor.toHEX("#rrggbb");        this.dataDict.lineWidth = path.lineWidth;        // 初始化点数组,并赋值开始位置的点        this.points = [touchLoc];        return true;    },复制代码

需要注意的事项:

① 橡皮擦处理的方式是用与画板背景色相同的颜色画线,并加粗线的宽度来实现的。

this.dataDict 记录的数据是为了通过 webSocket 传递到看板,来使看板同步画线。

3、触摸移动事件处理

onTouchMoved: function (touch, event) {        // 获取触摸点数据        var touchLoc = touch.getLocation();        touchLoc = this.node.parent.convertToNodeSpaceAR(touchLoc);        // 添加到点数组内        this.points.push(touchLoc);        // 获取当前画的path实例,并更新内部展现点数据        var path = this.group.children[this.group.children.length - 1];        path.points(this.points);    },复制代码

需要注意的事项:

① 每次获取的都是group中最新的一条path去画。

4、触摸事件结束处理

onTouchEnded: function(touch, event) {        // 获取触摸点数据        var path = this.group.children[this.group.children.length - 1];        path.points(this.points);        // 获取结束时间点        this.dataDict.endTime = new Date().getTime();        // 将点数组转化为相对于node宽高的映射位置        this.pointDicts = [];        for (var i = 0; i < this.points.length; i++) {            let point = this.points[i];            var pointDict = {};            pointDict.x = point.x / this.node.width;            pointDict.y = point.y / this.node.height;            this.pointDicts.push(pointDict);        }        this.dataDict.points = this.pointDicts;        let sendData = this.dataDict;        // 本地测试同步数据        // this.lookDraw.startDraw(sendData);        // 网络同步数据        if (window.room_user) {            var drawAction = gameAction.getDrawDataAction(window.room_user, sendData)            happySocket.sendData(drawAction)        }    },复制代码

需要注意的事项:

① 首先为了适应不同的屏幕,需要获取到实际画点的相对于宽高的映射点。

② 本地测试与网络同步数据可根据自己项目做相应的处理。

③ 也可在本地搭建webSocket去模拟实际服务器传输,可以看。

4、其他处理(比如清屏、橡皮擦)

// 清屏    clearAll: function() {        this.group.ctx.clear();        this.group.children = [];        this.isClearMode = false;        // 初始化清屏的数据        this.dataDict = {};        this.dataDict.dataEvent = 'clear';        let sendData = this.dataDict;        // 本地测试同步数据        // this.lookDraw.startDraw(sendData);        // 网络同步数据        if (window.room_user) {            var drawAction = gameAction.getDrawDataAction(window.room_user, sendData)            happySocket.sendData(drawAction)        }    },    // 橡皮擦    rubber: function() {        this.isClearMode = true;    },复制代码

需要注意的事项:

① 清屏的action会放入看板事件队列中,在画完最后一条线后执行。具体看看板代码。

三、看板核心代码

1、初始化参数(要与画板保持一致)

onLoad: function () {        // 初始化数据        this.lineWidth = 5;        this.strokeColor = cc.color(0, 0, 0);        this.isClearMode = false;        this.group = this.addComponent('R.group');        this.time = 3.0;        this.duration = 1.0;        this.pathArray = [];        // 监听画板数据        happyDispatch.addEventListener('happyAction', this.receiveData, this);    },复制代码

需要注意的事项:

this.pathArray 为画线的事件队列。

2、开始画线

// 开始画线    startDraw: function (dataDict) {        // 判断是否是清屏        if (dataDict.dataEvent === 'clear') {            this.pathArray.push(dataDict);            return;        }        // 初始化线        let path = this.group.addPath();        path.strokeColor = cc.color(0, 0, 0).fromHEX(dataDict.strokeColor);        path.lineWidth = dataDict.lineWidth;        path.fillColor = 'none';        // 映射还原点        var pathPoints = dataDict.points;        var userPoints = [];        for (var i = 0; i < pathPoints.length; i++) {            let pointDict = pathPoints[i];            var point = cc.p(pointDict.x * this.node.width, pointDict.y * this.node.height);            userPoints.push(point);        }        // 画线并隐藏        path.points(userPoints.reverse())        var pathLength = path.getTotalLength();        path.dashOffset = pathLength;        path.dashArray = [pathLength];        // 设置path字典        var pathDict = {};        pathDict.path = path;        pathDict.duration = (dataDict.endTime - dataDict.startTime) / 1000.0;        // 将path字典存入数组               this.pathArray.push(pathDict);    },复制代码

需要注意的事项:

① 清屏数据结构与画线不同所以特殊处理。

② 线的动画显示,实质上是已经画了,不过被隐藏了,只不过是在一定时间里按比例显示出来。

3、处理画线队列(在update

update: function (dt) {        // 时间递增        this.time += dt;        // 设置显示比例        let percent = this.time / this.duration;        // 显示比例超过1 更新到队列中的下一条线        if (percent > 1) {            // 假如队列有path,排除没画线时出错            if (this.pathArray.length > 0) {                // 假如是清屏命令 直接清屏退出此次update                if (this.pathArray[0].dataEvent === 'clear') {                    this.clearAll();                    this.pathArray.shift();                    return;                }                // 比较是否是当前path,是的话移除                if (this.path === this.pathArray[0].path) {                    this.pathArray.shift();                }            }            // 在移除之后(或者第一次) 判断队列还有没有path,有的话继续画            if (this.pathArray.length > 0) {                // 假如是清屏命令 直接清屏退出此次update                if (this.pathArray[0].dataEvent === 'clear') {                    this.clearAll();                    this.pathArray.shift();                    return;                }                // 开始新一条线的显示(初始化)                this.path = this.pathArray[0].path;                this.pathLength = this.path.getTotalLength();                this.time = 0;                this.duration = this.pathArray[0].duration;                percent = 0;            }            return;        }        // 根据时间刷新画笔的显示        this.path.dashOffset = this.pathLength * (1 - percent);        this.path._dirty = true;    },});复制代码

四、相关资源

1、

2、

需要注意的事项:

① 按照中的安装教程安装时,记得后两步即:git submodule update --initnpm install需要在终端cd到项目所在的文件夹执行,不是全局的。

五、嘿嘿!你懂得!

本文首发于我的,希望大家多多支持!

转载地址:http://nzbso.baihongyu.com/

你可能感兴趣的文章
PHP高级教程-安全邮件
查看>>
JavaScript中:表达式和语句的区别
查看>>
[svc]linux的inode和block-软硬链接
查看>>
微信小程序实现给循环列表添加点击样式实例
查看>>
高通 打开 wifi 驱动 log
查看>>
新手学委托之初识委托(一)
查看>>
"通过jconsole(或者thread dump),可以看到线程停在了transfer方法的while循环处"
查看>>
nginx 跑php时找不到文件报no input file specified.
查看>>
[Step By Step]SAP Visual Intelligence新增公式数据列(SAP HANA中提取数据)
查看>>
WinForm 代码实现以管理员身份运行
查看>>
.NET:CLR via C# Manifest
查看>>
Android获取ROOT权限
查看>>
Lucene的多域查询、结果中查询、查询结果分页、高亮查询结果和结果评分
查看>>
Method Draw – 很好用的 SVG 在线编辑器
查看>>
Leetcode: Search Insert Position
查看>>
LeetCode::Remove Duplicates from Sorted List II [具体分析]
查看>>
Spark SQL源代码分析之核心流程
查看>>
yum subversion puppet puppet-server
查看>>
C数据类型
查看>>
ARM标准汇编与GNU汇编
查看>>