随着小游戏的不断发展,Cocos Creator 成了开发者进行游戏开发的宠儿。Cocos Creator 作为一个优秀的游戏引擎框架,同时提供了优秀的编辑器 Cocos Creator ,对图像渲染,UI 系统和动画系统都有良好的 API 进行支持,同时支持构建发布在多个平台。且 Cocos Creator 将整套手机页游解决方案整合在了编辑器工具里,无需在多个软件之间穿梭,只要打开编辑器,各种一键式的自动化流程就能花最少的时间精力,解决代码编辑的许多问题。
问题直击
咱们废话不多说,直接看问题。
Cocos Creator 提供了 Mask 遮罩组件,其用于规定子节点可渲染的范围,带有 Mask 组件的节点会使用该节点的约束框(也就是 属性检查器 中 Node 组件的 Size 规定的范围)创建一个渲染遮罩,该节点的所有子节点都会依据这个遮罩进行裁剪,遮罩范围外的将不会渲染。通过这个组件可以只能将子节点裁剪成多边形或者是椭圆,并不能实现与拼图碎片一样的有序但不规则形状。
那么,在 Cocos Creator 中如何将图片进行自定义裁剪,实现凹凸有秩的拼图碎片形状,先来看一下成图。
核心思路
对裁剪功能进行扩展应用,使用 Cocos Creator 提供的 API(Graphics),绘制 Mask 路径,对基础裁剪形状进行自定义,实现不规则图形的裁剪。
- 使用 Cocos Creator 创建项目
- 子元素使用 Mask 组件进行遮罩、裁剪
- 将 cc.Mask 中的 _graphics 函数原始内容清空,逻辑重写。
- 使用 lintTo()、bezierCurveTo() 重新绘制裁剪路径
绘制碎片 CreateChipMask
单独看一个碎片,每个碎片有4个边,每一边可以分为3个部分:直线、曲线、直线。其中直线部分的长度是一致的,曲线部分又可以分为3种情况:凹、凸、直线,所以拼图碎片是有规律的不规则形状。
-
graphics 重新绘制拼图碎片裁剪路径,依次按照上、右、下、左的顺利进行。首先设置基础绘制字段:
const defaultChip = { start: { x: -100, y: 0 }, w: 150, h: 150, r: 25, circleStatus: [0, 0, 1, 1], offset: 32, space:0 }
字段 默认值 说明 start {x:0,y:0} 裁剪路径的起始点 w 150 碎片的宽度 h 150 碎片的高度 r 25 碎片单边曲线的距离的一半 circleStatus [0,0,1,1] 描述碎片每边曲线的状态:0(直线)1(凸)-1(凹),依次对应上、右、下、左 offset 32 三阶贝塞尔曲线两个控制点的偏移量,决定曲线的弧度 space 0 每个碎片之间的空隙(碎片的宽高包括空隙的距离) -
根据基础绘制字段,配合上面拼图碎片示意图,得到以下值:
a) 碎片的实际宽度:chip.w = chip.w - chip.space (高度同理)
b) 碎片单边(上、下)直线的长度 lineW= chip.w / 2 - chip.r ,若是凸曲线,需要再减去 chip.space,即 lineHN = chip.h / 2 - chip.r + chip.space(高度同理)
-
利用 graphics.moveTo(start.x, start.y) 把路径移动到画布指定点,首先绘制‘上边‘,分别绘制碎片‘上边’的3个部分
a) 直线
利用 graphics.lineTo 绘制直线。起始点为基础绘制字段start 的值,直线终点为
graphics.lineTo(start.x + (circleStatus[0] == 1 ? lineWN : lineW), start.y)
b) 曲线
若 circleStatus 设置的是 0,即直线,则不用绘制此部分,若是曲线,则利用
graphics.bezierCurveTo
三次贝塞尔曲线绘制。绘制的起始点即 a) 步骤的终点,终点则是:(起始点(start.x) + 碎片的宽度(chip.w) - 直线部分的长度(linW/lineWN),start.y)
其中 CPS1 与 CPS2 为绘制三次贝塞尔曲线需要 2 个控制点,这 2 个控制点需在同一方向。偏移量 chip.offset 决定的曲线的凹凸状态。
c)直线
依然是利用
graphics.lineTo
绘制直线,单边最后一部分的终点即为(起始点(start.x)+碎片的宽度(chip.w),start.y)
-
参照步骤 7 的思路即可完成右、下、左的路径绘制。
-
最后,将绘制的路径闭合、绘制路径、填充。
ctx.close(); // 闭合
ctx.stroke(); // 绘制已定义的路径
ctx.fill(); // 填充
到此我们就完成了基本碎片的绘制工作。
图片碎片化
接下来,就是将一整张图,分割成有序的碎片。
-
使用 Cocos Creator 官网提供的工具、步骤创建项目
-
根据官网文档操作,新建场景,在层级管理器新建空节点(clip),并添加 Mask 组件,在该节点下,新建 Sprite 节点,用于放置需要被裁剪的图片(空节点下,可以根据需求放置任意节点,都会被裁剪)。最后将改空节点(clip)设置成预制资源 clipRrefab。
-
在该项目资源管理器中新建脚本文件 stage.js ,层级管理器中新建空节点(stage),并在该节点下引入 stage.js 脚本以及 clipRrefab 预制资源。
-
在 stage.js 脚本中,设置图片的基本信息
const picture = { w: 980, h: 700, chipW: 140, chipH: 140, rowNum: 6, column: 8 }
字段 说明 w 图片初始宽 h 图片初始高 chipW 碎片的宽 chipH 碎片的高 rowNum 图片需要裁剪的行数 column 图片需要裁剪的列数 -
调用预制资源,并将 cc.Mask 下的 _graphics 默认路径清除。
-
寻找每个碎片的凹凸规律。除了边界碎片,碎片左边与右边的凹凸状态一样,上边与下边的凹凸状态一样,即左边是凹,则右边必是凹。
// 碎片 top bottom let t = 0 if (row % 2 == 0) { t = col % 2 == 0 ? 1 : -1 } else { t = col % 2 == 0 ? -1 : 1 } // 碎片 right left let r = 0 if (row % 2 == 0) { r = col % 2 == 0 ? -1 : 1 } else { r = col % 2 == 0 ? 1 : -1 }
-
调用绘制图片 CreateChipMask,实现图片拼图状态。
CreateChipMask.createMask(graphics, { start: { x: picture.chipW * (col - 1), y: -picture.chipH * (row - 1) }, w: picture.chipW, // 碎片的高 h: picture.chipH, circleStatus: [row == 1 ? 0 : t, col == picture.column - 1 ? 0 : r, row == picture.rowNum - 1 ? 0 : t, col == 1 ? 0 : r], space:2 })
其中,第一行(最后一行),碎片上边(下边)的状态为直线,第一列(最后一列),碎片左边(右边)的状态为直线。
代码直通车:github.com/yangxiaolu1…
总结
不知不觉中已经到了尾声,小编一改往日的风格,没有过多的废话,没有名词的解释,只是描述了自己的实现思路,希望大家能够明白。
欢迎来扰!!!