内置tween管理器

This commit is contained in:
yhh
2021-07-03 12:27:21 +08:00
parent 13a001c258
commit dc3d639824
26 changed files with 3719 additions and 142 deletions

View File

@@ -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;

View File

@@ -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;
}
}
}

View File

@@ -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)

View File

@@ -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));
}
/**

View File

@@ -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;

View 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;
}
}
}

View 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);
}
}
}
}

View 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);
}
}
}
}

View 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;
}
}
}

View 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>;
}
}

View 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;
}
}

View 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;
}
}

View 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);
}
}

View 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;
}
}
}

View 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);
}
}
}
}

View 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;
}
}
}
}

View 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
View 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();
}
}

View 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
View 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));
}
}
}