【Cocos Creator 实战】04 - 如何给拼图加上吸附效果

文章目录

  • 概览
    • 主要内容
    • 项目资源
  • 开搞
    • Cocos Creator 中的坐标系
    • 锚点(Anchor)
    • 吸附规则
    • 核心代码
  • 总结
    • 知识点
    • 下一步

继续继续。

上一篇地址:【Cocos Creator 实战】03 - 如何「拿起」拼图游戏的每块图片

概览

主要内容

来看看今天要做的内容:

  • Cocos Creator 中坐标系的基本知识
  • 如何给拼图游戏加上吸附效果

你问我什么是吸附?我咋解释,直接看看效果吧:

【Cocos Creator 实战】04 - 如何给拼图加上吸附效果_第1张图片

项目资源

  • 项目地址:https://github.com/BottleMan/Bottle-s-Jigsaw/tree/04_adsorption
  • 演示地址:点击前往

推荐大家先把项目 clone 到本地,然后参考着代码来看本篇文章。
我的每篇文章会对应一个分支,大家直接看对应的分支就可以,master 对应的是最新的内容,会整合各个分支。
演示地址也是对应每篇文章独立部署的。

开搞

Cocos Creator 中的坐标系

Creator 中的坐标系原则与笛卡尔坐标系相同,原理如下图:

【Cocos Creator 实战】04 - 如何给拼图加上吸附效果_第2张图片
即,如果面向屏幕的话,向右是 x 轴 正方向,向上是 y 轴 正方向,垂直于屏幕的是 z 轴 正方向。

结合我们上一篇文章说的 zIndex,这回是不是理解的更好了。

那对于 Creator 中来讲,我们的坐标系可以按照下图来画:

注意几点哈:

1、z轴 是垂直于屏幕的,有点立体空间的思维,不是斜着的
2、我图上每个轴的剪头的粗细没有关系,那是我使用工具的问题,主要看方向
3、我把三个轴的交叉点放在了正中间,那他们交叉点的位置坐标就是 (0,0,0)

我们先不考虑 z 轴,为什么 xy 轴(0,0) 坐标在中间呢?

这就涉及到下一个知识点:锚点(Anchor)

锚点(Anchor)

锚点其实主要有两个作用:

1、表示用自身节点的哪个位置作为在父节点中设置位置的点
2、表示自身节点本地坐标系的初始原点位置,即子节点使用的坐标系的原点位置

是不是有点蒙圈,我们看看例子(请忽略我粗糙的绘画技巧,对灯发誓,我尽力了):

【Cocos Creator 实战】04 - 如何给拼图加上吸附效果_第3张图片
假设在一个坐标系里面,有三个节点分别是红黄蓝,他们的锚点分别如上图标注,那么他们在坐标系中的位置将会如图中所示:

  • 锚点(0,0) 的会把自己左下角的位置作为在父节点中设置位置的点
  • 锚点(0.5,0.5) 的会把自己中心位置作为在父节点中设置位置的点
  • 锚点(1,1) 的会把自己右上角的位置作为在父节点中设置位置的点

同样的,该位置(左下、中心、右上)也是作为其子节点所使用坐标系的原点,如图上所画。

明白了么,刚开始没懂没事,其实锚点不只是从0到1,任何数值都可以。

目前我们需要的比较简单,如果大家理解起来实在困难的话,就先理解一下 (0.5,0.5),记住所有节点默认的位置都是指其中心点的位置就可以了。

我们的项目也都是使用的默认的 (0.5,0.5)

我的建议也是,除非你真的明白了这个东西是干什么的,不然就用默认的就好了,一般也没必要设置。

吸附规则

上面说了那么多,都是为了解释下面的吸附规则。

其实设计吸附的规则有很多,你也可以根据自己的理解写一套自己的算法出来,但无论哪种算法,都离不开节点位置的计算,而节点位置的的计算又肯定离不开上面的两个知识点:坐标系、锚点。

下来来说说我设计的吸附规则:

1、首先我们能得到每张拼图的位置(Position),即每张图的正中间
【Cocos Creator 实战】04 - 如何给拼图加上吸附效果_第4张图片
2、我们把这些点扩充一下,把每张图片相邻一个图片位置的点也标注出来:


这些点目前已经显示在屏幕之外了,不用管,位置肯定在那,只是屏幕没显示下而已。

3、我们以这些点为中心,各自画一个半径为 100 的圆(图中黄色部分)


大家不要看画功啊,领会精神。

4、然后我们就可以设计,当一块拼图被拿起又放下的时候,如果他的位置(Position)落在了我们这里某一个黄色圆圈内,那我们就把他的位置自动移动到该黄色圆圈对应的红色中心点上,即吸附过去。


比如上图中右下角绿色的点表示右下角拼图的位置,他落在了其中一个黄色圈内,那他就要自动移动到黄圈中的红点位置,完成吸附。

当然,这个位置可以是写死的,就是每个图片会被吸附的位置在程序初始化的时候就指定,我们也可以做成灵活的,在放下拼图的时候动态计算所有节点的周围的位置,这样能做到拼图的位置可以随意变换,效果好一点。

毕竟我们是要打造全世界最好的拼图游戏的,体验要好。

核心代码

首先,修改 item.js 文件,在拖拽完成的回调中,把当前拖拽的节点作为参数返回去:

        this.node.on(cc.Node.EventType.TOUCH_END, function () {
            this.opacity = 255;

            self.moveEndCb = self.moveEndCb || function () {
            };
            self.moveEndCb(self.node); // 把当前节点作为参数返回去
        }, this.node);

然后,修改 item-manager.js 文件中拖放结束的回调方法:

    __moveEnd(node) {
        console.info('end');

        let picHeight = node.height;
        let picWidth = node.width;
        let nodeVec = cc.v2({x: node.position.x, y: node.position.y});
        let itemManager = node.parent.getComponent('item-manager');
        let conditions = [
            {x: picWidth, y: 0},
            {x: (-1) * picWidth, y: 0},
            {x: 0, y: picHeight},
            {x: 0, y: (-1) * picHeight},
        ];

        for (let i = 0; i < itemManager.items.length; i++) {
            let itemNode = itemManager.items[i].node;
            let itemPos = itemNode.position;
            let isMoved = false;

            for (let j = 0; j < conditions.length; j++) {
                let con = conditions[j];
                let targetVec = cc.v2({
                    x: itemPos.x + con.x,
                    y: itemPos.y + con.y
                });
                let distance = targetVec.sub(nodeVec).mag();
                if (distance > 100) continue; // 100即为上面图中黄色圆圈的半径

                isMoved = true;

                let action = cc.moveTo(0.1, targetVec);
                node.runAction(action);
            }

            if (!isMoved) continue;
            break;
        }

        cc.loader.loadRes('sound/drop', cc.AudioClip, function (err, clip) {
            cc.audioEngine.playEffect(clip, false);
        });
    },

我们的吸附位置,即上面图中红点的位置是实时计算的,获取各个节点位置要先获取到 item-manager

let itemManager = node.parent.getComponent('item-manager');

那对应的各个节点就可以直接拿出来了:

let itemNode = itemManager.items[i].node;

conditions 表示每个拼图对应的四个点的相对位置,分别是上下左右各距离一个图片的位置。

这里我们是用过 Vec2 也就是 cc.v2 的方式来表示节点的位置的,因为这样能比较方便的计算两个节点间的距离。

let distance = targetVec.sub(nodeVec).mag();
if (distance > 100) continue;

上面的 100 就是我们黄色圆的半径,大家可以根据需要灵活改变,但是要合理哈,太小了起不到吸附效果,太大的话,嘿嘿,你可以设置成 10000 看看效果。

还有最后一个,移动节点的动画,我们通过 动作(action) 来实现:

let action = cc.moveTo(0.1, targetVec);
node.runAction(action);

这里就是表示该节点会用 0.1s 移动到(moveTo) targetVec 位置,好理解吧。

关于动作,要讲的话会有很多,这里大家先简单了解一下就好。

总结

知识点

1、Cocos Creator 中的坐标系
2、锚点的概念
3、设计了一套吸附规则
4、简单接触了 Vec2
5、简单接触了 动作(Action)

下一步

这篇文章花了我将近3天时间,其实代码很好写,但是想把其中的原理讲清楚,还真是麻烦。

可能理解能力比较好的朋友会觉得我写的啰嗦,那没办法,照顾一下牛顿同学吧。

想想下一步,我们是不是也该设计一下胜利规则了,不然玩了半天,也都是自嗨,都不知道拼的对不对。

那么,如何判断拼图游戏已经结束(胜利)呢?

请听下回分解吧。

下一篇地址:【Cocos Creator 实战】05 - 如何判断拼图完成(胜利)

你可能感兴趣的:(Cocos,Creator,实战,Cocos,Creator,实战,Cocos,Creator,教程,拼图,教程)