300字范文,内容丰富有趣,生活中的好帮手!
300字范文 > Cocos Creator 实现画板(你画我猜)

Cocos Creator 实现画板(你画我猜)

时间:2023-02-23 11:07:50

相关推荐

Cocos Creator 实现画板(你画我猜)

前言

本例是基于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) {// 假如是清屏命令 直接清屏退出此次updateif (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) {// 假如是清屏命令 直接清屏退出此次updateif (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、raphael_github

2、raphael_demo

需要注意的事项:

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

五、嘿嘿!你懂得!

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

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。