mirror of
https://github.com/smallmain/cocos-enhance-kit.git
synced 2025-11-24 08:37:36 +00:00
初始化
This commit is contained in:
267
engine/cocos2d/animation/animation-animator.js
Normal file
267
engine/cocos2d/animation/animation-animator.js
Normal file
@@ -0,0 +1,267 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
https://www.cocos.com/
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated engine source code (the "Software"), a limited,
|
||||
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
|
||||
to use Cocos Creator solely to develop games on your target platforms. You shall
|
||||
not use Cocos Creator software for developing other software or tools that's
|
||||
used for developing games. You are not granted to publish, distribute,
|
||||
sublicense, and/or sell copies of Cocos Creator.
|
||||
|
||||
The software or tools in this License Agreement are licensed, not sold.
|
||||
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
const js = cc.js;
|
||||
const Playable = require('./playable');
|
||||
const { EventAnimCurve, EventInfo } = require('./animation-curves');
|
||||
const WrapModeMask = require('./types').WrapModeMask;
|
||||
const binarySearch = require('../core/utils/binary-search').binarySearchEpsilon;
|
||||
|
||||
// The actual animator for Animation Component
|
||||
|
||||
function AnimationAnimator (target, animation) {
|
||||
Playable.call(this);
|
||||
this.target = target;
|
||||
this.animation = animation;
|
||||
|
||||
this._anims = new js.array.MutableForwardIterator([]);
|
||||
}
|
||||
js.extend(AnimationAnimator, Playable);
|
||||
let p = AnimationAnimator.prototype;
|
||||
|
||||
p.playState = function (state, startTime) {
|
||||
if (!state.clip) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!state.curveLoaded) {
|
||||
initClipData(this.target, state);
|
||||
}
|
||||
|
||||
state.animator = this;
|
||||
state.play();
|
||||
|
||||
if (typeof startTime === 'number') {
|
||||
state.setTime(startTime);
|
||||
}
|
||||
|
||||
this.play();
|
||||
};
|
||||
|
||||
p.stopStatesExcept = function (state) {
|
||||
let iterator = this._anims;
|
||||
let array = iterator.array;
|
||||
for (iterator.i = 0; iterator.i < array.length; ++iterator.i) {
|
||||
let anim = array[iterator.i];
|
||||
if (anim === state) {
|
||||
continue;
|
||||
}
|
||||
|
||||
this.stopState(anim);
|
||||
}
|
||||
};
|
||||
|
||||
p.addAnimation = function (anim) {
|
||||
let index = this._anims.array.indexOf(anim);
|
||||
if (index === -1) {
|
||||
this._anims.push(anim);
|
||||
}
|
||||
|
||||
anim._setEventTarget(this.animation);
|
||||
};
|
||||
|
||||
p.removeAnimation = function (anim) {
|
||||
let index = this._anims.array.indexOf(anim);
|
||||
if (index >= 0) {
|
||||
this._anims.fastRemoveAt(index);
|
||||
|
||||
if (this._anims.array.length === 0) {
|
||||
this.stop();
|
||||
}
|
||||
}
|
||||
else {
|
||||
cc.errorID(3907);
|
||||
}
|
||||
|
||||
anim.animator = null;
|
||||
};
|
||||
|
||||
p.sample = function () {
|
||||
let iterator = this._anims;
|
||||
let array = iterator.array;
|
||||
for (iterator.i = 0; iterator.i < array.length; ++iterator.i) {
|
||||
let anim = array[iterator.i];
|
||||
anim.sample();
|
||||
}
|
||||
};
|
||||
|
||||
p.stopState = function (state) {
|
||||
if (state) {
|
||||
state.stop();
|
||||
}
|
||||
};
|
||||
|
||||
p.pauseState = function (state) {
|
||||
if (state) {
|
||||
state.pause();
|
||||
}
|
||||
};
|
||||
|
||||
p.resumeState = function (state) {
|
||||
if (state) {
|
||||
state.resume();
|
||||
}
|
||||
|
||||
if (this.isPaused) {
|
||||
this.resume();
|
||||
}
|
||||
};
|
||||
|
||||
p.setStateTime = function (state, time) {
|
||||
if (time !== undefined) {
|
||||
if (state) {
|
||||
state.setTime(time);
|
||||
state.sample();
|
||||
}
|
||||
}
|
||||
else {
|
||||
time = state;
|
||||
|
||||
let array = this._anims.array;
|
||||
for (let i = 0; i < array.length; ++i) {
|
||||
let anim = array[i];
|
||||
anim.setTime(time);
|
||||
anim.sample();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
p.onStop = function () {
|
||||
let iterator = this._anims;
|
||||
let array = iterator.array;
|
||||
for (iterator.i = 0; iterator.i < array.length; ++iterator.i) {
|
||||
let anim = array[iterator.i];
|
||||
anim.stop();
|
||||
}
|
||||
};
|
||||
|
||||
p.onPause = function () {
|
||||
let array = this._anims.array;
|
||||
for (let i = 0; i < array.length; ++i) {
|
||||
let anim = array[i];
|
||||
anim.pause();
|
||||
|
||||
// need to unbind animator to anim, or it maybe cannot be gc.
|
||||
anim.animator = null;
|
||||
}
|
||||
};
|
||||
|
||||
p.onResume = function () {
|
||||
let array = this._anims.array;
|
||||
for (let i = 0; i < array.length; ++i) {
|
||||
let anim = array[i];
|
||||
|
||||
// rebind animator to anim
|
||||
anim.animator = this;
|
||||
|
||||
anim.resume();
|
||||
}
|
||||
};
|
||||
|
||||
p._reloadClip = function (state) {
|
||||
initClipData(this.target, state);
|
||||
};
|
||||
|
||||
// 这个方法应该是 SampledAnimCurve 才能用
|
||||
function createBatchedProperty (propPath, firstDotIndex, mainValue, animValue) {
|
||||
mainValue = mainValue.clone();
|
||||
let nextValue = mainValue;
|
||||
let leftIndex = firstDotIndex + 1;
|
||||
let rightIndex = propPath.indexOf('.', leftIndex);
|
||||
|
||||
// scan property path
|
||||
while (rightIndex !== -1) {
|
||||
let nextName = propPath.slice(leftIndex, rightIndex);
|
||||
nextValue = nextValue[nextName];
|
||||
leftIndex = rightIndex + 1;
|
||||
rightIndex = propPath.indexOf('.', leftIndex);
|
||||
}
|
||||
let lastPropName = propPath.slice(leftIndex);
|
||||
nextValue[lastPropName] = animValue;
|
||||
|
||||
return mainValue;
|
||||
}
|
||||
|
||||
if (CC_TEST) {
|
||||
cc._Test.createBatchedProperty = createBatchedProperty;
|
||||
}
|
||||
|
||||
|
||||
function initClipData (root, state) {
|
||||
let clip = state.clip;
|
||||
|
||||
state.duration = clip.duration;
|
||||
state.speed = clip.speed;
|
||||
state.wrapMode = clip.wrapMode;
|
||||
state.frameRate = clip.sample;
|
||||
|
||||
if ((state.wrapMode & WrapModeMask.Loop) === WrapModeMask.Loop) {
|
||||
state.repeatCount = Infinity;
|
||||
}
|
||||
else {
|
||||
state.repeatCount = 1;
|
||||
}
|
||||
|
||||
let curves = state.curves = clip.createCurves(state, root);
|
||||
|
||||
// events curve
|
||||
|
||||
let events = clip.events;
|
||||
|
||||
if (!CC_EDITOR && events) {
|
||||
let curve;
|
||||
|
||||
for (let i = 0, l = events.length; i < l; i++) {
|
||||
if (!curve) {
|
||||
curve = new EventAnimCurve();
|
||||
curve.target = root;
|
||||
curves.push(curve);
|
||||
}
|
||||
|
||||
let eventData = events[i];
|
||||
let ratio = eventData.frame / state.duration;
|
||||
|
||||
let eventInfo;
|
||||
let index = binarySearch(curve.ratios, ratio);
|
||||
if (index >= 0) {
|
||||
eventInfo = curve.events[index];
|
||||
}
|
||||
else {
|
||||
eventInfo = new EventInfo();
|
||||
curve.ratios.push(ratio);
|
||||
curve.events.push(eventInfo);
|
||||
}
|
||||
|
||||
eventInfo.add(eventData.func, eventData.params);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (CC_TEST) {
|
||||
cc._Test.initClipData = initClipData;
|
||||
}
|
||||
|
||||
|
||||
module.exports = AnimationAnimator;
|
||||
308
engine/cocos2d/animation/animation-clip.js
Normal file
308
engine/cocos2d/animation/animation-clip.js
Normal file
@@ -0,0 +1,308 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
https://www.cocos.com/
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated engine source code (the "Software"), a limited,
|
||||
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
|
||||
to use Cocos Creator solely to develop games on your target platforms. You shall
|
||||
not use Cocos Creator software for developing other software or tools that's
|
||||
used for developing games. You are not granted to publish, distribute,
|
||||
sublicense, and/or sell copies of Cocos Creator.
|
||||
|
||||
The software or tools in this License Agreement are licensed, not sold.
|
||||
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
const WrapMode = require('./types').WrapMode;
|
||||
const { DynamicAnimCurve, quickFindIndex } = require('./animation-curves');
|
||||
const sampleMotionPaths = require('./motion-path-helper').sampleMotionPaths;
|
||||
const binarySearch = require('../core/utils/binary-search').binarySearchEpsilon;
|
||||
|
||||
/**
|
||||
* !#en Class for animation data handling.
|
||||
* !#zh 动画剪辑,用于存储动画数据。
|
||||
* @class AnimationClip
|
||||
* @extends Asset
|
||||
*/
|
||||
var AnimationClip = cc.Class({
|
||||
name: 'cc.AnimationClip',
|
||||
extends: cc.Asset,
|
||||
|
||||
properties: {
|
||||
_duration: {
|
||||
default: 0,
|
||||
type: cc.Float,
|
||||
},
|
||||
|
||||
/**
|
||||
* !#en Duration of this animation.
|
||||
* !#zh 动画的持续时间。
|
||||
* @property duration
|
||||
* @type {Number}
|
||||
*/
|
||||
duration: {
|
||||
get: function () { return this._duration; },
|
||||
},
|
||||
|
||||
/**
|
||||
* !#en FrameRate of this animation.
|
||||
* !#zh 动画的帧速率。
|
||||
* @property sample
|
||||
* @type {Number}
|
||||
*/
|
||||
sample: {
|
||||
default: 60,
|
||||
},
|
||||
|
||||
/**
|
||||
* !#en Speed of this animation.
|
||||
* !#zh 动画的播放速度。
|
||||
* @property speed
|
||||
* @type {Number}
|
||||
*/
|
||||
speed: {
|
||||
default: 1
|
||||
},
|
||||
|
||||
/**
|
||||
* !#en WrapMode of this animation.
|
||||
* !#zh 动画的循环模式。
|
||||
* @property wrapMode
|
||||
* @type {WrapMode}
|
||||
*/
|
||||
wrapMode: {
|
||||
default: WrapMode.Normal
|
||||
},
|
||||
|
||||
/**
|
||||
* !#en Curve data.
|
||||
* !#zh 曲线数据。
|
||||
* @property curveData
|
||||
* @type {Object}
|
||||
* @example {@link cocos2d/core/animation-clip/curve-data.js}
|
||||
*/
|
||||
curveData: {
|
||||
default: {},
|
||||
visible: false,
|
||||
},
|
||||
|
||||
/**
|
||||
* !#en Event data.
|
||||
* !#zh 事件数据。
|
||||
* @property events
|
||||
* @type {Object[]}
|
||||
* @example {@link cocos2d/core/animation-clip/event-data.js}
|
||||
* @typescript events: {frame: number, func: string, params: string[]}[]
|
||||
*/
|
||||
events: {
|
||||
default: [],
|
||||
visible: false,
|
||||
}
|
||||
},
|
||||
|
||||
statics: {
|
||||
/**
|
||||
* !#en Crate clip with a set of sprite frames
|
||||
* !#zh 使用一组序列帧图片来创建动画剪辑
|
||||
* @method createWithSpriteFrames
|
||||
* @param {[SpriteFrame]} spriteFrames
|
||||
* @param {Number} sample
|
||||
* @return {AnimationClip}
|
||||
* @static
|
||||
* @example
|
||||
*
|
||||
* var clip = cc.AnimationClip.createWithSpriteFrames(spriteFrames, 10);
|
||||
*
|
||||
*/
|
||||
createWithSpriteFrames: function (spriteFrames, sample) {
|
||||
if (!Array.isArray(spriteFrames)) {
|
||||
cc.errorID(3905);
|
||||
return null;
|
||||
}
|
||||
|
||||
var clip = new AnimationClip();
|
||||
clip.sample = sample || clip.sample;
|
||||
|
||||
clip._duration = spriteFrames.length / clip.sample;
|
||||
|
||||
var frames = [];
|
||||
var step = 1 / clip.sample;
|
||||
|
||||
for (var i = 0, l = spriteFrames.length; i < l; i++) {
|
||||
frames[i] = { frame: (i * step), value: spriteFrames[i] };
|
||||
}
|
||||
|
||||
clip.curveData = {
|
||||
comps: {
|
||||
// component
|
||||
'cc.Sprite': {
|
||||
// component properties
|
||||
'spriteFrame': frames
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return clip;
|
||||
}
|
||||
},
|
||||
|
||||
onLoad () {
|
||||
this._duration = Number.parseFloat(this.duration);
|
||||
this.speed = Number.parseFloat(this.speed);
|
||||
this.wrapMode = Number.parseInt(this.wrapMode);
|
||||
this.frameRate = Number.parseFloat(this.sample);
|
||||
},
|
||||
|
||||
createPropCurve (target, propPath, keyframes) {
|
||||
let motionPaths = [];
|
||||
let isMotionPathProp = target instanceof cc.Node && propPath === 'position';
|
||||
|
||||
let curve = new DynamicAnimCurve();
|
||||
|
||||
// 缓存目标对象,所以 Component 必须一开始都创建好并且不能运行时动态替换……
|
||||
curve.target = target;
|
||||
curve.prop = propPath;
|
||||
|
||||
// for each keyframes
|
||||
for (let i = 0, l = keyframes.length; i < l; i++) {
|
||||
let keyframe = keyframes[i];
|
||||
let ratio = keyframe.frame / this.duration;
|
||||
curve.ratios.push(ratio);
|
||||
|
||||
if (isMotionPathProp) {
|
||||
motionPaths.push(keyframe.motionPath);
|
||||
}
|
||||
|
||||
let curveValue = keyframe.value;
|
||||
curve.values.push(curveValue);
|
||||
|
||||
let curveTypes = keyframe.curve;
|
||||
if (curveTypes) {
|
||||
if (typeof curveTypes === 'string') {
|
||||
curve.types.push(curveTypes);
|
||||
continue;
|
||||
}
|
||||
else if (Array.isArray(curveTypes)) {
|
||||
if (curveTypes[0] === curveTypes[1] &&
|
||||
curveTypes[2] === curveTypes[3]) {
|
||||
curve.types.push(DynamicAnimCurve.Linear);
|
||||
}
|
||||
else {
|
||||
curve.types.push(DynamicAnimCurve.Bezier(curveTypes));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
curve.types.push(DynamicAnimCurve.Linear);
|
||||
}
|
||||
|
||||
if (isMotionPathProp) {
|
||||
sampleMotionPaths(motionPaths, curve, this.duration, this.sample, target);
|
||||
}
|
||||
|
||||
// if every piece of ratios are the same, we can use the quick function to find frame index.
|
||||
let ratios = curve.ratios;
|
||||
let currRatioDif, lastRatioDif;
|
||||
let canOptimize = true;
|
||||
let EPSILON = 1e-6;
|
||||
for (let i = 1, l = ratios.length; i < l; i++) {
|
||||
currRatioDif = ratios[i] - ratios[i-1];
|
||||
if (i === 1) {
|
||||
lastRatioDif = currRatioDif;
|
||||
}
|
||||
else if (Math.abs(currRatioDif - lastRatioDif) > EPSILON) {
|
||||
canOptimize = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
curve._findFrameIndex = canOptimize ? quickFindIndex : binarySearch;
|
||||
|
||||
// find the lerp function
|
||||
let firstValue = curve.values[0];
|
||||
if (firstValue !== undefined && firstValue !== null && !curve._lerp) {
|
||||
if (typeof firstValue === 'number') {
|
||||
curve._lerp = DynamicAnimCurve.prototype._lerpNumber;
|
||||
}
|
||||
else if (firstValue instanceof cc.Quat) {
|
||||
curve._lerp = DynamicAnimCurve.prototype._lerpQuat;
|
||||
}
|
||||
else if (firstValue instanceof cc.Vec2) {
|
||||
curve._lerp = DynamicAnimCurve.prototype._lerpVector2;
|
||||
}
|
||||
else if (firstValue instanceof cc.Vec3) {
|
||||
curve._lerp = DynamicAnimCurve.prototype._lerpVector3;
|
||||
}
|
||||
else if (firstValue.lerp) {
|
||||
curve._lerp = DynamicAnimCurve.prototype._lerpObject;
|
||||
}
|
||||
}
|
||||
|
||||
return curve;
|
||||
},
|
||||
|
||||
createTargetCurves (target, curveData, curves) {
|
||||
let propsData = curveData.props;
|
||||
let compsData = curveData.comps;
|
||||
|
||||
if (propsData) {
|
||||
for (let propPath in propsData) {
|
||||
let data = propsData[propPath];
|
||||
let curve = this.createPropCurve(target, propPath, data);
|
||||
|
||||
curves.push(curve);
|
||||
}
|
||||
}
|
||||
|
||||
if (compsData) {
|
||||
for (let compName in compsData) {
|
||||
let comp = target.getComponent(compName);
|
||||
|
||||
if (!comp) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let compData = compsData[compName];
|
||||
for (let propPath in compData) {
|
||||
let data = compData[propPath];
|
||||
let curve = this.createPropCurve(comp, propPath, data);
|
||||
|
||||
curves.push(curve);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
createCurves (state, root) {
|
||||
let curveData = this.curveData;
|
||||
let childrenCurveDatas = curveData.paths;
|
||||
let curves = [];
|
||||
|
||||
this.createTargetCurves(root, curveData, curves);
|
||||
|
||||
for (let namePath in childrenCurveDatas) {
|
||||
let target = cc.find(namePath, root);
|
||||
|
||||
if (!target) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let childCurveDatas = childrenCurveDatas[namePath];
|
||||
this.createTargetCurves(target, childCurveDatas, curves);
|
||||
}
|
||||
|
||||
return curves;
|
||||
}
|
||||
});
|
||||
|
||||
cc.AnimationClip = module.exports = AnimationClip;
|
||||
464
engine/cocos2d/animation/animation-curves.js
Normal file
464
engine/cocos2d/animation/animation-curves.js
Normal file
@@ -0,0 +1,464 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
https://www.cocos.com/
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated engine source code (the "Software"), a limited,
|
||||
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
|
||||
to use Cocos Creator solely to develop games on your target platforms. You shall
|
||||
not use Cocos Creator software for developing other software or tools that's
|
||||
used for developing games. You are not granted to publish, distribute,
|
||||
sublicense, and/or sell copies of Cocos Creator.
|
||||
|
||||
The software or tools in this License Agreement are licensed, not sold.
|
||||
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
const bezierByTime = require('./bezier').bezierByTime;
|
||||
|
||||
const binarySearch = require('../core/utils/binary-search').binarySearchEpsilon;
|
||||
const WrapModeMask = require('./types').WrapModeMask;
|
||||
const WrappedInfo = require('./types').WrappedInfo;
|
||||
|
||||
/**
|
||||
* Compute a new ratio by curve type
|
||||
* @param {Number} ratio - The origin ratio
|
||||
* @param {Array|String} type - If it's Array, then ratio will be computed with bezierByTime. If it's string, then ratio will be computed with cc.easing function
|
||||
*/
|
||||
function computeRatioByType (ratio, type) {
|
||||
if (typeof type === 'string') {
|
||||
var func = cc.easing[type];
|
||||
if (func) {
|
||||
ratio = func(ratio);
|
||||
}
|
||||
else {
|
||||
cc.errorID(3906, type);
|
||||
}
|
||||
}
|
||||
else if (Array.isArray(type)) {
|
||||
// bezier curve
|
||||
ratio = bezierByTime(type, ratio);
|
||||
}
|
||||
|
||||
return ratio;
|
||||
}
|
||||
|
||||
//
|
||||
// 动画数据类,相当于 AnimationClip。
|
||||
// 虽然叫做 AnimCurve,但除了曲线,可以保存任何类型的值。
|
||||
//
|
||||
// @class AnimCurve
|
||||
//
|
||||
//
|
||||
var AnimCurve = cc.Class({
|
||||
name: 'cc.AnimCurve',
|
||||
|
||||
//
|
||||
// @method sample
|
||||
// @param {number} time
|
||||
// @param {number} ratio - The normalized time specified as a number between 0.0 and 1.0 inclusive.
|
||||
// @param {AnimationState} state
|
||||
//
|
||||
sample: function (time, ratio, state) {},
|
||||
|
||||
onTimeChangedManually: undefined
|
||||
});
|
||||
|
||||
/**
|
||||
* 当每两帧之前的间隔都一样的时候可以使用此函数快速查找 index
|
||||
*/
|
||||
function quickFindIndex (ratios, ratio) {
|
||||
var length = ratios.length - 1;
|
||||
|
||||
if (length === 0) return 0;
|
||||
|
||||
var start = ratios[0];
|
||||
if (ratio < start) return 0;
|
||||
|
||||
var end = ratios[length];
|
||||
if (ratio > end) return ~ratios.length;
|
||||
|
||||
ratio = (ratio - start) / (end - start);
|
||||
|
||||
var eachLength = 1 / length;
|
||||
var index = ratio / eachLength;
|
||||
var floorIndex = index | 0;
|
||||
var EPSILON = 1e-6;
|
||||
|
||||
if ((index - floorIndex) < EPSILON) {
|
||||
return floorIndex;
|
||||
}
|
||||
else if ((floorIndex + 1 - index) < EPSILON) {
|
||||
return floorIndex + 1;
|
||||
}
|
||||
|
||||
return ~(floorIndex + 1);
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
// @class DynamicAnimCurve
|
||||
//
|
||||
// @extends AnimCurve
|
||||
//
|
||||
var DynamicAnimCurve = cc.Class({
|
||||
name: 'cc.DynamicAnimCurve',
|
||||
extends: AnimCurve,
|
||||
|
||||
ctor () {
|
||||
// cache last frame index
|
||||
this._cachedIndex = 0;
|
||||
},
|
||||
|
||||
properties: {
|
||||
|
||||
// The object being animated.
|
||||
// @property target
|
||||
// @type {object}
|
||||
target: null,
|
||||
|
||||
// The name of the property being animated.
|
||||
// @property prop
|
||||
// @type {string}
|
||||
prop: '',
|
||||
|
||||
// The values of the keyframes. (y)
|
||||
// @property values
|
||||
// @type {any[]}
|
||||
values: [],
|
||||
|
||||
// The keyframe ratio of the keyframe specified as a number between 0.0 and 1.0 inclusive. (x)
|
||||
// @property ratios
|
||||
// @type {number[]}
|
||||
ratios: [],
|
||||
|
||||
// @property types
|
||||
// @param {object[]}
|
||||
// Each array item maybe type:
|
||||
// - [x, x, x, x]: Four control points for bezier
|
||||
// - null: linear
|
||||
types: [],
|
||||
},
|
||||
|
||||
_findFrameIndex: binarySearch,
|
||||
_lerp: undefined,
|
||||
|
||||
_lerpNumber (from, to, t) {
|
||||
return from + (to - from) * t;
|
||||
},
|
||||
|
||||
_lerpObject (from, to, t) {
|
||||
return from.lerp(to, t);
|
||||
},
|
||||
|
||||
_lerpQuat: (function () {
|
||||
let out = cc.quat();
|
||||
return function (from, to, t) {
|
||||
return from.lerp(to, t, out);
|
||||
};
|
||||
})(),
|
||||
|
||||
_lerpVector2: (function () {
|
||||
let out = cc.v2();
|
||||
return function (from, to, t) {
|
||||
return from.lerp(to, t, out);
|
||||
};
|
||||
})(),
|
||||
|
||||
_lerpVector3: (function () {
|
||||
let out = cc.v3();
|
||||
return function (from, to, t) {
|
||||
return from.lerp(to, t, out);
|
||||
};
|
||||
})(),
|
||||
|
||||
sample (time, ratio, state) {
|
||||
let values = this.values;
|
||||
let ratios = this.ratios;
|
||||
let frameCount = ratios.length;
|
||||
|
||||
if (frameCount === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// only need to refind frame index when ratio is out of range of last from ratio and to ratio.
|
||||
let shoudRefind = true;
|
||||
let cachedIndex = this._cachedIndex;
|
||||
if (cachedIndex < 0) {
|
||||
cachedIndex = ~cachedIndex;
|
||||
if (cachedIndex > 0 && cachedIndex < ratios.length) {
|
||||
let fromRatio = ratios[cachedIndex - 1];
|
||||
let toRatio = ratios[cachedIndex];
|
||||
if (ratio > fromRatio && ratio < toRatio) {
|
||||
shoudRefind = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (shoudRefind) {
|
||||
this._cachedIndex = this._findFrameIndex(ratios, ratio);
|
||||
}
|
||||
|
||||
// evaluate value
|
||||
let value;
|
||||
let index = this._cachedIndex;
|
||||
if (index < 0) {
|
||||
index = ~index;
|
||||
|
||||
if (index <= 0) {
|
||||
value = values[0];
|
||||
}
|
||||
else if (index >= frameCount) {
|
||||
value = values[frameCount - 1];
|
||||
}
|
||||
else {
|
||||
var fromVal = values[index - 1];
|
||||
|
||||
if (!this._lerp) {
|
||||
value = fromVal;
|
||||
}
|
||||
else {
|
||||
var fromRatio = ratios[index - 1];
|
||||
var toRatio = ratios[index];
|
||||
var type = this.types[index - 1];
|
||||
var ratioBetweenFrames = (ratio - fromRatio) / (toRatio - fromRatio);
|
||||
|
||||
if (type) {
|
||||
ratioBetweenFrames = computeRatioByType(ratioBetweenFrames, type);
|
||||
}
|
||||
|
||||
// calculate value
|
||||
var toVal = values[index];
|
||||
|
||||
value = this._lerp(fromVal, toVal, ratioBetweenFrames);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
value = values[index];
|
||||
}
|
||||
|
||||
this.target[this.prop] = value;
|
||||
}
|
||||
});
|
||||
|
||||
DynamicAnimCurve.Linear = null;
|
||||
DynamicAnimCurve.Bezier = function (controlPoints) {
|
||||
return controlPoints;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Event information,
|
||||
* @class EventInfo
|
||||
*
|
||||
*/
|
||||
var EventInfo = function () {
|
||||
this.events = [];
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Function} [func] event function
|
||||
* @param {Object[]} [params] event params
|
||||
*/
|
||||
EventInfo.prototype.add = function (func, params) {
|
||||
this.events.push({
|
||||
func: func || '',
|
||||
params: params || []
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @class EventAnimCurve
|
||||
*
|
||||
* @extends AnimCurve
|
||||
*/
|
||||
var EventAnimCurve = cc.Class({
|
||||
name: 'cc.EventAnimCurve',
|
||||
extends: AnimCurve,
|
||||
|
||||
properties: {
|
||||
/**
|
||||
* The object being animated.
|
||||
* @property target
|
||||
* @type {object}
|
||||
*/
|
||||
target: null,
|
||||
|
||||
/** The keyframe ratio of the keyframe specified as a number between 0.0 and 1.0 inclusive. (x)
|
||||
* @property ratios
|
||||
* @type {number[]}
|
||||
*/
|
||||
ratios: [],
|
||||
|
||||
/**
|
||||
* @property events
|
||||
* @type {EventInfo[]}
|
||||
*/
|
||||
events: [],
|
||||
|
||||
_wrappedInfo: {
|
||||
default: function () {
|
||||
return new WrappedInfo();
|
||||
}
|
||||
},
|
||||
|
||||
_lastWrappedInfo: null,
|
||||
|
||||
_ignoreIndex: NaN
|
||||
},
|
||||
|
||||
_wrapIterations: function (iterations) {
|
||||
if (iterations - (iterations | 0) === 0) iterations -= 1;
|
||||
return iterations | 0;
|
||||
},
|
||||
|
||||
sample: function (time, ratio, state) {
|
||||
var length = this.ratios.length;
|
||||
|
||||
var currentWrappedInfo = state.getWrappedInfo(state.time, this._wrappedInfo);
|
||||
var direction = currentWrappedInfo.direction;
|
||||
var currentIndex = binarySearch(this.ratios, currentWrappedInfo.ratio);
|
||||
if (currentIndex < 0) {
|
||||
currentIndex = ~currentIndex - 1;
|
||||
|
||||
// if direction is inverse, then increase index
|
||||
if (direction < 0) currentIndex += 1;
|
||||
}
|
||||
|
||||
if (this._ignoreIndex !== currentIndex) {
|
||||
this._ignoreIndex = NaN;
|
||||
}
|
||||
|
||||
currentWrappedInfo.frameIndex = currentIndex;
|
||||
|
||||
if (!this._lastWrappedInfo) {
|
||||
this._fireEvent(currentIndex);
|
||||
this._lastWrappedInfo = new WrappedInfo(currentWrappedInfo);
|
||||
return;
|
||||
}
|
||||
|
||||
var wrapMode = state.wrapMode;
|
||||
var currentIterations = this._wrapIterations(currentWrappedInfo.iterations);
|
||||
|
||||
var lastWrappedInfo = this._lastWrappedInfo;
|
||||
var lastIterations = this._wrapIterations(lastWrappedInfo.iterations);
|
||||
var lastIndex = lastWrappedInfo.frameIndex;
|
||||
var lastDirection = lastWrappedInfo.direction;
|
||||
|
||||
var interationsChanged = lastIterations !== -1 && currentIterations !== lastIterations;
|
||||
|
||||
if (lastIndex === currentIndex && interationsChanged && length === 1) {
|
||||
this._fireEvent(0);
|
||||
}
|
||||
else if (lastIndex !== currentIndex || interationsChanged) {
|
||||
direction = lastDirection;
|
||||
|
||||
do {
|
||||
if (lastIndex !== currentIndex) {
|
||||
if (direction === -1 && lastIndex === 0 && currentIndex > 0) {
|
||||
if ((wrapMode & WrapModeMask.PingPong) === WrapModeMask.PingPong) {
|
||||
direction *= -1;
|
||||
}
|
||||
else {
|
||||
lastIndex = length;
|
||||
}
|
||||
|
||||
lastIterations ++;
|
||||
}
|
||||
else if (direction === 1 && lastIndex === length - 1 && currentIndex < length - 1) {
|
||||
if ((wrapMode & WrapModeMask.PingPong) === WrapModeMask.PingPong) {
|
||||
direction *= -1;
|
||||
}
|
||||
else {
|
||||
lastIndex = -1;
|
||||
}
|
||||
|
||||
lastIterations ++;
|
||||
}
|
||||
|
||||
if (lastIndex === currentIndex) break;
|
||||
if (lastIterations > currentIterations) break;
|
||||
}
|
||||
|
||||
lastIndex += direction;
|
||||
|
||||
cc.director.getAnimationManager().pushDelayEvent(this, '_fireEvent', [lastIndex]);
|
||||
} while (lastIndex !== currentIndex && lastIndex > -1 && lastIndex < length);
|
||||
}
|
||||
|
||||
this._lastWrappedInfo.set(currentWrappedInfo);
|
||||
},
|
||||
|
||||
_fireEvent: function (index) {
|
||||
if (index < 0 || index >= this.events.length || this._ignoreIndex === index) return;
|
||||
|
||||
var eventInfo = this.events[index];
|
||||
var events = eventInfo.events;
|
||||
|
||||
if ( !this.target.isValid ) {
|
||||
return;
|
||||
}
|
||||
|
||||
var components = this.target._components;
|
||||
|
||||
for (var i = 0; i < events.length; i++) {
|
||||
var event = events[i];
|
||||
var funcName = event.func;
|
||||
|
||||
for (var j = 0; j < components.length; j++) {
|
||||
var component = components[j];
|
||||
var func = component[funcName];
|
||||
|
||||
if (func) func.apply(component, event.params);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
onTimeChangedManually: function (time, state) {
|
||||
this._lastWrappedInfo = null;
|
||||
this._ignoreIndex = NaN;
|
||||
|
||||
var info = state.getWrappedInfo(time, this._wrappedInfo);
|
||||
var direction = info.direction;
|
||||
var frameIndex = binarySearch(this.ratios, info.ratio);
|
||||
|
||||
// only ignore when time not on a frame index
|
||||
if (frameIndex < 0) {
|
||||
frameIndex = ~frameIndex - 1;
|
||||
|
||||
// if direction is inverse, then increase index
|
||||
if (direction < 0) frameIndex += 1;
|
||||
|
||||
this._ignoreIndex = frameIndex;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
if (CC_TEST) {
|
||||
cc._Test.DynamicAnimCurve = DynamicAnimCurve;
|
||||
cc._Test.EventAnimCurve = EventAnimCurve;
|
||||
cc._Test.quickFindIndex = quickFindIndex;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
AnimCurve: AnimCurve,
|
||||
DynamicAnimCurve: DynamicAnimCurve,
|
||||
EventAnimCurve: EventAnimCurve,
|
||||
EventInfo: EventInfo,
|
||||
computeRatioByType: computeRatioByType,
|
||||
quickFindIndex: quickFindIndex
|
||||
};
|
||||
93
engine/cocos2d/animation/animation-manager.js
Normal file
93
engine/cocos2d/animation/animation-manager.js
Normal file
@@ -0,0 +1,93 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
https://www.cocos.com/
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated engine source code (the "Software"), a limited,
|
||||
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
|
||||
to use Cocos Creator solely to develop games on your target platforms. You shall
|
||||
not use Cocos Creator software for developing other software or tools that's
|
||||
used for developing games. You are not granted to publish, distribute,
|
||||
sublicense, and/or sell copies of Cocos Creator.
|
||||
|
||||
The software or tools in this License Agreement are licensed, not sold.
|
||||
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
var js = cc.js;
|
||||
|
||||
var AnimationManager = cc.Class({
|
||||
ctor: function () {
|
||||
this._anims = new js.array.MutableForwardIterator([]);
|
||||
this._delayEvents = [];
|
||||
|
||||
cc.director._scheduler && cc.director._scheduler.enableForTarget(this);
|
||||
},
|
||||
|
||||
// for manager
|
||||
|
||||
update: function (dt) {
|
||||
var iterator = this._anims;
|
||||
var array = iterator.array;
|
||||
for (iterator.i = 0; iterator.i < array.length; ++iterator.i) {
|
||||
var anim = array[iterator.i];
|
||||
if (anim._isPlaying && !anim._isPaused) {
|
||||
anim.update(dt);
|
||||
}
|
||||
}
|
||||
|
||||
var events = this._delayEvents;
|
||||
for (let i = 0; i < events.length; i++) {
|
||||
var event = events[i];
|
||||
event.target[event.func].apply(event.target, event.args);
|
||||
}
|
||||
events.length = 0;
|
||||
|
||||
},
|
||||
|
||||
destruct: function () {},
|
||||
|
||||
|
||||
/**
|
||||
* @param {AnimationState} anim
|
||||
*/
|
||||
addAnimation: function (anim) {
|
||||
var index = this._anims.array.indexOf(anim);
|
||||
if (index === -1) {
|
||||
this._anims.push(anim);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {AnimationState} anim
|
||||
*/
|
||||
removeAnimation: function (anim) {
|
||||
var index = this._anims.array.indexOf(anim);
|
||||
if (index >= 0) {
|
||||
this._anims.fastRemoveAt(index);
|
||||
}
|
||||
else {
|
||||
cc.errorID(3907);
|
||||
}
|
||||
},
|
||||
|
||||
pushDelayEvent: function (target, func, args) {
|
||||
this._delayEvents.push({
|
||||
target: target,
|
||||
func: func,
|
||||
args: args
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
cc.AnimationManager = module.exports = AnimationManager;
|
||||
523
engine/cocos2d/animation/animation-state.js
Normal file
523
engine/cocos2d/animation/animation-state.js
Normal file
@@ -0,0 +1,523 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
https://www.cocos.com/
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated engine source code (the "Software"), a limited,
|
||||
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
|
||||
to use Cocos Creator solely to develop games on your target platforms. You shall
|
||||
not use Cocos Creator software for developing other software or tools that's
|
||||
used for developing games. You are not granted to publish, distribute,
|
||||
sublicense, and/or sell copies of Cocos Creator.
|
||||
|
||||
The software or tools in this License Agreement are licensed, not sold.
|
||||
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
var js = cc.js;
|
||||
var Playable = require('./playable');
|
||||
|
||||
var Types = require('./types');
|
||||
var WrappedInfo = Types.WrappedInfo;
|
||||
var WrapMode = Types.WrapMode;
|
||||
var WrapModeMask = Types.WrapModeMask;
|
||||
|
||||
/**
|
||||
* !#en
|
||||
* The AnimationState gives full control over animation playback process.
|
||||
* In most cases the Animation Component is sufficient and easier to use. Use the AnimationState if you need full control.
|
||||
* !#zh
|
||||
* AnimationState 完全控制动画播放过程。<br/>
|
||||
* 大多数情况下 动画组件 是足够和易于使用的。如果您需要更多的动画控制接口,请使用 AnimationState。
|
||||
* @class AnimationState
|
||||
* @extends Playable
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @method constructor
|
||||
* @param {AnimationClip} clip
|
||||
* @param {String} [name]
|
||||
*/
|
||||
function AnimationState (clip, name) {
|
||||
Playable.call(this);
|
||||
|
||||
// Mark whether the current frame is played.
|
||||
// When set new time to animation state, we should ensure the frame at the specified time being played at next update.
|
||||
this._currentFramePlayed = false;
|
||||
|
||||
this._delay = 0;
|
||||
this._delayTime = 0;
|
||||
|
||||
this._wrappedInfo = new WrappedInfo();
|
||||
this._lastWrappedInfo = null;
|
||||
|
||||
this._process = process;
|
||||
|
||||
this._clip = clip;
|
||||
this._name = name || (clip && clip.name);
|
||||
|
||||
/**
|
||||
* @property animator
|
||||
* @type {AnimationAnimator}
|
||||
* @private
|
||||
*/
|
||||
this.animator = null;
|
||||
|
||||
/**
|
||||
* !#en The curves list.
|
||||
* !#zh 曲线列表。
|
||||
* @property curves
|
||||
* @type {Object[]}
|
||||
*/
|
||||
this.curves = [];
|
||||
|
||||
// http://www.w3.org/TR/web-animations/#idl-def-AnimationTiming
|
||||
|
||||
/**
|
||||
* !#en The start delay which represents the number of seconds from an animation's start time to the start of
|
||||
* the active interval.
|
||||
* !#zh 延迟多少秒播放。
|
||||
*
|
||||
* @property delay
|
||||
* @type {Number}
|
||||
* @default 0
|
||||
*/
|
||||
this.delay = 0;
|
||||
|
||||
/**
|
||||
* !#en The animation's iteration count property.
|
||||
*
|
||||
* A real number greater than or equal to zero (including positive infinity) representing the number of times
|
||||
* to repeat the animation node.
|
||||
*
|
||||
* Values less than zero and NaN values are treated as the value 1.0 for the purpose of timing model
|
||||
* calculations.
|
||||
*
|
||||
* !#zh 迭代次数,指动画播放多少次后结束, normalize time。 如 2.5(2次半)
|
||||
*
|
||||
* @property repeatCount
|
||||
* @type {Number}
|
||||
* @default 1
|
||||
*/
|
||||
this.repeatCount = 1;
|
||||
|
||||
/**
|
||||
* !#en The iteration duration of this animation in seconds. (length)
|
||||
* !#zh 单次动画的持续时间,秒。
|
||||
*
|
||||
* @property duration
|
||||
* @type {Number}
|
||||
* @readOnly
|
||||
*/
|
||||
this.duration = 1;
|
||||
|
||||
/**
|
||||
* !#en The animation's playback speed. 1 is normal playback speed.
|
||||
* !#zh 播放速率。
|
||||
* @property speed
|
||||
* @type {Number}
|
||||
* @default: 1.0
|
||||
*/
|
||||
this.speed = 1;
|
||||
|
||||
/**
|
||||
* !#en
|
||||
* Wrapping mode of the playing animation.
|
||||
* Notice : dynamic change wrapMode will reset time and repeatCount property
|
||||
* !#zh
|
||||
* 动画循环方式。
|
||||
* 需要注意的是,动态修改 wrapMode 时,会重置 time 以及 repeatCount
|
||||
*
|
||||
* @property wrapMode
|
||||
* @type {WrapMode}
|
||||
* @default: WrapMode.Normal
|
||||
*/
|
||||
this.wrapMode = WrapMode.Normal;
|
||||
|
||||
/**
|
||||
* !#en The current time of this animation in seconds.
|
||||
* !#zh 动画当前的时间,秒。
|
||||
* @property time
|
||||
* @type {Number}
|
||||
* @default 0
|
||||
*/
|
||||
this.time = 0;
|
||||
|
||||
// Animation as event target
|
||||
this._target = null;
|
||||
this._lastframeEventOn = false;
|
||||
this.emit = function () {
|
||||
var args = new Array(arguments.length);
|
||||
for (var i = 0, l = args.length; i < l; i++) {
|
||||
args[i] = arguments[i];
|
||||
}
|
||||
cc.director.getAnimationManager().pushDelayEvent(this, '_emit', args);
|
||||
};
|
||||
}
|
||||
js.extend(AnimationState, Playable);
|
||||
|
||||
var proto = AnimationState.prototype;
|
||||
|
||||
proto._emit = function (type, state) {
|
||||
if (this._target && this._target.isValid) {
|
||||
this._target.emit(type, type, state);
|
||||
}
|
||||
};
|
||||
|
||||
proto.on = function (type, callback, target) {
|
||||
if (this._target && this._target.isValid) {
|
||||
if (type === 'lastframe') {
|
||||
this._lastframeEventOn = true;
|
||||
}
|
||||
return this._target.on(type, callback, target);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
proto.once = function (type, callback, target) {
|
||||
if (this._target && this._target.isValid) {
|
||||
if (type === 'lastframe') {
|
||||
this._lastframeEventOn = true;
|
||||
}
|
||||
let self = this;
|
||||
return this._target.once(type, function (event) {
|
||||
callback.call(target, event);
|
||||
self._lastframeEventOn = false;
|
||||
});
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
proto.off = function (type, callback, target) {
|
||||
if (this._target && this._target.isValid) {
|
||||
if (type === 'lastframe') {
|
||||
if (!this._target.hasEventListener(type)) {
|
||||
this._lastframeEventOn = false;
|
||||
}
|
||||
}
|
||||
this._target.off(type, callback, target);
|
||||
}
|
||||
};
|
||||
|
||||
proto._setEventTarget = function (target) {
|
||||
this._target = target;
|
||||
};
|
||||
|
||||
proto.onPlay = function () {
|
||||
// replay
|
||||
this.setTime(0);
|
||||
this._delayTime = this._delay;
|
||||
|
||||
cc.director.getAnimationManager().addAnimation(this);
|
||||
|
||||
if (this.animator) {
|
||||
this.animator.addAnimation(this);
|
||||
}
|
||||
|
||||
this.emit('play', this);
|
||||
};
|
||||
|
||||
proto.onStop = function () {
|
||||
if (!this.isPaused) {
|
||||
cc.director.getAnimationManager().removeAnimation(this);
|
||||
}
|
||||
|
||||
if (this.animator) {
|
||||
this.animator.removeAnimation(this);
|
||||
}
|
||||
|
||||
this.emit('stop', this);
|
||||
};
|
||||
|
||||
proto.onResume = function () {
|
||||
cc.director.getAnimationManager().addAnimation(this);
|
||||
this.emit('resume', this);
|
||||
};
|
||||
|
||||
proto.onPause = function () {
|
||||
cc.director.getAnimationManager().removeAnimation(this);
|
||||
this.emit('pause', this);
|
||||
};
|
||||
|
||||
proto.setTime = function (time) {
|
||||
this._currentFramePlayed = false;
|
||||
this.time = time || 0;
|
||||
|
||||
var curves = this.curves;
|
||||
for (var i = 0, l = curves.length; i < l; i++) {
|
||||
var curve = curves[i];
|
||||
if (curve.onTimeChangedManually) {
|
||||
curve.onTimeChangedManually(time, this);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function process () {
|
||||
// sample
|
||||
var info = this.sample();
|
||||
|
||||
if (this._lastframeEventOn) {
|
||||
var lastInfo;
|
||||
if (!this._lastWrappedInfo) {
|
||||
lastInfo = this._lastWrappedInfo = new WrappedInfo(info);
|
||||
} else {
|
||||
lastInfo = this._lastWrappedInfo;
|
||||
}
|
||||
|
||||
if (this.repeatCount > 1 && ((info.iterations | 0) > (lastInfo.iterations | 0))) {
|
||||
this.emit('lastframe', this);
|
||||
}
|
||||
|
||||
lastInfo.set(info);
|
||||
}
|
||||
|
||||
if (info.stopped) {
|
||||
this.stop();
|
||||
this.emit('finished', this);
|
||||
}
|
||||
}
|
||||
|
||||
function simpleProcess () {
|
||||
var time = this.time;
|
||||
var duration = this.duration;
|
||||
|
||||
if (time > duration) {
|
||||
time = time % duration;
|
||||
if (time === 0) time = duration;
|
||||
}
|
||||
else if (time < 0) {
|
||||
time = time % duration;
|
||||
if (time !== 0) time += duration;
|
||||
}
|
||||
|
||||
var ratio = time / duration;
|
||||
|
||||
var curves = this.curves;
|
||||
for (var i = 0, len = curves.length; i < len; i++) {
|
||||
var curve = curves[i];
|
||||
curve.sample(time, ratio, this);
|
||||
}
|
||||
|
||||
if (this._lastframeEventOn) {
|
||||
if (this._lastIterations === undefined) {
|
||||
this._lastIterations = ratio;
|
||||
}
|
||||
|
||||
if ((this.time > 0 && this._lastIterations > ratio) || (this.time < 0 && this._lastIterations < ratio)) {
|
||||
this.emit('lastframe', this);
|
||||
}
|
||||
|
||||
this._lastIterations = ratio;
|
||||
}
|
||||
}
|
||||
|
||||
proto.update = function (delta) {
|
||||
// calculate delay time
|
||||
|
||||
if (this._delayTime > 0) {
|
||||
this._delayTime -= delta;
|
||||
if (this._delayTime > 0) {
|
||||
// still waiting
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// make first frame perfect
|
||||
|
||||
//var playPerfectFirstFrame = (this.time === 0);
|
||||
if (this._currentFramePlayed) {
|
||||
this.time += (delta * this.speed);
|
||||
}
|
||||
else {
|
||||
this._currentFramePlayed = true;
|
||||
}
|
||||
|
||||
this._process();
|
||||
};
|
||||
|
||||
proto._needRevers = function (currentIterations) {
|
||||
var wrapMode = this.wrapMode;
|
||||
var needRevers = false;
|
||||
|
||||
if ((wrapMode & WrapModeMask.PingPong) === WrapModeMask.PingPong) {
|
||||
var isEnd = currentIterations - (currentIterations | 0) === 0;
|
||||
if (isEnd && (currentIterations > 0)) {
|
||||
currentIterations -= 1;
|
||||
}
|
||||
|
||||
var isOddIteration = currentIterations & 1;
|
||||
if (isOddIteration) {
|
||||
needRevers = !needRevers;
|
||||
}
|
||||
}
|
||||
if ((wrapMode & WrapModeMask.Reverse) === WrapModeMask.Reverse) {
|
||||
needRevers = !needRevers;
|
||||
}
|
||||
return needRevers;
|
||||
};
|
||||
|
||||
proto.getWrappedInfo = function (time, info) {
|
||||
info = info || new WrappedInfo();
|
||||
|
||||
var stopped = false;
|
||||
var duration = this.duration;
|
||||
var repeatCount = this.repeatCount;
|
||||
|
||||
var currentIterations = time > 0 ? (time / duration) : -(time / duration);
|
||||
if (currentIterations >= repeatCount) {
|
||||
currentIterations = repeatCount;
|
||||
|
||||
stopped = true;
|
||||
var tempRatio = repeatCount - (repeatCount | 0);
|
||||
if (tempRatio === 0) {
|
||||
tempRatio = 1; // 如果播放过,动画不复位
|
||||
}
|
||||
time = tempRatio * duration * (time > 0 ? 1 : -1);
|
||||
}
|
||||
|
||||
if (time > duration) {
|
||||
var tempTime = time % duration;
|
||||
time = tempTime === 0 ? duration : tempTime;
|
||||
}
|
||||
else if (time < 0) {
|
||||
time = time % duration;
|
||||
if (time !== 0 ) time += duration;
|
||||
}
|
||||
|
||||
var needRevers = false;
|
||||
var shouldWrap = this._wrapMode & WrapModeMask.ShouldWrap;
|
||||
if (shouldWrap) {
|
||||
needRevers = this._needRevers(currentIterations);
|
||||
}
|
||||
|
||||
var direction = needRevers ? -1 : 1;
|
||||
if (this.speed < 0) {
|
||||
direction *= -1;
|
||||
}
|
||||
|
||||
// calculate wrapped time
|
||||
if (shouldWrap && needRevers) {
|
||||
time = duration - time;
|
||||
}
|
||||
|
||||
info.ratio = time / duration;
|
||||
info.time = time;
|
||||
info.direction = direction;
|
||||
info.stopped = stopped;
|
||||
info.iterations = currentIterations;
|
||||
|
||||
return info;
|
||||
};
|
||||
|
||||
proto.sample = function () {
|
||||
var info = this.getWrappedInfo(this.time, this._wrappedInfo);
|
||||
var curves = this.curves;
|
||||
for (var i = 0, len = curves.length; i < len; i++) {
|
||||
var curve = curves[i];
|
||||
curve.sample(info.time, info.ratio, this);
|
||||
}
|
||||
|
||||
return info;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* !#en The clip that is being played by this animation state.
|
||||
* !#zh 此动画状态正在播放的剪辑。
|
||||
* @property clip
|
||||
* @type {AnimationClip}
|
||||
* @final
|
||||
*/
|
||||
js.get(proto, 'clip', function () {
|
||||
return this._clip;
|
||||
});
|
||||
|
||||
/**
|
||||
* !#en The name of the playing animation.
|
||||
* !#zh 动画的名字
|
||||
* @property name
|
||||
* @type {String}
|
||||
* @readOnly
|
||||
*/
|
||||
js.get(proto, 'name', function () {
|
||||
return this._name;
|
||||
});
|
||||
|
||||
js.obsolete(proto, 'AnimationState.length', 'duration');
|
||||
|
||||
js.getset(proto, 'curveLoaded',
|
||||
function () {
|
||||
return this.curves.length > 0;
|
||||
},
|
||||
function () {
|
||||
this.curves.length = 0;
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
js.getset(proto, 'wrapMode',
|
||||
function () {
|
||||
return this._wrapMode;
|
||||
},
|
||||
function (value) {
|
||||
this._wrapMode = value;
|
||||
|
||||
if (CC_EDITOR) return;
|
||||
|
||||
// dynamic change wrapMode will need reset time to 0
|
||||
this.time = 0;
|
||||
|
||||
if (value & WrapModeMask.Loop) {
|
||||
this.repeatCount = Infinity;
|
||||
}
|
||||
else {
|
||||
this.repeatCount = 1;
|
||||
}
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
js.getset(proto, 'repeatCount',
|
||||
function () {
|
||||
return this._repeatCount;
|
||||
},
|
||||
function (value) {
|
||||
this._repeatCount = value;
|
||||
|
||||
var shouldWrap = this._wrapMode & WrapModeMask.ShouldWrap;
|
||||
var reverse = (this.wrapMode & WrapModeMask.Reverse) === WrapModeMask.Reverse;
|
||||
if (value === Infinity && !shouldWrap && !reverse) {
|
||||
this._process = simpleProcess;
|
||||
}
|
||||
else {
|
||||
this._process = process;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
js.getset(proto, 'delay',
|
||||
function () {
|
||||
return this._delay;
|
||||
},
|
||||
function (value) {
|
||||
this._delayTime = this._delay = value;
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
cc.AnimationState = module.exports = AnimationState;
|
||||
213
engine/cocos2d/animation/bezier.js
Normal file
213
engine/cocos2d/animation/bezier.js
Normal file
@@ -0,0 +1,213 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
https://www.cocos.com/
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated engine source code (the "Software"), a limited,
|
||||
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
|
||||
to use Cocos Creator solely to develop games on your target platforms. You shall
|
||||
not use Cocos Creator software for developing other software or tools that's
|
||||
used for developing games. You are not granted to publish, distribute,
|
||||
sublicense, and/or sell copies of Cocos Creator.
|
||||
|
||||
The software or tools in this License Agreement are licensed, not sold.
|
||||
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
//var bezier = (function () {
|
||||
// function B1 (t) { return (t * t * t); }
|
||||
// function B2 (t) { return (3 * t * t * (1 - t)); }
|
||||
// function B3 (t) { return (3 * t * (1 - t) * (1 - t)); }
|
||||
// function B4 (t) { return ((1 - t) * (1 - t) * (1 - t)); }
|
||||
// function bezier (C1, C2, C3, C4, t) {
|
||||
// return C1 * B1(t) + C2 * B2(t) + C3 * B3(t) + C4 * B4(t);
|
||||
// }
|
||||
//
|
||||
// //function bezier (C1, C2, C3, C4, t, out) {
|
||||
// // out.x = C1.x * B1(t) + C2.x * B2(t) + C3.x * B3(t) + C4.x * B4(t);
|
||||
// // out.y = C1.y * B1(t) + C2.y * B2(t) + C3.y * B3(t) + C4.y * B4(t);
|
||||
// //}
|
||||
//
|
||||
// return bezier;
|
||||
//})();
|
||||
function bezier (C1, C2, C3, C4, t) {
|
||||
var t1 = 1 - t;
|
||||
return t1 * (t1 * (C1 + (C2 * 3 - C1) * t) + C3 * 3 * t * t) + C4 * t * t * t;
|
||||
}
|
||||
//function bezier (c0, c1, c2, c3, t) {
|
||||
// var cy = 3.0 * (c1);
|
||||
// var by = 3.0 * (c3 - c1) - cy;
|
||||
// var ay = 1 - cy - by;
|
||||
// return (ay * t * t * t) + (by * t * t) + (cy * t);
|
||||
//}
|
||||
|
||||
//var sin = Math.sin;
|
||||
var cos = Math.cos,
|
||||
acos = Math.acos,
|
||||
max = Math.max,
|
||||
//atan2 = Math.atan2,
|
||||
pi = Math.PI,
|
||||
tau = 2 * pi,
|
||||
sqrt = Math.sqrt;
|
||||
|
||||
function crt (v) {
|
||||
if (v < 0) {
|
||||
return -Math.pow(-v, 1 / 3);
|
||||
}
|
||||
else {
|
||||
return Math.pow(v, 1 / 3);
|
||||
}
|
||||
}
|
||||
|
||||
//function align (curve, line) {
|
||||
// var tx = line.p1.x,
|
||||
// ty = line.p1.y,
|
||||
// a = -atan2(line.p2.y-ty, line.p2.x-tx);
|
||||
// curve = [{x:0, y:1}, {x: curve[0], y: 1-curve[1]}, {x: curve[2], y: 1-curve[3]}, {x:1, y:0}];
|
||||
// return curve.map(function(v) {
|
||||
// return {
|
||||
// x: (v.x-tx)*cos(a) - (v.y-ty)*sin(a),
|
||||
// y: (v.x-tx)*sin(a) + (v.y-ty)*cos(a)
|
||||
// };
|
||||
// });
|
||||
//}
|
||||
|
||||
// Modified from http://jsbin.com/yibipofeqi/1/edit, optimized for animations.
|
||||
// The origin Cardano's algorithm is based on http://www.trans4mind.com/personal_development/mathematics/polynomials/cubicAlgebra.htm
|
||||
function cardano (curve, x) {
|
||||
// align curve with the intersecting line:
|
||||
//var line = {p1: {x: x, y: 0}, p2: {x: x, y: 1}};
|
||||
//var aligned = align(curve, line);
|
||||
//// and rewrite from [a(1-t)^3 + 3bt(1-t)^2 + 3c(1-t)t^2 + dt^3] form
|
||||
// pa = aligned[0].y,
|
||||
// pb = aligned[1].y,
|
||||
// pc = aligned[2].y,
|
||||
// pd = aligned[3].y;
|
||||
////// curve = [{x:0, y:1}, {x: curve[0], y: 1-curve[1]}, {x: curve[2], y: 1-curve[3]}, {x:1, y:0}];
|
||||
var pa = x - 0;
|
||||
var pb = x - curve[0];
|
||||
var pc = x - curve[2];
|
||||
var pd = x - 1;
|
||||
|
||||
// to [t^3 + at^2 + bt + c] form:
|
||||
var pa3 = pa * 3;
|
||||
var pb3 = pb * 3;
|
||||
var pc3 = pc * 3;
|
||||
var d = (-pa + pb3 - pc3 + pd),
|
||||
rd = 1 / d,
|
||||
r3 = 1 / 3,
|
||||
a = (pa3 - 6 * pb + pc3) * rd,
|
||||
a3 = a * r3,
|
||||
b = (-pa3 + pb3) * rd,
|
||||
c = pa * rd,
|
||||
// then, determine p and q:
|
||||
p = (3 * b - a * a) * r3,
|
||||
p3 = p * r3,
|
||||
q = (2 * a * a * a - 9 * a * b + 27 * c) / 27,
|
||||
q2 = q / 2,
|
||||
// and determine the discriminant:
|
||||
discriminant = q2 * q2 + p3 * p3 * p3,
|
||||
// and some reserved variables
|
||||
u1, v1, x1, x2, x3;
|
||||
|
||||
// If the discriminant is negative, use polar coordinates
|
||||
// to get around square roots of negative numbers
|
||||
if (discriminant < 0) {
|
||||
var mp3 = -p * r3,
|
||||
mp33 = mp3 * mp3 * mp3,
|
||||
r = sqrt(mp33),
|
||||
// compute cosphi corrected for IEEE float rounding:
|
||||
t = -q / (2 * r),
|
||||
cosphi = t < -1 ? -1 : t > 1 ? 1 : t,
|
||||
phi = acos(cosphi),
|
||||
crtr = crt(r),
|
||||
t1 = 2 * crtr;
|
||||
x1 = t1 * cos(phi * r3) - a3;
|
||||
x2 = t1 * cos((phi + tau) * r3) - a3;
|
||||
x3 = t1 * cos((phi + 2 * tau) * r3) - a3;
|
||||
|
||||
// choose best percentage
|
||||
if (0 <= x1 && x1 <= 1) {
|
||||
if (0 <= x2 && x2 <= 1) {
|
||||
if (0 <= x3 && x3 <= 1) {
|
||||
return max(x1, x2, x3);
|
||||
}
|
||||
else {
|
||||
return max(x1, x2);
|
||||
}
|
||||
}
|
||||
else if (0 <= x3 && x3 <= 1) {
|
||||
return max(x1, x3);
|
||||
}
|
||||
else {
|
||||
return x1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (0 <= x2 && x2 <= 1) {
|
||||
if (0 <= x3 && x3 <= 1) {
|
||||
return max(x2, x3);
|
||||
}
|
||||
else {
|
||||
return x2;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return x3;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (discriminant === 0) {
|
||||
u1 = q2 < 0 ? crt(-q2) : -crt(q2);
|
||||
x1 = 2 * u1 - a3;
|
||||
x2 = -u1 - a3;
|
||||
|
||||
// choose best percentage
|
||||
if (0 <= x1 && x1 <= 1) {
|
||||
if (0 <= x2 && x2 <= 1) {
|
||||
return max(x1, x2);
|
||||
}
|
||||
else {
|
||||
return x1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return x2;
|
||||
}
|
||||
}
|
||||
// one real root, and two imaginary roots
|
||||
else {
|
||||
var sd = sqrt(discriminant);
|
||||
u1 = crt(-q2 + sd);
|
||||
v1 = crt(q2 + sd);
|
||||
x1 = u1 - v1 - a3;
|
||||
return x1;
|
||||
}
|
||||
}
|
||||
|
||||
function bezierByTime (controlPoints, x) {
|
||||
var percent = cardano(controlPoints, x); // t
|
||||
var p1y = controlPoints[1]; // b
|
||||
var p2y = controlPoints[3]; // c
|
||||
// return bezier(0, p1y, p2y, 1, percent);
|
||||
return ((1 - percent) * (p1y + (p2y - p1y) * percent) * 3 + percent * percent) * percent;
|
||||
}
|
||||
|
||||
if (CC_TEST) {
|
||||
cc._Test.bezier = bezier;
|
||||
cc._Test.bezierByTime = bezierByTime;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
bezier: bezier,
|
||||
bezierByTime: bezierByTime
|
||||
};
|
||||
538
engine/cocos2d/animation/easing.js
Normal file
538
engine/cocos2d/animation/easing.js
Normal file
@@ -0,0 +1,538 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
https://www.cocos.com/
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated engine source code (the "Software"), a limited,
|
||||
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
|
||||
to use Cocos Creator solely to develop games on your target platforms. You shall
|
||||
not use Cocos Creator software for developing other software or tools that's
|
||||
used for developing games. You are not granted to publish, distribute,
|
||||
sublicense, and/or sell copies of Cocos Creator.
|
||||
|
||||
The software or tools in this License Agreement are licensed, not sold.
|
||||
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
/**
|
||||
* @module cc
|
||||
*/
|
||||
|
||||
/**
|
||||
* !#en
|
||||
* This class provide easing methods for {{#crossLink "tween"}}{{/crossLink}} class.<br>
|
||||
* Demonstratio: https://easings.net/
|
||||
* !#zh
|
||||
* 缓动函数类,为 {{#crossLink "Tween"}}{{/crossLink}} 提供缓动效果函数。<br>
|
||||
* 函数效果演示: https://easings.net/
|
||||
* @class Easing
|
||||
*/
|
||||
|
||||
var easing = {
|
||||
constant: function () { return 0; },
|
||||
linear: function (k) { return k; },
|
||||
|
||||
// quad
|
||||
// easing equation function for a quadratic (t^2)
|
||||
// @param t: Current time (in frames or seconds).
|
||||
// @return: The correct value.
|
||||
|
||||
/**
|
||||
* !#en Easing in with quadratic formula. From slow to fast.
|
||||
* !#zh 平方曲线缓入函数。运动由慢到快。
|
||||
* @method quadIn
|
||||
* @param {Number} t The current time as a percentage of the total time.
|
||||
* @return {Number} The correct value
|
||||
*/
|
||||
quadIn: function (k) { return k * k; },
|
||||
/**
|
||||
* !#en Easing out with quadratic formula. From fast to slow.
|
||||
* !#zh 平方曲线缓出函数。运动由快到慢。
|
||||
* @method quadOut
|
||||
* @param {Number} t The current time as a percentage of the total time.
|
||||
* @return {Number} The correct value
|
||||
*/
|
||||
quadOut: function (k) { return k * ( 2 - k ); },
|
||||
/**
|
||||
* !#en Easing in and out with quadratic formula. From slow to fast, then back to slow.
|
||||
* !#zh 平方曲线缓入缓出函数。运动由慢到快再到慢。
|
||||
* @method quadInOut
|
||||
* @param {Number} t The current time as a percentage of the total time.
|
||||
* @return {Number} The correct value
|
||||
*/
|
||||
quadInOut: function (k) {
|
||||
if (( k *= 2 ) < 1) {
|
||||
return 0.5 * k * k;
|
||||
}
|
||||
return -0.5 * ( --k * ( k - 2 ) - 1 );
|
||||
},
|
||||
|
||||
// cubic
|
||||
// easing equation function for a cubic (t^3)
|
||||
// @param t: Current time (in frames or seconds).
|
||||
// @return: The correct value.
|
||||
|
||||
/**
|
||||
* !#en Easing in with cubic formula. From slow to fast.
|
||||
* !#zh 立方曲线缓入函数。运动由慢到快。
|
||||
* @method cubicIn
|
||||
* @param {Number} t The current time as a percentage of the total time.
|
||||
* @return {Number} The correct value.
|
||||
*/
|
||||
cubicIn: function (k) { return k * k * k; },
|
||||
/**
|
||||
* !#en Easing out with cubic formula. From slow to fast.
|
||||
* !#zh 立方曲线缓出函数。运动由快到慢。
|
||||
* @method cubicOut
|
||||
* @param {Number} t The current time as a percentage of the total time.
|
||||
* @return {Number} The correct value.
|
||||
*/
|
||||
cubicOut: function (k) { return --k * k * k + 1; },
|
||||
/**
|
||||
* !#en Easing in and out with cubic formula. From slow to fast, then back to slow.
|
||||
* !#zh 立方曲线缓入缓出函数。运动由慢到快再到慢。
|
||||
* @method cubicInOut
|
||||
* @param {Number} t The current time as a percentage of the total time.
|
||||
* @return {Number} The correct value.
|
||||
*/
|
||||
cubicInOut: function (k) {
|
||||
if (( k *= 2 ) < 1) {
|
||||
return 0.5 * k * k * k;
|
||||
}
|
||||
return 0.5 * ( ( k -= 2 ) * k * k + 2 );
|
||||
},
|
||||
|
||||
// quart
|
||||
// easing equation function for a quartic (t^4)
|
||||
// @param t: Current time (in frames or seconds).
|
||||
// @return: The correct value.
|
||||
|
||||
/**
|
||||
* !#en Easing in with quartic formula. From slow to fast.
|
||||
* !#zh 四次方曲线缓入函数。运动由慢到快。
|
||||
* @method quartIn
|
||||
* @param {Number} t The current time as a percentage of the total time.
|
||||
* @return {Number} The correct value.
|
||||
*/
|
||||
quartIn: function (k) { return k * k * k * k; },
|
||||
/**
|
||||
* !#en Easing out with quartic formula. From fast to slow.
|
||||
* !#zh 四次方曲线缓出函数。运动由快到慢。
|
||||
* @method quartOut
|
||||
* @param {Number} t The current time as a percentage of the total time.
|
||||
* @return {Number} The correct value.
|
||||
*/
|
||||
quartOut: function (k) { return 1 - ( --k * k * k * k ); },
|
||||
/**
|
||||
* !#en Easing in and out with quartic formula. From slow to fast, then back to slow.
|
||||
* !#zh 四次方曲线缓入缓出函数。运动由慢到快再到慢。
|
||||
* @method quartInOut
|
||||
* @param {Number} t The current time as a percentage of the total time.
|
||||
* @return {Number} The correct value.
|
||||
*/
|
||||
quartInOut: function (k) {
|
||||
if (( k *= 2 ) < 1) {
|
||||
return 0.5 * k * k * k * k;
|
||||
}
|
||||
return -0.5 * ( ( k -= 2 ) * k * k * k - 2 );
|
||||
},
|
||||
|
||||
// quint
|
||||
// easing equation function for a quintic (t^5)
|
||||
// @param t: Current time (in frames or seconds).
|
||||
// @return: The correct value.
|
||||
|
||||
/**
|
||||
* !#en Easing in with quintic formula. From slow to fast.
|
||||
* !#zh 五次方曲线缓入函数。运动由慢到快。
|
||||
* @method quintIn
|
||||
* @param {Number} t The current time as a percentage of the total time.
|
||||
* @return {Number} The correct value.
|
||||
*/
|
||||
quintIn: function (k) { return k * k * k * k * k; },
|
||||
/**
|
||||
* !#en Easing out with quintic formula. From fast to slow.
|
||||
* !#zh 五次方曲线缓出函数。运动由快到慢。
|
||||
* @method quintOut
|
||||
* @param {Number} t The current time as a percentage of the total time.
|
||||
* @return {Number} The correct value.
|
||||
*/
|
||||
quintOut: function (k) { return --k * k * k * k * k + 1; },
|
||||
/**
|
||||
* !#en Easing in and out with quintic formula. From slow to fast, then back to slow.
|
||||
* !#zh 五次方曲线缓入缓出函数。运动由慢到快再到慢。
|
||||
* @method quintInOut
|
||||
* @param {Number} t The current time as a percentage of the total time.
|
||||
* @return {Number} The correct value.
|
||||
*/
|
||||
quintInOut: function (k) {
|
||||
if (( k *= 2 ) < 1) {
|
||||
return 0.5 * k * k * k * k * k;
|
||||
}
|
||||
return 0.5 * ( ( k -= 2 ) * k * k * k * k + 2 );
|
||||
},
|
||||
|
||||
// sine
|
||||
// easing equation function for a sinusoidal (sin(t))
|
||||
// @param t: Current time (in frames or seconds).
|
||||
// @return: The correct value.
|
||||
|
||||
/**
|
||||
* !#en Easing in and out with sine formula. From slow to fast.
|
||||
* !#zh 正弦曲线缓入函数。运动由慢到快。
|
||||
* @method sineIn
|
||||
* @param {Number} t The current time as a percentage of the total time.
|
||||
* @return {Number} The correct value.
|
||||
*/
|
||||
sineIn: function (k) { return 1 - Math.cos(k * Math.PI / 2); },
|
||||
/**
|
||||
* !#en Easing in and out with sine formula. From fast to slow.
|
||||
* !#zh 正弦曲线缓出函数。运动由快到慢。
|
||||
* @method sineOut
|
||||
* @param {Number} t The current time as a percentage of the total time.
|
||||
* @return {Number} The correct value.
|
||||
*/
|
||||
sineOut: function (k) { return Math.sin(k * Math.PI / 2); },
|
||||
/**
|
||||
* !#en Easing in and out with sine formula. From slow to fast, then back to slow.
|
||||
* !#zh 正弦曲线缓入缓出函数。运动由慢到快再到慢。
|
||||
* @method sineInOut
|
||||
* @param {Number} t The current time as a percentage of the total time.
|
||||
* @return {Number} The correct value.
|
||||
*/
|
||||
sineInOut: function (k) { return 0.5 * ( 1 - Math.cos(Math.PI * k) ); },
|
||||
|
||||
// expo
|
||||
// easing equation function for an exponential (2^t)
|
||||
// param t: Current time (in frames or seconds).
|
||||
// return: The correct value.
|
||||
|
||||
/**
|
||||
* !#en Easing in and out with exponential formula. From slow to fast.
|
||||
* !#zh 指数曲线缓入函数。运动由慢到快。
|
||||
* @method expoIn
|
||||
* @param {Number} t The current time as a percentage of the total time.
|
||||
* @return {Number} The correct value.
|
||||
*/
|
||||
expoIn: function (k) { return k === 0 ? 0 : Math.pow(1024, k - 1); },
|
||||
/**
|
||||
* !#en Easing in and out with exponential formula. From fast to slow.
|
||||
* !#zh 指数曲线缓出函数。运动由快到慢。
|
||||
* @method expoOut
|
||||
* @param {Number} t The current time as a percentage of the total time.
|
||||
* @return {Number} The correct value.
|
||||
*/
|
||||
expoOut: function (k) { return k === 1 ? 1 : 1 - Math.pow(2, -10 * k); },
|
||||
/**
|
||||
* !#en Easing in and out with exponential formula. From slow to fast.
|
||||
* !#zh 指数曲线缓入和缓出函数。运动由慢到很快再到慢。
|
||||
* @method expoInOut
|
||||
* @param {Number} t The current time as a percentage of the total time, then back to slow.
|
||||
* @return {Number} The correct value.
|
||||
*/
|
||||
expoInOut: function (k) {
|
||||
if (k === 0) {
|
||||
return 0;
|
||||
}
|
||||
if (k === 1) {
|
||||
return 1;
|
||||
}
|
||||
if (( k *= 2 ) < 1) {
|
||||
return 0.5 * Math.pow(1024, k - 1);
|
||||
}
|
||||
return 0.5 * ( -Math.pow(2, -10 * ( k - 1 )) + 2 );
|
||||
},
|
||||
|
||||
// circ
|
||||
// easing equation function for a circular (sqrt(1-t^2))
|
||||
// @param t: Current time (in frames or seconds).
|
||||
// @return: The correct value.
|
||||
|
||||
/**
|
||||
* !#en Easing in and out with circular formula. From slow to fast.
|
||||
* !#zh 循环公式缓入函数。运动由慢到快。
|
||||
* @method circIn
|
||||
* @param {Number} t The current time as a percentage of the total time.
|
||||
* @return {Number} The correct value.
|
||||
*/
|
||||
circIn: function (k) { return 1 - Math.sqrt(1 - k * k); },
|
||||
/**
|
||||
* !#en Easing in and out with circular formula. From fast to slow.
|
||||
* !#zh 循环公式缓出函数。运动由快到慢。
|
||||
* @method circOut
|
||||
* @param {Number} t The current time as a percentage of the total time.
|
||||
* @return {Number} The correct value.
|
||||
*/
|
||||
circOut: function (k) { return Math.sqrt(1 - ( --k * k )); },
|
||||
/**
|
||||
* !#en Easing in and out with circular formula. From slow to fast.
|
||||
* !#zh 指数曲线缓入缓出函数。运动由慢到很快再到慢。
|
||||
* @method circInOut
|
||||
* @param {Number} t The current time as a percentage of the total time, then back to slow.
|
||||
* @return {Number} The correct value.
|
||||
*/
|
||||
circInOut: function (k) {
|
||||
if (( k *= 2 ) < 1) {
|
||||
return -0.5 * ( Math.sqrt(1 - k * k) - 1);
|
||||
}
|
||||
return 0.5 * ( Math.sqrt(1 - ( k -= 2) * k) + 1);
|
||||
},
|
||||
|
||||
// elastic
|
||||
// easing equation function for an elastic (exponentially decaying sine wave)
|
||||
// @param t: Current time (in frames or seconds).
|
||||
// @return: The correct value.
|
||||
// recommand value: elastic (t)
|
||||
|
||||
/**
|
||||
* !#en Easing in action with a spring oscillating effect.
|
||||
* !#zh 弹簧回震效果的缓入函数。
|
||||
* @method elasticIn
|
||||
* @param {Number} t The current time as a percentage of the total time.
|
||||
* @return {Number} The correct value.
|
||||
*/
|
||||
elasticIn: function (k) {
|
||||
var s, a = 0.1, p = 0.4;
|
||||
if (k === 0) {
|
||||
return 0;
|
||||
}
|
||||
if (k === 1) {
|
||||
return 1;
|
||||
}
|
||||
if (!a || a < 1) {
|
||||
a = 1;
|
||||
s = p / 4;
|
||||
}
|
||||
else {
|
||||
s = p * Math.asin(1 / a) / ( 2 * Math.PI );
|
||||
}
|
||||
return -( a * Math.pow(2, 10 * ( k -= 1 )) * Math.sin(( k - s ) * ( 2 * Math.PI ) / p) );
|
||||
},
|
||||
/**
|
||||
* !#en Easing out action with a spring oscillating effect.
|
||||
* !#zh 弹簧回震效果的缓出函数。
|
||||
* @method elasticOut
|
||||
* @param {Number} t The current time as a percentage of the total time.
|
||||
* @return {Number} The correct value.
|
||||
*/
|
||||
elasticOut: function (k) {
|
||||
var s, a = 0.1, p = 0.4;
|
||||
if (k === 0) {
|
||||
return 0;
|
||||
}
|
||||
if (k === 1) {
|
||||
return 1;
|
||||
}
|
||||
if (!a || a < 1) {
|
||||
a = 1;
|
||||
s = p / 4;
|
||||
}
|
||||
else {
|
||||
s = p * Math.asin(1 / a) / ( 2 * Math.PI );
|
||||
}
|
||||
return ( a * Math.pow(2, -10 * k) * Math.sin(( k - s ) * ( 2 * Math.PI ) / p) + 1 );
|
||||
},
|
||||
/**
|
||||
* !#en Easing in and out action with a spring oscillating effect.
|
||||
* !#zh 弹簧回震效果的缓入缓出函数。
|
||||
* @method elasticInOut
|
||||
* @param {Number} t The current time as a percentage of the total time.
|
||||
* @return {Number} The correct value.
|
||||
*/
|
||||
elasticInOut: function (k) {
|
||||
var s, a = 0.1, p = 0.4;
|
||||
if (k === 0) {
|
||||
return 0;
|
||||
}
|
||||
if (k === 1) {
|
||||
return 1;
|
||||
}
|
||||
if (!a || a < 1) {
|
||||
a = 1;
|
||||
s = p / 4;
|
||||
}
|
||||
else {
|
||||
s = p * Math.asin(1 / a) / ( 2 * Math.PI );
|
||||
}
|
||||
if (( k *= 2 ) < 1) {
|
||||
return -0.5 *
|
||||
( a * Math.pow(2, 10 * ( k -= 1 )) * Math.sin(( k - s ) * ( 2 * Math.PI ) / p) );
|
||||
}
|
||||
return a * Math.pow(2, -10 * ( k -= 1 )) * Math.sin(( k - s ) * ( 2 * Math.PI ) / p) * 0.5 + 1;
|
||||
},
|
||||
|
||||
// back
|
||||
// easing equation function for a back (overshooting cubic easing: (s+1)*t^3 - s*t^2)
|
||||
// @param t: Current time (in frames or seconds).
|
||||
// @return: The correct value.
|
||||
|
||||
/**
|
||||
* !#en Easing in action with "back up" behavior.
|
||||
* !#zh 回退效果的缓入函数。
|
||||
* @method backIn
|
||||
* @param {Number} t The current time as a percentage of the total time.
|
||||
* @return {Number} The correct value.
|
||||
*/
|
||||
backIn: function (k) {
|
||||
var s = 1.70158;
|
||||
return k * k * ( ( s + 1 ) * k - s );
|
||||
},
|
||||
/**
|
||||
* !#en Easing out action with "back up" behavior.
|
||||
* !#zh 回退效果的缓出函数。
|
||||
* @method backOut
|
||||
* @param {Number} t The current time as a percentage of the total time.
|
||||
* @return {Number} The correct value.
|
||||
*/
|
||||
backOut: function (k) {
|
||||
var s = 1.70158;
|
||||
return --k * k * ( ( s + 1 ) * k + s ) + 1;
|
||||
},
|
||||
/**
|
||||
* !#en Easing in and out action with "back up" behavior.
|
||||
* !#zh 回退效果的缓入缓出函数。
|
||||
* @method backInOut
|
||||
* @param {Number} t The current time as a percentage of the total time.
|
||||
* @return {Number} The correct value.
|
||||
*/
|
||||
backInOut: function (k) {
|
||||
var s = 1.70158 * 1.525;
|
||||
if (( k *= 2 ) < 1) {
|
||||
return 0.5 * ( k * k * ( ( s + 1 ) * k - s ) );
|
||||
}
|
||||
return 0.5 * ( ( k -= 2 ) * k * ( ( s + 1 ) * k + s ) + 2 );
|
||||
},
|
||||
|
||||
// bounce
|
||||
// easing equation function for a bounce (exponentially decaying parabolic bounce)
|
||||
// @param t: Current time (in frames or seconds).
|
||||
// @return: The correct value.
|
||||
|
||||
/**
|
||||
* !#en Easing in action with bouncing effect.
|
||||
* !#zh 弹跳效果的缓入函数。
|
||||
* @method bounceIn
|
||||
* @param {Number} t The current time as a percentage of the total time.
|
||||
* @return {Number} The correct value.
|
||||
*/
|
||||
bounceIn: function (k) {
|
||||
return 1 - easing.bounceOut(1 - k);
|
||||
},
|
||||
/**
|
||||
* !#en Easing out action with bouncing effect.
|
||||
* !#zh 弹跳效果的缓出函数。
|
||||
* @method bounceOut
|
||||
* @param {Number} t The current time as a percentage of the total time.
|
||||
* @return {Number} The correct value.
|
||||
*/
|
||||
bounceOut: function (k) {
|
||||
if (k < ( 1 / 2.75 )) {
|
||||
return 7.5625 * k * k;
|
||||
}
|
||||
else if (k < ( 2 / 2.75 )) {
|
||||
return 7.5625 * ( k -= ( 1.5 / 2.75 ) ) * k + 0.75;
|
||||
}
|
||||
else if (k < ( 2.5 / 2.75 )) {
|
||||
return 7.5625 * ( k -= ( 2.25 / 2.75 ) ) * k + 0.9375;
|
||||
}
|
||||
else {
|
||||
return 7.5625 * ( k -= ( 2.625 / 2.75 ) ) * k + 0.984375;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* !#en Easing in and out action with bouncing effect.
|
||||
* !#zh 弹跳效果的缓入缓出函数。
|
||||
* @method bounceInOut
|
||||
* @param {Number} t The current time as a percentage of the total time.
|
||||
* @return {Number} The correct value.
|
||||
*/
|
||||
bounceInOut: function (k) {
|
||||
if (k < 0.5) {
|
||||
return easing.bounceIn(k * 2) * 0.5;
|
||||
}
|
||||
return easing.bounceOut(k * 2 - 1) * 0.5 + 0.5;
|
||||
},
|
||||
|
||||
/**
|
||||
* !#en Target will run action with smooth effect.
|
||||
* !#zh 平滑效果函数。
|
||||
* @method smooth
|
||||
* @param {Number} t The current time as a percentage of the total time.
|
||||
* @return {Number} The correct value.
|
||||
*/
|
||||
// t<=0: 0 | 0<t<1: 3*t^2 - 2*t^3 | t>=1: 1
|
||||
smooth: function (t) {
|
||||
if (t <= 0) {
|
||||
return 0;
|
||||
}
|
||||
if (t >= 1) {
|
||||
return 1;
|
||||
}
|
||||
return t * t * (3 - 2 * t);
|
||||
},
|
||||
|
||||
/**
|
||||
* !#en Target will run action with fade effect.
|
||||
* !#zh 渐褪效果函数。
|
||||
* @method fade
|
||||
* @param {Number} t The current time as a percentage of the total time.
|
||||
* @return {Number} The correct value.
|
||||
*/
|
||||
// t<=0: 0 | 0<t<1: 6*t^5 - 15*t^4 + 10*t^3 | t>=1: 1
|
||||
fade: function (t) {
|
||||
if (t <= 0) {
|
||||
return 0;
|
||||
}
|
||||
if (t >= 1) {
|
||||
return 1;
|
||||
}
|
||||
return t * t * t * (t * (t * 6 - 15) + 10);
|
||||
},
|
||||
};
|
||||
|
||||
function _makeOutIn (fnIn, fnOut) {
|
||||
return function (k) {
|
||||
if (k < 0.5) {
|
||||
return fnOut(k * 2) / 2;
|
||||
}
|
||||
return fnIn(2 * k - 1) / 2 + 0.5;
|
||||
};
|
||||
}
|
||||
easing.quadOutIn = _makeOutIn(easing.quadIn, easing.quadOut);
|
||||
easing.cubicOutIn = _makeOutIn(easing.cubicIn, easing.cubicOut);
|
||||
easing.quartOutIn = _makeOutIn(easing.quartIn, easing.quartOut);
|
||||
easing.quintOutIn = _makeOutIn(easing.quintIn, easing.quintOut);
|
||||
easing.sineOutIn = _makeOutIn(easing.sineIn, easing.sineOut);
|
||||
easing.expoOutIn = _makeOutIn(easing.expoIn, easing.expoOut);
|
||||
easing.circOutIn = _makeOutIn(easing.circIn, easing.circOut);
|
||||
easing.backOutIn = _makeOutIn(easing.backIn, easing.backOut);
|
||||
easing.bounceIn = function (k) { return 1 - easing.bounceOut(1 - k); };
|
||||
easing.bounceInOut = function (k) {
|
||||
if (k < 0.5) {
|
||||
return easing.bounceIn(k * 2) * 0.5;
|
||||
}
|
||||
return easing.bounceOut(k * 2 - 1) * 0.5 + 0.5;
|
||||
};
|
||||
easing.bounceOutIn = _makeOutIn(easing.bounceIn, easing.bounceOut);
|
||||
|
||||
/**
|
||||
* @module cc
|
||||
*/
|
||||
|
||||
/**
|
||||
* !#en This is a Easing instance.
|
||||
* !#zh 这是一个 Easing 类实例。
|
||||
* @property easing
|
||||
* @type Easing
|
||||
*/
|
||||
|
||||
cc.easing = module.exports = easing;
|
||||
34
engine/cocos2d/animation/index.js
Normal file
34
engine/cocos2d/animation/index.js
Normal file
@@ -0,0 +1,34 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
https://www.cocos.com/
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated engine source code (the "Software"), a limited,
|
||||
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
|
||||
to use Cocos Creator solely to develop games on your target platforms. You shall
|
||||
not use Cocos Creator software for developing other software or tools that's
|
||||
used for developing games. You are not granted to publish, distribute,
|
||||
sublicense, and/or sell copies of Cocos Creator.
|
||||
|
||||
The software or tools in this License Agreement are licensed, not sold.
|
||||
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
require('./bezier');
|
||||
require('./easing');
|
||||
require('./types');
|
||||
require('./motion-path-helper');
|
||||
require('./animation-curves');
|
||||
require('./animation-clip');
|
||||
require('./animation-manager');
|
||||
require('./animation-state');
|
||||
require('./animation-animator');
|
||||
415
engine/cocos2d/animation/motion-path-helper.js
Normal file
415
engine/cocos2d/animation/motion-path-helper.js
Normal file
@@ -0,0 +1,415 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
https://www.cocos.com/
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated engine source code (the "Software"), a limited,
|
||||
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
|
||||
to use Cocos Creator solely to develop games on your target platforms. You shall
|
||||
not use Cocos Creator software for developing other software or tools that's
|
||||
used for developing games. You are not granted to publish, distribute,
|
||||
sublicense, and/or sell copies of Cocos Creator.
|
||||
|
||||
The software or tools in this License Agreement are licensed, not sold.
|
||||
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
var DynamicAnimCurve = require('./animation-curves').DynamicAnimCurve;
|
||||
var computeRatioByType = require('./animation-curves').computeRatioByType;
|
||||
|
||||
var bezier = require('./bezier').bezier;
|
||||
var binarySearch = require('../core/utils/binary-search').binarySearchEpsilon;
|
||||
|
||||
var v2 = cc.v2;
|
||||
|
||||
function Curve (points) {
|
||||
this.points = points || [];
|
||||
this.beziers = [];
|
||||
this.ratios = [];
|
||||
this.progresses = [];
|
||||
|
||||
this.length = 0;
|
||||
|
||||
this.computeBeziers();
|
||||
}
|
||||
Curve.prototype.computeBeziers = function () {
|
||||
this.beziers.length = 0;
|
||||
this.ratios.length = 0;
|
||||
this.progresses.length = 0;
|
||||
this.length = 0;
|
||||
|
||||
var bezier;
|
||||
|
||||
for (var i = 1; i < this.points.length; i++) {
|
||||
var startPoint = this.points[i - 1];
|
||||
var endPoint = this.points[i];
|
||||
bezier = new Bezier();
|
||||
bezier.start = startPoint.pos;
|
||||
bezier.startCtrlPoint = startPoint.out;
|
||||
bezier.end = endPoint.pos;
|
||||
bezier.endCtrlPoint = endPoint.in;
|
||||
this.beziers.push(bezier);
|
||||
|
||||
this.length += bezier.getLength();
|
||||
}
|
||||
|
||||
var current = 0;
|
||||
for (var i = 0; i < this.beziers.length; i++) {
|
||||
bezier = this.beziers[i];
|
||||
this.ratios[i] = bezier.getLength() / this.length;
|
||||
this.progresses[i] = current = current + this.ratios[i];
|
||||
}
|
||||
|
||||
return this.beziers;
|
||||
};
|
||||
|
||||
function Bezier () {
|
||||
this.start = v2();
|
||||
this.end = v2();
|
||||
this.startCtrlPoint = v2(); // cp0, cp1
|
||||
this.endCtrlPoint = v2(); // cp2, cp3
|
||||
}
|
||||
|
||||
// Get point at relative position in curve according to arc length
|
||||
// - u [0 .. 1]
|
||||
Bezier.prototype.getPointAt = function ( u ) {
|
||||
var t = this.getUtoTmapping( u );
|
||||
return this.getPoint( t );
|
||||
};
|
||||
|
||||
|
||||
// Get point at time t
|
||||
// - t [0 .. 1]
|
||||
Bezier.prototype.getPoint = function ( t ) {
|
||||
var x = bezier(this.start.x, this.startCtrlPoint.x, this.endCtrlPoint.x, this.end.x, t);
|
||||
var y = bezier(this.start.y, this.startCtrlPoint.y, this.endCtrlPoint.y, this.end.y, t);
|
||||
|
||||
return new v2(x, y);
|
||||
};
|
||||
|
||||
// Get total curve arc length
|
||||
Bezier.prototype.getLength = function () {
|
||||
|
||||
var lengths = this.getLengths();
|
||||
return lengths[ lengths.length - 1 ];
|
||||
|
||||
};
|
||||
|
||||
// Get list of cumulative segment lengths
|
||||
Bezier.prototype.getLengths = function ( divisions ) {
|
||||
|
||||
if ( ! divisions ) divisions = (this.__arcLengthDivisions) ? (this.__arcLengthDivisions): 200;
|
||||
|
||||
if ( this.cacheArcLengths
|
||||
&& ( this.cacheArcLengths.length === divisions + 1 )) {
|
||||
|
||||
//console.log( "cached", this.cacheArcLengths );
|
||||
return this.cacheArcLengths;
|
||||
|
||||
}
|
||||
|
||||
var cache = [];
|
||||
var current, last = this.getPoint( 0 ), vector = v2();
|
||||
var p, sum = 0;
|
||||
|
||||
cache.push( 0 );
|
||||
|
||||
for ( p = 1; p <= divisions; p ++ ) {
|
||||
|
||||
current = this.getPoint ( p / divisions );
|
||||
vector.x = last.x - current.x;
|
||||
vector.y = last.y - current.y;
|
||||
sum += vector.mag();
|
||||
cache.push( sum );
|
||||
last = current;
|
||||
|
||||
}
|
||||
|
||||
this.cacheArcLengths = cache;
|
||||
|
||||
return cache; // { sums: cache, sum:sum }; Sum is in the last element.
|
||||
};
|
||||
|
||||
Bezier.prototype.getUtoTmapping = function ( u, distance ) {
|
||||
|
||||
var arcLengths = this.getLengths();
|
||||
|
||||
var i = 0, il = arcLengths.length;
|
||||
|
||||
var targetArcLength; // The targeted u distance value to get
|
||||
|
||||
if ( distance ) {
|
||||
targetArcLength = distance;
|
||||
} else {
|
||||
targetArcLength = u * arcLengths[ il - 1 ];
|
||||
}
|
||||
|
||||
//var time = Date.now();
|
||||
|
||||
// binary search for the index with largest value smaller than target u distance
|
||||
|
||||
var low = 0, high = il - 1, comparison;
|
||||
|
||||
while ( low <= high ) {
|
||||
|
||||
i = Math.floor( low + ( high - low ) / 2 ); // less likely to overflow, though probably not issue here, JS doesn't really have integers, all numbers are floats
|
||||
|
||||
comparison = arcLengths[ i ] - targetArcLength;
|
||||
|
||||
if ( comparison < 0 ) {
|
||||
|
||||
low = i + 1;
|
||||
continue;
|
||||
|
||||
} else if ( comparison > 0 ) {
|
||||
|
||||
high = i - 1;
|
||||
continue;
|
||||
|
||||
} else {
|
||||
|
||||
high = i;
|
||||
break;
|
||||
|
||||
// DONE
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
i = high;
|
||||
|
||||
//console.log('b' , i, low, high, Date.now()- time);
|
||||
|
||||
if ( arcLengths[ i ] === targetArcLength ) {
|
||||
|
||||
var t = i / ( il - 1 );
|
||||
return t;
|
||||
|
||||
}
|
||||
|
||||
// we could get finer grain at lengths, or use simple interpolatation between two points
|
||||
|
||||
var lengthBefore = arcLengths[ i ];
|
||||
var lengthAfter = arcLengths[ i + 1 ];
|
||||
|
||||
var segmentLength = lengthAfter - lengthBefore;
|
||||
|
||||
// determine where we are between the 'before' and 'after' points
|
||||
|
||||
var segmentFraction = ( targetArcLength - lengthBefore ) / segmentLength;
|
||||
|
||||
// add that fractional amount to t
|
||||
|
||||
var t = ( i + segmentFraction ) / ( il -1 );
|
||||
|
||||
return t;
|
||||
};
|
||||
|
||||
|
||||
function checkMotionPath(motionPath) {
|
||||
if (!Array.isArray(motionPath)) return false;
|
||||
|
||||
for (let i = 0, l = motionPath.length; i < l; i++) {
|
||||
let controls = motionPath[i];
|
||||
|
||||
if (!Array.isArray(controls) || controls.length !== 6) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function sampleMotionPaths (motionPaths, data, duration, fps, target) {
|
||||
|
||||
function createControlPoints(array) {
|
||||
if (array instanceof cc.Vec2) {
|
||||
return {
|
||||
in: array,
|
||||
pos: array,
|
||||
out: array
|
||||
};
|
||||
}
|
||||
else if (Array.isArray(array) && array.length === 6) {
|
||||
return {
|
||||
in: v2(array[2], array[3]),
|
||||
pos: v2(array[0], array[1]),
|
||||
out: v2(array[4], array[5])
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
in: cc.Vec2.ZERO,
|
||||
pos: cc.Vec2.ZERO,
|
||||
out: cc.Vec2.ZERO
|
||||
};
|
||||
}
|
||||
|
||||
let values = data.values = data.values.map(function (value) {
|
||||
if (Array.isArray(value)) {
|
||||
value = value.length === 2 ? cc.v2(value[0], value[1]) : cc.v3(value[0], value[1], value[2]);
|
||||
}
|
||||
return value;
|
||||
});
|
||||
|
||||
if (motionPaths.length === 0 || values.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
let motionPathValid = false;
|
||||
for (let i = 0; i < motionPaths.length; i++) {
|
||||
let motionPath = motionPaths[i];
|
||||
if (motionPath && !checkMotionPath(motionPath)) {
|
||||
cc.errorID(3904, target ? target.name : '', 'position', i);
|
||||
motionPath = null;
|
||||
}
|
||||
if (motionPath && motionPath.length > 0) {
|
||||
motionPathValid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!motionPathValid) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (values.length === 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
var types = data.types;
|
||||
var ratios = data.ratios;
|
||||
|
||||
var newValues = data.values = [];
|
||||
var newTypes = data.types = [];
|
||||
var newRatios = data.ratios = [];
|
||||
|
||||
function addNewDatas (value, type, ratio) {
|
||||
newValues.push(value);
|
||||
newTypes.push(type);
|
||||
newRatios.push(ratio);
|
||||
}
|
||||
|
||||
// ensure every ratio section's length is the same
|
||||
var startRatioOffset = 0;
|
||||
|
||||
var EPSILON = 1e-6;
|
||||
var newType = DynamicAnimCurve.Linear;
|
||||
|
||||
// do not need to compute last path
|
||||
for (var i = 0, l = motionPaths.length; i < l-1; i++) {
|
||||
var motionPath = motionPaths[i];
|
||||
|
||||
var ratio = ratios[i];
|
||||
var nextRatio = ratios[i + 1];
|
||||
var betweenRatio = nextRatio - ratio;
|
||||
|
||||
var value = values[i];
|
||||
var nextValue = values[i + 1];
|
||||
|
||||
var type = types[i];
|
||||
|
||||
var results = [];
|
||||
var progress = startRatioOffset / betweenRatio;
|
||||
var speed = 1 / (betweenRatio * duration * fps);
|
||||
var finalProgress;
|
||||
|
||||
if (motionPath && motionPath.length > 0) {
|
||||
var points = [];
|
||||
points.push(createControlPoints(value));
|
||||
|
||||
for (var j = 0, l2 = motionPath.length; j < l2; j++) {
|
||||
var controlPoints = createControlPoints(motionPath[j]);
|
||||
points.push(controlPoints);
|
||||
}
|
||||
|
||||
points.push(createControlPoints(nextValue));
|
||||
|
||||
// create Curve to compute beziers
|
||||
var curve = new Curve(points);
|
||||
curve.computeBeziers();
|
||||
|
||||
// sample beziers
|
||||
var progresses = curve.progresses;
|
||||
|
||||
while ( 1 - progress > EPSILON) {
|
||||
finalProgress = progress;
|
||||
|
||||
finalProgress = computeRatioByType(finalProgress, type);
|
||||
|
||||
var pos, bezier, normal, length;
|
||||
|
||||
if (finalProgress < 0) {
|
||||
bezier = curve.beziers[0];
|
||||
length = (0 - finalProgress) * bezier.getLength();
|
||||
normal = bezier.start.sub(bezier.endCtrlPoint).normalize();
|
||||
pos = bezier.start.add(normal.mul(length));
|
||||
}
|
||||
else if (finalProgress > 1) {
|
||||
bezier = curve.beziers[curve.beziers.length - 1];
|
||||
length = (finalProgress - 1) * bezier.getLength();
|
||||
normal = bezier.end.sub(bezier.startCtrlPoint).normalize();
|
||||
pos = bezier.end.add(normal.mul(length));
|
||||
}
|
||||
else {
|
||||
var bezierIndex = binarySearch(progresses, finalProgress);
|
||||
if (bezierIndex < 0) bezierIndex = ~bezierIndex;
|
||||
|
||||
finalProgress -= bezierIndex > 0 ? progresses[bezierIndex - 1] : 0;
|
||||
finalProgress = finalProgress / curve.ratios[bezierIndex];
|
||||
|
||||
pos = curve.beziers[bezierIndex].getPointAt(finalProgress);
|
||||
}
|
||||
|
||||
results.push(pos);
|
||||
progress += speed;
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
while ( 1 - progress > EPSILON) {
|
||||
finalProgress = progress;
|
||||
|
||||
finalProgress = computeRatioByType(finalProgress, type);
|
||||
|
||||
results.push(value.lerp(nextValue, finalProgress));
|
||||
|
||||
progress += speed;
|
||||
}
|
||||
}
|
||||
|
||||
newType = type === 'constant' ? type : DynamicAnimCurve.Linear;
|
||||
|
||||
for (var j = 0, l2 = results.length; j < l2; j++) {
|
||||
var newRatio = ratio + startRatioOffset + speed * j * betweenRatio;
|
||||
addNewDatas(results[j], newType, newRatio);
|
||||
}
|
||||
|
||||
if (Math.abs(progress - 1) > EPSILON) // progress > 1
|
||||
startRatioOffset = (progress - 1) * betweenRatio;
|
||||
else
|
||||
startRatioOffset = 0;
|
||||
}
|
||||
|
||||
if (ratios[ratios.length - 1] !== newRatios[newRatios.length -1]) {
|
||||
addNewDatas(values[values.length - 1], newType, ratios[ratios.length - 1]);
|
||||
}
|
||||
}
|
||||
|
||||
if (CC_TEST) {
|
||||
cc._Test.sampleMotionPaths = sampleMotionPaths;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
sampleMotionPaths: sampleMotionPaths,
|
||||
Curve: Curve,
|
||||
Bezier: Bezier
|
||||
};
|
||||
170
engine/cocos2d/animation/playable.js
Normal file
170
engine/cocos2d/animation/playable.js
Normal file
@@ -0,0 +1,170 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
https://www.cocos.com/
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated engine source code (the "Software"), a limited,
|
||||
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
|
||||
to use Cocos Creator solely to develop games on your target platforms. You shall
|
||||
not use Cocos Creator software for developing other software or tools that's
|
||||
used for developing games. You are not granted to publish, distribute,
|
||||
sublicense, and/or sell copies of Cocos Creator.
|
||||
|
||||
The software or tools in this License Agreement are licensed, not sold.
|
||||
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
var js = cc.js;
|
||||
const debug = require('../core/CCDebug');
|
||||
|
||||
/**
|
||||
* @class Playable
|
||||
*
|
||||
*/
|
||||
function Playable () {
|
||||
this._isPlaying = false;
|
||||
this._isPaused = false;
|
||||
this._stepOnce = false;
|
||||
}
|
||||
|
||||
var prototype = Playable.prototype;
|
||||
|
||||
/**
|
||||
* !#en Is playing or paused in play mode?
|
||||
* !#zh 当前是否正在播放。
|
||||
* @property isPlaying
|
||||
* @type {boolean}
|
||||
* @default false
|
||||
* @readOnly
|
||||
*/
|
||||
js.get(prototype, 'isPlaying', function () {
|
||||
return this._isPlaying;
|
||||
}, true);
|
||||
|
||||
/**
|
||||
* !#en Is currently paused? This can be true even if in edit mode(isPlaying == false).
|
||||
* !#zh 当前是否正在暂停
|
||||
* @property isPaused
|
||||
* @type {boolean}
|
||||
* @default false
|
||||
* @readOnly
|
||||
*/
|
||||
js.get(prototype, 'isPaused', function () {
|
||||
return this._isPaused;
|
||||
}, true);
|
||||
|
||||
// virtual
|
||||
|
||||
var virtual = function () {};
|
||||
/**
|
||||
* @method onPlay
|
||||
* @private
|
||||
*/
|
||||
prototype.onPlay = virtual;
|
||||
/**
|
||||
* @method onPause
|
||||
* @private
|
||||
*/
|
||||
prototype.onPause = virtual;
|
||||
/**
|
||||
* @method onResume
|
||||
* @private
|
||||
*/
|
||||
prototype.onResume = virtual;
|
||||
/**
|
||||
* @method onStop
|
||||
* @private
|
||||
*/
|
||||
prototype.onStop = virtual;
|
||||
/**
|
||||
* @method onError
|
||||
* @param {string} errorCode
|
||||
* @private
|
||||
*/
|
||||
prototype.onError = virtual;
|
||||
|
||||
// public
|
||||
|
||||
/**
|
||||
* !#en Play this animation.
|
||||
* !#zh 播放动画。
|
||||
* @method play
|
||||
*/
|
||||
prototype.play = function () {
|
||||
if (this._isPlaying) {
|
||||
if (this._isPaused) {
|
||||
this._isPaused = false;
|
||||
this.onResume();
|
||||
}
|
||||
else {
|
||||
this.onError(debug.getError(3912));
|
||||
}
|
||||
}
|
||||
else {
|
||||
this._isPlaying = true;
|
||||
this.onPlay();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* !#en Stop this animation.
|
||||
* !#zh 停止动画播放。
|
||||
* @method stop
|
||||
*/
|
||||
prototype.stop = function () {
|
||||
if (this._isPlaying) {
|
||||
this._isPlaying = false;
|
||||
this.onStop();
|
||||
|
||||
// need reset pause flag after onStop
|
||||
this._isPaused = false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* !#en Pause this animation.
|
||||
* !#zh 暂停动画。
|
||||
* @method pause
|
||||
*/
|
||||
prototype.pause = function () {
|
||||
if (this._isPlaying && !this._isPaused) {
|
||||
this._isPaused = true;
|
||||
this.onPause();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* !#en Resume this animation.
|
||||
* !#zh 重新播放动画。
|
||||
* @method resume
|
||||
*/
|
||||
prototype.resume = function () {
|
||||
if (this._isPlaying && this._isPaused) {
|
||||
this._isPaused = false;
|
||||
this.onResume();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* !#en Perform a single frame step.
|
||||
* !#zh 执行一帧动画。
|
||||
* @method step
|
||||
*/
|
||||
prototype.step = function () {
|
||||
this.pause();
|
||||
this._stepOnce = true;
|
||||
if (!this._isPlaying) {
|
||||
this.play();
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = Playable;
|
||||
125
engine/cocos2d/animation/types.js
Normal file
125
engine/cocos2d/animation/types.js
Normal file
@@ -0,0 +1,125 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
https://www.cocos.com/
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated engine source code (the "Software"), a limited,
|
||||
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
|
||||
to use Cocos Creator solely to develop games on your target platforms. You shall
|
||||
not use Cocos Creator software for developing other software or tools that's
|
||||
used for developing games. You are not granted to publish, distribute,
|
||||
sublicense, and/or sell copies of Cocos Creator.
|
||||
|
||||
The software or tools in this License Agreement are licensed, not sold.
|
||||
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
var WrapModeMask = {
|
||||
Loop: 1 << 1,
|
||||
ShouldWrap: 1 << 2,
|
||||
// Reserved: 1 << 3,
|
||||
PingPong: 1 << 4 | 1 << 1 | 1 << 2, // Loop, ShouldWrap
|
||||
Reverse: 1 << 5 | 1 << 2, // ShouldWrap
|
||||
};
|
||||
|
||||
/**
|
||||
* !#en Specifies how time is treated when it is outside of the keyframe range of an Animation.
|
||||
* !#zh 动画使用的循环模式。
|
||||
* @enum WrapMode
|
||||
* @memberof cc
|
||||
*/
|
||||
var WrapMode = cc.Enum({
|
||||
|
||||
/**
|
||||
* !#en Reads the default wrap mode set higher up.
|
||||
* !#zh 向 Animation Component 或者 AnimationClip 查找 wrapMode
|
||||
* @property {Number} Default
|
||||
*/
|
||||
Default: 0,
|
||||
|
||||
/**
|
||||
* !#en All iterations are played as specified.
|
||||
* !#zh 动画只播放一遍
|
||||
* @property {Number} Normal
|
||||
*/
|
||||
Normal: 1,
|
||||
|
||||
/**
|
||||
* !#en All iterations are played in the reverse direction from the way they are specified.
|
||||
* !#zh 从最后一帧或结束位置开始反向播放,到第一帧或开始位置停止
|
||||
* @property {Number} Reverse
|
||||
*/
|
||||
Reverse: WrapModeMask.Reverse,
|
||||
|
||||
/**
|
||||
* !#en When time reaches the end of the animation, time will continue at the beginning.
|
||||
* !#zh 循环播放
|
||||
* @property {Number} Loop
|
||||
*/
|
||||
Loop: WrapModeMask.Loop,
|
||||
|
||||
/**
|
||||
* !#en All iterations are played in the reverse direction from the way they are specified.
|
||||
* And when time reaches the start of the animation, time will continue at the ending.
|
||||
* !#zh 反向循环播放
|
||||
* @property {Number} LoopReverse
|
||||
*/
|
||||
LoopReverse: WrapModeMask.Loop | WrapModeMask.Reverse,
|
||||
|
||||
/**
|
||||
* !#en Even iterations are played as specified, odd iterations are played in the reverse direction from the way they
|
||||
* are specified.
|
||||
* !#zh 从第一帧播放到最后一帧,然后反向播放回第一帧,到第一帧后再正向播放,如此循环
|
||||
* @property {Number} PingPong
|
||||
*/
|
||||
PingPong: WrapModeMask.PingPong,
|
||||
|
||||
/**
|
||||
* !#en Even iterations are played in the reverse direction from the way they are specified, odd iterations are played
|
||||
* as specified.
|
||||
* !#zh 从最后一帧开始反向播放,其他同 PingPong
|
||||
* @property {Number} PingPongReverse
|
||||
*/
|
||||
PingPongReverse: WrapModeMask.PingPong | WrapModeMask.Reverse
|
||||
});
|
||||
|
||||
cc.WrapMode = WrapMode;
|
||||
|
||||
// For internal
|
||||
function WrappedInfo (info) {
|
||||
if (info) {
|
||||
this.set(info);
|
||||
return;
|
||||
}
|
||||
|
||||
this.ratio = 0;
|
||||
this.time = 0;
|
||||
this.direction = 1;
|
||||
this.stopped = true;
|
||||
this.iterations = 0;
|
||||
this.frameIndex = undefined;
|
||||
}
|
||||
|
||||
WrappedInfo.prototype.set = function (info) {
|
||||
this.ratio = info.ratio;
|
||||
this.time = info.time;
|
||||
this.direction = info.direction;
|
||||
this.stopped = info.stopped;
|
||||
this.iterations = info.iterations;
|
||||
this.frameIndex = info.frameIndex;
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
WrapModeMask,
|
||||
WrapMode,
|
||||
WrappedInfo
|
||||
};
|
||||
Reference in New Issue
Block a user