内置tween管理器
This commit is contained in:
@@ -43,6 +43,7 @@ module es {
|
||||
Core.emitter.addObserver(CoreEvents.frameUpdated, this.update, this);
|
||||
|
||||
Core.registerGlobalManager(this._coroutineManager);
|
||||
Core.registerGlobalManager(new TweenManager());
|
||||
Core.registerGlobalManager(this._timerManager);
|
||||
Core.entitySystemsEnabled = enableEntitySystems;
|
||||
|
||||
|
||||
@@ -3,11 +3,11 @@ module es {
|
||||
public getwidth() {
|
||||
return this.bounds.width;
|
||||
}
|
||||
|
||||
|
||||
public getheight() {
|
||||
return this.bounds.height;
|
||||
}
|
||||
|
||||
|
||||
protected _bounds: es.Rectangle = new es.Rectangle();
|
||||
public getbounds(): es.Rectangle {
|
||||
if (this._areBoundsDirty) {
|
||||
@@ -21,44 +21,45 @@ module es {
|
||||
return this.getbounds();
|
||||
}
|
||||
protected _areBoundsDirty: boolean = true;
|
||||
|
||||
public color: Color = Color.White;
|
||||
|
||||
public get renderLayer() {
|
||||
return this._renderLayer;
|
||||
}
|
||||
public set renderLayer(value: number) {
|
||||
this.setRenderLayer(value);
|
||||
}
|
||||
|
||||
|
||||
protected _renderLayer: number = 0;
|
||||
|
||||
|
||||
public onEntityTransformChanged(comp: transform.Component) {
|
||||
this._areBoundsDirty = true;
|
||||
}
|
||||
|
||||
|
||||
public get localOffset() {
|
||||
return this._localOffset;
|
||||
}
|
||||
public set localOffset(value: es.Vector2) {
|
||||
this.setLocalOffset(value);
|
||||
}
|
||||
|
||||
|
||||
public setLocalOffset(offset: es.Vector2) {
|
||||
if (!this._localOffset.equals(offset)) {
|
||||
this._localOffset = offset;
|
||||
this._areBoundsDirty = true;
|
||||
}
|
||||
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public get isVisible() {
|
||||
return this._isVisible;
|
||||
}
|
||||
|
||||
|
||||
public set isVisible(value: boolean) {
|
||||
if (this._isVisible != value) {
|
||||
this._isVisible = value;
|
||||
|
||||
|
||||
if (this._isVisible) {
|
||||
this.onBecameVisible();
|
||||
} else {
|
||||
@@ -66,44 +67,44 @@ module es {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public debugRenderEnabled: boolean = true;
|
||||
|
||||
|
||||
protected _isVisible: boolean = false;
|
||||
protected _localOffset: es.Vector2 = new es.Vector2();
|
||||
|
||||
|
||||
public abstract render(batcher: IBatcher, camera: ICamera): void;
|
||||
|
||||
|
||||
protected onBecameVisible() {
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
protected onBecameInvisible() {
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
public setRenderLayer(renderLayer: number): RenderableComponent {
|
||||
if (renderLayer != this._renderLayer) {
|
||||
let oldRenderLayer = this._renderLayer;
|
||||
this._renderLayer = renderLayer;
|
||||
|
||||
|
||||
if (this.entity != null && this.entity.scene != null)
|
||||
es.Core.scene.renderableComponents.updateRenderableRenderLayer(this, oldRenderLayer, this._renderLayer);
|
||||
}
|
||||
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public isVisibleFromCamera(cam: ICamera): boolean {
|
||||
this.isVisible = cam.bounds.intersects(this.bounds);
|
||||
|
||||
|
||||
return this.isVisible;
|
||||
}
|
||||
|
||||
|
||||
public debugRender(batcher: IBatcher) {
|
||||
if (!this.debugRenderEnabled)
|
||||
return;
|
||||
|
||||
|
||||
let collider = null;
|
||||
for (let i = 0; i < this.entity.components.buffer.length; i++) {
|
||||
let component = this.entity.components.buffer[i];
|
||||
@@ -112,14 +113,21 @@ module es {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (collider == null) {
|
||||
batcher.drawHollowRect(this.bounds.x, this.bounds.y, this.bounds.width, this.bounds.height, new Color(255, 255, 0));
|
||||
batcher.end();
|
||||
}
|
||||
|
||||
|
||||
batcher.drawPixel(es.Vector2.add(this.entity.transform.position, this._localOffset), new Color(153, 50, 204), 4);
|
||||
batcher.end();
|
||||
}
|
||||
|
||||
public tweenColorTo(to: Color, duration: number) {
|
||||
const tween = Pool.obtain(RenderableColorTween);
|
||||
tween.setTarget(this);
|
||||
tween.initialize(tween, to, duration);
|
||||
return tween;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -491,6 +491,66 @@ module es {
|
||||
}
|
||||
}
|
||||
|
||||
public tweenPositionTo(to: Vector2, duration: number = 0.3): ITween<Vector2> {
|
||||
const tween = Pool.obtain(TransformVector2Tween);
|
||||
tween.setTargetAndType(this.transform, TransformTargetType.position);
|
||||
tween.initialize(tween, to, duration);
|
||||
|
||||
return tween;
|
||||
}
|
||||
|
||||
public tweenLocalPositionTo(to: Vector2, duration = 0.3): ITween<Vector2> {
|
||||
const tween = Pool.obtain(TransformVector2Tween);
|
||||
tween.setTargetAndType(this.transform, TransformTargetType.localPosition);
|
||||
tween.initialize(tween, to, duration);
|
||||
|
||||
return tween;
|
||||
}
|
||||
|
||||
public tweenScaleTo(to: Vector2, duration?: number);
|
||||
public tweenScaleTo(to: number, duration?: number);
|
||||
public tweenScaleTo(to: Vector2 | number, duration: number = 0.3) {
|
||||
if (typeof (to) == 'number') {
|
||||
return this.tweenScaleTo(new Vector2(to, to), duration);
|
||||
}
|
||||
|
||||
const tween = Pool.obtain(TransformVector2Tween);
|
||||
tween.setTargetAndType(this.transform, TransformTargetType.scale);
|
||||
tween.initialize(tween, to, duration);
|
||||
|
||||
return tween;
|
||||
}
|
||||
|
||||
public tweenLocalScaleTo(to: Vector2, duration?);
|
||||
public tweenLocalScaleTo(to: number, duration?);
|
||||
public tweenLocalScaleTo(to: Vector2 | number, duration = 0.3) {
|
||||
if (typeof (to) == 'number') {
|
||||
return this.tweenLocalScaleTo(new Vector2(to, to), duration);
|
||||
}
|
||||
|
||||
const tween = Pool.obtain(TransformVector2Tween);
|
||||
tween.setTargetAndType(this.transform, TransformTargetType.localScale);
|
||||
tween.initialize(tween, to, duration);
|
||||
|
||||
return tween;
|
||||
}
|
||||
|
||||
public tweenRotationDegreesTo(to: number, duration = 0.3) {
|
||||
const tween = Pool.obtain(TransformVector2Tween);
|
||||
tween.setTargetAndType(this.transform, TransformTargetType.rotationDegrees);
|
||||
tween.initialize(tween, new Vector2(to, to), duration);
|
||||
|
||||
return tween;
|
||||
}
|
||||
|
||||
public tweenLocalRotationDegreesTo(to: number, duration = 0.3) {
|
||||
const tween = Pool.obtain(TransformVector2Tween);
|
||||
tween.setTargetAndType(this.transform, TransformTargetType.localRotationDegrees);
|
||||
tween.initialize(tween, new Vector2(to, to), duration);
|
||||
|
||||
return tween;
|
||||
}
|
||||
|
||||
public compareTo(other: Entity): number {
|
||||
let compare = this._updateOrder - other._updateOrder;
|
||||
if (compare == 0)
|
||||
|
||||
@@ -13,9 +13,9 @@ module es {
|
||||
public static getPoint(p0: Vector2, p1: Vector2, p2: Vector2, t: number): Vector2 {
|
||||
t = MathHelper.clamp01(t);
|
||||
let oneMinusT = 1 - t;
|
||||
return new Vector2(oneMinusT * oneMinusT).multiply(p0)
|
||||
.addEqual(new Vector2(2 * oneMinusT * t).multiply(p1))
|
||||
.addEqual(new Vector2(t * t).multiply(p2));
|
||||
return p0.scale(oneMinusT * oneMinusT)
|
||||
.addEqual(p1.scale(2 * oneMinusT * t))
|
||||
.addEqual(p2.scale(t * t));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -29,11 +29,11 @@ module es {
|
||||
public static getPointThree(start: Vector2, firstControlPoint: Vector2, secondControlPoint: Vector2,
|
||||
end: Vector2, t: number): Vector2 {
|
||||
t = MathHelper.clamp01(t);
|
||||
let oneMinusT = 1 - t;
|
||||
return new Vector2(oneMinusT * oneMinusT * oneMinusT).multiply(start)
|
||||
.addEqual(new Vector2(3 * oneMinusT * oneMinusT * t).multiply(firstControlPoint))
|
||||
.addEqual(new Vector2(3 * oneMinusT * t * t).multiply(secondControlPoint))
|
||||
.addEqual(new Vector2(t * t * t).multiply(end));
|
||||
const oneMinusT = 1 - t;
|
||||
return start.scale(oneMinusT * oneMinusT * oneMinusT)
|
||||
.addEqual(firstControlPoint.scale(3 * oneMinusT * oneMinusT * t))
|
||||
.addEqual(secondControlPoint.scale(3 * oneMinusT * t * t))
|
||||
.addEqual(end.scale(t * t * t));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -3,7 +3,7 @@ module es {
|
||||
export class AngleConstraint extends Constraint {
|
||||
public stiffness: number = 0;
|
||||
public angleInRadius: number = 0;
|
||||
|
||||
|
||||
_particleA: Particle;
|
||||
_centerParticle: Particle;
|
||||
_particleC: Particle;
|
||||
|
||||
51
source/src/Tween/AbstractTweenable.ts
Normal file
51
source/src/Tween/AbstractTweenable.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
module es {
|
||||
/**
|
||||
* AbstractTweenable作为你可能想做的任何可以执行的自定义类的基础。
|
||||
* 这些类不同于ITweens,因为他们没有实现ITweenT接口。
|
||||
* 它只是说一个AbstractTweenable不仅仅是将一个值从开始移动到结束。
|
||||
* 它可以做任何需要每帧执行的事情。
|
||||
*/
|
||||
export abstract class AbstractTweenable implements ITweenable {
|
||||
protected _isPaused: boolean;
|
||||
|
||||
/**
|
||||
* abstractTweenable在完成后往往会被保留下来。
|
||||
* 这个标志可以让它们在内部知道自己当前是否被TweenManager盯上了,以便在必要时可以重新添加自己。
|
||||
*/
|
||||
protected _isCurrentlyManagedByTweenManager: boolean;
|
||||
|
||||
public abstract tick(): boolean;
|
||||
|
||||
public recycleSelf() {
|
||||
}
|
||||
|
||||
public isRunning(): boolean {
|
||||
return this._isCurrentlyManagedByTweenManager && !this._isPaused;
|
||||
}
|
||||
|
||||
public start() {
|
||||
if (this._isCurrentlyManagedByTweenManager) {
|
||||
this._isPaused = false;
|
||||
return;
|
||||
}
|
||||
|
||||
TweenManager.addTween(this);
|
||||
this._isCurrentlyManagedByTweenManager = true;
|
||||
this._isPaused = false;
|
||||
}
|
||||
|
||||
public pause() {
|
||||
this._isPaused = true;
|
||||
}
|
||||
|
||||
public resume() {
|
||||
this._isPaused = false;
|
||||
}
|
||||
|
||||
public stop(bringToCompletion: boolean = false) {
|
||||
TweenManager.removeTween(this);
|
||||
this._isCurrentlyManagedByTweenManager = false;
|
||||
this._isPaused = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
207
source/src/Tween/Easing/EaseType.ts
Normal file
207
source/src/Tween/Easing/EaseType.ts
Normal file
@@ -0,0 +1,207 @@
|
||||
module es {
|
||||
export enum EaseType {
|
||||
linear,
|
||||
|
||||
sineIn,
|
||||
sineOut,
|
||||
sineInOut,
|
||||
|
||||
quadIn,
|
||||
quadOut,
|
||||
quadInOut,
|
||||
|
||||
quintIn,
|
||||
quintOut,
|
||||
quintInOut,
|
||||
|
||||
cubicIn,
|
||||
cubicOut,
|
||||
cubicInOut,
|
||||
|
||||
quartIn,
|
||||
quartOut,
|
||||
quartInOut,
|
||||
|
||||
expoIn,
|
||||
expoOut,
|
||||
expoInOut,
|
||||
|
||||
circleIn,
|
||||
circleOut,
|
||||
circleInOut,
|
||||
|
||||
elasticIn,
|
||||
elasticOut,
|
||||
elasticInOut,
|
||||
punch,
|
||||
|
||||
backIn,
|
||||
backOut,
|
||||
backInOut,
|
||||
|
||||
bounceIn,
|
||||
bounceOut,
|
||||
bounceInOut
|
||||
}
|
||||
|
||||
/**
|
||||
* 助手的一个方法,它接收一个EaseType,并通过给定的持续时间和时间参数来应用该Ease方程。
|
||||
* 我们这样做是为了避免传来传去的Funcs为垃圾收集器制造大量垃圾
|
||||
*/
|
||||
export class EaseHelper {
|
||||
/**
|
||||
* 返回 easeType 的相反 EaseType
|
||||
* @param easeType
|
||||
*/
|
||||
public static oppositeEaseType(easeType: EaseType) {
|
||||
switch (easeType) {
|
||||
case EaseType.linear:
|
||||
return easeType;
|
||||
|
||||
case EaseType.backIn:
|
||||
return EaseType.backOut;
|
||||
case EaseType.backOut:
|
||||
return EaseType.backIn;
|
||||
case EaseType.backInOut:
|
||||
return easeType;
|
||||
|
||||
case EaseType.bounceIn:
|
||||
return EaseType.bounceOut;
|
||||
case EaseType.bounceOut:
|
||||
return EaseType.bounceIn;
|
||||
case EaseType.bounceInOut:
|
||||
return easeType;
|
||||
|
||||
case EaseType.circleIn:
|
||||
return EaseType.circleOut;
|
||||
case EaseType.circleOut:
|
||||
return EaseType.circleIn;
|
||||
case EaseType.circleInOut:
|
||||
return easeType;
|
||||
|
||||
case EaseType.cubicIn:
|
||||
return EaseType.cubicOut;
|
||||
case EaseType.cubicOut:
|
||||
return EaseType.cubicIn;
|
||||
case EaseType.circleInOut:
|
||||
return easeType;
|
||||
|
||||
case EaseType.punch:
|
||||
return easeType;
|
||||
|
||||
case EaseType.expoIn:
|
||||
return EaseType.expoOut;
|
||||
case EaseType.expoOut:
|
||||
return EaseType.expoIn;
|
||||
case EaseType.expoInOut:
|
||||
return easeType;
|
||||
|
||||
case EaseType.quadIn:
|
||||
return EaseType.quadOut;
|
||||
case EaseType.quadOut:
|
||||
return EaseType.quadIn;
|
||||
case EaseType.quadInOut:
|
||||
return easeType;
|
||||
|
||||
case EaseType.quartIn:
|
||||
return EaseType.quadOut;
|
||||
case EaseType.quartOut:
|
||||
return EaseType.quartIn;
|
||||
case EaseType.quadInOut:
|
||||
return easeType;
|
||||
|
||||
case EaseType.sineIn:
|
||||
return EaseType.sineOut;
|
||||
case EaseType.sineOut:
|
||||
return EaseType.sineIn;
|
||||
case EaseType.sineInOut:
|
||||
return easeType;
|
||||
|
||||
default:
|
||||
return easeType;
|
||||
}
|
||||
}
|
||||
|
||||
public static ease(easeType: EaseType, t: number, duration: number) {
|
||||
switch (easeType) {
|
||||
case EaseType.linear:
|
||||
return Easing.Linear.easeNone(t, duration);
|
||||
|
||||
case EaseType.backIn:
|
||||
return Easing.Back.easeIn(t, duration);
|
||||
case EaseType.backOut:
|
||||
return Easing.Back.easeOut(t, duration);
|
||||
case EaseType.backInOut:
|
||||
return Easing.Back.easeInOut(t, duration);
|
||||
|
||||
case EaseType.bounceIn:
|
||||
return Easing.Bounce.easeIn(t, duration);
|
||||
case EaseType.bounceOut:
|
||||
return Easing.Bounce.easeOut(t, duration);
|
||||
case EaseType.bounceInOut:
|
||||
return Easing.Bounce.easeInOut(t, duration);
|
||||
|
||||
case EaseType.circleIn:
|
||||
return Easing.Circular.easeIn(t, duration);
|
||||
case EaseType.circleOut:
|
||||
return Easing.Circular.easeOut(t, duration);
|
||||
case EaseType.circleInOut:
|
||||
return Easing.Circular.easeInOut(t, duration);
|
||||
|
||||
case EaseType.cubicIn:
|
||||
return Easing.Cubic.easeIn(t, duration);
|
||||
case EaseType.cubicOut:
|
||||
return Easing.Cubic.easeOut(t, duration);
|
||||
case EaseType.cubicInOut:
|
||||
return Easing.Cubic.easeInOut(t, duration);
|
||||
|
||||
case EaseType.elasticIn:
|
||||
return Easing.Elastic.easeIn(t, duration);
|
||||
case EaseType.elasticOut:
|
||||
return Easing.Elastic.easeOut(t, duration);
|
||||
case EaseType.elasticInOut:
|
||||
return Easing.Elastic.easeInOut(t, duration);
|
||||
case EaseType.punch:
|
||||
return Easing.Elastic.punch(t, duration);
|
||||
|
||||
case EaseType.expoIn:
|
||||
return Easing.Exponential.easeIn(t, duration);
|
||||
case EaseType.expoOut:
|
||||
return Easing.Exponential.easeOut(t, duration);
|
||||
case EaseType.expoInOut:
|
||||
return Easing.Exponential.easeInOut(t, duration);
|
||||
|
||||
case EaseType.quadIn:
|
||||
return Easing.Quadratic.easeIn(t, duration);
|
||||
case EaseType.quadOut:
|
||||
return Easing.Quadratic.easeOut(t, duration);
|
||||
case EaseType.quadInOut:
|
||||
return Easing.Quadratic.easeInOut(t, duration);
|
||||
|
||||
case EaseType.quadIn:
|
||||
return Easing.Quadratic.easeIn(t, duration);
|
||||
case EaseType.quadOut:
|
||||
return Easing.Quadratic.easeOut(t, duration);
|
||||
case EaseType.quadInOut:
|
||||
return Easing.Quadratic.easeInOut(t, duration);
|
||||
|
||||
case EaseType.quintIn:
|
||||
return Easing.Quintic.easeIn(t, duration);
|
||||
case EaseType.quintOut:
|
||||
return Easing.Quintic.easeOut(t, duration);
|
||||
case EaseType.quintInOut:
|
||||
return Easing.Quintic.easeInOut(t, duration);
|
||||
|
||||
case EaseType.sineIn:
|
||||
return Easing.Sinusoidal.easeIn(t, duration);
|
||||
case EaseType.sineOut:
|
||||
return Easing.Sinusoidal.easeOut(t, duration);
|
||||
case EaseType.sineInOut:
|
||||
return Easing.Sinusoidal.easeInOut(t, duration);
|
||||
|
||||
default:
|
||||
return Easing.Linear.easeNone(t, duration);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
230
source/src/Tween/Easing/Easing.ts
Normal file
230
source/src/Tween/Easing/Easing.ts
Normal file
@@ -0,0 +1,230 @@
|
||||
module es {
|
||||
/**
|
||||
* 标准缓和方程通过将b和c参数(起始值和变化值)用0和1替换,然后进行简化。
|
||||
* 这样做的目的是为了让我们可以得到一个0 - 1之间的原始值(除了弹性/反弹故意超过界限),然后用这个值来lerp任何东西
|
||||
*/
|
||||
export module Easing {
|
||||
export class Linear {
|
||||
public static easeNone(t: number, d: number) {
|
||||
return t / d;
|
||||
}
|
||||
}
|
||||
|
||||
export class Quadratic {
|
||||
public static easeIn(t: number, d: number) {
|
||||
return (t /= d) * t;
|
||||
}
|
||||
|
||||
public static easeOut(t: number, d: number) {
|
||||
return -1 * (t /= d) * (t - 2);
|
||||
}
|
||||
|
||||
public static easeInOut(t: number, d: number) {
|
||||
if ((t /= d / 2) < 1)
|
||||
return 0.5 * t * t;
|
||||
return -0.5 * ((--t) * (t - 2) - 1);
|
||||
}
|
||||
}
|
||||
|
||||
export class Back {
|
||||
public static easeIn(t: number, d: number) {
|
||||
return (t /= d) * t * ((1.70158 + 1) * t - 1.70158);
|
||||
}
|
||||
|
||||
public static easeOut(t: number, d: number) {
|
||||
return ((t = t / d - 1) * t * ((1.70158 + 1) * t + 1.70158) + 1);
|
||||
}
|
||||
|
||||
public static easeInOut(t: number, d: number) {
|
||||
let s = 1.70158;
|
||||
if ((t /= d / 2) < 1) {
|
||||
return 0.5 * (t * t * (((s *= (1.525)) + 1) * t - s));
|
||||
}
|
||||
|
||||
return 0.5 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2);
|
||||
}
|
||||
}
|
||||
|
||||
export class Bounce {
|
||||
public static easeOut(t: number, d: number) {
|
||||
if ((t /= d) < (1 / 2.75)) {
|
||||
return (7.5625 * t * t);
|
||||
} else if (t < (2 / 2.75)) {
|
||||
return (7.5625 * (t -= (1.5 / 2.75)) * t + 0.75);
|
||||
} else if (t < (2.5 / 2.75)) {
|
||||
return (7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375);
|
||||
} else {
|
||||
return (7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375);
|
||||
}
|
||||
}
|
||||
|
||||
public static easeIn(t: number, d: number) {
|
||||
return 1 - this.easeOut(d - t, d);
|
||||
}
|
||||
|
||||
public static easeInOut(t: number, d: number) {
|
||||
if (t < d / 2)
|
||||
return this.easeIn(t * 2, d) * 0.5;
|
||||
else
|
||||
return this.easeOut(t * 2 - d, d) * 0.5 + 1 * 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
export class Circular {
|
||||
public static easeIn(t: number, d: number) {
|
||||
return -(Math.sqrt(1 - (t /= d) * t) - 1);
|
||||
}
|
||||
|
||||
public static easeOut(t: number, d: number) {
|
||||
return Math.sqrt(1 - (t = t / d - 1) * t);
|
||||
}
|
||||
|
||||
public static easeInOut(t: number, d: number) {
|
||||
if ((t /= d / 2) < 1)
|
||||
return -0.5 * (Math.sqrt(1 - t * t) - 1);
|
||||
return 0.5 * (Math.sqrt(1 - (t -= 2) * t) + 1);
|
||||
}
|
||||
}
|
||||
|
||||
export class Cubic {
|
||||
public static easeIn(t: number, d: number) {
|
||||
return (t /= d) * t * t;
|
||||
}
|
||||
|
||||
public static easeOut(t: number, d: number) {
|
||||
return ((t = t / d - 1) * t * t + 1);
|
||||
}
|
||||
|
||||
public static easeInOut(t: number, d: number) {
|
||||
if ((t /= d / 2) < 1)
|
||||
return 0.5 * t * t * t;
|
||||
return 0.5 * ((t -= 2) * t * t + 2);
|
||||
}
|
||||
}
|
||||
|
||||
export class Elastic {
|
||||
public static easeIn(t: number, d: number) {
|
||||
if (t == 0)
|
||||
return 0;
|
||||
|
||||
if ((t /= d) == 1)
|
||||
return 1;
|
||||
|
||||
let p = d * 0.3;
|
||||
let s = p / 4;
|
||||
return -(1 * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p));
|
||||
}
|
||||
|
||||
public static easeOut(t: number, d: number) {
|
||||
if (t == 0)
|
||||
return 0;
|
||||
|
||||
if ((t /= d) == 1)
|
||||
return 1;
|
||||
|
||||
let p = d * 0.3;
|
||||
let s = p / 4;
|
||||
return (1 * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + 1);
|
||||
}
|
||||
|
||||
public static easeInOut(t: number, d: number) {
|
||||
if (t == 0)
|
||||
return 0;
|
||||
|
||||
if ((t /= d / 2) == 2)
|
||||
return 1;
|
||||
|
||||
let p = d * (0.3 * 1.5);
|
||||
let s = p / 4;
|
||||
if (t < 1)
|
||||
return -0.5 * (Math.pow(2, 10 * (t -= 1)) * Math.sin(t * d - s) * (2 * Math.PI) / p);
|
||||
|
||||
return (Math.pow(2, -10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p) * 0.5 + 1);
|
||||
}
|
||||
|
||||
public static punch(t: number, d: number) {
|
||||
if (t == 0)
|
||||
return 0;
|
||||
|
||||
if ((t /= d) == 1)
|
||||
return 0;
|
||||
|
||||
const p = 0.3;
|
||||
return (Math.pow(2, -10 * t) * Math.sin(t * (2 * Math.PI) / p));
|
||||
}
|
||||
}
|
||||
|
||||
export class Exponential {
|
||||
public static easeIn(t: number, d: number) {
|
||||
return (t == 0) ? 0 : Math.pow(2, 10 * (t / d - 1));
|
||||
}
|
||||
|
||||
public static easeOut(t: number, d: number) {
|
||||
return t == d ? 1 : (-Math.pow(2, -10 * t / d) + 1);
|
||||
}
|
||||
|
||||
public static easeInOut(t: number, d: number) {
|
||||
if (t == 0)
|
||||
return 0;
|
||||
|
||||
if (t == d)
|
||||
return 1;
|
||||
|
||||
if ((t /= d / 2) < 1) {
|
||||
return 0.5 * Math.pow(2, 10 * (t - 1));
|
||||
}
|
||||
return 0.5 * (-Math.pow(2, -10 * --t) + 2);
|
||||
}
|
||||
}
|
||||
|
||||
export class Quartic {
|
||||
public static easeIn(t: number, d: number) {
|
||||
return (t /= d) * t * t * t;
|
||||
}
|
||||
|
||||
public static easeOut(t: number, d: number) {
|
||||
return -1 * ((t = t / d - 1) * t * t * t - 1);
|
||||
}
|
||||
|
||||
public static easeInOut(t: number, d: number) {
|
||||
t /= d / 2;
|
||||
if (t < 1)
|
||||
return 0.5 * t * t * t * t;
|
||||
|
||||
t -= 2;
|
||||
return -0.5 * (t * t * t * t - 2);
|
||||
}
|
||||
}
|
||||
|
||||
export class Quintic {
|
||||
public static easeIn(t: number, d: number) {
|
||||
return (t /= d) * t * t * t * t;
|
||||
}
|
||||
|
||||
public static easeOut(t: number, d: number) {
|
||||
return ((t = t / d - 1) * t * t * t * t + 1);
|
||||
}
|
||||
|
||||
public static easeInOut(t: number, d: number) {
|
||||
if ((t /= d / 2) < 1)
|
||||
return 0.5 * t * t * t * t * t;
|
||||
|
||||
return 0.5 * ((t -= 2) * t * t * t * t + 2);
|
||||
}
|
||||
}
|
||||
|
||||
export class Sinusoidal {
|
||||
public static easeIn(t: number, d: number) {
|
||||
return -1 * Math.cos(t / d * (Math.PI / 2)) + 1;
|
||||
}
|
||||
|
||||
public static easeOut(t: number, d: number) {
|
||||
return Math.sin(t / d * (Math.PI / 2));
|
||||
}
|
||||
|
||||
public static easeInOut(t: number, d: number) {
|
||||
return -0.5 * (Math.cos(Math.PI * t / d) - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
84
source/src/Tween/Easing/Lerps.ts
Normal file
84
source/src/Tween/Easing/Lerps.ts
Normal file
@@ -0,0 +1,84 @@
|
||||
module es {
|
||||
/**
|
||||
* 一系列静态方法来处理所有常见的tween类型结构,以及它们的unclamped lerps.unclamped lerps对于超过0-1范围的bounce、elastic或其他tweens是必需的
|
||||
*/
|
||||
export class Lerps {
|
||||
public static lerp(from: Color, to: Color, t: number);
|
||||
public static lerp(from: number, to: number, t: number);
|
||||
public static lerp(from: Rectangle, to: Rectangle, t: number);
|
||||
public static lerp(from: Vector2, to: Vector2, t: number);
|
||||
public static lerp(from: any, to: any, t: number) {
|
||||
if (typeof(from) == "number" && typeof(to) == "number") {
|
||||
return from + (to - from) * t;
|
||||
}
|
||||
|
||||
if (from instanceof Color && to instanceof Color) {
|
||||
const t255 = t * 255;
|
||||
return new Color(from.r + (to.r - from.r) * t255 / 255, from.g + (to.g - from.g) * t255 / 255,
|
||||
from.b + (to.b - from.b) * t255 / 255, from.a + (to.a - from.a) * t255 / 255)
|
||||
}
|
||||
|
||||
if (from instanceof Rectangle && to instanceof Rectangle) {
|
||||
return new Rectangle(
|
||||
(from.x + (to.x - from.x) * t),
|
||||
(from.y + (to.x - from.y) * t),
|
||||
(from.width + (to.width - from.width) * t),
|
||||
(from.height + (to.height - from.height) * t)
|
||||
);
|
||||
}
|
||||
|
||||
if (from instanceof Vector2 && to instanceof Vector2) {
|
||||
return new Vector2(from.x + (to.x - from.x) * t, from.y + (to.y - from.y) * t);
|
||||
}
|
||||
}
|
||||
|
||||
public static angleLerp(from: Vector2, to: Vector2, t: number) {
|
||||
// 我们计算这个lerp的最短角差
|
||||
let toMinusFrom = new Vector2(MathHelper.deltaAngle(from.x, to.x), MathHelper.deltaAngle(from.y, to.y));
|
||||
return new Vector2(from.x + toMinusFrom.x * t, from.y + toMinusFrom.y * t);
|
||||
}
|
||||
|
||||
public static ease(easeType: EaseType, from: Rectangle, to: Rectangle, t: number, duration: number);
|
||||
public static ease(easeType: EaseType, from: Vector2, to: Vector2, t: number, duration: number);
|
||||
public static ease(easeType: EaseType, from: number, to: number, t: number, duration: number);
|
||||
public static ease(easeType: EaseType, from: Color, to: Color, t: number, duration: number);
|
||||
public static ease(easeType: EaseType, from: any, to: any, t: number, duration: number) {
|
||||
if (typeof(from) == 'number' && typeof(to) == "number") {
|
||||
return this.lerp(from, to, EaseHelper.ease(easeType, t, duration));
|
||||
}
|
||||
|
||||
if (from instanceof Vector2 && to instanceof Vector2) {
|
||||
return this.lerp(from, to, EaseHelper.ease(easeType, t, duration));
|
||||
}
|
||||
|
||||
if (from instanceof Rectangle && to instanceof Rectangle) {
|
||||
return this.lerp(from, to, EaseHelper.ease(easeType, t, duration));
|
||||
}
|
||||
|
||||
if (from instanceof Color && to instanceof Color) {
|
||||
return this.lerp(from, to, EaseHelper.ease(easeType, t, duration));
|
||||
}
|
||||
}
|
||||
|
||||
public static easeAngle(easeType: EaseType, from: Vector2, to: Vector2, t: number, duration: number) {
|
||||
return this.angleLerp(from, to, EaseHelper.ease(easeType, t, duration));
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用半隐式欧拉方法。速度较慢,但总是很稳定。见
|
||||
* http://allenchou.net/2015/04/game-math-more-on-numeric-springing/
|
||||
* @param currentValue
|
||||
* @param targetValue
|
||||
* @param velocity Velocity的引用。如果在两次调用之间改变targetValue,请务必将其重置为0
|
||||
* @param dampingRatio 值越低,阻尼越小,值越高,阻尼越大,导致弹簧度越小,应在0.01-1之间,以避免系统不稳定
|
||||
* @param angularFrequency 角频率为2pi(弧度/秒)意味着振荡在一秒钟内完成一个完整的周期,即1Hz.应小于35左右才能保持稳定
|
||||
*/
|
||||
public static fastSpring(currentValue: Vector2, targetValue: Vector2, velocity: Vector2,
|
||||
dampingRatio: number, angularFrequency: number) {
|
||||
velocity.add(velocity.scale(-2 * Time.deltaTime * dampingRatio * angularFrequency)
|
||||
.add(targetValue.sub(currentValue).scale(Time.deltaTime * angularFrequency * angularFrequency)));
|
||||
currentValue.add(velocity.scale(Time.deltaTime));
|
||||
return currentValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
79
source/src/Tween/Interfaces/ITween.ts
Normal file
79
source/src/Tween/Interfaces/ITween.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
module es {
|
||||
/**
|
||||
* 一系列强类型、可链式的方法来设置各种tween属性
|
||||
*/
|
||||
export interface ITween<T> extends ITweenControl {
|
||||
/**
|
||||
* 设置该tween的易用性类型
|
||||
* @param easeType
|
||||
*/
|
||||
setEaseType(easeType: EaseType): ITween<T>;
|
||||
/**
|
||||
* 设置启动tween前的延迟
|
||||
* @param delay
|
||||
*/
|
||||
setDelay(delay: number): ITween<T>;
|
||||
/**
|
||||
* 设置tween的持续时间
|
||||
* @param duration
|
||||
*/
|
||||
setDuration(duration: number): ITween<T>;
|
||||
/**
|
||||
* 设置这个tween使用的timeScale。
|
||||
* TimeScale将与Time.deltaTime/Time.unscaledDeltaTime相乘,从而得到tween实际使用的delta时间
|
||||
* @param timeScale
|
||||
*/
|
||||
setTimeScale(timeScale: number): ITween<T>;
|
||||
/**
|
||||
* 设置tween使用Time.unscaledDeltaTime代替Time.deltaTime
|
||||
*/
|
||||
setIsTimeScaleIndependent(): ITween<T>;
|
||||
/**
|
||||
* 设置当tween完成时应该调用的动作
|
||||
* @param completionHandler
|
||||
*/
|
||||
setCompletionHandler(completionHandler: (tween: ITween<T>) => void): ITween<T>;
|
||||
/**
|
||||
* 设置tween的循环类型。一个pingpong循环意味着从开始-结束-开始
|
||||
* @param loopType
|
||||
* @param loops
|
||||
* @param delayBetweenLoops
|
||||
*/
|
||||
setLoops(loopType: LoopType, loops: number, delayBetweenLoops: number): ITween<T>;
|
||||
/**
|
||||
* 设置tween的起始位置
|
||||
* @param from
|
||||
*/
|
||||
setFrom(from: T): ITween<T>;
|
||||
/**
|
||||
* 通过重置tween的from/to值和持续时间,为重复使用tween做准备。
|
||||
* @param from
|
||||
* @param to
|
||||
* @param duration
|
||||
*/
|
||||
prepareForReuse(from: T, to: T, duration: number): ITween<T>;
|
||||
/**
|
||||
* 如果为true(默认值),tween将在使用后被回收。
|
||||
* 如果在TweenManager类中进行了配置,所有的Tween<T>子类都有自己相关的自动缓存
|
||||
* @param shouldRecycleTween
|
||||
*/
|
||||
setRecycleTween(shouldRecycleTween: boolean): ITween<T>;
|
||||
/**
|
||||
* 帮助程序,只是将tween的to值设置为相对于其当前值的+从使tween
|
||||
*/
|
||||
setIsRelative(): ITween<T>;
|
||||
/**
|
||||
* 允许你通过tween.context.context来设置任何可检索的对象引用。
|
||||
* 这对于避免完成处理程序方法的闭包分配是很方便的。
|
||||
* 你也可以在TweenManager中搜索具有特定上下文的所有tweens
|
||||
* @param context
|
||||
*/
|
||||
setContext(context): ITween<T>;
|
||||
/**
|
||||
* 允许你添加一个tween,这个tween完成后会被运行。
|
||||
* 注意 nextTween 必须是一个 ITweenable! 同时注意,所有的ITweenT都是ITweenable
|
||||
* @param nextTween
|
||||
*/
|
||||
setNextTween(nextTween: ITweenable): ITween<T>;
|
||||
}
|
||||
}
|
||||
24
source/src/Tween/Interfaces/ITweenControl.ts
Normal file
24
source/src/Tween/Interfaces/ITweenControl.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
module es {
|
||||
/**
|
||||
* 更多具体的Tween播放控制在这里
|
||||
*/
|
||||
export interface ITweenControl extends ITweenable {
|
||||
/**
|
||||
* 当使用匿名方法时,您可以在任何回调(如完成处理程序)中使用该属性来避免分配
|
||||
*/
|
||||
context;
|
||||
/**
|
||||
* 将tween扭曲为elapsedTime,并将其限制在0和duration之间,无论tween对象是暂停、完成还是运行,都会立即更新
|
||||
* @param elapsedTime 所用时间
|
||||
*/
|
||||
jumpToElapsedTime(elapsedTime: number);
|
||||
/**
|
||||
* 当从StartCoroutine调用时,它将直到tween完成
|
||||
*/
|
||||
waitForCompletion(): any;
|
||||
/**
|
||||
* 获取tween的目标,如果TweenTargets不一定都是一个对象,则为null,它的唯一真正用途是让TweenManager按目标查找tweens的列表
|
||||
*/
|
||||
getTargetObject(): any;
|
||||
}
|
||||
}
|
||||
19
source/src/Tween/Interfaces/ITweenTarget.ts
Normal file
19
source/src/Tween/Interfaces/ITweenTarget.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
module es {
|
||||
/**
|
||||
* 任何想要被weened的对象都需要实现这个功能。
|
||||
* TweenManager内部喜欢做一个简单的对象来实现这个接口,并存储一个对被tweened对象的引用
|
||||
*/
|
||||
export interface ITweenTarget<T> {
|
||||
/**
|
||||
* 在你选择的对象上设置最终的tweened值
|
||||
* @param value
|
||||
*/
|
||||
setTweenedValue(value: T);
|
||||
|
||||
getTweenedValue(): T;
|
||||
/**
|
||||
* 获取tween的目标,如果TweenTargets不一定都是一个对象,则为null,它的唯一真正用途是让TweenManager按目标查找tweens的列表
|
||||
*/
|
||||
getTargetObject(): any;
|
||||
}
|
||||
}
|
||||
34
source/src/Tween/Interfaces/ITweenable.ts
Normal file
34
source/src/Tween/Interfaces/ITweenable.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
module es {
|
||||
export interface ITweenable {
|
||||
/**
|
||||
* 就像内部的Update一样,每一帧都被TweenManager调用
|
||||
*/
|
||||
tick(): boolean;
|
||||
/**
|
||||
* 当一个tween被移除时,由TweenManager调用。子
|
||||
* 类可以选择自己回收。子类应该首先在其实现中检查_shouldRecycleTween bool!
|
||||
*/
|
||||
recycleSelf();
|
||||
/**
|
||||
* 检查是否有tween在运行
|
||||
*/
|
||||
isRunning(): boolean;
|
||||
/**
|
||||
* 启动tween
|
||||
*/
|
||||
start();
|
||||
/**
|
||||
* 暂停
|
||||
*/
|
||||
pause();
|
||||
/**
|
||||
* 暂停后恢复tween
|
||||
*/
|
||||
resume();
|
||||
/**
|
||||
* 停止tween,并可选择将其完成
|
||||
* @param bringToCompletion
|
||||
*/
|
||||
stop(bringToCompletion: boolean);
|
||||
}
|
||||
}
|
||||
44
source/src/Tween/PropertyTweens.ts
Normal file
44
source/src/Tween/PropertyTweens.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
module es {
|
||||
/**
|
||||
* 通用ITweenTarget用于所有属性tweens。
|
||||
*/
|
||||
class PropertyTarget<T> implements ITweenTarget<T> {
|
||||
protected _target;
|
||||
protected _propertyName;
|
||||
|
||||
constructor(target, propertyName: string) {
|
||||
this._target = target;
|
||||
this._propertyName = propertyName;
|
||||
}
|
||||
|
||||
public getTargetObject() {
|
||||
return this._target;
|
||||
}
|
||||
|
||||
public setTweenedValue(value: T) {
|
||||
this._target[this._propertyName] = value;
|
||||
}
|
||||
|
||||
public getTweenedValue(): T {
|
||||
return this._target[this._propertyName];
|
||||
}
|
||||
}
|
||||
|
||||
export class PropertyTweens {
|
||||
public static NumberPropertyTo(self, memberName: string, to: number, duration: number): ITween<number> {
|
||||
let tweenTarget = new PropertyTarget<number>(self, memberName);
|
||||
let tween = TweenManager.cacheNumberTweens ? Pool.obtain<NumberTween>(NumberTween) : new NumberTween();
|
||||
tween.initialize(tweenTarget, to, duration);
|
||||
|
||||
return tween;
|
||||
}
|
||||
|
||||
public static Vector2PropertyTo(self, memeberName: string, to: Vector2, duration: number): ITween<Vector2> {
|
||||
let tweenTarget = new PropertyTarget<Vector2>(self, memeberName);
|
||||
let tween = TweenManager.cacheVector2Tweens ? Pool.obtain<Vector2Tween>(Vector2Tween) : new Vector2Tween();
|
||||
tween.initialize(tweenTarget, to, duration);
|
||||
|
||||
return tween;
|
||||
}
|
||||
}
|
||||
}
|
||||
38
source/src/Tween/RenderableColorTween.ts
Normal file
38
source/src/Tween/RenderableColorTween.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
///<reference path="./Tweens.ts"/>
|
||||
module es {
|
||||
export class RenderableColorTween extends ColorTween implements ITweenTarget<Color> {
|
||||
_renderable: RenderableComponent;
|
||||
|
||||
setTweenedValue(value: Color) {
|
||||
this._renderable.color = value;
|
||||
}
|
||||
|
||||
getTweenedValue(): Color {
|
||||
return this._renderable.color;
|
||||
}
|
||||
|
||||
public getTargetObject() {
|
||||
return this._renderable;
|
||||
}
|
||||
|
||||
public updateValue() {
|
||||
this.setTweenedValue(Lerps.ease(this._easeType, this._fromValue, this._toValue, this._elapsedTime, this._duration));
|
||||
}
|
||||
|
||||
public setTarget(renderable: RenderableComponent) {
|
||||
this._renderable = renderable;
|
||||
}
|
||||
|
||||
public recycleSelf() {
|
||||
if (this._shouldRecycleTween) {
|
||||
this._renderable = null;
|
||||
this._target = null;
|
||||
this._nextTween = null;
|
||||
}
|
||||
|
||||
if (this._shouldRecycleTween && TweenManager.cacheColorTweens) {
|
||||
Pool.free(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
100
source/src/Tween/TransformSpringTween.ts
Normal file
100
source/src/Tween/TransformSpringTween.ts
Normal file
@@ -0,0 +1,100 @@
|
||||
module es {
|
||||
export class TransformSpringTween extends AbstractTweenable {
|
||||
public get targetType() {
|
||||
return this._targetType;
|
||||
}
|
||||
|
||||
private _transform: Transform;
|
||||
private _targetType: TransformTargetType;
|
||||
private _targetValue: Vector2;
|
||||
private _velocity: Vector2;
|
||||
|
||||
// 阻尼比(dampingRatio)和角频率(angularFrequency)的配置是公开的,以便于在设计时进行调整
|
||||
|
||||
/**
|
||||
* 值越低,阻尼越小,值越高,阻尼越大,导致弹簧度越小,应在0.01-1之间,以避免系统不稳定
|
||||
*/
|
||||
public dampingRatio: number = 0.23;
|
||||
/**
|
||||
* 角频率为2pi(弧度/秒)意味着振荡在一秒钟内完成一个完整的周期,即1Hz.应小于35左右才能保持稳定角频率
|
||||
*/
|
||||
public angularFrequency: number = 25;
|
||||
|
||||
constructor(transform: Transform, targetType: TransformTargetType, targetValue: Vector2) {
|
||||
super();
|
||||
this._transform = transform;
|
||||
this._targetType = targetType;
|
||||
this.setTargetValue(targetValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* 你可以在任何时候调用setTargetValue来重置目标值到一个新的Vector2。
|
||||
* 如果你没有调用start来添加spring tween,它会为你调用
|
||||
* @param targetValue
|
||||
*/
|
||||
public setTargetValue(targetValue: Vector2) {
|
||||
this._velocity = Vector2.zero;
|
||||
this._targetValue = targetValue;
|
||||
|
||||
if (!this._isCurrentlyManagedByTweenManager)
|
||||
this.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* lambda应该是振荡幅度减少50%时的理想持续时间
|
||||
* @param lambda
|
||||
*/
|
||||
public updateDampingRatioWithHalfLife(lambda: number) {
|
||||
this.dampingRatio = (-lambda / this.angularFrequency) * Math.log(0.5);
|
||||
}
|
||||
|
||||
public tick() {
|
||||
if (!this._isPaused)
|
||||
this.setTweenedValue(Lerps.fastSpring(this.getCurrentValueOfTweenedTargetType(), this._targetValue, this._velocity,
|
||||
this.dampingRatio, this.angularFrequency));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private setTweenedValue(value: Vector2) {
|
||||
switch (this._targetType) {
|
||||
case TransformTargetType.position:
|
||||
this._transform.position = value;
|
||||
break;
|
||||
case TransformTargetType.localPosition:
|
||||
this._transform.localPosition = value;
|
||||
break;
|
||||
case TransformTargetType.scale:
|
||||
this._transform.scale = value;
|
||||
break;
|
||||
case TransformTargetType.localScale:
|
||||
this._transform.localScale = value;
|
||||
break;
|
||||
case TransformTargetType.rotationDegrees:
|
||||
this._transform.rotationDegrees = value.x;
|
||||
case TransformTargetType.localRotationDegrees:
|
||||
this._transform.localRotationDegrees = value.x;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private getCurrentValueOfTweenedTargetType() {
|
||||
switch (this._targetType) {
|
||||
case TransformTargetType.position:
|
||||
return this._transform.position;
|
||||
case TransformTargetType.localPosition:
|
||||
return this._transform.localPosition;
|
||||
case TransformTargetType.scale:
|
||||
return this._transform.scale;
|
||||
case TransformTargetType.localScale:
|
||||
return this._transform.localScale;
|
||||
case TransformTargetType.rotationDegrees:
|
||||
return new Vector2(this._transform.rotationDegrees);
|
||||
case TransformTargetType.localRotationDegrees:
|
||||
return new Vector2(this._transform.localRotationDegrees, 0);
|
||||
default:
|
||||
return Vector2.zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
90
source/src/Tween/TransformVector2Tween.ts
Normal file
90
source/src/Tween/TransformVector2Tween.ts
Normal file
@@ -0,0 +1,90 @@
|
||||
///<reference path="./Tweens.ts"/>
|
||||
module es {
|
||||
/**
|
||||
* 对任何与Transform相关的属性tweens都是有用的枚举
|
||||
*/
|
||||
export enum TransformTargetType {
|
||||
position,
|
||||
localPosition,
|
||||
scale,
|
||||
localScale,
|
||||
rotationDegrees,
|
||||
localRotationDegrees,
|
||||
}
|
||||
|
||||
/**
|
||||
* 这是一个特殊的情况,因为Transform是迄今为止最被ween的对象。
|
||||
* 我们将Tween和ITweenTarget封装在一个单一的、可缓存的类中
|
||||
*/
|
||||
export class TransformVector2Tween extends Vector2Tween implements ITweenTarget<Vector2> {
|
||||
private _transform: Transform;
|
||||
private _targetType: TransformTargetType;
|
||||
|
||||
public setTweenedValue(value: Vector2) {
|
||||
switch (this._targetType) {
|
||||
case TransformTargetType.position:
|
||||
this._transform.position = value;
|
||||
break;
|
||||
case TransformTargetType.localPosition:
|
||||
this._transform.localPosition = value;
|
||||
break;
|
||||
case TransformTargetType.scale:
|
||||
this._transform.scale = value;
|
||||
break;
|
||||
case TransformTargetType.localScale:
|
||||
this._transform.localScale = value;
|
||||
break;
|
||||
case TransformTargetType.rotationDegrees:
|
||||
this._transform.rotationDegrees = value.x;
|
||||
case TransformTargetType.localRotationDegrees:
|
||||
this._transform.localRotationDegrees = value.x;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public getTweenedValue(): Vector2 {
|
||||
switch (this._targetType) {
|
||||
case TransformTargetType.position:
|
||||
return this._transform.position;
|
||||
case TransformTargetType.localPosition:
|
||||
return this._transform.localPosition;
|
||||
case TransformTargetType.scale:
|
||||
return this._transform.scale;
|
||||
case TransformTargetType.localScale:
|
||||
return this._transform.localScale;
|
||||
case TransformTargetType.rotationDegrees:
|
||||
return new Vector2(this._transform.rotationDegrees, this._transform.rotationDegrees);
|
||||
case TransformTargetType.localRotationDegrees:
|
||||
return new Vector2(this._transform.localRotationDegrees, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public getTargetObject() {
|
||||
return this._transform;
|
||||
}
|
||||
|
||||
public setTargetAndType(transform: Transform, targetType: TransformTargetType) {
|
||||
this._transform = transform;
|
||||
this._targetType = targetType;
|
||||
}
|
||||
|
||||
protected updateValue() {
|
||||
// 非相对角勒普的特殊情况,使他们采取尽可能短的旋转
|
||||
if ((this._targetType == TransformTargetType.rotationDegrees ||
|
||||
this._targetType == TransformTargetType.localRotationDegrees) && !this._isRelative) {
|
||||
this.setTweenedValue(Lerps.easeAngle(this._easeType, this._fromValue, this._toValue, this._elapsedTime, this._duration));
|
||||
} else {
|
||||
this.setTweenedValue(Lerps.ease(this._easeType, this._fromValue, this._toValue, this._elapsedTime, this._duration));
|
||||
}
|
||||
}
|
||||
|
||||
public recycleSelf() {
|
||||
if (this._shouldRecycleTween) {
|
||||
this._target = null;
|
||||
this._nextTween = null;
|
||||
this._transform = null;
|
||||
Pool.free(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
319
source/src/Tween/Tween.ts
Normal file
319
source/src/Tween/Tween.ts
Normal file
@@ -0,0 +1,319 @@
|
||||
module es {
|
||||
export enum LoopType {
|
||||
none,
|
||||
restartFromBeginning,
|
||||
pingpong
|
||||
}
|
||||
|
||||
export enum TweenState {
|
||||
running,
|
||||
paused,
|
||||
complete
|
||||
}
|
||||
|
||||
export abstract class Tween<T> implements ITweenable, ITween<T> {
|
||||
protected _target: ITweenTarget<T>;
|
||||
protected _isFromValueOverridden: boolean;
|
||||
protected _fromValue: T;
|
||||
protected _toValue: T;
|
||||
protected _easeType: EaseType;
|
||||
protected _shouldRecycleTween: boolean = true;
|
||||
protected _isRelative: boolean;
|
||||
protected _completionHandler: (tween: ITween<T>) => void;
|
||||
protected _loopCompleteHandler: (tween: ITween<T>) => void;
|
||||
protected _nextTween: ITweenable;
|
||||
|
||||
protected _tweenState: TweenState = TweenState.complete;
|
||||
private _isTimeScaleIndependent: boolean;
|
||||
protected _delay: number;
|
||||
protected _duration: number;
|
||||
protected _timeScale: number = 1;
|
||||
protected _elapsedTime: number;
|
||||
|
||||
protected _loopType: LoopType;
|
||||
protected _loops: number;
|
||||
protected _delayBetweenLoops: number;
|
||||
private _isRunningInReverse: boolean;
|
||||
|
||||
public context: any;
|
||||
|
||||
public setEaseType(easeType: EaseType): ITween<T> {
|
||||
this._easeType = easeType;
|
||||
return this;
|
||||
}
|
||||
|
||||
public setDelay(delay: number): ITween<T> {
|
||||
this._delay = delay;
|
||||
this._elapsedTime = -this._delay;
|
||||
return this;
|
||||
}
|
||||
|
||||
public setDuration(duration: number): ITween<T> {
|
||||
this._duration = duration;
|
||||
return this;
|
||||
}
|
||||
|
||||
public setTimeScale(timeSclae: number): ITween<T> {
|
||||
this._timeScale = timeSclae;
|
||||
return this;
|
||||
}
|
||||
|
||||
public setIsTimeScaleIndependent(): ITween<T> {
|
||||
this._isTimeScaleIndependent = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public setCompletionHandler(completeHandler: (tween: ITween<T>) => void): ITween<T> {
|
||||
this._completionHandler = completeHandler;
|
||||
return this;
|
||||
}
|
||||
|
||||
public setLoops(loopType: LoopType, loops: number = 1, delayBetweenLoops: number = 0): ITween<T> {
|
||||
this._loopType = loopType;
|
||||
this._delayBetweenLoops = delayBetweenLoops;
|
||||
|
||||
if (loops < 0)
|
||||
loops = -1;
|
||||
|
||||
if (loopType == LoopType.pingpong)
|
||||
loops = loops * 2;
|
||||
|
||||
this._loops = loops;
|
||||
return this;
|
||||
}
|
||||
|
||||
public setLoopCompletionHanlder(loopCompleteHandler: (tween: ITween<T>) => void): ITween<T> {
|
||||
this._loopCompleteHandler = loopCompleteHandler;
|
||||
return this;
|
||||
}
|
||||
|
||||
public setFrom(from: T): ITween<T> {
|
||||
this._isFromValueOverridden = true;
|
||||
this._fromValue = from;
|
||||
return this;
|
||||
}
|
||||
|
||||
public prepareForReuse(from: T, to: T, duration: number): ITween<T> {
|
||||
this.initialize(this._target, to, duration);
|
||||
return this;
|
||||
}
|
||||
|
||||
public setRecycleTween(shouldRecycleTween: boolean): ITween<T> {
|
||||
this._shouldRecycleTween = shouldRecycleTween;
|
||||
return this;
|
||||
}
|
||||
|
||||
public abstract setIsRelative(): ITween<T>;
|
||||
|
||||
public setContext(context): ITween<T> {
|
||||
this.context = context;
|
||||
return this;
|
||||
}
|
||||
|
||||
public setNextTween(nextTween: ITweenable): ITween<T> {
|
||||
this._nextTween = nextTween;
|
||||
return this;
|
||||
}
|
||||
|
||||
public tick(): boolean {
|
||||
if (this._tweenState == TweenState.paused)
|
||||
return false;
|
||||
|
||||
// 当我们进行循环时,我们会在0和持续时间之间限制数值
|
||||
let elapsedTimeExcess = 0;
|
||||
if (!this._isRunningInReverse && this._elapsedTime >= this._duration) {
|
||||
elapsedTimeExcess = this._elapsedTime - this._duration;
|
||||
this._elapsedTime = this._duration;
|
||||
this._tweenState = TweenState.complete;
|
||||
} else if (this._isRunningInReverse && this._elapsedTime <= 0) {
|
||||
elapsedTimeExcess = 0 - this._elapsedTime;
|
||||
this._elapsedTime = 0;
|
||||
this._tweenState = TweenState.complete;
|
||||
}
|
||||
|
||||
// 当我们延迟开始tween的时候,经过的时间会是负数,所以不要更新这个值。
|
||||
if (this._elapsedTime >= 0 && this._elapsedTime <= this._duration) {
|
||||
this.updateValue();
|
||||
}
|
||||
|
||||
|
||||
// 如果我们有一个loopType,并且我们是Complete(意味着我们达到了0或持续时间)处理循环。
|
||||
// handleLooping将采取任何多余的elapsedTime,并将其因子化,并在必要时调用udpateValue来保持tween的完美准确性
|
||||
if (this._loopType != LoopType.none && this._tweenState == TweenState.complete && this._loops != 0) {
|
||||
this.handleLooping(elapsedTimeExcess);
|
||||
}
|
||||
|
||||
let deltaTime = this._isTimeScaleIndependent ? Time.unscaledDeltaTime : Time.deltaTime;
|
||||
deltaTime *= this._timeScale;
|
||||
|
||||
// 我们需要减去deltaTime
|
||||
if (this._isRunningInReverse)
|
||||
this._elapsedTime -= deltaTime;
|
||||
else
|
||||
this._elapsedTime += deltaTime;
|
||||
|
||||
if (this._tweenState == TweenState.complete) {
|
||||
this._completionHandler && this._completionHandler(this);
|
||||
|
||||
// 如果我们有一个nextTween,把它添加到TweenManager中,这样它就可以开始运行了
|
||||
if (this._nextTween != null) {
|
||||
this._nextTween.start();
|
||||
this._nextTween = null;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public recycleSelf() {
|
||||
if (this._shouldRecycleTween) {
|
||||
this._target = null;
|
||||
this._nextTween = null;
|
||||
}
|
||||
}
|
||||
|
||||
public isRunning(): boolean {
|
||||
return this._tweenState == TweenState.running;
|
||||
}
|
||||
|
||||
public start() {
|
||||
if (!this._isFromValueOverridden)
|
||||
this._fromValue = this._target.getTargetObject();
|
||||
|
||||
if (this._tweenState == TweenState.complete) {
|
||||
this._tweenState = TweenState.running;
|
||||
TweenManager.addTween(this);
|
||||
}
|
||||
}
|
||||
|
||||
public pause() {
|
||||
this._tweenState = TweenState.paused;
|
||||
}
|
||||
|
||||
public resume() {
|
||||
this._tweenState = TweenState.running;
|
||||
}
|
||||
|
||||
public stop(bringToCompletion: boolean = false) {
|
||||
this._tweenState = TweenState.complete;
|
||||
|
||||
if (bringToCompletion) {
|
||||
// 如果我们逆向运行,我们在0处结束,否则我们进入持续时间
|
||||
this._elapsedTime = this._isRunningInReverse ? 0 : this._duration;
|
||||
this._loopType = LoopType.none;
|
||||
this._loops = 0;
|
||||
|
||||
// TweenManager将在下一个tick上进行删除处理
|
||||
} else {
|
||||
TweenManager.removeTween(this);
|
||||
}
|
||||
}
|
||||
|
||||
public jumpToElapsedTime(elapsedTime) {
|
||||
this._elapsedTime = MathHelper.clamp(elapsedTime, 0, this._duration);
|
||||
this.updateValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* 反转当前的tween,如果是向前走,就会向后走,反之亦然
|
||||
*/
|
||||
public reverseTween() {
|
||||
this._isRunningInReverse = !this._isRunningInReverse;
|
||||
}
|
||||
|
||||
/**
|
||||
* 当通过StartCoroutine调用时,这将一直持续到tween完成
|
||||
*/
|
||||
public * waitForCompletion() {
|
||||
while (this._tweenState != TweenState.complete)
|
||||
yield null;
|
||||
}
|
||||
|
||||
public getTargetObject() {
|
||||
return this._target.getTargetObject();
|
||||
}
|
||||
|
||||
private resetState() {
|
||||
this.context = null;
|
||||
this._completionHandler = this._loopCompleteHandler = null;
|
||||
this._isFromValueOverridden = false;
|
||||
this._isTimeScaleIndependent = false;
|
||||
this._tweenState = TweenState.complete;
|
||||
|
||||
// TODO: 我认为在没有得到用户同意的情况下,我们绝对不应该从_shouldRecycleTween=false。需要研究和思考
|
||||
// this._shouldRecycleTween = true;
|
||||
this._isRelative = false;
|
||||
this._easeType = TweenManager.defaultEaseType;
|
||||
|
||||
if (this._nextTween != null) {
|
||||
this._nextTween.recycleSelf();
|
||||
this._nextTween = null;
|
||||
}
|
||||
|
||||
this._delay = 0;
|
||||
this._duration = 0;
|
||||
this._timeScale = 1;
|
||||
this._elapsedTime = 0;
|
||||
this._loopType = LoopType.none;
|
||||
this._delayBetweenLoops = 0;
|
||||
this._loops = 0;
|
||||
this._isRunningInReverse = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将所有状态重置为默认值,并根据传入的参数设置初始状态。
|
||||
* 这个方法作为一个切入点,这样Tween子类就可以调用它,这样tweens就可以被回收。
|
||||
* 当回收时,构造函数不会再被调用,所以这个方法封装了构造函数要做的事情
|
||||
* @param target
|
||||
* @param to
|
||||
* @param duration
|
||||
*/
|
||||
public initialize(target: ITweenTarget<T>, to: T, duration: number) {
|
||||
// 重置状态,以防我们被回收
|
||||
this.resetState();
|
||||
|
||||
this._target = target;
|
||||
this._toValue = to;
|
||||
this._duration = duration;
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理循环逻辑
|
||||
* @param elapsedTimeExcess
|
||||
*/
|
||||
private handleLooping(elapsedTimeExcess: number) {
|
||||
this._loops--;
|
||||
if (this._loopType == LoopType.pingpong) {
|
||||
this.reverseTween();
|
||||
}
|
||||
|
||||
if (this._loopType == LoopType.restartFromBeginning || this._loops % 2 == 0) {
|
||||
this._loopCompleteHandler && this._completionHandler(this);
|
||||
}
|
||||
|
||||
// 如果我们还有循环要处理,就把我们的状态重置为Running,这样我们就可以继续处理它们了
|
||||
if (this._loops != 0) {
|
||||
this._tweenState = TweenState.running;
|
||||
|
||||
// 现在,我们需要设置我们的经过时间,并考虑到我们的elapsedTimeExcess
|
||||
if (this._loopType == LoopType.restartFromBeginning) {
|
||||
this._elapsedTime = elapsedTimeExcess - this._delayBetweenLoops;
|
||||
} else {
|
||||
if (this._isRunningInReverse)
|
||||
this._elapsedTime += this._delayBetweenLoops - elapsedTimeExcess;
|
||||
else
|
||||
this._elapsedTime = elapsedTimeExcess - this._delayBetweenLoops;
|
||||
}
|
||||
|
||||
// 如果我们有一个elapsedTimeExcess,并且没有delayBetweenLoops,则更新该值
|
||||
if (this._delayBetweenLoops == 0 && elapsedTimeExcess > 0) {
|
||||
this.updateValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract updateValue();
|
||||
}
|
||||
}
|
||||
152
source/src/Tween/TweenManager.ts
Normal file
152
source/src/Tween/TweenManager.ts
Normal file
@@ -0,0 +1,152 @@
|
||||
///<reference path="./Easing/EaseType.ts" />
|
||||
///<reference path="../Utils/GlobalManager.ts"/>
|
||||
module es {
|
||||
export class TweenManager extends GlobalManager {
|
||||
public static defaultEaseType: EaseType = EaseType.quartIn;
|
||||
|
||||
/**
|
||||
* 如果为真,当加载新关卡时,活动的tween列表将被清除
|
||||
*/
|
||||
public static removeAllTweensOnLevelLoad: boolean = false;
|
||||
|
||||
/**
|
||||
* 这里支持各种类型的自动缓存。请
|
||||
* 注意,只有在使用扩展方法启动tweens时,或者在做自定义tweens时从缓存中获取tween时,缓存才会起作用。
|
||||
* 关于如何获取缓存的tween,请参见扩展方法的实现
|
||||
*/
|
||||
public static cacheNumberTweens = true;
|
||||
public static cacheVector2Tweens = true;
|
||||
public static cacheColorTweens = true;
|
||||
public static cacheRectTweens = false;
|
||||
|
||||
/**
|
||||
* 当前所有活跃用户的内部列表
|
||||
*/
|
||||
private _activeTweens: ITweenable[] = [];
|
||||
private _tempTweens: ITweenable[] = [];
|
||||
/**
|
||||
* 标志表示tween更新循环正在运行
|
||||
*/
|
||||
private _isUpdating: boolean;
|
||||
/**
|
||||
* 便于暴露一个静态的API以方便访问
|
||||
*/
|
||||
private static _instance: TweenManager;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
TweenManager._instance = this;
|
||||
}
|
||||
|
||||
public update() {
|
||||
this._isUpdating = true;
|
||||
|
||||
// 反向循环,这样我们就可以把完成的weens删除了
|
||||
for (let i = this._activeTweens.length - 1; i >= 0; --i) {
|
||||
let tween = this._activeTweens[i];
|
||||
if (tween.tick())
|
||||
this._tempTweens.push(tween);
|
||||
}
|
||||
|
||||
this._isUpdating = false;
|
||||
|
||||
for (let i = 0; i < this._tempTweens.length; i++) {
|
||||
this._tempTweens[i].recycleSelf();
|
||||
new List(this._activeTweens).remove(this._tempTweens[i]);
|
||||
}
|
||||
|
||||
this._tempTweens.length = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将一个tween添加到活动tweens列表中
|
||||
* @param tween
|
||||
*/
|
||||
public static addTween(tween: ITweenable) {
|
||||
TweenManager._instance._activeTweens.push(tween);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从当前的tweens列表中删除一个tween
|
||||
* @param tween
|
||||
*/
|
||||
public static removeTween(tween: ITweenable) {
|
||||
if (TweenManager._instance._isUpdating) {
|
||||
TweenManager._instance._tempTweens.push(tween);
|
||||
} else {
|
||||
tween.recycleSelf();
|
||||
new List(TweenManager._instance._activeTweens).remove(tween);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止所有的tween并选择地把他们全部完成
|
||||
* @param bringToCompletion
|
||||
*/
|
||||
public static stopAllTweens(bringToCompletion: boolean = false) {
|
||||
for (let i = TweenManager._instance._activeTweens.length - 1; i >= 0; --i)
|
||||
TweenManager._instance._activeTweens[i].stop(bringToCompletion);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回具有特定上下文的所有tweens。
|
||||
* Tweens以ITweenable的形式返回,因为这就是TweenManager所知道的所有内容
|
||||
* @param context
|
||||
*/
|
||||
public static allTweensWithContext(context): ITweenable[] {
|
||||
let foundTweens = [];
|
||||
for (let i = 0; i < TweenManager._instance._activeTweens.length; i++) {
|
||||
if ((TweenManager._instance._activeTweens[i] as ITweenControl).context == context)
|
||||
foundTweens.push(TweenManager._instance._activeTweens[i]);
|
||||
}
|
||||
|
||||
return foundTweens;
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止所有给定上下文的tweens
|
||||
* @param context
|
||||
* @param bringToCompletion
|
||||
*/
|
||||
public static stopAllTweensWithContext(context, bringToCompletion: boolean = false) {
|
||||
for (let i = TweenManager._instance._activeTweens.length - 1; i >= 0; --i) {
|
||||
if ((TweenManager._instance._activeTweens[i] as ITweenControl).context == context)
|
||||
TweenManager._instance._activeTweens[i].stop(bringToCompletion);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回具有特定目标的所有tweens。
|
||||
* Tweens以ITweenControl的形式返回,因为TweenManager只知道这些
|
||||
* @param target
|
||||
*/
|
||||
public static allTweenWithTarget(target): ITweenable[] {
|
||||
let foundTweens = [];
|
||||
|
||||
for (let i = 0; i < TweenManager._instance._activeTweens.length; i++) {
|
||||
if (TweenManager._instance._activeTweens[i]) {
|
||||
let tweenControl = TweenManager._instance._activeTweens[i] as ITweenControl;
|
||||
if (tweenControl.getTargetObject() == target)
|
||||
foundTweens.push(TweenManager._instance._activeTweens[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return foundTweens;
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止所有具有TweenManager知道的特定目标的tweens
|
||||
* @param target
|
||||
* @param bringToCompletion
|
||||
*/
|
||||
public static stopAllTweensWithTarget(target, bringToCompletion: boolean = false) {
|
||||
for (let i = TweenManager._instance._activeTweens.length - 1; i >= 0; --i) {
|
||||
if (TweenManager._instance._activeTweens[i]) {
|
||||
let tweenControl = TweenManager._instance._activeTweens[i] as ITweenControl;
|
||||
if (tweenControl.getTargetObject() == target)
|
||||
tweenControl.stop(bringToCompletion);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
117
source/src/Tween/Tweens.ts
Normal file
117
source/src/Tween/Tweens.ts
Normal file
@@ -0,0 +1,117 @@
|
||||
///<reference path="./Tween.ts"/>
|
||||
module es {
|
||||
export class NumberTween extends Tween<number> {
|
||||
public static create(): NumberTween {
|
||||
return TweenManager.cacheNumberTweens ? Pool.obtain(NumberTween) : new NumberTween();
|
||||
}
|
||||
|
||||
constructor(target?: ITweenTarget<number>, to?: number, duration?: number) {
|
||||
super();
|
||||
this.initialize(target, to, duration);
|
||||
}
|
||||
|
||||
public setIsRelative(): ITween<number> {
|
||||
this._isRelative = true;
|
||||
this._toValue += this._fromValue;
|
||||
return this;
|
||||
}
|
||||
|
||||
protected updateValue() {
|
||||
this._target.setTweenedValue(Lerps.ease(this._easeType, this._fromValue, this._toValue, this._elapsedTime, this._duration));
|
||||
}
|
||||
|
||||
public recycleSelf() {
|
||||
super.recycleSelf();
|
||||
|
||||
if (this._shouldRecycleTween && TweenManager.cacheNumberTweens)
|
||||
Pool.free(this);
|
||||
}
|
||||
}
|
||||
|
||||
export class Vector2Tween extends Tween<Vector2> {
|
||||
public static create(): Vector2Tween {
|
||||
return TweenManager.cacheVector2Tweens ? Pool.obtain(Vector2Tween) : new Vector2Tween();
|
||||
}
|
||||
|
||||
constructor(target?: ITweenTarget<Vector2>, to?: Vector2, duration?: number) {
|
||||
super();
|
||||
this.initialize(target, to, duration);
|
||||
}
|
||||
|
||||
public setIsRelative(): ITween<Vector2> {
|
||||
this._isRelative = true;
|
||||
this._toValue.add(this._fromValue);
|
||||
return this;
|
||||
}
|
||||
|
||||
protected updateValue() {
|
||||
this._target.setTweenedValue(Lerps.ease(this._easeType, this._fromValue, this._toValue, this._elapsedTime, this._duration));
|
||||
}
|
||||
|
||||
public recycleSelf() {
|
||||
super.recycleSelf();
|
||||
|
||||
if (this._shouldRecycleTween && TweenManager.cacheVector2Tweens)
|
||||
Pool.free(this);
|
||||
}
|
||||
}
|
||||
|
||||
export class RectangleTween extends Tween<Rectangle> {
|
||||
public static create(): RectangleTween {
|
||||
return TweenManager.cacheRectTweens ? Pool.obtain(RectangleTween) : new RectangleTween();
|
||||
}
|
||||
|
||||
constructor(target?: ITweenTarget<Rectangle>, to?: Rectangle, duration?: number) {
|
||||
super();
|
||||
this.initialize(target, to, duration);
|
||||
}
|
||||
|
||||
public setIsRelative(): ITween<Rectangle> {
|
||||
this._isRelative = true;
|
||||
this._toValue = new Rectangle(
|
||||
this._toValue.x + this._fromValue.x,
|
||||
this._toValue.y + this._fromValue.y,
|
||||
this._toValue.width + this._fromValue.width,
|
||||
this._toValue.height + this._fromValue.height);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
protected updateValue() {
|
||||
this._target.setTweenedValue(Lerps.ease(this._easeType, this._fromValue, this._toValue, this._elapsedTime, this._duration));
|
||||
}
|
||||
|
||||
public recycleSelf() {
|
||||
super.recycleSelf();
|
||||
|
||||
if (this._shouldRecycleTween && TweenManager.cacheRectTweens)
|
||||
Pool.free(this);
|
||||
}
|
||||
}
|
||||
|
||||
export class ColorTween extends Tween<Color> {
|
||||
public static create() : ColorTween {
|
||||
return TweenManager.cacheColorTweens ? Pool.obtain(ColorTween) : new ColorTween();
|
||||
|
||||
}
|
||||
|
||||
constructor(target?: ITweenTarget<Color>, to?: Color, duration?: number) {
|
||||
super();
|
||||
|
||||
this.initialize(target, to, duration);
|
||||
}
|
||||
|
||||
public setIsRelative() {
|
||||
this._isRelative = true;
|
||||
this._toValue.r += this._fromValue.r;
|
||||
this._toValue.g += this._fromValue.g;
|
||||
this._toValue.b += this._fromValue.b;
|
||||
this._toValue.a += this._fromValue.a;
|
||||
return this;
|
||||
}
|
||||
|
||||
protected updateValue() {
|
||||
this._target.setTweenedValue(Lerps.ease(this._easeType, this._fromValue as any, this._toValue as any, this._elapsedTime, this._duration));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user