Cocos Creator 不规则裁剪--拼图碎片

3,244 阅读5分钟

随着小游戏的不断发展,Cocos Creator 成了开发者进行游戏开发的宠儿。Cocos Creator 作为一个优秀的游戏引擎框架,同时提供了优秀的编辑器 Cocos Creator ,对图像渲染,UI 系统和动画系统都有良好的 API 进行支持,同时支持构建发布在多个平台。且 Cocos Creator 将整套手机页游解决方案整合在了编辑器工具里,无需在多个软件之间穿梭,只要打开编辑器,各种一键式的自动化流程就能花最少的时间精力,解决代码编辑的许多问题。

问题直击

咱们废话不多说,直接看问题。

Cocos Creator 提供了 Mask 遮罩组件,其用于规定子节点可渲染的范围,带有 Mask 组件的节点会使用该节点的约束框(也就是 属性检查器 中 Node 组件的 Size 规定的范围)创建一个渲染遮罩,该节点的所有子节点都会依据这个遮罩进行裁剪,遮罩范围外的将不会渲染。通过这个组件可以只能将子节点裁剪成多边形或者是椭圆,并不能实现与拼图碎片一样的有序但不规则形状。

那么,在 Cocos Creator 中如何将图片进行自定义裁剪,实现凹凸有秩的拼图碎片形状,先来看一下成图。

核心思路

对裁剪功能进行扩展应用,使用 Cocos Creator 提供的 API(Graphics),绘制 Mask 路径,对基础裁剪形状进行自定义,实现不规则图形的裁剪。

  1. 使用 Cocos Creator 创建项目
  2. 子元素使用 Mask 组件进行遮罩、裁剪
  3. 将 cc.Mask 中的 _graphics 函数原始内容清空,逻辑重写。
  4. 使用 lintTo()、bezierCurveTo() 重新绘制裁剪路径

绘制碎片 CreateChipMask

单独看一个碎片,每个碎片有4个边,每一边可以分为3个部分:直线、曲线、直线。其中直线部分的长度是一致的,曲线部分又可以分为3种情况:凹、凸、直线,所以拼图碎片是有规律的不规则形状。

  1. 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}裁剪路径的起始点
    w150碎片的宽度
    h150碎片的高度
    r25碎片单边曲线的距离的一半
    circleStatus[0,0,1,1]描述碎片每边曲线的状态:0(直线)1(凸)-1(凹),依次对应上、右、下、左
    offset32三阶贝塞尔曲线两个控制点的偏移量,决定曲线的弧度
    space0每个碎片之间的空隙(碎片的宽高包括空隙的距离)
  2. 根据基础绘制字段,配合上面拼图碎片示意图,得到以下值:

    a) 碎片的实际宽度:chip.w = chip.w - chip.space (高度同理)

    b) 碎片单边(上、下)直线的长度 lineW= chip.w / 2 - chip.r ,若是凸曲线,需要再减去 chip.space,即 lineHN = chip.h / 2 - chip.r + chip.space(高度同理)

  3. 利用 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)
    
  4. 参照步骤 7 的思路即可完成右、下、左的路径绘制。

  5. 最后,将绘制的路径闭合、绘制路径、填充。

ctx.close(); // 闭合
ctx.stroke(); // 绘制已定义的路径
ctx.fill(); // 填充

到此我们就完成了基本碎片的绘制工作。

图片碎片化

接下来,就是将一整张图,分割成有序的碎片。

  1. 使用 Cocos Creator 官网提供的工具、步骤创建项目

  2. 根据官网文档操作,新建场景,在层级管理器新建空节点(clip),并添加 Mask 组件,在该节点下,新建 Sprite 节点,用于放置需要被裁剪的图片(空节点下,可以根据需求放置任意节点,都会被裁剪)。最后将改空节点(clip)设置成预制资源 clipRrefab。

  3. 在该项目资源管理器中新建脚本文件 stage.js ,层级管理器中新建空节点(stage),并在该节点下引入 stage.js 脚本以及 clipRrefab 预制资源。

  4. 在 stage.js 脚本中,设置图片的基本信息

    const picture = {
        w: 980,
        h: 700,
        chipW: 140,
        chipH: 140,
        rowNum: 6,
        column: 8
    }
    
    字段说明
    w图片初始宽
    h图片初始高
    chipW碎片的宽
    chipH碎片的高
    rowNum图片需要裁剪的行数
    column图片需要裁剪的列数
  5. 调用预制资源,并将 cc.Mask 下的 _graphics 默认路径清除。

  6. 寻找每个碎片的凹凸规律。除了边界碎片,碎片左边与右边的凹凸状态一样,上边与下边的凹凸状态一样,即左边是凹,则右边必是凹。

    // 碎片 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
    }
    
  7. 调用绘制图片 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…

总结

不知不觉中已经到了尾声,小编一改往日的风格,没有过多的废话,没有名词的解释,只是描述了自己的实现思路,希望大家能够明白。

欢迎来扰!!!