内置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
-3
View File
@@ -10,6 +10,3 @@
[submodule "extensions/behaviourTree-ai"]
path = extensions/behaviourTree-ai
url = https://github.com/esengine/BehaviourTree-ai
[submodule "extensions/ecs-tween"]
path = extensions/ecs-tween
url = https://github.com/esengine/ecs-tween
+1 -4
View File
@@ -5,13 +5,10 @@ ecs-framework 的目标是成为功能强大的框架。它为您构建游戏提
- AABB,圆和多边形碰撞/触发检测
- 高效的协程,可在多个帧或动画定时中分解大型任务(Core.startCoroutine
- 通过Astar和广度优先搜索提供寻路支持,以查找图块地图或您自己的自定义格式 ( 参见 https://github.com/esengine/ecs-astar )
- tween系统。任何number / Vector / 矩形/字段或属性都可以tween。 (参见 https://github.com/esengine/ecs-tween
- tween系统。任何number / Vector / 矩形/字段或属性都可以tween。
- 针对核心事件的优化的事件发射器(发射器类),您也可以将其添加到自己的任何类中
- 延迟和重复任务的调度程序(核心调度方法)
## 关于ECS-FRAMEWORK
该项目由Nez项目由C#转为Typescript。感谢该项目提供的思路:https://github.com/prime31/Nez
## 交流群
点击链接加入群聊【ecs游戏框架交流】:https://jq.qq.com/?_wv=1027&k=29w1Nud6
+616 -32
View File
@@ -423,6 +423,14 @@ declare module es {
* 从实体中删除所有组件
*/
removeAllComponents(): void;
tweenPositionTo(to: Vector2, duration?: number): ITween<Vector2>;
tweenLocalPositionTo(to: Vector2, duration?: number): ITween<Vector2>;
tweenScaleTo(to: Vector2, duration?: number): any;
tweenScaleTo(to: number, duration?: number): any;
tweenLocalScaleTo(to: Vector2, duration?: any): any;
tweenLocalScaleTo(to: number, duration?: any): any;
tweenRotationDegreesTo(to: number, duration?: number): TransformVector2Tween;
tweenLocalRotationDegreesTo(to: number, duration?: number): TransformVector2Tween;
compareTo(other: Entity): number;
equals(other: Entity): boolean;
getHashCode(): number;
@@ -1506,6 +1514,7 @@ declare module es {
getbounds(): es.Rectangle;
readonly bounds: Rectangle;
protected _areBoundsDirty: boolean;
color: Color;
renderLayer: number;
protected _renderLayer: number;
onEntityTransformChanged(comp: transform.Component): void;
@@ -1521,6 +1530,7 @@ declare module es {
setRenderLayer(renderLayer: number): RenderableComponent;
isVisibleFromCamera(cam: ICamera): boolean;
debugRender(batcher: IBatcher): void;
tweenColorTo(to: Color, duration: number): RenderableColorTween;
}
}
declare module es {
@@ -4224,6 +4234,612 @@ declare module es {
debugRender(batcher: IBatcher): void;
}
}
declare module es {
/**
* AbstractTweenable作为你可能想做的任何可以执行的自定义类的基础。
* 这些类不同于ITweens,因为他们没有实现ITweenT接口。
* 它只是说一个AbstractTweenable不仅仅是将一个值从开始移动到结束。
* 它可以做任何需要每帧执行的事情。
*/
abstract class AbstractTweenable implements ITweenable {
protected _isPaused: boolean;
/**
* abstractTweenable在完成后往往会被保留下来。
* 这个标志可以让它们在内部知道自己当前是否被TweenManager盯上了,以便在必要时可以重新添加自己。
*/
protected _isCurrentlyManagedByTweenManager: boolean;
abstract tick(): boolean;
recycleSelf(): void;
isRunning(): boolean;
start(): void;
pause(): void;
resume(): void;
stop(bringToCompletion?: boolean): void;
}
}
declare module es {
class PropertyTweens {
static NumberPropertyTo(self: any, memberName: string, to: number, duration: number): ITween<number>;
static Vector2PropertyTo(self: any, memeberName: string, to: Vector2, duration: number): ITween<Vector2>;
}
}
declare module es {
enum LoopType {
none = 0,
restartFromBeginning = 1,
pingpong = 2
}
enum TweenState {
running = 0,
paused = 1,
complete = 2
}
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;
protected _isRelative: boolean;
protected _completionHandler: (tween: ITween<T>) => void;
protected _loopCompleteHandler: (tween: ITween<T>) => void;
protected _nextTween: ITweenable;
protected _tweenState: TweenState;
private _isTimeScaleIndependent;
protected _delay: number;
protected _duration: number;
protected _timeScale: number;
protected _elapsedTime: number;
protected _loopType: LoopType;
protected _loops: number;
protected _delayBetweenLoops: number;
private _isRunningInReverse;
context: any;
setEaseType(easeType: EaseType): ITween<T>;
setDelay(delay: number): ITween<T>;
setDuration(duration: number): ITween<T>;
setTimeScale(timeSclae: number): ITween<T>;
setIsTimeScaleIndependent(): ITween<T>;
setCompletionHandler(completeHandler: (tween: ITween<T>) => void): ITween<T>;
setLoops(loopType: LoopType, loops?: number, delayBetweenLoops?: number): ITween<T>;
setLoopCompletionHanlder(loopCompleteHandler: (tween: ITween<T>) => void): ITween<T>;
setFrom(from: T): ITween<T>;
prepareForReuse(from: T, to: T, duration: number): ITween<T>;
setRecycleTween(shouldRecycleTween: boolean): ITween<T>;
abstract setIsRelative(): ITween<T>;
setContext(context: any): ITween<T>;
setNextTween(nextTween: ITweenable): ITween<T>;
tick(): boolean;
recycleSelf(): void;
isRunning(): boolean;
start(): void;
pause(): void;
resume(): void;
stop(bringToCompletion?: boolean): void;
jumpToElapsedTime(elapsedTime: any): void;
/**
* 反转当前的tween,如果是向前走,就会向后走,反之亦然
*/
reverseTween(): void;
/**
* 当通过StartCoroutine调用时,这将一直持续到tween完成
*/
waitForCompletion(): IterableIterator<any>;
getTargetObject(): any;
private resetState;
/**
* 将所有状态重置为默认值,并根据传入的参数设置初始状态。
* 这个方法作为一个切入点,这样Tween子类就可以调用它,这样tweens就可以被回收。
* 当回收时,构造函数不会再被调用,所以这个方法封装了构造函数要做的事情
* @param target
* @param to
* @param duration
*/
initialize(target: ITweenTarget<T>, to: T, duration: number): void;
/**
* 处理循环逻辑
* @param elapsedTimeExcess
*/
private handleLooping;
protected abstract updateValue(): any;
}
}
declare module es {
class NumberTween extends Tween<number> {
static create(): NumberTween;
constructor(target?: ITweenTarget<number>, to?: number, duration?: number);
setIsRelative(): ITween<number>;
protected updateValue(): void;
recycleSelf(): void;
}
class Vector2Tween extends Tween<Vector2> {
static create(): Vector2Tween;
constructor(target?: ITweenTarget<Vector2>, to?: Vector2, duration?: number);
setIsRelative(): ITween<Vector2>;
protected updateValue(): void;
recycleSelf(): void;
}
class RectangleTween extends Tween<Rectangle> {
static create(): RectangleTween;
constructor(target?: ITweenTarget<Rectangle>, to?: Rectangle, duration?: number);
setIsRelative(): ITween<Rectangle>;
protected updateValue(): void;
recycleSelf(): void;
}
class ColorTween extends Tween<Color> {
static create(): ColorTween;
constructor(target?: ITweenTarget<Color>, to?: Color, duration?: number);
setIsRelative(): this;
protected updateValue(): void;
}
}
declare module es {
class RenderableColorTween extends ColorTween implements ITweenTarget<Color> {
_renderable: RenderableComponent;
setTweenedValue(value: Color): void;
getTweenedValue(): Color;
getTargetObject(): RenderableComponent;
updateValue(): void;
setTarget(renderable: RenderableComponent): void;
recycleSelf(): void;
}
}
declare module es {
class TransformSpringTween extends AbstractTweenable {
readonly targetType: TransformTargetType;
private _transform;
private _targetType;
private _targetValue;
private _velocity;
/**
* 值越低,阻尼越小,值越高,阻尼越大,导致弹簧度越小,应在0.01-1之间,以避免系统不稳定
*/
dampingRatio: number;
/**
* 角频率为2pi(弧度/秒)意味着振荡在一秒钟内完成一个完整的周期,即1Hz.应小于35左右才能保持稳定角频率
*/
angularFrequency: number;
constructor(transform: Transform, targetType: TransformTargetType, targetValue: Vector2);
/**
* 你可以在任何时候调用setTargetValue来重置目标值到一个新的Vector2。
* 如果你没有调用start来添加spring tween,它会为你调用
* @param targetValue
*/
setTargetValue(targetValue: Vector2): void;
/**
* lambda应该是振荡幅度减少50%时的理想持续时间
* @param lambda
*/
updateDampingRatioWithHalfLife(lambda: number): void;
tick(): boolean;
private setTweenedValue;
private getCurrentValueOfTweenedTargetType;
}
}
declare module es {
/**
* 对任何与Transform相关的属性tweens都是有用的枚举
*/
enum TransformTargetType {
position = 0,
localPosition = 1,
scale = 2,
localScale = 3,
rotationDegrees = 4,
localRotationDegrees = 5
}
/**
* 这是一个特殊的情况,因为Transform是迄今为止最被ween的对象。
* 我们将Tween和ITweenTarget封装在一个单一的、可缓存的类中
*/
class TransformVector2Tween extends Vector2Tween implements ITweenTarget<Vector2> {
private _transform;
private _targetType;
setTweenedValue(value: Vector2): void;
getTweenedValue(): Vector2;
getTargetObject(): Transform;
setTargetAndType(transform: Transform, targetType: TransformTargetType): void;
protected updateValue(): void;
recycleSelf(): void;
}
}
declare module es {
enum EaseType {
linear = 0,
sineIn = 1,
sineOut = 2,
sineInOut = 3,
quadIn = 4,
quadOut = 5,
quadInOut = 6,
quintIn = 7,
quintOut = 8,
quintInOut = 9,
cubicIn = 10,
cubicOut = 11,
cubicInOut = 12,
quartIn = 13,
quartOut = 14,
quartInOut = 15,
expoIn = 16,
expoOut = 17,
expoInOut = 18,
circleIn = 19,
circleOut = 20,
circleInOut = 21,
elasticIn = 22,
elasticOut = 23,
elasticInOut = 24,
punch = 25,
backIn = 26,
backOut = 27,
backInOut = 28,
bounceIn = 29,
bounceOut = 30,
bounceInOut = 31
}
/**
* 助手的一个方法,它接收一个EaseType,并通过给定的持续时间和时间参数来应用该Ease方程。
* 我们这样做是为了避免传来传去的Funcs为垃圾收集器制造大量垃圾
*/
class EaseHelper {
/**
* 返回 easeType 的相反 EaseType
* @param easeType
*/
static oppositeEaseType(easeType: EaseType): EaseType.linear | EaseType.sineIn | EaseType.sineOut | EaseType.sineInOut | EaseType.quadIn | EaseType.quadOut | EaseType.quadInOut | EaseType.quintIn | EaseType.quintOut | EaseType.quintInOut | EaseType.cubicIn | EaseType.cubicOut | EaseType.cubicInOut | EaseType.quartIn | EaseType.quartInOut | EaseType.expoIn | EaseType.expoOut | EaseType.expoInOut | EaseType.circleIn | EaseType.circleOut | EaseType.circleInOut | EaseType.elasticIn | EaseType.elasticOut | EaseType.elasticInOut | EaseType.punch | EaseType.backIn | EaseType.backOut | EaseType.backInOut | EaseType.bounceIn | EaseType.bounceOut | EaseType.bounceInOut;
static ease(easeType: EaseType, t: number, duration: number): number;
}
}
declare module es {
class GlobalManager {
_enabled: boolean;
/**
* 如果true则启用了GlobalManager。
* 状态的改变会导致调用OnEnabled/OnDisable
*/
/**
* 如果true则启用了GlobalManager。
* 状态的改变会导致调用OnEnabled/OnDisable
* @param value
*/
enabled: boolean;
/**
* 启用/禁用这个GlobalManager
* @param isEnabled
*/
setEnabled(isEnabled: boolean): void;
/**
* 此GlobalManager启用时调用
*/
onEnabled(): void;
/**
* 此GlobalManager禁用时调用
*/
onDisabled(): void;
/**
* 在frame .update之前调用每一帧
*/
update(): void;
}
}
declare module es {
class TweenManager extends GlobalManager {
static defaultEaseType: EaseType;
/**
* 如果为真,当加载新关卡时,活动的tween列表将被清除
*/
static removeAllTweensOnLevelLoad: boolean;
/**
* 这里支持各种类型的自动缓存。请
* 注意,只有在使用扩展方法启动tweens时,或者在做自定义tweens时从缓存中获取tween时,缓存才会起作用。
* 关于如何获取缓存的tween,请参见扩展方法的实现
*/
static cacheNumberTweens: boolean;
static cacheVector2Tweens: boolean;
static cacheColorTweens: boolean;
static cacheRectTweens: boolean;
/**
* 当前所有活跃用户的内部列表
*/
private _activeTweens;
private _tempTweens;
/**
* 标志表示tween更新循环正在运行
*/
private _isUpdating;
/**
* 便于暴露一个静态的API以方便访问
*/
private static _instance;
constructor();
update(): void;
/**
* 将一个tween添加到活动tweens列表中
* @param tween
*/
static addTween(tween: ITweenable): void;
/**
* 从当前的tweens列表中删除一个tween
* @param tween
*/
static removeTween(tween: ITweenable): void;
/**
* 停止所有的tween并选择地把他们全部完成
* @param bringToCompletion
*/
static stopAllTweens(bringToCompletion?: boolean): void;
/**
* 返回具有特定上下文的所有tweens。
* Tweens以ITweenable的形式返回,因为这就是TweenManager所知道的所有内容
* @param context
*/
static allTweensWithContext(context: any): ITweenable[];
/**
* 停止所有给定上下文的tweens
* @param context
* @param bringToCompletion
*/
static stopAllTweensWithContext(context: any, bringToCompletion?: boolean): void;
/**
* 返回具有特定目标的所有tweens。
* Tweens以ITweenControl的形式返回,因为TweenManager只知道这些
* @param target
*/
static allTweenWithTarget(target: any): ITweenable[];
/**
* 停止所有具有TweenManager知道的特定目标的tweens
* @param target
* @param bringToCompletion
*/
static stopAllTweensWithTarget(target: any, bringToCompletion?: boolean): void;
}
}
declare module es {
/**
* 标准缓和方程通过将b和c参数(起始值和变化值)用0和1替换,然后进行简化。
* 这样做的目的是为了让我们可以得到一个0 - 1之间的原始值(除了弹性/反弹故意超过界限),然后用这个值来lerp任何东西
*/
module Easing {
class Linear {
static easeNone(t: number, d: number): number;
}
class Quadratic {
static easeIn(t: number, d: number): number;
static easeOut(t: number, d: number): number;
static easeInOut(t: number, d: number): number;
}
class Back {
static easeIn(t: number, d: number): number;
static easeOut(t: number, d: number): number;
static easeInOut(t: number, d: number): number;
}
class Bounce {
static easeOut(t: number, d: number): number;
static easeIn(t: number, d: number): number;
static easeInOut(t: number, d: number): number;
}
class Circular {
static easeIn(t: number, d: number): number;
static easeOut(t: number, d: number): number;
static easeInOut(t: number, d: number): number;
}
class Cubic {
static easeIn(t: number, d: number): number;
static easeOut(t: number, d: number): number;
static easeInOut(t: number, d: number): number;
}
class Elastic {
static easeIn(t: number, d: number): number;
static easeOut(t: number, d: number): number;
static easeInOut(t: number, d: number): number;
static punch(t: number, d: number): number;
}
class Exponential {
static easeIn(t: number, d: number): number;
static easeOut(t: number, d: number): number;
static easeInOut(t: number, d: number): number;
}
class Quartic {
static easeIn(t: number, d: number): number;
static easeOut(t: number, d: number): number;
static easeInOut(t: number, d: number): number;
}
class Quintic {
static easeIn(t: number, d: number): number;
static easeOut(t: number, d: number): number;
static easeInOut(t: number, d: number): number;
}
class Sinusoidal {
static easeIn(t: number, d: number): number;
static easeOut(t: number, d: number): number;
static easeInOut(t: number, d: number): number;
}
}
}
declare module es {
/**
* 一系列静态方法来处理所有常见的tween类型结构,以及它们的unclamped lerps.unclamped lerps对于超过0-1范围的bounce、elastic或其他tweens是必需的
*/
class Lerps {
static lerp(from: Color, to: Color, t: number): any;
static lerp(from: number, to: number, t: number): any;
static lerp(from: Rectangle, to: Rectangle, t: number): any;
static lerp(from: Vector2, to: Vector2, t: number): any;
static angleLerp(from: Vector2, to: Vector2, t: number): Vector2;
static ease(easeType: EaseType, from: Rectangle, to: Rectangle, t: number, duration: number): any;
static ease(easeType: EaseType, from: Vector2, to: Vector2, t: number, duration: number): any;
static ease(easeType: EaseType, from: number, to: number, t: number, duration: number): any;
static ease(easeType: EaseType, from: Color, to: Color, t: number, duration: number): any;
static easeAngle(easeType: EaseType, from: Vector2, to: Vector2, t: number, duration: number): Vector2;
/**
* 使用半隐式欧拉方法。速度较慢,但总是很稳定。见
* 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左右才能保持稳定
*/
static fastSpring(currentValue: Vector2, targetValue: Vector2, velocity: Vector2, dampingRatio: number, angularFrequency: number): Vector2;
}
}
declare module es {
/**
* 一系列强类型、可链式的方法来设置各种tween属性
*/
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: any): ITween<T>;
/**
* 允许你添加一个tween,这个tween完成后会被运行。
* 注意 nextTween 必须是一个 ITweenable! 同时注意,所有的ITweenT都是ITweenable
* @param nextTween
*/
setNextTween(nextTween: ITweenable): ITween<T>;
}
}
declare module es {
/**
* 更多具体的Tween播放控制在这里
*/
interface ITweenControl extends ITweenable {
/**
* 当使用匿名方法时,您可以在任何回调(如完成处理程序)中使用该属性来避免分配
*/
context: any;
/**
* 将tween扭曲为elapsedTime,并将其限制在0和duration之间,无论tween对象是暂停、完成还是运行,都会立即更新
* @param elapsedTime 所用时间
*/
jumpToElapsedTime(elapsedTime: number): any;
/**
* 当从StartCoroutine调用时,它将直到tween完成
*/
waitForCompletion(): any;
/**
* 获取tween的目标,如果TweenTargets不一定都是一个对象,则为null,它的唯一真正用途是让TweenManager按目标查找tweens的列表
*/
getTargetObject(): any;
}
}
declare module es {
/**
* 任何想要被weened的对象都需要实现这个功能。
* TweenManager内部喜欢做一个简单的对象来实现这个接口,并存储一个对被tweened对象的引用
*/
interface ITweenTarget<T> {
/**
* 在你选择的对象上设置最终的tweened值
* @param value
*/
setTweenedValue(value: T): any;
getTweenedValue(): T;
/**
* 获取tween的目标,如果TweenTargets不一定都是一个对象,则为null,它的唯一真正用途是让TweenManager按目标查找tweens的列表
*/
getTargetObject(): any;
}
}
declare module es {
interface ITweenable {
/**
* 就像内部的Update一样,每一帧都被TweenManager调用
*/
tick(): boolean;
/**
* 当一个tween被移除时,由TweenManager调用。子
* 类可以选择自己回收。子类应该首先在其实现中检查_shouldRecycleTween bool!
*/
recycleSelf(): any;
/**
* 检查是否有tween在运行
*/
isRunning(): boolean;
/**
* 启动tween
*/
start(): any;
/**
* 暂停
*/
pause(): any;
/**
* 暂停后恢复tween
*/
resume(): any;
/**
* 停止tween,并可选择将其完成
* @param bringToCompletion
*/
stop(bringToCompletion: boolean): any;
}
}
declare module es {
interface IAnimFrame {
t: number;
@@ -4293,38 +4909,6 @@ declare module es {
private forOwn;
}
}
declare module es {
class GlobalManager {
_enabled: boolean;
/**
* 如果true则启用了GlobalManager。
* 状态的改变会导致调用OnEnabled/OnDisable
*/
/**
* 如果true则启用了GlobalManager。
* 状态的改变会导致调用OnEnabled/OnDisable
* @param value
*/
enabled: boolean;
/**
* 启用/禁用这个GlobalManager
* @param isEnabled
*/
setEnabled(isEnabled: boolean): void;
/**
* 此GlobalManager启用时调用
*/
onEnabled(): void;
/**
* 此GlobalManager禁用时调用
*/
onDisabled(): void;
/**
* 在frame .update之前调用每一帧
*/
update(): void;
}
}
declare module es {
class Hash {
/**
+1408 -65
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
File diff suppressed because one or more lines are too long
+1
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;
@@ -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;
}
}
}
+60
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)
+8 -8
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));
}
/**
@@ -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
View File
@@ -0,0 +1,51 @@
module es {
/**
* AbstractTweenable作为你可能想做的任何可以执行的自定义类的基础
* ITweensITweenT接口
* 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
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
}
/**
* EaseTypeEase方程
* 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
View File
@@ -0,0 +1,230 @@
module es {
/**
* b和c参数01
* 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
View File
@@ -0,0 +1,84 @@
module es {
/**
* tween类型结构unclamped lerps.unclamped lerps对于超过0-1bounceelastic或其他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的引用targetValue0
* @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
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>;
/**
* tweentween完成后会被运行
* nextTween ITweenable! ITweenT都是ITweenable
* @param nextTween
*/
setNextTween(nextTween: ITweenable): ITween<T>;
}
}
@@ -0,0 +1,24 @@
module es {
/**
* Tween播放控制在这里
*/
export interface ITweenControl extends ITweenable {
/**
* 使使
*/
context;
/**
* tween扭曲为elapsedTime0duration之间tween对象是暂停
* @param elapsedTime
*/
jumpToElapsedTime(elapsedTime: number);
/**
* StartCoroutine调用时tween完成
*/
waitForCompletion(): any;
/**
* tween的目标TweenTargets不一定都是一个对象nullTweenManager按目标查找tweens的列表
*/
getTargetObject(): any;
}
}
@@ -0,0 +1,19 @@
module es {
/**
* weened的对象都需要实现这个功能
* TweenManager内部喜欢做一个简单的对象来实现这个接口tweened对象的引用
*/
export interface ITweenTarget<T> {
/**
* tweened值
* @param value
*/
setTweenedValue(value: T);
getTweenedValue(): T;
/**
* tween的目标TweenTargets不一定都是一个对象nullTweenManager按目标查找tweens的列表
*/
getTargetObject(): any;
}
}
+34
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);
}
}
+44
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;
}
}
}
+38
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);
}
}
}
}
+100
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;
}
}
}
}
+90
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
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();
}
}
+152
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
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));
}
}
}