Cocos Creator之自定义Action

Cocos Creator之自定义Action

  • 自定义Action
  • 特殊需求 - 用TypeScript自定义Action
    • 需求
    • 方案
  • 使用方法

自定义Action

学习自定义Action的最好方法是去查看Cocos Creator中常用动作的写法。比如cc.MoveTo继承了cc.MoveBy,而cc.MoveBy则进一步继承了cc.ActionInterval
可以从cocos-creator的引擎源码找到cc.MoveBy的相关定义:

cc.MoveBy = cc.Class({
    name: 'cc.MoveBy',
    extends: cc.ActionInterval,

    ctor:function (duration, deltaPos, deltaY) {
        this._positionDelta = cc.v2(0, 0);
        this._startPosition = cc.v2(0, 0);
        this._previousPosition = cc.v2(0, 0);

        deltaPos !== undefined && cc.MoveBy.prototype.initWithDuration.call(this, duration, deltaPos, deltaY);	
    }
    ...
})

如果需要自定义Action只需要按照自己的需求仿照cc.MoveBy的定义写一个就行了。如实现cc.ActionInterval类的initWithDurationstartWithTargetupdate方法。「sprite 圆形运动,圆周运动」给出了自定义一个圆周运动的三种方案,其中第一种方案就是集成cc.ActionInterval,自定义Action的方法。这里不再赘述。

特殊需求 - 用TypeScript自定义Action

因为自己做cocos creator时用的ts语言,在写法上与之前提到的略有不同。目的是实现精灵绕某一点旋转一定的角度。

需求

  1. 根据精灵自身旋转角度和给定半径确定精灵圆周运动的圆心。
  2. 在精灵圆周运动过程中自动调整精灵自身的旋转角度。

方案

这里给出实现的源码,并做相关解释。

const {ccclass, property} = cc._decorator;

export default class ArcMove extends cc.ActionInterval {

    name: string = "CircleMove";
    _positionDelta: cc.Vec2;
    _previousPosition: cc.Vec2;
    /**圆心 */
    _centre:cc.Vec2;
    /**半径 */
    _R: number = 0;
    /**设置节点旋转度数 */
    _angle;
    /**节点 */
    _target: cc.Node;
    /**节点在圆上的初始位置(角度)*/
    _initAngle:number = 0;
    /**圆周运动方向 counter-clockwise(逆时针方向)默认false*/
    _ccw: boolean = false;
    /**节点初始自身rotation */
    _rotation: number = 0;
    /**
     * 
     * @param duration 
     * @param R 半径
     * @param angle 绕圆心旋转角度(360度为完整圆)
     */
    constructor(duration, R, angle=360){
        super();
        this._positionDelta = cc.v2(0,0);
        this._centre  = cc.v2(0,0);
        this._previousPosition = cc.v2(0,0);
        this._R = R;
        this.initWithDuration(duration, R, angle);
    }

    initWithDuration(duration, R, angle):boolean {
        if(super["initWithDuration"](duration, this)){
            this._R = R;
            this._angle = angle;
            return true
        }
        return false;
    }

    startWithTarget(target:cc.Node) {
        super["startWithTarget"](this, target);
        this._target = target;
        // 根据节点scaleX判断圆周运动方向(顺/逆时针)
        if(target.scaleX == 1){
            this._ccw = false;
        }else{
            this._ccw = true;
        }
        // 根据节点自身倾角和半径计算圆心
        let angle = -(target.rotation + 90);
        let v1:cc.Vec2 = new cc.Vec2(Math.cos(angle/180*Math.PI), Math.sin(angle/180*Math.PI));
        let center: cc.Vec2 = v1.mul(this._R).add(target.position);
        this._centre .x = center.x;
        this._centre .y = center.y;
        // 计算节点在圆上初始位置
        this._initAngle = 90 - target.rotation;
        this._rotation = target.rotation;
        cc.log("在圆上角度:" + this._initAngle);
    }

    update (dt) {
        if (this._target) {
            var locStartPosition = this._centre ;
            
            if (cc.macro.ENABLE_STACKABLE_ACTIONS) {
                let dir: number = -1;
                if(this._ccw){
                    dir = 1;
                }
                var R = this._R;
                var rat = this._initAngle * Math.PI / 180 + dir * dt * Math.PI * 2 * (this._angle / 360);
                var x = locStartPosition.x + R * Math.cos(rat);
                var y = locStartPosition.y + R * Math.sin(rat);
                this._target.setPosition(x, y);
                this._target.rotation = this._rotation + dt * this._angle;
                let a = 1;
            } else {
                this._target.setPosition(locStartPosition.x + x, locStartPosition.y + y);
            }
        }
    }
}
export var arcMove = function(duration, R, angle){
    return new ArcMove(duration, R, angle);
}

这里的_positionDelta和_previousPosition暂时没有用到。由于需要根据精灵的自身旋转角度和给定的半径得出圆心。随后从当前位置开始圆周运动并调整精灵的自身旋转角度。_angle指定精灵的圆周运动度数,一圈是360,具体运动度数可以任意设置。_target则是精灵节点,在initWithTarget中完成初始化。_initAngle记录的是初始时,从水平方向到精灵的旋转角度,即记录精灵在圆上的初始位置。_rotation记录精灵初始的自身旋转角度。
js中重写initWithDurationinitWithTarget方法是通过cc.ActionInterval.prototype.initWithXXX.call()的方式进行的。但ts似乎没有把接口暴露出来,因此这里采用了super["initWithXXX"]()的形式。
余下内容计算出圆心、初始圆上位置等等。在update函数中,需要注意dt,比如给定精灵的运动时间duration为3秒,dt的变化还是从0到1.

使用方法

在使用的时候,import 该类。
let action = arMove(3, 100, 180);
随后节点runAction即可。

你可能感兴趣的:(Cocos,Creator)