diff --git a/.gitignore b/.gitignore index 284e865b9..064d35512 100644 --- a/.gitignore +++ b/.gitignore @@ -29,6 +29,7 @@ ehthumbs.db Thumbs.db # Build +.vs/ build/ bld/ bin/ diff --git a/GruntFile.js b/GruntFile.js index 7b06665d9..71572ce69 100644 --- a/GruntFile.js +++ b/GruntFile.js @@ -131,6 +131,20 @@ module.exports = function (grunt) { stdout: true, failOnError: true } + }, + + // + // Compile visual tests + // + visual: { + command: function() { + var files = grunt.file.expand("./sandbox/web/tests/*/*.ts"); + return 'tsc ' + files.join(' '); + }, + options: { + stdout: true, + failOnError: true + } } }, @@ -208,9 +222,11 @@ module.exports = function (grunt) { // Compile sample game grunt.registerTask('sample', ['shell:sample']); + + grunt.registerTask('visual', ['shell:visual']); // Default task - compile, test, build dists - grunt.registerTask('default', ['tslint:src', 'tests', 'coveralls', 'shell:tsc', 'minified', 'concat', 'copy', 'sample', 'shell:nuget']); + grunt.registerTask('default', ['tslint:src', 'tests', 'coveralls', 'shell:tsc', 'minified', 'concat', 'copy', 'sample', 'visual', 'shell:nuget']); grunt.registerTask('compile', ['shell:tsc', 'minified', 'concat', 'copy', 'shell:nuget']) diff --git a/dist/Excalibur.0.5.1.nupkg b/dist/Excalibur.0.5.1.nupkg deleted file mode 100644 index 56549f34d..000000000 Binary files a/dist/Excalibur.0.5.1.nupkg and /dev/null differ diff --git a/dist/Excalibur.0.6.0.nupkg b/dist/Excalibur.0.6.0.nupkg new file mode 100644 index 000000000..ce041717d Binary files /dev/null and b/dist/Excalibur.0.6.0.nupkg differ diff --git a/dist/Excalibur.d.ts b/dist/Excalibur.d.ts index 01802ca5d..2343a6795 100644 --- a/dist/Excalibur.d.ts +++ b/dist/Excalibur.d.ts @@ -265,6 +265,7 @@ declare module ex { declare module ex { /** * A simple 2D point on a plane + * @obsolete Use [[Vector|vector]]s instead of [[Point|points]] */ class Point { x: number; @@ -466,6 +467,7 @@ declare module ex.Util { function getPosition(el: HTMLElement): Point; function addItemToArray(item: T, array: T[]): boolean; function removeItemToArray(item: T, array: T[]): boolean; + function contains(array: Array, obj: any): boolean; function getOppositeSide(side: ex.Side): Side; /** * Excaliburs dynamically resizing collection @@ -579,10 +581,38 @@ declare module ex { * * Excalibur offers many sprite effects such as [[Effects.Colorize]] to let you manipulate * sprites. Keep in mind, more effects requires more power and can lead to memory or CPU - * constraints and hurt performance. + * constraints and hurt performance. Each effect must be reprocessed every frame for each sprite. * * It's still recommended to create an [[Animation]] or build in your effects to the sprites * for optimal performance. + * + * There are a number of convenience methods available to perform sprite effects. Sprite effects are + * side-effecting. + * + * ```typescript + * + * var playerSprite = new ex.Sprite(txPlayer, 0, 0, 80, 80); + * + * // darken a sprite by a percentage + * playerSprite.darken(.2); // 20% + * + * // lighten a sprite by a percentage + * playerSprite.lighten(.2); // 20% + * + * // saturate a sprite by a percentage + * playerSprite.saturate(.2); // 20% + * + * // implement a custom effect + * class CustomEffect implements ex.EffectsISpriteEffect { + * + * updatePixel(x: number, y: number, imageData: ImageData) { + * // modify ImageData + * } + * } + * + * playerSprite.addEffect(new CustomEffect()); + * + * ``` */ class Sprite implements IDrawable { sx: number; @@ -837,7 +867,8 @@ declare module ex { * Sprite Fonts * * Sprite fonts are a used in conjunction with a [[Label]] to specify - * a particular bitmap as a font. + * a particular bitmap as a font. Note that some font features are not + * supported by Sprite fonts. * * ## Generating the font sheet * @@ -917,9 +948,19 @@ declare module ex { image: Texture; private alphabet; private caseInsensitive; + spWidth: number; + spHeight: number; private _spriteLookup; private _colorLookup; private _currentColor; + private _currentOpacity; + private _sprites; + private _textShadowOn; + private _textShadowDirty; + private _textShadowColor; + private _textShadowSprites; + private _shadowOffsetX; + private _shadowOffsetY; /** * @param image The backing image texture to build the SpriteFont * @param alphabet A string representing all the characters in the image, in row major order. @@ -936,6 +977,34 @@ declare module ex { getTextSprites(): { [key: string]: Sprite; }; + /** + * Sets the text shadow for sprite fonts + * @param offsetX The x offset in pixels to place the shadow + * @param offsetY The y offset in pixles to place the shadow + * @param shadowColor The color of the text shadow + */ + setTextShadow(offsetX: number, offsetY: number, shadowColor: Color): void; + /** + * Toggles text shadows on or off + */ + useTextShadow(on: boolean): void; + /** + * Draws the current sprite font + */ + draw(ctx: CanvasRenderingContext2D, text: string, x: number, y: number, options: ISpriteFontOptions): void; + private _parseOptions(options); + } + /** + * Specify various font attributes for sprite fonts + */ + interface ISpriteFontOptions { + color?: Color; + opacity?: number; + fontSize?: number; + letterSpacing?: number; + textAlign?: TextAlign; + baseAlign?: BaseAlign; + maxWidth?: number; } } declare module ex { @@ -1342,6 +1411,12 @@ declare module ex { * @param handler Event handler for the thrown event */ off(eventName: string, handler?: (event?: GameEvent) => void): void; + /** + * Emits a new event + * @param eventName Name of the event to emit + * @param eventObject Data associated with this event + */ + emit(eventName: string, eventObject?: GameEvent): void; /** * You may wish to extend native Excalibur functionality in vanilla Javascript. * Any method on a class inheriting [[Class]] may be extended to support @@ -1549,8 +1624,19 @@ declare module ex { */ class BaseCamera { protected _follow: Actor; - protected _focus: Point; - protected _lerp: boolean; + focus: Point; + lerp: boolean; + x: number; + y: number; + z: number; + dx: number; + dy: number; + dz: number; + ax: number; + ay: number; + az: number; + rotation: number; + rx: number; private _cameraMoving; private _currentLerpTime; private _lerpDuration; @@ -1575,13 +1661,14 @@ declare module ex { */ setActorToFollow(actor: Actor): void; /** - * Returns the focal point of the camera + * Returns the focal point of the camera, a new point giving the x and y position of the camera */ getFocus(): Point; /** * Sets the focal point of the camera. This value can only be set if there is no actor to be followed. * @param x The x coordinate of the focal point * @param y The y coordinate of the focal point + * @deprecated */ setFocus(x: number, y: number): void; /** @@ -2076,11 +2163,6 @@ declare module ex { * in future versions to support multiple timelines/scripts, better eventing, * and a more robust API to allow for complex and customized actions. * - * ## Known Issues - * - * **Rotation actions do not use shortest angle** - * [Issue #282](https://github.com/excaliburjs/Excalibur/issues/282) - * */ class ActionContext { private _actors; @@ -2094,6 +2176,16 @@ declare module ex { clearActions(): void; addActorToContext(actor: Actor): void; removeActorFromContext(actor: Actor): void; + /** + * This method will move an actor to the specified `x` and `y` position over the + * specified duration using a given [[EasingFunctions]] and return back the actor. This + * method is part of the actor 'Action' fluent API allowing action chaining. + * @param x The x location to move the actor to + * @param y The y location to move the actor to + * @param duration The time it should take the actor to move to the new location in milliseconds + * @param easingFcn Use [[EasingFunctions]] or a custom function to use to calculate position + */ + easeTo(x: number, y: number, duration: number, easingFcn?: (currentTime: number, startValue: number, endValue: number, duration: number) => number): ActionContext; /** * This method will move an actor to the specified x and y position at the * speed specified (in pixels per second) and return back the actor. This @@ -2224,7 +2316,26 @@ declare module ex { * Groups are used for logically grouping Actors so they can be acted upon * in bulk. * - * @todo Document this + * ## Using Groups + * + * Groups can be used to detect collisions across a large nubmer of actors. For example + * perhaps a large group of "enemy" actors. + * + * ```typescript + * var enemyShips = engine.currentScene.createGroup("enemy"); + * var enemies = [...]; // Large array of enemies; + * enemyShips.add(enemies); + * + * var player = new Actor(); + * engine.currentScene.add(player); + * + * enemyShips.on('collision', function(ev: CollisionEvent){ + * if (e.other === player) { + * //console.log("collision with player!"); + * } + * }); + * + * ``` */ class Group extends Class implements IActionable { name: string; @@ -2343,6 +2454,13 @@ declare module ex { * * ``` * + * ## Scene Lifecycle + * + * A [[Scene|scene]] has a basic lifecycle that dictacts how it is initialized, updated, and drawn. Once a [[Scene|scene]] is added to + * the [[Engine|engine]] it will follow this lifecycle. + * + * ![Scene Lifecycle](/assets/images/docs/SceneLifeCycle.png) + * * ## Extending scenes * * For more complex games, you might want more control over a scene in which @@ -2457,12 +2575,6 @@ declare module ex { * this is where you should cleanup any DOM UI or event handlers needed for the scene. */ onDeactivate(): void; - /** - * Publish an event to all actors in the scene - * @param eventType The name of the event to publish - * @param event The event object to send - */ - publish(eventType: string, event: GameEvent): void; /** * Updates all the actors and timers in the scene. Called by the [[Engine]]. * @param engine Reference to the current Engine @@ -2535,6 +2647,8 @@ declare module ex { removeUIActor(actor: Actor): void; /** * Adds an actor to the scene, once this is done the actor will be drawn and updated. + * + * @obsolete Use [[add]] instead. */ addChild(actor: Actor): void; /** @@ -2597,32 +2711,44 @@ declare module ex { } declare module ex { /** - * Standard easing functions for motion in Excalibur + * Standard easing functions for motion in Excalibur, defined on a domain of [0, duration] and a range from [+startValue,+endValue] + * Given a time, the function will return a value from postive startValue to postive endValue. + * + * ```js + * function Linear (t) { + * return t * t; + * } * - * easeInQuad: function (t) { return t * t }, - * // decelerating to zero velocity - * easeOutQuad: function (t) { return t * (2 - t) }, - * // acceleration until halfway, then deceleration - * easeInOutQuad: function (t) { return t < .5 ? 2 * t * t : -1 + (4 - 2 * t) * t }, - * // accelerating from zero velocity - * easeInCubic: function (t) { return t * t * t }, - * // decelerating to zero velocity - * easeOutCubic: function (t) { return (--t) * t * t + 1 }, - * // acceleration until halfway, then deceleration - * easeInOutCubic: function (t) { return t < .5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1 }, * // accelerating from zero velocity - * easeInQuart: function (t) { return t * t * t * t }, + * function EaseInQuad (t) { + * return t * t; + * } + * * // decelerating to zero velocity - * easeOutQuart: function (t) { return 1 - (--t) * t * t * t }, + * function EaseOutQuad (t) { + * return t * (2 - t); + * } + * * // acceleration until halfway, then deceleration - * easeInOutQuart: function (t) { return t < .5 ? 8 * t * t * t * t : 1 - 8 * (--t) * t * t * t }, + * function EaseInOutQuad (t) { + * return t < .5 ? 2 * t * t : -1 + (4 - 2 * t) * t; + * } + * * // accelerating from zero velocity - * easeInQuint: function (t) { return t * t * t * t * t }, + * function EaseInCubic (t) { + * return t * t * t; + * } + * * // decelerating to zero velocity - * easeOutQuint: function (t) { return 1 + (--t) * t * t * t * t }, - * // acceleration until halfway, then deceleration - * easeInOutQuint: function (t) { return t < .5 ? 16 * t * t * t * t * t : 1 + 16 * (--t) * t * t * t * t } + * function EaseOutCubic (t) { + * return (--t) * t * t + 1; + * } * + * // acceleration until halfway, then deceleration + * function EaseInOutCubic (t) { + * return t < .5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1; + * } + * ``` */ class EasingFunctions { static Linear: (currentTime: number, startValue: number, endValue: number, duration: number) => number; @@ -2659,7 +2785,16 @@ declare module ex { * * // add player to the current scene * game.add(player); + * * ``` + * `game.add` is a convenience method for adding an `Actor` to the current scene. The equivalent verbose call is `game.currentScene.add`. + * + * ## Actor Lifecycle + * + * An [[Actor|actor]] has a basic lifecycle that dictacts how it is initialized, updated, and drawn. Once an actor is part of a + * [[Scene|scene]], it will follow this lifecycle. + * + * ![Actor Lifecycle](/assets/images/docs/ActorLifeCycle.png) * * ## Extending actors * @@ -2729,7 +2864,7 @@ declare module ex { * * The [[update]] method is passed an instance of the Excalibur engine, which * can be used to perform coordinate math or access global state. It is also - * passed `delta` which is the time since the last frame, which can be used + * passed `delta` which is the time in milliseconds since the last frame, which can be used * to perform time-based movement or time-based math (such as a timer). * * **TypeScript** @@ -2741,7 +2876,7 @@ declare module ex { * * // check if player died * if (this.health <= 0) { - * this.triggerEvent("death"); + * this.emit("death"); * this.onDeath(); * return; * } @@ -2758,7 +2893,7 @@ declare module ex { * * // check if player died * if (this.health <= 0) { - * this.triggerEvent("death"); + * this.emit("death"); * this.onDeath(); * return; * } @@ -2770,13 +2905,16 @@ declare module ex { * * Override the [[draw]] method to perform any custom drawing. For simple games, * you don't need to override `draw`, instead you can use [[addDrawing]] and [[setDrawing]] - * to manipulate the textures/animations that the actor is using. + * to manipulate the [[Sprite|sprites]]/[[Animation|animations]] that the actor is using. * * ### Working with Textures & Sprites * - * A common usage is to use a [[Texture]] or [[Sprite]] for an actor. If you are using the [[Loader]] to - * pre-load assets, you can simply assign an actor a [[Texture]] to draw. You can - * also create a [[Texture.asSprite|sprite from a Texture]] to quickly create a [[Sprite]] instance. + * Think of a [[Texture|texture]] as the raw image file that will be loaded into Excalibur. In order for it to be drawn + * it must be converted to a [[Sprite.sprite]]. + * + * A common usage is to load a [[Texture]] and convert it to a [[Sprite]] for an actor. If you are using the [[Loader]] to + * pre-load assets, you can simply assign an actor a [[Sprite]] to draw. You can also create a + * [[Texture.asSprite|sprite from a Texture]] to quickly create a [[Sprite]] instance. * * ```ts * // assume Resources.TxPlayer is a 80x80 png image @@ -2815,7 +2953,8 @@ declare module ex { * ### Custom drawing * * You can always override the default drawing logic for an actor in the [[draw]] method, - * for example, to draw complex shapes or to use the raw Canvas API. + * for example, to draw complex shapes or to use the raw + * [[https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D|Canvas API]]. * * Usually you should call `super.draw` to perform the base drawing logic, but other times * you may want to take over the drawing completely. @@ -2846,33 +2985,45 @@ declare module ex { * ## Collision Detection * * By default Actors do not participate in collisions. If you wish to make - * an actor participate, you need to enable the [[CollisionDetectionModule]] + * an actor participate, you need to switch from the default [[CollisionType.PreventCollision|prevent collision]] + * to [[CollisionType.Active|active]], [[CollisionType.Fixed|fixed]], or [[CollisionType.Passive|passive]] collision type. * * ```ts * public Player extends ex.Actor { * constructor() { * super(); - * - * // enable the pipeline - * this.pipelines.push(new ex.CollisionDetectionModule()); - * * // set preferred CollisionType * this.collisionType = ex.CollisionType.Active; * } * } - * ``` * - * ### Collision Groups + * // or set the collisionType + * + * var actor = new ex.Actor(); + * actor.collisionType = ex.CollisionType.Active; * + * ``` + * ### Collision Groups * TODO, needs more information. * + * ## Traits + * + * Traits describe actor behavior that occurs every update. If you wish to build a generic behavior + * without needing to extend every actor you can do it with a trait, a good example of this may be + * plugging in an external collision detection library like [[https://github.com/kripken/box2d.js/|Box2D]] or + * [[http://wellcaffeinated.net/PhysicsJS/|PhysicsJS]] by wrapping it in a trait. Removing traits can also make your + * actors more efficient. + * + * Default traits provided by Excalibur are [[Traits.CapturePointer|pointer capture]], + * [[Traits.CollisionDetection|tile map collision]], [[Traits.Movement|Euler style movement]], + * and [[Traits.OffscreenCulling|offscreen culling]]. + * + * * ## Known Issues * * **Actor bounding boxes do not rotate** * [Issue #68](https://github.com/excaliburjs/Excalibur/issues/68) * - * **Setting opacity when using a color doesn't do anything** - * [Issue #364](https://github.com/excaliburjs/Excalibur/issues/364) */ class Actor extends ex.Class implements IActionable { /** @@ -2884,11 +3035,11 @@ declare module ex { */ id: number; /** - * The x coordinate of the actor (left edge) + * The x coordinate of the actor (middle if anchor is (0.5, 0.5) left edge if anchor is (0, 0)) */ x: number; /** - * The y coordinate of the actor (top edge) + * The y coordinate of the actor (middle if anchor is (0.5, 0.5) and top edge if anchor is (0, 0)) */ y: number; /** @@ -3060,12 +3211,12 @@ declare module ex { * move with it. * @param actor The child actor to add */ - addChild(actor: Actor): void; + add(actor: Actor): void; /** * Removes a child actor from this actor. * @param actor The child actor to remove */ - removeChild(actor: Actor): void; + remove(actor: Actor): void; /** * Sets the current drawing of the actor to the drawing corresponding to * the key. @@ -3104,14 +3255,6 @@ declare module ex { * @param actor The child actor to remove */ setZIndex(newIndex: number): void; - /** - * Artificially trigger an event on an actor, useful when creating custom events. - * @param eventName The name of the event to trigger - * @param event The event object to pass to the callback - * - * @obsolete Will be replaced with `emit` - */ - triggerEvent(eventName: string, event?: GameEvent): void; /** * Adds an actor to a collision group. Actors with no named collision groups are * considered to be in every collision group. @@ -3231,6 +3374,7 @@ declare module ex { within(actor: Actor, distance: number): boolean; /** * Clears all queued actions from the Actor + * @obsolete Use [[ActionContext.clearActions|Actor.actions.clearActions]] */ clearActions(): void; /** @@ -3241,6 +3385,7 @@ declare module ex { * @param y The y location to move the actor to * @param duration The time it should take the actor to move to the new location in milliseconds * @param easingFcn Use [[EasingFunctions]] or a custom function to use to calculate position + * @obsolete Use [[ActionContext.easeTo|Actor.actions.easeTo]] */ easeTo(x: number, y: number, duration: number, easingFcn?: (currentTime: number, startValue: number, endValue: number, duration: number) => number): Actor; /** @@ -3250,6 +3395,7 @@ declare module ex { * @param x The x location to move the actor to * @param y The y location to move the actor to * @param speed The speed in pixels per second to move + * @obsolete Use [[ActionContext.moveTo|Actor.actions.moveTo]] */ moveTo(x: number, y: number, speed: number): Actor; /** @@ -3259,6 +3405,7 @@ declare module ex { * @param x The x location to move the actor to * @param y The y location to move the actor to * @param duration The time it should take the actor to move to the new location in milliseconds + * @obsolete Use [[ActionContext.moveBy|Actor.actions.moveBy]] */ moveBy(x: number, y: number, duration: number): Actor; /** @@ -3267,6 +3414,7 @@ declare module ex { * method is part of the actor 'Action' fluent API allowing action chaining. * @param angleRadians The angle to rotate to in radians * @param speed The angular velocity of the rotation specified in radians per second + * @obsolete Use [[ActionContext.rotateTo|Actor.actions.rotateTo]] */ rotateTo(angleRadians: number, speed: number, rotationType?: RotationType): Actor; /** @@ -3275,6 +3423,7 @@ declare module ex { * of the actor 'Action' fluent API allowing action chaining. * @param angleRadians The angle to rotate to in radians * @param duration The time it should take the actor to complete the rotation in milliseconds + * @obsolete Use [[ActionContext.rotateBy|ex.Actor.actions.rotateBy]] */ rotateBy(angleRadians: number, duration: number, rotationType?: RotationType): Actor; /** @@ -3286,6 +3435,7 @@ declare module ex { * @param sizeY The scaling factor in the y direction to apply * @param speedX The speed of scaling in the x direction specified in magnitude increase per second * @param speedY The speed of scaling in the y direction specified in magnitude increase per second + * @obsolete Use [[ActionContext.scaleTo|Actor.actions.scaleTo]] */ scaleTo(sizeX: number, sizeY: number, speedX: number, speedY: number): Actor; /** @@ -3295,6 +3445,7 @@ declare module ex { * @param sizeX The scaling factor in the x direction to apply * @param sizeY The scaling factor in the y direction to apply * @param duration The time it should take to complete the scaling in milliseconds + * @obsolete Use [[ActionContext.scaleBy|Actor.actions.scaleBy]] */ scaleBy(sizeX: number, sizeY: number, duration: number): Actor; /** @@ -3305,6 +3456,7 @@ declare module ex { * @param timeVisible The amount of time to stay visible per blink in milliseconds * @param timeNotVisible The amount of time to stay not visible per blink in milliseconds * @param numBlinks The number of times to blink + * @obsolete Use [[ActionContext.blink|Actor.actions.blink]] */ blink(timeVisible: number, timeNotVisible: number, numBlinks?: number): Actor; /** @@ -3313,6 +3465,7 @@ declare module ex { * part of the actor 'Action' fluent API allowing action chaining. * @param opacity The ending opacity * @param duration The time it should take to fade the actor (in milliseconds) + * @obsolete Use [[ActionContext.fade|Actor.actions.fade]] */ fade(opacity: number, duration: number): Actor; /** @@ -3320,18 +3473,21 @@ declare module ex { * `duration` (in milliseconds). This method is part of the actor * 'Action' fluent API allowing action chaining. * @param duration The amount of time to delay the next action in the queue from executing in milliseconds + * @obsolete Use [[ActionContext.delay|Actor.actions.delay]] */ delay(duration: number): Actor; /** * This method will add an action to the queue that will remove the actor from the * scene once it has completed its previous actions. Any actions on the * action queue after this action will not be executed. + * @obsolete Use [[ActionContext.die|Actor.actions.die]] */ die(): Actor; /** * This method allows you to call an arbitrary method as the next action in the * action queue. This is useful if you want to execute code in after a specific * action, i.e An actor arrives at a destination after traversing a path + * @obsolete Use [[ActionContext.callMethod|Actor.actions.callMethod]] */ callMethod(method: () => any): Actor; /** @@ -3341,18 +3497,21 @@ declare module ex { * the actor 'Action' fluent API allowing action chaining * @param times The number of times to repeat all the previous actions in the action queue. If nothing is specified the actions will * repeat forever + * @obsolete Use [[ActionContext.repeat|Actor.actions.repeat]] */ repeat(times?: number): Actor; /** * This method will cause the actor to repeat all of the previously * called actions forever. This method is part of the actor 'Action' * fluent API allowing action chaining. + * @obsolete Use [[ActionContext.repeatForever|Actor.actions.repeatForever]] */ repeatForever(): Actor; /** * This method will cause the actor to follow another at a specified distance * @param actor The actor to follow * @param followDistance The distance to maintain when following, if not specified the actor will follow at the current distance. + * @obsolete Use [[ActionContext.follow|Actor.actions.follow]] */ follow(actor: Actor, followDistance?: number): Actor; /** @@ -3360,11 +3519,13 @@ declare module ex { * collide ("meet") at a specified speed. * @param actor The actor to meet * @param speed The speed in pixels per second to move, if not specified it will match the speed of the other actor + * @obsolete Use [[ActionContext.meet|Actor.actions.meet]] */ meet(actor: Actor, speed?: number): Actor; /** * Returns a promise that resolves when the current action queue up to now * is finished. + * @obsolete Use [[ActionContext.asPromise|Actor.actions.asPromise]] */ asPromise(): Promise; private _getCalculatedAnchor(); @@ -3410,6 +3571,7 @@ declare module ex { * Actors with the `Elastic` setting will behave the same as `Active`, except that they will * "bounce" in the opposite direction given their velocity dx/dy. This is a naive implementation meant for * prototyping, for a more robust elastic collision listen to the "collision" event and perform your custom logic. + * @obsolete This behavior will be handled by a future physics system */ Elastic = 3, /** @@ -3552,22 +3714,23 @@ declare module ex { } declare module ex { /** - * An enum representing all of the built in event types for Excalibur - * @obsolete Phasing this out in favor of classes - */ - enum EventType { - Collision = 0, - EnterViewPort = 1, - ExitViewPort = 2, - Blur = 3, - Focus = 4, - Update = 5, - Activate = 6, - Deactivate = 7, - Initialize = 8, - } - /** - * Base event type in Excalibur that all other event types derive from. + * Base event type in Excalibur that all other event types derive from. Not all event types are thrown on all Excalibur game objects, + * some events are unique to a type, others are not. + * + * Excalibur events follow the convention that the name of the thrown event for listening will be the same as the Event object in all + * lower case with the 'Event' suffix removed. + * + * For example: + * - PreDrawEvent event object and "predraw" as the event name + * + * ```typescript + * + * actor.on('predraw', (evtObj: PreDrawEvent) => { + * // do some pre drawing + * }) + * + * ``` + * */ class GameEvent { /** @@ -3576,7 +3739,104 @@ declare module ex { target: any; } /** - * Subscribe event thrown when handlers for events other than subscribe are added + * The 'predraw' event is emitted on actors, scenes, and engine before drawing starts. Actors' predraw happens inside their graphics + * transform so that all drawing takes place with the actor as the origin. + * + */ + class PreDrawEvent extends GameEvent { + ctx: CanvasRenderingContext2D; + delta: any; + target: any; + constructor(ctx: CanvasRenderingContext2D, delta: any, target: any); + } + /** + * The 'postdraw' event is emitted on actors, scenes, and engine after drawing finishes. Actors' postdraw happens inside their graphics + * transform so that all drawing takes place with the actor as the origin. + * + */ + class PostDrawEvent extends GameEvent { + ctx: CanvasRenderingContext2D; + delta: any; + target: any; + constructor(ctx: CanvasRenderingContext2D, delta: any, target: any); + } + /** + * The 'predebugdraw' event is emitted on actors, scenes, and engine before debug drawing starts. + */ + class PreDebugDrawEvent extends GameEvent { + ctx: CanvasRenderingContext2D; + target: any; + constructor(ctx: CanvasRenderingContext2D, target: any); + } + /** + * The 'postdebugdraw' event is emitted on actors, scenes, and engine after debug drawing starts. + */ + class PostDebugDrawEvent extends GameEvent { + ctx: CanvasRenderingContext2D; + target: any; + constructor(ctx: CanvasRenderingContext2D, target: any); + } + /** + * The 'preupdate' event is emitted on actors, scenes, and engine before the update starts. + */ + class PreUpdateEvent extends GameEvent { + engine: Engine; + delta: any; + target: any; + constructor(engine: Engine, delta: any, target: any); + } + /** + * The 'postupdate' event is emitted on actors, scenes, and engine after the update ends. This is equivalent to the obsolete 'update' + * event. + */ + class PostUpdateEvent extends GameEvent { + engine: Engine; + delta: any; + target: any; + constructor(engine: Engine, delta: any, target: any); + } + /** + * Event received when a gamepad is connected to Excalibur. [[Input.Gamepads|engine.input.gamepads]] receives this event. + */ + class GamepadConnectEvent extends GameEvent { + index: number; + gamepad: ex.Input.Gamepad; + constructor(index: number, gamepad: ex.Input.Gamepad); + } + /** + * Event received when a gamepad is disconnected from Excalibur. [[Input.Gamepads|engine.input.gamepads]] receives this event. + */ + class GamepadDisconnectEvent extends GameEvent { + index: number; + constructor(index: number); + } + /** + * Gamepad button event. See [[Gamepads]] for information on responding to controller input. [[Gamepad]] instances receive this event; + */ + class GamepadButtonEvent extends ex.GameEvent { + button: ex.Input.Buttons; + value: number; + /** + * @param button The Gamepad button + * @param value A numeric value between 0 and 1 + */ + constructor(button: ex.Input.Buttons, value: number); + } + /** + * Gamepad axis event. See [[Gamepads]] for information on responding to controller input. [[Gamepad]] instances receive this event; + */ + class GamepadAxisEvent extends ex.GameEvent { + axis: ex.Input.Axes; + value: number; + /** + * @param axis The Gamepad axis + * @param value A numeric value between -1 and 1 + */ + constructor(axis: ex.Input.Axes, value: number); + } + /** + * Subscribe event thrown when handlers for events other than subscribe are added. Meta event that is received by + * [[EventDispatcher|event dispatchers]]. */ class SubscribeEvent extends GameEvent { topic: string; @@ -3584,7 +3844,8 @@ declare module ex { constructor(topic: string, handler: (event?: GameEvent) => void); } /** - * Unsubscribe event thrown when handlers for events other than unsubscribe are removed + * Unsubscribe event thrown when handlers for events other than unsubscribe are removed. Meta event that is received by + * [[EventDispatcher|event dispatchers]]. */ class UnsubscribeEvent extends GameEvent { topic: string; @@ -3592,19 +3853,19 @@ declare module ex { constructor(topic: string, handler: (event?: GameEvent) => void); } /** - * Event received by the Engine when the browser window is visible + * Event received by the [[Engine]] when the browser window is visible on a screen. */ class VisibleEvent extends GameEvent { constructor(); } /** - * Event received by the Engine when the browser window is hidden + * Event received by the [[Engine]] when the browser window is hidden from all screens. */ class HiddenEvent extends GameEvent { constructor(); } /** - * Event thrown on an actor when a collision has occured + * Event thrown on an [[Actor|actor]] when a collision has occured */ class CollisionEvent extends GameEvent { actor: Actor; @@ -3619,7 +3880,8 @@ declare module ex { constructor(actor: Actor, other: Actor, side: Side, intersection: Vector); } /** - * Event thrown on a game object on Excalibur update + * Event thrown on a game object on Excalibur update, this is equivalent to postupdate. + * @obsolete Please use [[PostUpdateEvent|postupdate]], or [[PreUpdateEvent|preupdate]]. */ class UpdateEvent extends GameEvent { delta: number; @@ -3629,7 +3891,7 @@ declare module ex { constructor(delta: number); } /** - * Event thrown on an Actor only once before the first update call + * Event thrown on an [[Actor]] only once before the first update call */ class InitializeEvent extends GameEvent { engine: Engine; @@ -3639,7 +3901,7 @@ declare module ex { constructor(engine: Engine); } /** - * Event thrown on a Scene on activation + * Event thrown on a [[Scene]] on activation */ class ActivateEvent extends GameEvent { oldScene: Scene; @@ -3649,7 +3911,7 @@ declare module ex { constructor(oldScene: Scene); } /** - * Event thrown on a Scene on deactivation + * Event thrown on a [[Scene]] on deactivation */ class DeactivateEvent extends GameEvent { newScene: Scene; @@ -3659,13 +3921,13 @@ declare module ex { constructor(newScene: Scene); } /** - * Event thrown on an Actor when it completely leaves the screen. + * Event thrown on an [[Actor]] when it completely leaves the screen. */ class ExitViewPortEvent extends GameEvent { constructor(); } /** - * Event thrown on an Actor when it completely leaves the screen. + * Event thrown on an [[Actor]] when it completely leaves the screen. */ class EnterViewPortEvent extends GameEvent { constructor(); @@ -3675,8 +3937,8 @@ declare module ex { /** * Excalibur's internal event dispatcher implementation. * Callbacks are fired immediately after an event is published. - * Typically you'd use [[Class.eventDispatcher]] since most classes in - * Excalibur inherit from [[Class]]. You'd rarely create an `EventDispatcher` + * Typically you will use [[Class.eventDispatcher]] since most classes in + * Excalibur inherit from [[Class]]. You will rarely create an `EventDispatcher` * yourself. * * When working with events, be sure to keep in mind the order of subscriptions @@ -3713,14 +3975,14 @@ declare module ex { * }); * * // trigger custom event - * player.triggerEvent("death", new DeathEvent()); + * player.emit("death", new DeathEvent()); * * ``` * * ## Example: Pub/Sub with Excalibur * * You can also create an EventDispatcher for any arbitrary object, for example - * a global game event aggregator (`vent`). Anything in your game can subscribe to + * a global game event aggregator (shown below as `vent`). Anything in your game can subscribe to * it, if the event aggregator is in the global scope. * * *Warning:* This can easily get out of hand. Avoid this usage, it just serves as @@ -3739,7 +4001,7 @@ declare module ex { * vent.subscribe("someevent", subscription); * * // publish an event somewhere in the game - * vent.publish("someevent", new ex.GameEvent()); + * vent.emit("someevent", new ex.GameEvent()); * ``` */ class EventDispatcher { @@ -3755,6 +4017,8 @@ declare module ex { * Publish an event for target * @param eventName The name of the event to publish * @param event Optionally pass an event data object to the handler + * + * @obsolete Use [[emit]] instead. */ publish(eventName: string, event?: GameEvent): void; /** @@ -4145,7 +4409,7 @@ declare module ex { * extend [[Actor]] allowing you to use all of the features that come with. * * The easiest way to create a `ParticleEmitter` is to use the - * [Particle Tester](http://excaliburjs.com/particle-tester/). + * [Particle Tester](http://excaliburjs.com/particle-tester/) to generate code for emitters. * * ## Example: Adding an emitter * @@ -4153,12 +4417,26 @@ declare module ex { * var actor = new ex.Actor(...); * var emitter = new ex.ParticleEmitter(...); * + * emitter.emitterType = ex.EmitterType.Circle; // Shape of emitter nozzle + * emitter.radius = 5; + * emitter.minVel = 100; + * emitter.maxVel = 200; + * emitter.minAngle = 0; + * emitter.maxAngle = Math.PI * 2; + * emitter.emitRate = 300; // 300 particles/second + * emitter.opacity = 0.5; + * emitter.fadeFlag = true; // fade particles overtime + * emitter.particleLife = 1000; // in milliseconds = 1 sec + * emitter.maxSize = 10; // in pixels + * emitter.minSize = 1; + * emitter.particleColor = ex.Color.Rose; + * * // set emitter settings - * emitter.isEmitting = true; + * emitter.isEmitting = true; // should the emitter be emitting * * // add the emitter as a child actor, it will draw on top of the parent actor * // and move with the parent - * actor.addChild(emitter); + * actor.add(emitter); * * // or, alternatively, add it to the current scene * engine.add(emitter); @@ -4274,7 +4552,7 @@ declare module ex { * Causes the emitter to emit particles * @param particleCount Number of particles to emit right now */ - emit(particleCount: number): void; + emitParticles(particleCount: number): void; clearParticles(): void; private _createParticle(); update(engine: Engine, delta: number): void; @@ -4850,7 +5128,8 @@ declare module ex { * is loaded, you can [[Sound.play|play]] it. * * ```js - * var sndPlayerDeath = new ex.Sound("/assets/snd/player-death.mp3", "/assets/snd/player-wav.mp3"); + * // define multiple sources (such as mp3/wav/ogg) as a browser fallback + * var sndPlayerDeath = new ex.Sound("/assets/snd/player-death.mp3", "/assets/snd/player-death.wav"); * * var loader = new ex.Loader(sndPlayerDeath); * @@ -5079,6 +5358,32 @@ declare module ex { } } declare module ex { + /** + * Enum representing the different font size units + * https://developer.mozilla.org/en-US/docs/Web/CSS/font-size + */ + enum FontUnit { + /** + * Em is a scalable unit, 1 em is equal to the current font size of the current element, parent elements can effect em values + */ + Em = 0, + /** + * Rem is similar to the Em, it is a scalable unit. 1 rem is eqaul to the font size of the root element + */ + Rem = 1, + /** + * Pixel is a unit of length in screen pixels + */ + Px = 2, + /** + * Point is a physical unit length (1/72 of an inch) + */ + Pt = 3, + /** + * Percent is a scalable unit similar to Em, the only difference is the Em units scale faster when Text-Size stuff + */ + Percent = 4, + } /** * Enum representing the different horizontal text alignments */ @@ -5234,10 +5539,18 @@ declare module ex { */ spriteFont: SpriteFont; /** - * The CSS font string (e.g. `10px sans-serif`, `10px Droid Sans Pro`). Web fonts + * The CSS font family string (e.g. `sans-serif`, `Droid Sans Pro`). Web fonts * are supported, same as in CSS. */ - font: string; + fontFamily: string; + /** + * The font size in the selected units, default is 10 (default units is pixel) + */ + fontSize: number; + /** + * The css units for a font size such as px, pt, em (SpriteFont only support px), by default is 'px'; + */ + fontUnit: FontUnit; /** * Gets or sets the horizontal text alignment property for the label. */ @@ -5274,12 +5587,13 @@ declare module ex { * @param spriteFont Use an Excalibur sprite font for the label's font, if a SpriteFont is provided it will take precendence * over a css font. */ - constructor(text?: string, x?: number, y?: number, font?: string, spriteFont?: SpriteFont); + constructor(text?: string, x?: number, y?: number, fontFamily?: string, spriteFont?: SpriteFont); /** * Returns the width of the text in the label (in pixels); * @param ctx Rending context to measure the string with */ getTextWidth(ctx: CanvasRenderingContext2D): number; + private _lookupFontUnit(fontUnit); private _lookupTextAlign(textAlign); private _lookupBaseAlign(baseAlign); /** @@ -5289,6 +5603,10 @@ declare module ex { * @param shadowColor The color of the text shadow */ setTextShadow(offsetX: number, offsetY: number, shadowColor: Color): void; + /** + * Toggles text shadows on or off, only applies when using sprite fonts + */ + useTextShadow(on: boolean): void; /** * Clears the current text shadow */ @@ -5300,6 +5618,73 @@ declare module ex { } } declare module ex { + /** + * Post Processors + * + * Sometimes it is necessary to apply an effect to the canvas after the engine has completed its drawing pass. A few reasons to do + * this might be creating a blur effect, adding a lighting effect, or changing how colors and pixels look. + * + * ## Basic post procesors + * + * To create and use a post processor you just need to implement a class that implements [[IPostProcessor]], which has one method + * [[IPostProcessor.process]]. Set the `out` canvas parameter to the final result, using the `image` pixel data. + * + * Click to read more about [[https://developer.mozilla.org/en-US/docs/Web/API/ImageData|ImageData]] on MDN. + * + * For example: + * ```typescript + * // simple way to grayscale, a faster way would be to implement using a webgl fragment shader + * class GrayscalePostProcessor implements IPostProcessor { + * process(image: ImageData, out: CanvasRenderingContext2D) { + * for(var i = 0; i < (image.height * image.width), i+=4){ + * // for pixel "i"" + * var r = image.data[i+0]; //0-255 + * var g = image.data[i+1]; //g + * var b = image.data[i+2]; //b + * image.data[i+3]; //a + * var result = Math.floor((r + g + b) / 3.0) | 0; // only valid on 0-255 integers `| 0` forces int + * image.data[i+0] = result; + * image.data[i+1] = result; + * image.data[i+2] = result; + * } + * // finish processing and write result + * out.putImageData(image, 0, 0); + * } + * } + * + * ``` + * + * ## Color Blind Corrector Post Processor + * + * Choosing colors that are friendly to players with color blindness is an important consideration when making a game. + * There is a significant portion of the population that has some form of color blindness, + * and choosing bad colors can make your game unplayable. We have built + * a post procesors that can shift your colors into as more visible range for the 3 most common types of + * [[https://en.wikipedia.org/wiki/Color_blindness|color blindness]]. + * + * - [[ColorBlindness.Protanope|Protanope]] + * - [[ColorBlindness.Deuteranope|Deuteranope]] + * - [[ColorBlindness.Tritanope|Tritanope]] + * + * This post processor can correct colors, and simulate color blindness. + * It is possible to use this on every game, but the game's performance + * will suffer measurably. It's better to use it as a helpful tool while developing your game. + * Remember, the best practice is to design with color blindness in mind. + * + * Example: + * ```typescript + * + * var game = new ex.Engine(); + * + * var colorBlindPostProcessor = new ex.ColorBlindCorrector(game, false, ColorBlindness.Protanope); + * + * // post processors evaluate left to right + * game.postProcessors.push(colorBlindPostProcessor); + * game.start(); + * + * ``` + * + */ interface IPostProcessor { process(image: ImageData, out: CanvasRenderingContext2D): void; } @@ -5388,7 +5773,7 @@ declare module ex.Input { * * ## Events * - * You can subscribe to pointer events through `engine.input.pointers`. A [[PointerEvent]] object is + * You can subscribe to pointer events through `engine.input.pointers.on`. A [[PointerEvent]] object is * passed to your handler which offers information about the pointer input being received. * * - `down` - When a pointer is pressed down (any mouse button or finger press) @@ -5411,7 +5796,7 @@ declare module ex.Input { * complex input and having control over every interaction. * * You can also use [[PointerScope.Canvas]] to only scope event handling to the game - * canvas. This is useful if you don't care about events that occur outside. + * canvas. This is useful if you don't care about events that occur outside the game. * * One real-world example is dragging and gestures. Sometimes a player will drag their * finger outside your game and then into it, expecting it to work. If [[PointerScope]] @@ -5420,8 +5805,8 @@ declare module ex.Input { * * ## Responding to input * - * The primary pointer can be a mouse, stylus, or 1 finger touch event. You - * can inspect what it is from the [[PointerEvent]] handled. + * The primary pointer can be a mouse, stylus, or single finger touch event. You + * can inspect what type of pointer it is from the [[PointerEvent]] handled. * * ```js * engine.input.pointers.primary.on("down", function (pe) { @@ -5473,9 +5858,10 @@ declare module ex.Input { * By default, [[Actor|Actors]] do not participate in pointer events. In other * words, when you "click" an Actor, it will not throw an event **for that Actor**, * only a generic pointer event for the game. This is to keep performance - * high and allow actors to "opt-in" to handling pointer events. + * high and allow actors to "opt-in" to handling pointer events. Actors will automatically + * opt-in if a pointer related event handler is set on them `actor.on("pointerdown", () => {})` for example. * - * To opt-in, set [[Actor.enableCapturePointer]] to `true` and the [[Actor]] will + * To opt-in manually, set [[Actor.enableCapturePointer]] to `true` and the [[Actor]] will * start publishing `pointerup` and `pointerdown` events. `pointermove` events * will not be published by default due to performance implications. If you want * an actor to receive move events, set [[ICapturePointerConfig.captureMoveEvents]] to @@ -5611,13 +5997,13 @@ declare module ex.Input { * Keyboard input * * Working with the keyboard is easy in Excalibur. You can inspect - * whether a button is [[Keyboard.isKeyDown|down]], [[Keyboard.isKeyUp|up]], or - * [[Keyboard.isKeyPressed|pressed]]. Common keys are held in the [[Input.Keys]] + * whether a button was just [[Keyboard.wasPressed|pressed]] or [[Keyboard.wasReleased|released]] this frame, or + * if the key is currently being [[Keyboard.isHeld|held]] down. Common keys are held in the [[Input.Keys]] * enumeration but you can pass any character code to the methods. * * Excalibur subscribes to the browser events and keeps track of - * what keys are currently down, up, or pressed. A key can be pressed - * for multiple frames, but a key cannot be down or up for more than one + * what keys are currently held, released, or pressed. A key can be held + * for multiple frames, but a key cannot be pressed or released for more than one subsequent * update frame. * * ## Inspecting the keyboard @@ -5625,19 +6011,36 @@ declare module ex.Input { * You can inspect [[Engine.input]] to see what the state of the keyboard * is during an update. * + * It is recommended that keyboard actions that directly effect actors be handled like so to improve code quality: * ```ts * class Player extends ex.Actor { * public update(engine, delta) { * - * if (engine.input.keyboard.isKeyPressed(ex.Input.Keys.W) || - * engine.input.keyboard.isKeyPressed(ex.Input.Keys.Up)) { + * if (engine.input.keyboard.isHeld(ex.Input.Keys.W) || + * engine.input.keyboard.isHeld(ex.Input.Keys.Up)) { * * player._moveForward(); * } * + * if (engine.input.keyboard.wasPressed(ex.Input.Keys.Right)) { + * player._fire(); + * } * } * } * ``` + * ## Events + * You can subscribe to keyboard events through `engine.input.keyboard.on`. A [[KeyEvent]] object is + * passed to your handler which offers information about the key that was part of the event. + * + * - `press` - When a key was just pressed this frame + * - `release` - When a key was just released this frame + * - `hold` - Whenever a key is in the down position + * + * ```ts + * engine.input.pointers.primary.on("press", (evt: KeyEvent) => {...}); + * engine.input.pointers.primary.on("release", (evt: KeyEvent) => {...}); + * engine.input.pointers.primary.on("hold", (evt: KeyEvent) => {...}); + * ``` */ class Keyboard extends ex.Class { private _keys; @@ -5655,20 +6058,20 @@ declare module ex.Input { */ getKeys(): Keys[]; /** - * Tests if a certain key is down. This is cleared at the end of the update frame. - * @param key Test wether a key is down + * Tests if a certain key was just pressed this frame. This is cleared at the end of the update frame. + * @param key Test wether a key was just pressed */ - isKeyDown(key: Keys): boolean; + wasPressed(key: Keys): boolean; /** - * Tests if a certain key is pressed. This is persisted between frames. - * @param key Test wether a key is pressed + * Tests if a certain key is held down. This is persisted between frames. + * @param key Test wether a key is held down */ - isKeyPressed(key: Keys): boolean; + isHeld(key: Keys): boolean; /** - * Tests if a certain key is up. This is cleared at the end of the update frame. - * @param key Test wether a key is up + * Tests if a certain key was just released this frame. This is cleared at the end of the update frame. + * @param key Test wether a key was just released */ - isKeyUp(key: Keys): boolean; + wasReleased(key: Keys): boolean; } } declare module ex.Input { @@ -5681,11 +6084,60 @@ declare module ex.Input { * You can query any [[Gamepad|Gamepads]] that are connected or listen to events ("button" and "axis"). * * You must opt-in to controller support ([[Gamepads.enabled]]) because it is a polling-based - * API, so we have to check it each update frame. + * API, so we have to check it each update frame. If an gamepad related event handler is set, you will + * automatically opt-in to controller polling. * - * Any number of gamepads are supported using the [[Gamepads.at]] method. If a [[Gamepad]] is + * HTML5 Gamepad API only supports a maximum of 4 gamepads. You can access them using the [[Gamepads.at]] method. If a [[Gamepad]] is * not connected, it will simply not throw events. * + * ## Gamepad Filtering + * + * Different browsers/devices are sometimes loose about the devices they consider Gamepads, you can set minimum device requirements with + * `engine.inpute.gamepads.setMinimumGamepadConfiguration` so that undesired devices are not reported to you (Touchpads, Mice, Web + * Cameras, etc.). + * ```js + * // ensures that only gamepads with at least 4 axis and 8 buttons are reported for events + * engine.input.gamepads.setMinimumGamepadConfiguration({ + * axis: 4, + * buttons: 8 + * }); + * ``` + * + * ## Events + * + * You can subscribe to gamepad connect and disconnect events through `engine.input.gamepads.on`. + * A [[GamepadConnectEvent]] or [[GamepadDisconnectEvent]] will be passed to you. + * + * - `connect` - When a gamepad connects it will fire this event and pass a [[GamepadConnectEvent]] with a reference to the gamepad. + * - `disconnect` - When a gamepad disconnects it will fire this event and pass a [[GamepadDisconnectEvent]] + * + * Once you have a reference to a gamepad you may listen to changes on that gamepad with `.on`. A [[GamepadButtonEvent]] or + * [[GamepadAxisEvent]] will be passed to you. + * - `button` - Whenever a button is pressed on the game + * - `axis` - Whenever an axis + * + * ```ts + * + * engine.input.gamepads.on('connect', (ce: ex.Input.GamepadConnectEvent) => { + * var newPlayer = CreateNewPlayer(); // pseudo-code for new player logic on gamepad connection + * console.log("Gamepad connected", ce); + * ce.gamepad.on('button', (be: ex.GamepadButtonEvent) => { + * if(be.button === ex.Input.Buttons.Face1) { + * newPlayer.jump(); + * } + * }); + * + * ce.gamepad.on('axis', (ae: ex.GamepadAxisEvent) => { + * if(ae.axis === ex.Input.Axis.LeftStickX && ae.value > .5){ + * newPlayer.moveRight(); + * } + * }) + * + * }); + * + * + * ``` + * * ## Responding to button input * * [[Buttons|Gamepad buttons]] typically have values between 0 and 1, however depending on @@ -5771,8 +6223,26 @@ declare module ex.Input { private _initSuccess; private _engine; private _navigator; + private _minimumConfiguration; constructor(engine: ex.Engine); init(): void; + /** + * Sets the minimum gamepad configuration, for example {axis: 4, buttons: 4} means + * this game requires at minimum 4 axis inputs and 4 buttons, this is not restrictive + * all other controllers with more axis or buttons are valid as well. If no minimum + * configuration is set all pads are valid. + */ + setMinimumGamepadConfiguration(config: IGamepadConfiguration): void; + /** + * When implicitely enabled, set the enabled flag and run an update so information is updated + */ + private _enableAndUpdate(); + /** + * Checks a navigator gamepad against the minimum configuration if present. + */ + private _isGamepadValid(pad); + on(eventName: string, handler: (event?: GameEvent) => void): void; + off(eventName: string, handler?: (event?: GameEvent) => void): void; /** * Updates Gamepad state and publishes Gamepad events */ @@ -5781,6 +6251,10 @@ declare module ex.Input { * Safely retrieves a Gamepad at a specific index and creates one if it doesn't yet exist */ at(index: number): Gamepad; + /** + * Returns a list of all valid gamepads that meet the minimum configuration requirment. + */ + getValidGamepads(): Gamepad[]; /** * Gets the number of connected gamepads */ @@ -5797,6 +6271,7 @@ declare module ex.Input { */ class Gamepad extends ex.Class { connected: boolean; + navigatorGamepad: INavigatorGamepad; private _buttons; private _axes; constructor(); @@ -5908,30 +6383,6 @@ declare module ex.Input { */ RightStickY = 3, } - /** - * Gamepad button event. See [[Gamepads]] for information on responding to controller input. - */ - class GamepadButtonEvent extends ex.GameEvent { - button: Buttons; - value: number; - /** - * @param button The Gamepad button - * @param value A numeric value between 0 and 1 - */ - constructor(button: Buttons, value: number); - } - /** - * Gamepad axis event. See [[Gamepads]] for information on responding to controller input. - */ - class GamepadAxisEvent extends ex.GameEvent { - axis: Axes; - value: number; - /** - * @param axis The Gamepad axis - * @param value A numeric value between -1 and 1 - */ - constructor(axis: Axes, value: number); - } /** * @internal */ @@ -5957,6 +6408,13 @@ declare module ex.Input { interface INavigatorGamepadEvent { gamepad: INavigatorGamepad; } + /** + * @internal + */ + interface IGamepadConfiguration { + axis: number; + buttons: number; + } } /** * # Welcome to the Excalibur API @@ -5973,7 +6431,7 @@ declare module ex.Input { * * ## Where to Start * - * These are the core concepts of Excalibur that you should be + * These are the core concepts of Excalibur that you should become * familiar with. * * - [[Engine|Intro to the Engine]] @@ -6012,6 +6470,7 @@ declare module ex.Input { * - [[Sound|Working with Sounds]] * - [[SpriteSheet|Working with SpriteSheets]] * - [[Animation|Working with Animations]] + * - [[TileMap|Working with TileMaps]] * * ## Effects and Particles * @@ -6020,6 +6479,7 @@ declare module ex.Input { * * - [[Effects|Sprite Effects]] * - [[ParticleEmitter|Particle Emitters]] + * - [[IPostProcessor|Post Processors]] * * ## Math * @@ -6100,9 +6560,11 @@ declare module ex { * * The Excalibur engine uses a simple main loop. The engine updates and renders * the "scene graph" which is the [[Scene|scenes]] and the tree of [[Actor|actors]] within that - * scene. Only one [[Scene]] can be active at once, the engine does not update/draw any other + * scene. Only one [[Scene]] can be active at a time. The engine does not update/draw any other * scene, which means any actors will not be updated/drawn if they are part of a deactivated scene. * + * ![Engine Lifecycle](/assets/images/docs/EngineLifeCycle.png) + * * **Scene Graph** * * ``` @@ -6121,13 +6583,13 @@ declare module ex { * * ### Update Loop * - * The first operation run is the [[Engine.update|update]] loop. [[Actor]] and [[Scene]] both implement + * The first operation run is the [[Engine._update|update]] loop. [[Actor]] and [[Scene]] both implement * an overridable/extendable `update` method. Use it to perform any logic-based operations * in your game for a particular class. * * ### Draw Loop * - * The next step is the [[Engine.draw|draw]] loop. A [[Scene]] loops through its child [[Actor|actors]] and + * The next step is the [[Engine._draw|draw]] loop. A [[Scene]] loops through its child [[Actor|actors]] and * draws each one. You can override the `draw` method on an actor to customize its drawing. * You should **not** perform any logic in a draw call, it should only relate to drawing. * @@ -6350,6 +6812,8 @@ declare module ex { * the [[currentScene]] may be drawn or updated. * * @param actor The actor to add to the [[currentScene]] + * + * @obsolete Use [[add]] instead. */ addChild(actor: Actor): void; /** @@ -6416,7 +6880,7 @@ declare module ex { add(tileMap: TileMap): void; /** * Adds an actor to the [[currentScene]] of the game. This is synonymous - * to calling `engine.currentScene.addChild(actor)`. + * to calling `engine.currentScene.add(actor)`. * * Actors can only be drawn if they are a member of a scene, and only * the [[currentScene]] may be drawn or updated. diff --git a/dist/Excalibur.js b/dist/Excalibur.js index 73d8b67c5..1442266d5 100644 --- a/dist/Excalibur.js +++ b/dist/Excalibur.js @@ -1,6 +1,6 @@ -/*! excalibur - v0.5.1 - 2015-09-14 +/*! excalibur - v0.6.0 - 2016-01-19 * https://github.com/excaliburjs/Excalibur -* Copyright (c) 2015 ; Licensed BSD-2-Clause*/ +* Copyright (c) 2016 ; Licensed BSD-2-Clause*/ if (typeof window === 'undefined') { window = { audioContext: function () { return; } }; } @@ -460,7 +460,7 @@ var ex; actorScreenCoords.x > engine.width || actorScreenCoords.y > engine.height) && isSpriteOffScreen) { - eventDispatcher.publish('exitviewport', new ex.ExitViewPortEvent()); + eventDispatcher.emit('exitviewport', new ex.ExitViewPortEvent()); actor.isOffScreen = true; } } @@ -470,7 +470,7 @@ var ex; actorScreenCoords.x < engine.width && actorScreenCoords.y < engine.height) || !isSpriteOffScreen) { - eventDispatcher.publish('enterviewport', new ex.EnterViewPortEvent()); + eventDispatcher.emit('enterviewport', new ex.EnterViewPortEvent()); actor.isOffScreen = false; } } @@ -515,7 +515,7 @@ var ex; } CollisionDetection.prototype.update = function (actor, engine, delta) { var eventDispatcher = actor.eventDispatcher; - if (actor.collisionType !== ex.CollisionType.PreventCollision) { + if (actor.collisionType !== ex.CollisionType.PreventCollision && engine.currentScene && engine.currentScene.tileMaps) { for (var j = 0; j < engine.currentScene.tileMaps.length; j++) { var map = engine.currentScene.tileMaps[j]; var intersectMap; @@ -527,7 +527,7 @@ var ex; break; } side = actor.getSideFromIntersect(intersectMap); - eventDispatcher.publish('collision', new ex.CollisionEvent(actor, null, side, intersectMap)); + eventDispatcher.emit('collision', new ex.CollisionEvent(actor, null, side, intersectMap)); if ((actor.collisionType === ex.CollisionType.Active || actor.collisionType === ex.CollisionType.Elastic)) { actor.y += intersectMap.y; actor.x += intersectMap.x; @@ -574,13 +574,13 @@ var ex; var __extends = (this && this.__extends) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } - __.prototype = b.prototype; - d.prototype = new __(); + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; var ex; (function (ex) { /** * A simple 2D point on a plane + * @obsolete Use [[Vector|vector]]s instead of [[Point|points]] */ var Point = (function () { /** @@ -1007,6 +1007,15 @@ var ex; return false; } Util.removeItemToArray = removeItemToArray; + function contains(array, obj) { + for (var i = 0; i < array.length; i++) { + if (array[i] === obj) { + return true; + } + } + return false; + } + Util.contains = contains; function getOppositeSide(side) { if (side === ex.Side.Top) { return ex.Side.Bottom; @@ -1202,10 +1211,38 @@ var ex; * * Excalibur offers many sprite effects such as [[Effects.Colorize]] to let you manipulate * sprites. Keep in mind, more effects requires more power and can lead to memory or CPU - * constraints and hurt performance. + * constraints and hurt performance. Each effect must be reprocessed every frame for each sprite. * * It's still recommended to create an [[Animation]] or build in your effects to the sprites * for optimal performance. + * + * There are a number of convenience methods available to perform sprite effects. Sprite effects are + * side-effecting. + * + * ```typescript + * + * var playerSprite = new ex.Sprite(txPlayer, 0, 0, 80, 80); + * + * // darken a sprite by a percentage + * playerSprite.darken(.2); // 20% + * + * // lighten a sprite by a percentage + * playerSprite.lighten(.2); // 20% + * + * // saturate a sprite by a percentage + * playerSprite.saturate(.2); // 20% + * + * // implement a custom effect + * class CustomEffect implements ex.EffectsISpriteEffect { + * + * updatePixel(x: number, y: number, imageData: ImageData) { + * // modify ImageData + * } + * } + * + * playerSprite.addEffect(new CustomEffect()); + * + * ``` */ var Sprite = (function () { /** @@ -1655,7 +1692,8 @@ var ex; * Sprite Fonts * * Sprite fonts are a used in conjunction with a [[Label]] to specify - * a particular bitmap as a font. + * a particular bitmap as a font. Note that some font features are not + * supported by Sprite fonts. * * ## Generating the font sheet * @@ -1747,9 +1785,21 @@ var ex; this.image = image; this.alphabet = alphabet; this.caseInsensitive = caseInsensitive; + this.spWidth = spWidth; + this.spHeight = spHeight; this._spriteLookup = {}; this._colorLookup = {}; - this._currentColor = ex.Color.Black; + this._currentColor = ex.Color.Black.clone(); + this._currentOpacity = 1.0; + this._sprites = {}; + // text shadow + this._textShadowOn = false; + this._textShadowDirty = true; + this._textShadowColor = ex.Color.Black.clone(); + this._textShadowSprites = {}; + this._shadowOffsetX = 5; + this._shadowOffsetY = 5; + this._sprites = this.getTextSprites(); } /** * Returns a dictionary that maps each character in the alphabet to the appropriate [[Sprite]]. @@ -1765,6 +1815,115 @@ var ex; } return lookup; }; + /** + * Sets the text shadow for sprite fonts + * @param offsetX The x offset in pixels to place the shadow + * @param offsetY The y offset in pixles to place the shadow + * @param shadowColor The color of the text shadow + */ + SpriteFont.prototype.setTextShadow = function (offsetX, offsetY, shadowColor) { + this._textShadowOn = true; + this._shadowOffsetX = offsetX; + this._shadowOffsetY = offsetY; + this._textShadowColor = shadowColor.clone(); + this._textShadowDirty = true; + for (var character in this._sprites) { + this._textShadowSprites[character] = this._sprites[character].clone(); + } + }; + /** + * Toggles text shadows on or off + */ + SpriteFont.prototype.useTextShadow = function (on) { + this._textShadowOn = on; + if (on) { + this.setTextShadow(5, 5, this._textShadowColor); + } + }; + /** + * Draws the current sprite font + */ + SpriteFont.prototype.draw = function (ctx, text, x, y, options) { + options = this._parseOptions(options); + if (this._currentColor.toString() !== options.color.toString() || this._currentOpacity !== options.opacity) { + this._currentOpacity = options.opacity; + this._currentColor = options.color; + for (var char in this._sprites) { + this._sprites[char].clearEffects(); + this._sprites[char].fill(options.color); + this._sprites[char].opacity(options.opacity); + } + } + if (this._textShadowOn && this._textShadowDirty && this._textShadowColor) { + for (var characterShadow in this._textShadowSprites) { + this._textShadowSprites[characterShadow].clearEffects(); + this._textShadowSprites[characterShadow].addEffect(new ex.Effects.Fill(this._textShadowColor.clone())); + } + this._textShadowDirty = false; + } + // find the current length of text in pixels + var sprite = this.sprites[0]; + // find the current height fo the text in pixels + var height = sprite.sheight; + // calculate appropriate scale for font size + var scale = options.fontSize / height; + var length = (text.length * sprite.swidth * scale) + (text.length * options.letterSpacing); + var currX = x; + if (options.textAlign === ex.TextAlign.Left || options.textAlign === ex.TextAlign.Start) { + currX = x; + } + else if (options.textAlign === ex.TextAlign.Right || options.textAlign === ex.TextAlign.End) { + currX = x - length; + } + else if (options.textAlign === ex.TextAlign.Center) { + currX = x - length / 2; + } + var currY = y - height * scale; + if (options.baseAlign === ex.BaseAlign.Top || options.baseAlign === ex.BaseAlign.Hanging) { + currY = y; + } + else if (options.baseAlign === ex.BaseAlign.Ideographic || + options.baseAlign === ex.BaseAlign.Bottom || + options.baseAlign === ex.BaseAlign.Alphabetic) { + currY = y - height * scale; + } + else if (options.baseAlign === ex.BaseAlign.Middle) { + currY = y - (height * scale) / 2; + } + for (var i = 0; i < text.length; i++) { + var character = text[i]; + if (this.caseInsensitive) { + character = character.toLowerCase(); + } + try { + // if text shadow + if (this._textShadowOn) { + this._textShadowSprites[character].scale.x = scale; + this._textShadowSprites[character].scale.y = scale; + this._textShadowSprites[character].draw(ctx, currX + this._shadowOffsetX, currY + this._shadowOffsetY); + } + var charSprite = this._sprites[character]; + charSprite.scale.x = scale; + charSprite.scale.y = scale; + charSprite.draw(ctx, currX, currY); + currX += (charSprite.width + options.letterSpacing); + } + catch (e) { + ex.Logger.getInstance().error("SpriteFont Error drawing char " + character); + } + } + }; + SpriteFont.prototype._parseOptions = function (options) { + return { + fontSize: options.fontSize || 10, + letterSpacing: options.letterSpacing || 0, + color: options.color || ex.Color.Black.clone(), + textAlign: typeof options.textAlign === undefined ? ex.TextAlign.Left : options.textAlign, + baseAlign: typeof options.baseAlign === undefined ? ex.BaseAlign.Bottom : options.baseAlign, + maxWidth: options.maxWidth || -1, + opacity: options.opacity || 0 + }; + }; return SpriteFont; })(SpriteSheet); ex.SpriteFont = SpriteFont; @@ -2481,6 +2640,14 @@ var ex; Class.prototype.off = function (eventName, handler) { this.eventDispatcher.unsubscribe(eventName, handler); }; + /** + * Emits a new event + * @param eventName Name of the event to emit + * @param eventObject Data associated with this event + */ + Class.prototype.emit = function (eventName, eventObject) { + this.eventDispatcher.emit(eventName, eventObject); + }; /** * You may wish to extend native Excalibur functionality in vanilla Javascript. * Any method on a class inheriting [[Class]] may be extended to support @@ -3121,8 +3288,8 @@ var ex; // todo fire collision events on left and right actor // todo resolve collisions // Publish collision events on both participants - this.left.eventDispatcher.publish('collision', new ex.CollisionEvent(this.left, this.right, this.side, this.intersect)); - this.right.eventDispatcher.publish('collision', new ex.CollisionEvent(this.right, this.left, ex.Util.getOppositeSide(this.side), this.intersect.scale(-1.0))); + this.left.eventDispatcher.emit('collision', new ex.CollisionEvent(this.left, this.right, this.side, this.intersect)); + this.right.eventDispatcher.emit('collision', new ex.CollisionEvent(this.right, this.left, ex.Util.getOppositeSide(this.side), this.intersect.scale(-1.0))); // If the actor is active push the actor out if its not passive var leftSide = this.side; if ((this.left.collisionType === ex.CollisionType.Active || @@ -3283,8 +3450,20 @@ var ex; */ var BaseCamera = (function () { function BaseCamera() { - this._focus = new ex.Point(0, 0); - this._lerp = false; + this.focus = new ex.Point(0, 0); + this.lerp = false; + // camera physical quantities + this.x = 0; + this.y = 0; + this.z = 1; + this.dx = 0; + this.dy = 0; + this.dz = 0; + this.ax = 0; + this.ay = 0; + this.az = 0; + this.rotation = 0; + this.rx = 0; this._cameraMoving = false; this._currentLerpTime = 0; this._lerpDuration = 1 * 1000; // 5 seconds @@ -3321,23 +3500,24 @@ var ex; this._follow = actor; }; /** - * Returns the focal point of the camera + * Returns the focal point of the camera, a new point giving the x and y position of the camera */ BaseCamera.prototype.getFocus = function () { - return this._focus; + return new ex.Point(this.x, this.y); }; /** * Sets the focal point of the camera. This value can only be set if there is no actor to be followed. * @param x The x coordinate of the focal point * @param y The y coordinate of the focal point + * @deprecated */ BaseCamera.prototype.setFocus = function (x, y) { - if (!this._follow && !this._lerp) { - this._focus.x = x; - this._focus.y = y; + if (!this._follow && !this.lerp) { + this.x = x; + this.y = y; } - if (this._lerp) { - this._lerpStart = this._focus.clone(); + if (this.lerp) { + this._lerpStart = this.getFocus().clone(); this._lerpEnd = new ex.Point(x, y); this._currentLerpTime = 0; this._cameraMoving = true; @@ -3389,16 +3569,24 @@ var ex; * Gets the current zoom scale */ BaseCamera.prototype.getZoom = function () { - return this._currentZoomScale; + return this.z; }; BaseCamera.prototype._setCurrentZoomScale = function (zoomScale) { - this._currentZoomScale = zoomScale; + this.z = zoomScale; }; /** * Applies the relevant transformations to the game canvas to "move" or apply effects to the Camera * @param delta The number of milliseconds since the last update */ BaseCamera.prototype.update = function (ctx, delta) { + // Update placements based on linear algebra + this.x += this.dx * delta / 1000; + this.y += this.dy * delta / 1000; + this.z += this.dz * delta / 1000; + this.dx += this.ax * delta / 1000; + this.dy += this.ay * delta / 1000; + this.dz += this.az * delta / 1000; + this.rotation += this.rx * delta / 1000; var focus = this.getFocus(); var xShake = 0; var yShake = 0; @@ -3408,19 +3596,19 @@ var ex; // if zoom is .5x then canvas is 2x as high var newCanvasWidth = canvasWidth / this.getZoom(); var newCanvasHeight = canvasHeight / this.getZoom(); - if (this._lerp) { + if (this.lerp) { if (this._currentLerpTime < this._lerpDuration && this._cameraMoving) { if (this._lerpEnd.x < this._lerpStart.x) { - this._focus.x = this._lerpStart.x - (this._easeInOutCubic(this._currentLerpTime, this._lerpEnd.x, this._lerpStart.x, this._lerpDuration) - this._lerpEnd.x); + this.x = this._lerpStart.x - (this._easeInOutCubic(this._currentLerpTime, this._lerpEnd.x, this._lerpStart.x, this._lerpDuration) - this._lerpEnd.x); } else { - this._focus.x = this._easeInOutCubic(this._currentLerpTime, this._lerpStart.x, this._lerpEnd.x, this._lerpDuration); + this.x = this._easeInOutCubic(this._currentLerpTime, this._lerpStart.x, this._lerpEnd.x, this._lerpDuration); } if (this._lerpEnd.y < this._lerpStart.y) { - this._focus.y = this._lerpStart.y - (this._easeInOutCubic(this._currentLerpTime, this._lerpEnd.y, this._lerpStart.y, this._lerpDuration) - this._lerpEnd.y); + this.y = this._lerpStart.y - (this._easeInOutCubic(this._currentLerpTime, this._lerpEnd.y, this._lerpStart.y, this._lerpDuration) - this._lerpEnd.y); } else { - this._focus.y = this._easeInOutCubic(this._currentLerpTime, this._lerpStart.y, this._lerpEnd.y, this._lerpDuration); + this.y = this._easeInOutCubic(this._currentLerpTime, this._lerpStart.y, this._lerpEnd.y, this._lerpDuration); } this._currentLerpTime += delta; } @@ -3443,16 +3631,17 @@ var ex; xShake = (Math.random() * this._shakeMagnitudeX | 0) + 1; yShake = (Math.random() * this._shakeMagnitudeY | 0) + 1; } - if (this._isDoneZooming()) { - this._isZooming = false; - this._elapsedZoomTime = 0; - this._zoomDuration = 0; - this._setCurrentZoomScale(this._maxZoomScale); - } - else { - this._elapsedZoomTime += delta; - this._setCurrentZoomScale(this.getZoom() + this._zoomIncrement * delta / 1000); - } + /*if (this._isDoneZooming()) { + this._isZooming = false; + this._elapsedZoomTime = 0; + this._zoomDuration = 0; + this._setCurrentZoomScale(this._maxZoomScale); + + } else { + this._elapsedZoomTime += delta; + + this._setCurrentZoomScale(this.getZoom() + this._zoomIncrement * delta / 1000); + }*/ ctx.scale(this.getZoom(), this.getZoom()); ctx.translate(-focus.x + newCanvasWidth / 2 + xShake, -focus.y + newCanvasHeight / 2 + yShake); }; @@ -3501,10 +3690,10 @@ var ex; } SideCamera.prototype.getFocus = function () { if (this._follow) { - return new ex.Point(this._follow.x + this._follow.getWidth() / 2, this._focus.y); + return new ex.Point(this._follow.x + this._follow.getWidth() / 2, this.focus.y); } else { - return this._focus; + return this.focus; } }; return SideCamera; @@ -3527,7 +3716,7 @@ var ex; return new ex.Point(this._follow.x + this._follow.getWidth() / 2, this._follow.y + this._follow.getHeight() / 2); } else { - return this._focus; + return this.focus; } }; return LockedCamera; @@ -4493,11 +4682,6 @@ var ex; * in future versions to support multiple timelines/scripts, better eventing, * and a more robust API to allow for complex and customized actions. * - * ## Known Issues - * - * **Rotation actions do not use shortest angle** - * [Issue #282](https://github.com/excaliburjs/Excalibur/issues/282) - * */ var ActionContext = (function () { function ActionContext() { @@ -4531,6 +4715,23 @@ var ex; this._queues.splice(index, 1); } }; + /** + * This method will move an actor to the specified `x` and `y` position over the + * specified duration using a given [[EasingFunctions]] and return back the actor. This + * method is part of the actor 'Action' fluent API allowing action chaining. + * @param x The x location to move the actor to + * @param y The y location to move the actor to + * @param duration The time it should take the actor to move to the new location in milliseconds + * @param easingFcn Use [[EasingFunctions]] or a custom function to use to calculate position + */ + ActionContext.prototype.easeTo = function (x, y, duration, easingFcn) { + if (easingFcn === void 0) { easingFcn = ex.EasingFunctions.Linear; } + var i = 0, len = this._queues.length; + for (i; i < len; i++) { + this._queues[i].add(new ex.Internal.Actions.EaseTo(this._actors[i], x, y, duration, easingFcn)); + } + return this; + }; /** * This method will move an actor to the specified x and y position at the * speed specified (in pixels per second) and return back the actor. This @@ -4782,7 +4983,26 @@ var ex; * Groups are used for logically grouping Actors so they can be acted upon * in bulk. * - * @todo Document this + * ## Using Groups + * + * Groups can be used to detect collisions across a large nubmer of actors. For example + * perhaps a large group of "enemy" actors. + * + * ```typescript + * var enemyShips = engine.currentScene.createGroup("enemy"); + * var enemies = [...]; // Large array of enemies; + * enemyShips.add(enemies); + * + * var player = new Actor(); + * engine.currentScene.add(player); + * + * enemyShips.on('collision', function(ev: CollisionEvent){ + * if (e.other === player) { + * //console.log("collision with player!"); + * } + * }); + * + * ``` */ var Group = (function (_super) { __extends(Group, _super); @@ -5190,6 +5410,13 @@ var ex; * * ``` * + * ## Scene Lifecycle + * + * A [[Scene|scene]] has a basic lifecycle that dictacts how it is initialized, updated, and drawn. Once a [[Scene|scene]] is added to + * the [[Engine|engine]] it will follow this lifecycle. + * + * ![Scene Lifecycle](/assets/images/docs/SceneLifeCycle.png) + * * ## Extending scenes * * For more complex games, you might want more control over a scene in which @@ -5309,23 +5536,13 @@ var ex; // will be overridden this._logger.debug('Scene.onDeactivate', this); }; - /** - * Publish an event to all actors in the scene - * @param eventType The name of the event to publish - * @param event The event object to send - */ - Scene.prototype.publish = function (eventType, event) { - var i = 0, len = this.children.length; - for (i; i < len; i++) { - this.children[i].triggerEvent(eventType, event); - } - }; /** * Updates all the actors and timers in the scene. Called by the [[Engine]]. * @param engine Reference to the current Engine * @param delta The number of milliseconds since the last update */ Scene.prototype.update = function (engine, delta) { + this.emit('preupdate', new ex.PreUpdateEvent(engine, delta, this)); var i, len; // Cycle through actors updating UI actors for (i = 0, len = this.uiActors.length; i < len; i++) { @@ -5364,6 +5581,7 @@ var ex; timer.update(delta); return !timer.complete; }); + this.emit('postupdate', new ex.PostUpdateEvent(engine, delta, this)); }; /** * Draws all the actors in the Scene. Called by the [[Engine]]. @@ -5371,6 +5589,7 @@ var ex; * @param delta The number of milliseconds since the last draw */ Scene.prototype.draw = function (ctx, delta) { + this.emit('predraw', new ex.PreDrawEvent(ctx, delta, this)); ctx.save(); if (this.camera) { this.camera.update(ctx, delta); @@ -5402,12 +5621,14 @@ var ex; this.uiActors[i].debugDraw(ctx); } } + this.emit('postdraw', new ex.PreDrawEvent(ctx, delta, this)); }; /** * Draws all the actors' debug information in the Scene. Called by the [[Engine]]. * @param ctx The current rendering context */ Scene.prototype.debugDraw = function (ctx) { + this.emit('predebugdraw', new ex.PreDebugDrawEvent(ctx, this)); var i, len; for (i = 0, len = this.tileMaps.length; i < len; i++) { this.tileMaps[i].debugDraw(ctx); @@ -5418,6 +5639,7 @@ var ex; // todo possibly enable this with excalibur flags features? //this._collisionResolver.debugDraw(ctx, 20); this.camera.debugDraw(ctx); + this.emit('postdebugdraw', new ex.PostDebugDrawEvent(ctx, this)); }; /** * Checks whether an actor is contained in this scene or not @@ -5427,18 +5649,28 @@ var ex; }; Scene.prototype.add = function (entity) { if (entity instanceof ex.UIActor) { - this.addUIActor(entity); + if (!ex.Util.contains(this.uiActors, entity)) { + this.addUIActor(entity); + } return; } if (entity instanceof ex.Actor) { - this.addChild(entity); - this._sortedDrawingTree.add(entity); + if (!ex.Util.contains(this.children, entity)) { + this.addChild(entity); + this._sortedDrawingTree.add(entity); + } + return; } if (entity instanceof ex.Timer) { - this.addTimer(entity); + if (!ex.Util.contains(this._timers, entity)) { + this.addTimer(entity); + } + return; } if (entity instanceof ex.TileMap) { - this.addTileMap(entity); + if (!ex.Util.contains(this.tileMaps, entity)) { + this.addTileMap(entity); + } } }; Scene.prototype.remove = function (entity) { @@ -5477,6 +5709,8 @@ var ex; }; /** * Adds an actor to the scene, once this is done the actor will be drawn and updated. + * + * @obsolete Use [[add]] instead. */ Scene.prototype.addChild = function (actor) { this._collisionResolver.register(actor); @@ -5585,32 +5819,44 @@ var ex; var ex; (function (ex) { /** - * Standard easing functions for motion in Excalibur + * Standard easing functions for motion in Excalibur, defined on a domain of [0, duration] and a range from [+startValue,+endValue] + * Given a time, the function will return a value from postive startValue to postive endValue. + * + * ```js + * function Linear (t) { + * return t * t; + * } * - * easeInQuad: function (t) { return t * t }, - * // decelerating to zero velocity - * easeOutQuad: function (t) { return t * (2 - t) }, - * // acceleration until halfway, then deceleration - * easeInOutQuad: function (t) { return t < .5 ? 2 * t * t : -1 + (4 - 2 * t) * t }, - * // accelerating from zero velocity - * easeInCubic: function (t) { return t * t * t }, - * // decelerating to zero velocity - * easeOutCubic: function (t) { return (--t) * t * t + 1 }, - * // acceleration until halfway, then deceleration - * easeInOutCubic: function (t) { return t < .5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1 }, * // accelerating from zero velocity - * easeInQuart: function (t) { return t * t * t * t }, + * function EaseInQuad (t) { + * return t * t; + * } + * * // decelerating to zero velocity - * easeOutQuart: function (t) { return 1 - (--t) * t * t * t }, + * function EaseOutQuad (t) { + * return t * (2 - t); + * } + * * // acceleration until halfway, then deceleration - * easeInOutQuart: function (t) { return t < .5 ? 8 * t * t * t * t : 1 - 8 * (--t) * t * t * t }, + * function EaseInOutQuad (t) { + * return t < .5 ? 2 * t * t : -1 + (4 - 2 * t) * t; + * } + * * // accelerating from zero velocity - * easeInQuint: function (t) { return t * t * t * t * t }, + * function EaseInCubic (t) { + * return t * t * t; + * } + * * // decelerating to zero velocity - * easeOutQuint: function (t) { return 1 + (--t) * t * t * t * t }, - * // acceleration until halfway, then deceleration - * easeInOutQuint: function (t) { return t < .5 ? 16 * t * t * t * t * t : 1 + 16 * (--t) * t * t * t * t } + * function EaseOutCubic (t) { + * return (--t) * t * t + 1; + * } * + * // acceleration until halfway, then deceleration + * function EaseInOutCubic (t) { + * return t < .5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1; + * } + * ``` */ var EasingFunctions = (function () { function EasingFunctions() { @@ -5701,7 +5947,16 @@ var ex; * * // add player to the current scene * game.add(player); + * * ``` + * `game.add` is a convenience method for adding an `Actor` to the current scene. The equivalent verbose call is `game.currentScene.add`. + * + * ## Actor Lifecycle + * + * An [[Actor|actor]] has a basic lifecycle that dictacts how it is initialized, updated, and drawn. Once an actor is part of a + * [[Scene|scene]], it will follow this lifecycle. + * + * ![Actor Lifecycle](/assets/images/docs/ActorLifeCycle.png) * * ## Extending actors * @@ -5771,7 +6026,7 @@ var ex; * * The [[update]] method is passed an instance of the Excalibur engine, which * can be used to perform coordinate math or access global state. It is also - * passed `delta` which is the time since the last frame, which can be used + * passed `delta` which is the time in milliseconds since the last frame, which can be used * to perform time-based movement or time-based math (such as a timer). * * **TypeScript** @@ -5783,7 +6038,7 @@ var ex; * * // check if player died * if (this.health <= 0) { - * this.triggerEvent("death"); + * this.emit("death"); * this.onDeath(); * return; * } @@ -5800,7 +6055,7 @@ var ex; * * // check if player died * if (this.health <= 0) { - * this.triggerEvent("death"); + * this.emit("death"); * this.onDeath(); * return; * } @@ -5812,13 +6067,16 @@ var ex; * * Override the [[draw]] method to perform any custom drawing. For simple games, * you don't need to override `draw`, instead you can use [[addDrawing]] and [[setDrawing]] - * to manipulate the textures/animations that the actor is using. + * to manipulate the [[Sprite|sprites]]/[[Animation|animations]] that the actor is using. * * ### Working with Textures & Sprites * - * A common usage is to use a [[Texture]] or [[Sprite]] for an actor. If you are using the [[Loader]] to - * pre-load assets, you can simply assign an actor a [[Texture]] to draw. You can - * also create a [[Texture.asSprite|sprite from a Texture]] to quickly create a [[Sprite]] instance. + * Think of a [[Texture|texture]] as the raw image file that will be loaded into Excalibur. In order for it to be drawn + * it must be converted to a [[Sprite.sprite]]. + * + * A common usage is to load a [[Texture]] and convert it to a [[Sprite]] for an actor. If you are using the [[Loader]] to + * pre-load assets, you can simply assign an actor a [[Sprite]] to draw. You can also create a + * [[Texture.asSprite|sprite from a Texture]] to quickly create a [[Sprite]] instance. * * ```ts * // assume Resources.TxPlayer is a 80x80 png image @@ -5857,7 +6115,8 @@ var ex; * ### Custom drawing * * You can always override the default drawing logic for an actor in the [[draw]] method, - * for example, to draw complex shapes or to use the raw Canvas API. + * for example, to draw complex shapes or to use the raw + * [[https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D|Canvas API]]. * * Usually you should call `super.draw` to perform the base drawing logic, but other times * you may want to take over the drawing completely. @@ -5888,33 +6147,45 @@ var ex; * ## Collision Detection * * By default Actors do not participate in collisions. If you wish to make - * an actor participate, you need to enable the [[CollisionDetectionModule]] + * an actor participate, you need to switch from the default [[CollisionType.PreventCollision|prevent collision]] + * to [[CollisionType.Active|active]], [[CollisionType.Fixed|fixed]], or [[CollisionType.Passive|passive]] collision type. * * ```ts * public Player extends ex.Actor { * constructor() { * super(); - * - * // enable the pipeline - * this.pipelines.push(new ex.CollisionDetectionModule()); - * * // set preferred CollisionType * this.collisionType = ex.CollisionType.Active; * } * } - * ``` * - * ### Collision Groups + * // or set the collisionType * + * var actor = new ex.Actor(); + * actor.collisionType = ex.CollisionType.Active; + * + * ``` + * ### Collision Groups * TODO, needs more information. * + * ## Traits + * + * Traits describe actor behavior that occurs every update. If you wish to build a generic behavior + * without needing to extend every actor you can do it with a trait, a good example of this may be + * plugging in an external collision detection library like [[https://github.com/kripken/box2d.js/|Box2D]] or + * [[http://wellcaffeinated.net/PhysicsJS/|PhysicsJS]] by wrapping it in a trait. Removing traits can also make your + * actors more efficient. + * + * Default traits provided by Excalibur are [[Traits.CapturePointer|pointer capture]], + * [[Traits.CollisionDetection|tile map collision]], [[Traits.Movement|Euler style movement]], + * and [[Traits.OffscreenCulling|offscreen culling]]. + * + * * ## Known Issues * * **Actor bounding boxes do not rotate** * [Issue #68](https://github.com/excaliburjs/Excalibur/issues/68) * - * **Setting opacity when using a color doesn't do anything** - * [Issue #364](https://github.com/excaliburjs/Excalibur/issues/364) */ var Actor = (function (_super) { __extends(Actor, _super); @@ -5933,11 +6204,11 @@ var ex; */ this.id = Actor.maxId++; /** - * The x coordinate of the actor (left edge) + * The x coordinate of the actor (middle if anchor is (0.5, 0.5) left edge if anchor is (0, 0)) */ this.x = 0; /** - * The y coordinate of the actor (top edge) + * The y coordinate of the actor (middle if anchor is (0.5, 0.5) and top edge if anchor is (0, 0)) */ this.y = 0; this._height = 0; @@ -6055,7 +6326,7 @@ var ex; } // Build default pipeline this.traits.push(new ex.Traits.Movement()); - //this.pipeline.push(new ex.CollisionDetectionModule()); + this.traits.push(new ex.Traits.CollisionDetection()); this.traits.push(new ex.Traits.OffscreenCulling()); this.traits.push(new ex.Traits.CapturePointer()); this.actionQueue = new ex.Internal.Actions.ActionQueue(this); @@ -6124,7 +6395,7 @@ var ex; * move with it. * @param actor The child actor to add */ - Actor.prototype.addChild = function (actor) { + Actor.prototype.add = function (actor) { actor.collisionType = CollisionType.PreventCollision; if (ex.Util.addItemToArray(actor, this.children)) { actor.parent = this; @@ -6134,7 +6405,7 @@ var ex; * Removes a child actor from this actor. * @param actor The child actor to remove */ - Actor.prototype.removeChild = function (actor) { + Actor.prototype.remove = function (actor) { if (ex.Util.removeItemToArray(actor, this.children)) { actor.parent = null; } @@ -6185,16 +6456,6 @@ var ex; this._zIndex = newIndex; this.scene.updateDrawTree(this); }; - /** - * Artificially trigger an event on an actor, useful when creating custom events. - * @param eventName The name of the event to trigger - * @param event The event object to pass to the callback - * - * @obsolete Will be replaced with `emit` - */ - Actor.prototype.triggerEvent = function (eventName, event) { - this.eventDispatcher.publish(eventName, event); - }; /** * Adds an actor to a collision group. Actors with no named collision groups are * considered to be in every collision group. @@ -6420,6 +6681,7 @@ var ex; }; /** * Clears all queued actions from the Actor + * @obsolete Use [[ActionContext.clearActions|Actor.actions.clearActions]] */ Actor.prototype.clearActions = function () { this.actionQueue.clearActions(); @@ -6432,6 +6694,7 @@ var ex; * @param y The y location to move the actor to * @param duration The time it should take the actor to move to the new location in milliseconds * @param easingFcn Use [[EasingFunctions]] or a custom function to use to calculate position + * @obsolete Use [[ActionContext.easeTo|Actor.actions.easeTo]] */ Actor.prototype.easeTo = function (x, y, duration, easingFcn) { if (easingFcn === void 0) { easingFcn = ex.EasingFunctions.Linear; } @@ -6445,6 +6708,7 @@ var ex; * @param x The x location to move the actor to * @param y The y location to move the actor to * @param speed The speed in pixels per second to move + * @obsolete Use [[ActionContext.moveTo|Actor.actions.moveTo]] */ Actor.prototype.moveTo = function (x, y, speed) { this.actionQueue.add(new ex.Internal.Actions.MoveTo(this, x, y, speed)); @@ -6457,6 +6721,7 @@ var ex; * @param x The x location to move the actor to * @param y The y location to move the actor to * @param duration The time it should take the actor to move to the new location in milliseconds + * @obsolete Use [[ActionContext.moveBy|Actor.actions.moveBy]] */ Actor.prototype.moveBy = function (x, y, duration) { this.actionQueue.add(new ex.Internal.Actions.MoveBy(this, x, y, duration)); @@ -6468,6 +6733,7 @@ var ex; * method is part of the actor 'Action' fluent API allowing action chaining. * @param angleRadians The angle to rotate to in radians * @param speed The angular velocity of the rotation specified in radians per second + * @obsolete Use [[ActionContext.rotateTo|Actor.actions.rotateTo]] */ Actor.prototype.rotateTo = function (angleRadians, speed, rotationType) { this.actionQueue.add(new ex.Internal.Actions.RotateTo(this, angleRadians, speed, rotationType)); @@ -6479,6 +6745,7 @@ var ex; * of the actor 'Action' fluent API allowing action chaining. * @param angleRadians The angle to rotate to in radians * @param duration The time it should take the actor to complete the rotation in milliseconds + * @obsolete Use [[ActionContext.rotateBy|ex.Actor.actions.rotateBy]] */ Actor.prototype.rotateBy = function (angleRadians, duration, rotationType) { this.actionQueue.add(new ex.Internal.Actions.RotateBy(this, angleRadians, duration, rotationType)); @@ -6493,6 +6760,7 @@ var ex; * @param sizeY The scaling factor in the y direction to apply * @param speedX The speed of scaling in the x direction specified in magnitude increase per second * @param speedY The speed of scaling in the y direction specified in magnitude increase per second + * @obsolete Use [[ActionContext.scaleTo|Actor.actions.scaleTo]] */ Actor.prototype.scaleTo = function (sizeX, sizeY, speedX, speedY) { this.actionQueue.add(new ex.Internal.Actions.ScaleTo(this, sizeX, sizeY, speedX, speedY)); @@ -6505,6 +6773,7 @@ var ex; * @param sizeX The scaling factor in the x direction to apply * @param sizeY The scaling factor in the y direction to apply * @param duration The time it should take to complete the scaling in milliseconds + * @obsolete Use [[ActionContext.scaleBy|Actor.actions.scaleBy]] */ Actor.prototype.scaleBy = function (sizeX, sizeY, duration) { this.actionQueue.add(new ex.Internal.Actions.ScaleBy(this, sizeX, sizeY, duration)); @@ -6518,6 +6787,7 @@ var ex; * @param timeVisible The amount of time to stay visible per blink in milliseconds * @param timeNotVisible The amount of time to stay not visible per blink in milliseconds * @param numBlinks The number of times to blink + * @obsolete Use [[ActionContext.blink|Actor.actions.blink]] */ Actor.prototype.blink = function (timeVisible, timeNotVisible, numBlinks) { if (numBlinks === void 0) { numBlinks = 1; } @@ -6530,6 +6800,7 @@ var ex; * part of the actor 'Action' fluent API allowing action chaining. * @param opacity The ending opacity * @param duration The time it should take to fade the actor (in milliseconds) + * @obsolete Use [[ActionContext.fade|Actor.actions.fade]] */ Actor.prototype.fade = function (opacity, duration) { this.actionQueue.add(new ex.Internal.Actions.Fade(this, opacity, duration)); @@ -6540,6 +6811,7 @@ var ex; * `duration` (in milliseconds). This method is part of the actor * 'Action' fluent API allowing action chaining. * @param duration The amount of time to delay the next action in the queue from executing in milliseconds + * @obsolete Use [[ActionContext.delay|Actor.actions.delay]] */ Actor.prototype.delay = function (duration) { this.actionQueue.add(new ex.Internal.Actions.Delay(this, duration)); @@ -6549,6 +6821,7 @@ var ex; * This method will add an action to the queue that will remove the actor from the * scene once it has completed its previous actions. Any actions on the * action queue after this action will not be executed. + * @obsolete Use [[ActionContext.die|Actor.actions.die]] */ Actor.prototype.die = function () { this.actionQueue.add(new ex.Internal.Actions.Die(this)); @@ -6558,6 +6831,7 @@ var ex; * This method allows you to call an arbitrary method as the next action in the * action queue. This is useful if you want to execute code in after a specific * action, i.e An actor arrives at a destination after traversing a path + * @obsolete Use [[ActionContext.callMethod|Actor.actions.callMethod]] */ Actor.prototype.callMethod = function (method) { this.actionQueue.add(new ex.Internal.Actions.CallMethod(this, method)); @@ -6570,6 +6844,7 @@ var ex; * the actor 'Action' fluent API allowing action chaining * @param times The number of times to repeat all the previous actions in the action queue. If nothing is specified the actions will * repeat forever + * @obsolete Use [[ActionContext.repeat|Actor.actions.repeat]] */ Actor.prototype.repeat = function (times) { if (!times) { @@ -6583,6 +6858,7 @@ var ex; * This method will cause the actor to repeat all of the previously * called actions forever. This method is part of the actor 'Action' * fluent API allowing action chaining. + * @obsolete Use [[ActionContext.repeatForever|Actor.actions.repeatForever]] */ Actor.prototype.repeatForever = function () { this.actionQueue.add(new ex.Internal.Actions.RepeatForever(this, this.actionQueue.getActions())); @@ -6592,6 +6868,7 @@ var ex; * This method will cause the actor to follow another at a specified distance * @param actor The actor to follow * @param followDistance The distance to maintain when following, if not specified the actor will follow at the current distance. + * @obsolete Use [[ActionContext.follow|Actor.actions.follow]] */ Actor.prototype.follow = function (actor, followDistance) { if (typeof followDistance === 'undefined') { @@ -6607,6 +6884,7 @@ var ex; * collide ("meet") at a specified speed. * @param actor The actor to meet * @param speed The speed in pixels per second to move, if not specified it will match the speed of the other actor + * @obsolete Use [[ActionContext.meet|Actor.actions.meet]] */ Actor.prototype.meet = function (actor, speed) { if (typeof speed === 'undefined') { @@ -6620,6 +6898,7 @@ var ex; /** * Returns a promise that resolves when the current action queue up to now * is finished. + * @obsolete Use [[ActionContext.asPromise|Actor.actions.asPromise]] */ Actor.prototype.asPromise = function () { var complete = new ex.Promise(); @@ -6639,9 +6918,10 @@ var ex; Actor.prototype.update = function (engine, delta) { if (!this._isInitialized) { this.onInitialize(engine); - this.eventDispatcher.publish('initialize', new ex.InitializeEvent(engine)); + this.eventDispatcher.emit('initialize', new ex.InitializeEvent(engine)); this._isInitialized = true; } + this.emit('preupdate', new ex.PreUpdateEvent(engine, delta, this)); var eventDispatcher = this.eventDispatcher; // Update action queue this.actionQueue.update(delta); @@ -6653,7 +6933,8 @@ var ex; for (var i = 0; i < this.traits.length; i++) { this.traits[i].update(this, engine, delta); } - eventDispatcher.publish(ex.EventType[ex.EventType.Update], new ex.UpdateEvent(delta)); + eventDispatcher.emit('update', new ex.UpdateEvent(delta)); + this.emit('postupdate', new ex.PostUpdateEvent(engine, delta, this)); }; /** * Called by the Engine, draws the actor to the screen @@ -6663,9 +6944,10 @@ var ex; Actor.prototype.draw = function (ctx, delta) { var anchorPoint = this._getCalculatedAnchor(); ctx.save(); - ctx.scale(this.scale.x, this.scale.y); ctx.translate(this.x, this.y); + ctx.scale(this.scale.x, this.scale.y); ctx.rotate(this.rotation); + this.emit('predraw', new ex.PreDrawEvent(ctx, delta, this)); // calculate changing opacity if (this.previousOpacity !== this.opacity) { for (var drawing in this.frames) { @@ -6694,8 +6976,11 @@ var ex; } // Draw child actors for (var i = 0; i < this.children.length; i++) { - this.children[i].draw(ctx, delta); + if (this.children[i].visible) { + this.children[i].draw(ctx, delta); + } } + this.emit('postdraw', new ex.PostDrawEvent(ctx, delta, this)); ctx.restore(); }; /** @@ -6703,6 +6988,7 @@ var ex; * @param ctx The rendering context */ Actor.prototype.debugDraw = function (ctx) { + this.emit('predebugdraw', new ex.PreDebugDrawEvent(ctx, this)); // Draw actor bounding box var bb = this.getBounds(); bb.debugDraw(ctx); @@ -6748,6 +7034,7 @@ var ex; this.children[i].debugDraw(ctx); } ctx.restore(); + this.emit('postdebugdraw', new ex.PostDebugDrawEvent(ctx, this)); }; /** * Indicates the next id to be set @@ -6780,6 +7067,7 @@ var ex; * Actors with the `Elastic` setting will behave the same as `Active`, except that they will * "bounce" in the opposite direction given their velocity dx/dy. This is a naive implementation meant for * prototyping, for a more robust elastic collision listen to the "collision" event and perform your custom logic. + * @obsolete This behavior will be handled by a future physics system */ CollisionType[CollisionType["Elastic"] = 3] = "Elastic"; /** @@ -7039,23 +7327,23 @@ var ex; var ex; (function (ex) { /** - * An enum representing all of the built in event types for Excalibur - * @obsolete Phasing this out in favor of classes - */ - (function (EventType) { - EventType[EventType["Collision"] = 0] = "Collision"; - EventType[EventType["EnterViewPort"] = 1] = "EnterViewPort"; - EventType[EventType["ExitViewPort"] = 2] = "ExitViewPort"; - EventType[EventType["Blur"] = 3] = "Blur"; - EventType[EventType["Focus"] = 4] = "Focus"; - EventType[EventType["Update"] = 5] = "Update"; - EventType[EventType["Activate"] = 6] = "Activate"; - EventType[EventType["Deactivate"] = 7] = "Deactivate"; - EventType[EventType["Initialize"] = 8] = "Initialize"; - })(ex.EventType || (ex.EventType = {})); - var EventType = ex.EventType; - /** - * Base event type in Excalibur that all other event types derive from. + * Base event type in Excalibur that all other event types derive from. Not all event types are thrown on all Excalibur game objects, + * some events are unique to a type, others are not. + * + * Excalibur events follow the convention that the name of the thrown event for listening will be the same as the Event object in all + * lower case with the 'Event' suffix removed. + * + * For example: + * - PreDrawEvent event object and "predraw" as the event name + * + * ```typescript + * + * actor.on('predraw', (evtObj: PreDrawEvent) => { + * // do some pre drawing + * }) + * + * ``` + * */ var GameEvent = (function () { function GameEvent() { @@ -7064,7 +7352,154 @@ var ex; })(); ex.GameEvent = GameEvent; /** - * Subscribe event thrown when handlers for events other than subscribe are added + * The 'predraw' event is emitted on actors, scenes, and engine before drawing starts. Actors' predraw happens inside their graphics + * transform so that all drawing takes place with the actor as the origin. + * + */ + var PreDrawEvent = (function (_super) { + __extends(PreDrawEvent, _super); + function PreDrawEvent(ctx, delta, target) { + _super.call(this); + this.ctx = ctx; + this.delta = delta; + this.target = target; + } + return PreDrawEvent; + })(GameEvent); + ex.PreDrawEvent = PreDrawEvent; + /** + * The 'postdraw' event is emitted on actors, scenes, and engine after drawing finishes. Actors' postdraw happens inside their graphics + * transform so that all drawing takes place with the actor as the origin. + * + */ + var PostDrawEvent = (function (_super) { + __extends(PostDrawEvent, _super); + function PostDrawEvent(ctx, delta, target) { + _super.call(this); + this.ctx = ctx; + this.delta = delta; + this.target = target; + } + return PostDrawEvent; + })(GameEvent); + ex.PostDrawEvent = PostDrawEvent; + /** + * The 'predebugdraw' event is emitted on actors, scenes, and engine before debug drawing starts. + */ + var PreDebugDrawEvent = (function (_super) { + __extends(PreDebugDrawEvent, _super); + function PreDebugDrawEvent(ctx, target) { + _super.call(this); + this.ctx = ctx; + this.target = target; + } + return PreDebugDrawEvent; + })(GameEvent); + ex.PreDebugDrawEvent = PreDebugDrawEvent; + /** + * The 'postdebugdraw' event is emitted on actors, scenes, and engine after debug drawing starts. + */ + var PostDebugDrawEvent = (function (_super) { + __extends(PostDebugDrawEvent, _super); + function PostDebugDrawEvent(ctx, target) { + _super.call(this); + this.ctx = ctx; + this.target = target; + } + return PostDebugDrawEvent; + })(GameEvent); + ex.PostDebugDrawEvent = PostDebugDrawEvent; + /** + * The 'preupdate' event is emitted on actors, scenes, and engine before the update starts. + */ + var PreUpdateEvent = (function (_super) { + __extends(PreUpdateEvent, _super); + function PreUpdateEvent(engine, delta, target) { + _super.call(this); + this.engine = engine; + this.delta = delta; + this.target = target; + } + return PreUpdateEvent; + })(GameEvent); + ex.PreUpdateEvent = PreUpdateEvent; + /** + * The 'postupdate' event is emitted on actors, scenes, and engine after the update ends. This is equivalent to the obsolete 'update' + * event. + */ + var PostUpdateEvent = (function (_super) { + __extends(PostUpdateEvent, _super); + function PostUpdateEvent(engine, delta, target) { + _super.call(this); + this.engine = engine; + this.delta = delta; + this.target = target; + } + return PostUpdateEvent; + })(GameEvent); + ex.PostUpdateEvent = PostUpdateEvent; + /** + * Event received when a gamepad is connected to Excalibur. [[Input.Gamepads|engine.input.gamepads]] receives this event. + */ + var GamepadConnectEvent = (function (_super) { + __extends(GamepadConnectEvent, _super); + function GamepadConnectEvent(index, gamepad) { + _super.call(this); + this.index = index; + this.gamepad = gamepad; + } + return GamepadConnectEvent; + })(GameEvent); + ex.GamepadConnectEvent = GamepadConnectEvent; + /** + * Event received when a gamepad is disconnected from Excalibur. [[Input.Gamepads|engine.input.gamepads]] receives this event. + */ + var GamepadDisconnectEvent = (function (_super) { + __extends(GamepadDisconnectEvent, _super); + function GamepadDisconnectEvent(index) { + _super.call(this); + this.index = index; + } + return GamepadDisconnectEvent; + })(GameEvent); + ex.GamepadDisconnectEvent = GamepadDisconnectEvent; + /** + * Gamepad button event. See [[Gamepads]] for information on responding to controller input. [[Gamepad]] instances receive this event; + */ + var GamepadButtonEvent = (function (_super) { + __extends(GamepadButtonEvent, _super); + /** + * @param button The Gamepad button + * @param value A numeric value between 0 and 1 + */ + function GamepadButtonEvent(button, value) { + _super.call(this); + this.button = button; + this.value = value; + } + return GamepadButtonEvent; + })(ex.GameEvent); + ex.GamepadButtonEvent = GamepadButtonEvent; + /** + * Gamepad axis event. See [[Gamepads]] for information on responding to controller input. [[Gamepad]] instances receive this event; + */ + var GamepadAxisEvent = (function (_super) { + __extends(GamepadAxisEvent, _super); + /** + * @param axis The Gamepad axis + * @param value A numeric value between -1 and 1 + */ + function GamepadAxisEvent(axis, value) { + _super.call(this); + this.axis = axis; + this.value = value; + } + return GamepadAxisEvent; + })(ex.GameEvent); + ex.GamepadAxisEvent = GamepadAxisEvent; + /** + * Subscribe event thrown when handlers for events other than subscribe are added. Meta event that is received by + * [[EventDispatcher|event dispatchers]]. */ var SubscribeEvent = (function (_super) { __extends(SubscribeEvent, _super); @@ -7077,7 +7512,8 @@ var ex; })(GameEvent); ex.SubscribeEvent = SubscribeEvent; /** - * Unsubscribe event thrown when handlers for events other than unsubscribe are removed + * Unsubscribe event thrown when handlers for events other than unsubscribe are removed. Meta event that is received by + * [[EventDispatcher|event dispatchers]]. */ var UnsubscribeEvent = (function (_super) { __extends(UnsubscribeEvent, _super); @@ -7090,7 +7526,7 @@ var ex; })(GameEvent); ex.UnsubscribeEvent = UnsubscribeEvent; /** - * Event received by the Engine when the browser window is visible + * Event received by the [[Engine]] when the browser window is visible on a screen. */ var VisibleEvent = (function (_super) { __extends(VisibleEvent, _super); @@ -7101,7 +7537,7 @@ var ex; })(GameEvent); ex.VisibleEvent = VisibleEvent; /** - * Event received by the Engine when the browser window is hidden + * Event received by the [[Engine]] when the browser window is hidden from all screens. */ var HiddenEvent = (function (_super) { __extends(HiddenEvent, _super); @@ -7112,7 +7548,7 @@ var ex; })(GameEvent); ex.HiddenEvent = HiddenEvent; /** - * Event thrown on an actor when a collision has occured + * Event thrown on an [[Actor|actor]] when a collision has occured */ var CollisionEvent = (function (_super) { __extends(CollisionEvent, _super); @@ -7132,7 +7568,8 @@ var ex; })(GameEvent); ex.CollisionEvent = CollisionEvent; /** - * Event thrown on a game object on Excalibur update + * Event thrown on a game object on Excalibur update, this is equivalent to postupdate. + * @obsolete Please use [[PostUpdateEvent|postupdate]], or [[PreUpdateEvent|preupdate]]. */ var UpdateEvent = (function (_super) { __extends(UpdateEvent, _super); @@ -7147,7 +7584,7 @@ var ex; })(GameEvent); ex.UpdateEvent = UpdateEvent; /** - * Event thrown on an Actor only once before the first update call + * Event thrown on an [[Actor]] only once before the first update call */ var InitializeEvent = (function (_super) { __extends(InitializeEvent, _super); @@ -7162,7 +7599,7 @@ var ex; })(GameEvent); ex.InitializeEvent = InitializeEvent; /** - * Event thrown on a Scene on activation + * Event thrown on a [[Scene]] on activation */ var ActivateEvent = (function (_super) { __extends(ActivateEvent, _super); @@ -7177,7 +7614,7 @@ var ex; })(GameEvent); ex.ActivateEvent = ActivateEvent; /** - * Event thrown on a Scene on deactivation + * Event thrown on a [[Scene]] on deactivation */ var DeactivateEvent = (function (_super) { __extends(DeactivateEvent, _super); @@ -7192,7 +7629,7 @@ var ex; })(GameEvent); ex.DeactivateEvent = DeactivateEvent; /** - * Event thrown on an Actor when it completely leaves the screen. + * Event thrown on an [[Actor]] when it completely leaves the screen. */ var ExitViewPortEvent = (function (_super) { __extends(ExitViewPortEvent, _super); @@ -7203,7 +7640,7 @@ var ex; })(GameEvent); ex.ExitViewPortEvent = ExitViewPortEvent; /** - * Event thrown on an Actor when it completely leaves the screen. + * Event thrown on an [[Actor]] when it completely leaves the screen. */ var EnterViewPortEvent = (function (_super) { __extends(EnterViewPortEvent, _super); @@ -7220,8 +7657,8 @@ var ex; /** * Excalibur's internal event dispatcher implementation. * Callbacks are fired immediately after an event is published. - * Typically you'd use [[Class.eventDispatcher]] since most classes in - * Excalibur inherit from [[Class]]. You'd rarely create an `EventDispatcher` + * Typically you will use [[Class.eventDispatcher]] since most classes in + * Excalibur inherit from [[Class]]. You will rarely create an `EventDispatcher` * yourself. * * When working with events, be sure to keep in mind the order of subscriptions @@ -7258,14 +7695,14 @@ var ex; * }); * * // trigger custom event - * player.triggerEvent("death", new DeathEvent()); + * player.emit("death", new DeathEvent()); * * ``` * * ## Example: Pub/Sub with Excalibur * * You can also create an EventDispatcher for any arbitrary object, for example - * a global game event aggregator (`vent`). Anything in your game can subscribe to + * a global game event aggregator (shown below as `vent`). Anything in your game can subscribe to * it, if the event aggregator is in the global scope. * * *Warning:* This can easily get out of hand. Avoid this usage, it just serves as @@ -7284,7 +7721,7 @@ var ex; * vent.subscribe("someevent", subscription); * * // publish an event somewhere in the game - * vent.publish("someevent", new ex.GameEvent()); + * vent.emit("someevent", new ex.GameEvent()); * ``` */ var EventDispatcher = (function () { @@ -7301,6 +7738,8 @@ var ex; * Publish an event for target * @param eventName The name of the event to publish * @param event Optionally pass an event data object to the handler + * + * @obsolete Use [[emit]] instead. */ EventDispatcher.prototype.publish = function (eventName, event) { if (!eventName) { @@ -7324,7 +7763,7 @@ var ex; i = 0; len = this._wiredEventDispatchers.length; for (i; i < len; i++) { - this._wiredEventDispatchers[i].publish(eventName, event); + this._wiredEventDispatchers[i].emit(eventName, event); } }; /** @@ -8033,7 +8472,7 @@ var ex; * extend [[Actor]] allowing you to use all of the features that come with. * * The easiest way to create a `ParticleEmitter` is to use the - * [Particle Tester](http://excaliburjs.com/particle-tester/). + * [Particle Tester](http://excaliburjs.com/particle-tester/) to generate code for emitters. * * ## Example: Adding an emitter * @@ -8041,12 +8480,26 @@ var ex; * var actor = new ex.Actor(...); * var emitter = new ex.ParticleEmitter(...); * + * emitter.emitterType = ex.EmitterType.Circle; // Shape of emitter nozzle + * emitter.radius = 5; + * emitter.minVel = 100; + * emitter.maxVel = 200; + * emitter.minAngle = 0; + * emitter.maxAngle = Math.PI * 2; + * emitter.emitRate = 300; // 300 particles/second + * emitter.opacity = 0.5; + * emitter.fadeFlag = true; // fade particles overtime + * emitter.particleLife = 1000; // in milliseconds = 1 sec + * emitter.maxSize = 10; // in pixels + * emitter.minSize = 1; + * emitter.particleColor = ex.Color.Rose; + * * // set emitter settings - * emitter.isEmitting = true; + * emitter.isEmitting = true; // should the emitter be emitting * * // add the emitter as a child actor, it will draw on top of the parent actor * // and move with the parent - * actor.addChild(emitter); + * actor.add(emitter); * * // or, alternatively, add it to the current scene * engine.add(emitter); @@ -8182,7 +8635,7 @@ var ex; * Causes the emitter to emit particles * @param particleCount Number of particles to emit right now */ - ParticleEmitter.prototype.emit = function (particleCount) { + ParticleEmitter.prototype.emitParticles = function (particleCount) { for (var i = 0; i < particleCount; i++) { this.particles.push(this._createParticle()); } @@ -8232,7 +8685,7 @@ var ex; this._particlesToEmit += this.emitRate * (delta / 1000); //var numParticles = Math.ceil(this.emitRate * delta / 1000); if (this._particlesToEmit > 1.0) { - this.emit(Math.floor(this._particlesToEmit)); + this.emitParticles(Math.floor(this._particlesToEmit)); this._particlesToEmit = this._particlesToEmit - Math.floor(this._particlesToEmit); } } @@ -8354,6 +8807,7 @@ var ex; this.width = images[0] ? images[0].width : 0; this.naturalWidth = images[0] ? images[0].naturalWidth : 0; this.naturalHeight = images[0] ? images[0].naturalHeight : 0; + this.freezeFrame = images.length - 1; } } /** @@ -9264,7 +9718,8 @@ var ex; * is loaded, you can [[Sound.play|play]] it. * * ```js - * var sndPlayerDeath = new ex.Sound("/assets/snd/player-death.mp3", "/assets/snd/player-wav.mp3"); + * // define multiple sources (such as mp3/wav/ogg) as a browser fallback + * var sndPlayerDeath = new ex.Sound("/assets/snd/player-death.mp3", "/assets/snd/player-death.wav"); * * var loader = new ex.Loader(sndPlayerDeath); * @@ -9846,6 +10301,33 @@ var ex; /// var ex; (function (ex) { + /** + * Enum representing the different font size units + * https://developer.mozilla.org/en-US/docs/Web/CSS/font-size + */ + (function (FontUnit) { + /** + * Em is a scalable unit, 1 em is equal to the current font size of the current element, parent elements can effect em values + */ + FontUnit[FontUnit["Em"] = 0] = "Em"; + /** + * Rem is similar to the Em, it is a scalable unit. 1 rem is eqaul to the font size of the root element + */ + FontUnit[FontUnit["Rem"] = 1] = "Rem"; + /** + * Pixel is a unit of length in screen pixels + */ + FontUnit[FontUnit["Px"] = 2] = "Px"; + /** + * Point is a physical unit length (1/72 of an inch) + */ + FontUnit[FontUnit["Pt"] = 3] = "Pt"; + /** + * Percent is a scalable unit similar to Em, the only difference is the Em units scale faster when Text-Size stuff + */ + FontUnit[FontUnit["Percent"] = 4] = "Percent"; + })(ex.FontUnit || (ex.FontUnit = {})); + var FontUnit = ex.FontUnit; /** * Enum representing the different horizontal text alignments */ @@ -10003,8 +10485,24 @@ var ex; * @param spriteFont Use an Excalibur sprite font for the label's font, if a SpriteFont is provided it will take precendence * over a css font. */ - function Label(text, x, y, font, spriteFont) { + function Label(text, x, y, fontFamily, spriteFont) { _super.call(this, x, y); + /** + * The font size in the selected units, default is 10 (default units is pixel) + */ + this.fontSize = 10; + /** + * The css units for a font size such as px, pt, em (SpriteFont only support px), by default is 'px'; + */ + this.fontUnit = FontUnit.Px; + /** + * Gets or sets the horizontal text alignment property for the label. + */ + this.textAlign = TextAlign.Left; + /** + * Gets or sets the baseline alignment property for the label. + */ + this.baseAlign = BaseAlign.Bottom; /** * Gets or sets the letter spacing on a Label. Only supported with Sprite Fonts. */ @@ -10025,9 +10523,8 @@ var ex; this.color = ex.Color.Black.clone(); this.spriteFont = spriteFont; this.collisionType = ex.CollisionType.PreventCollision; - this.font = font || '10px sans-serif'; // coallesce to default canvas font + this.fontFamily = fontFamily || '10px sans-serif'; // coallesce to default canvas font if (spriteFont) { - this._textSprites = spriteFont.getTextSprites(); } } /** @@ -10036,12 +10533,28 @@ var ex; */ Label.prototype.getTextWidth = function (ctx) { var oldFont = ctx.font; - ctx.font = this.font; + ctx.font = this.fontFamily; var width = ctx.measureText(this.text).width; ctx.font = oldFont; return width; }; // TypeScript doesn't support string enums :( + Label.prototype._lookupFontUnit = function (fontUnit) { + switch (fontUnit) { + case FontUnit.Em: + return 'em'; + case FontUnit.Rem: + return 'rem'; + case FontUnit.Pt: + return 'pt'; + case FontUnit.Px: + return 'px'; + case FontUnit.Percent: + return '%'; + default: + return 'px'; + } + }; Label.prototype._lookupTextAlign = function (textAlign) { switch (textAlign) { case TextAlign.Left: @@ -10083,14 +10596,13 @@ var ex; * @param shadowColor The color of the text shadow */ Label.prototype.setTextShadow = function (offsetX, offsetY, shadowColor) { - this._textShadowOn = true; - this._shadowOffsetX = offsetX; - this._shadowOffsetY = offsetY; - this._shadowColor = shadowColor.clone(); - this._shadowColorDirty = true; - for (var character in this._textSprites) { - this._shadowSprites[character] = this._textSprites[character].clone(); - } + this.spriteFont.setTextShadow(offsetX, offsetY, shadowColor); + }; + /** + * Toggles text shadows on or off, only applies when using sprite fonts + */ + Label.prototype.useTextShadow = function (on) { + this.spriteFont.useTextShadow(on); }; /** * Clears the current text shadow @@ -10103,22 +10615,25 @@ var ex; }; Label.prototype.update = function (engine, delta) { _super.prototype.update.call(this, engine, delta); - if (this.spriteFont && (this._color !== this.color || this.previousOpacity !== this.opacity)) { - for (var character in this._textSprites) { - this._textSprites[character].clearEffects(); - this._textSprites[character].fill(this.color.clone()); - this._textSprites[character].opacity(this.opacity); - } - this._color = this.color; - this.previousOpacity = this.opacity; - } - if (this.spriteFont && this._textShadowOn && this._shadowColorDirty && this._shadowColor) { - for (var characterShadow in this._shadowSprites) { - this._shadowSprites[characterShadow].clearEffects(); - this._shadowSprites[characterShadow].addEffect(new ex.Effects.Fill(this._shadowColor.clone())); - } - this._shadowColorDirty = false; - } + /* + if (this.spriteFont && (this._color !== this.color || this.previousOpacity !== this.opacity)) { + for (var character in this._textSprites) { + this._textSprites[character].clearEffects(); + this._textSprites[character].fill(this.color.clone()); + this._textSprites[character].opacity(this.opacity); + + } + this._color = this.color; + this.previousOpacity = this.opacity; + } + + if (this.spriteFont && this._textShadowOn && this._shadowColorDirty && this._shadowColor) { + for (var characterShadow in this._shadowSprites) { + this._shadowSprites[characterShadow].clearEffects(); + this._shadowSprites[characterShadow].addEffect(new Effects.Fill(this._shadowColor.clone())); + } + this._shadowColorDirty = false; + }*/ }; Label.prototype.draw = function (ctx, delta) { ctx.save(); @@ -10137,21 +10652,14 @@ var ex; }; Label.prototype._fontDraw = function (ctx, delta, sprites) { if (this.spriteFont) { - var currX = 0; - for (var i = 0; i < this.text.length; i++) { - var character = this.text[i]; - if (this.caseInsensitive) { - character = character.toLowerCase(); - } - try { - var charSprite = sprites[character]; - charSprite.draw(ctx, currX, 0); - currX += (charSprite.swidth + this.letterSpacing); - } - catch (e) { - ex.Logger.getInstance().error('SpriteFont Error drawing char ' + character); - } - } + this.spriteFont.draw(ctx, this.text, 0, 0, { + color: this.color.clone(), + baseAlign: this.baseAlign, + textAlign: this.textAlign, + fontSize: this.fontSize, + letterSpacing: this.letterSpacing, + opacity: this.opacity + }); } else { var oldAlign = ctx.textAlign; @@ -10162,7 +10670,7 @@ var ex; this.color.a = this.opacity; } ctx.fillStyle = this.color.toString(); - ctx.font = this.font; + ctx.font = "" + this.fontSize + this._lookupFontUnit(this.fontUnit) + " " + this.fontFamily; if (this.maxWidth) { ctx.fillText(this.text, 0, 0, this.maxWidth); } @@ -10270,7 +10778,7 @@ var ex; * * ## Events * - * You can subscribe to pointer events through `engine.input.pointers`. A [[PointerEvent]] object is + * You can subscribe to pointer events through `engine.input.pointers.on`. A [[PointerEvent]] object is * passed to your handler which offers information about the pointer input being received. * * - `down` - When a pointer is pressed down (any mouse button or finger press) @@ -10293,7 +10801,7 @@ var ex; * complex input and having control over every interaction. * * You can also use [[PointerScope.Canvas]] to only scope event handling to the game - * canvas. This is useful if you don't care about events that occur outside. + * canvas. This is useful if you don't care about events that occur outside the game. * * One real-world example is dragging and gestures. Sometimes a player will drag their * finger outside your game and then into it, expecting it to work. If [[PointerScope]] @@ -10302,8 +10810,8 @@ var ex; * * ## Responding to input * - * The primary pointer can be a mouse, stylus, or 1 finger touch event. You - * can inspect what it is from the [[PointerEvent]] handled. + * The primary pointer can be a mouse, stylus, or single finger touch event. You + * can inspect what type of pointer it is from the [[PointerEvent]] handled. * * ```js * engine.input.pointers.primary.on("down", function (pe) { @@ -10355,9 +10863,10 @@ var ex; * By default, [[Actor|Actors]] do not participate in pointer events. In other * words, when you "click" an Actor, it will not throw an event **for that Actor**, * only a generic pointer event for the game. This is to keep performance - * high and allow actors to "opt-in" to handling pointer events. + * high and allow actors to "opt-in" to handling pointer events. Actors will automatically + * opt-in if a pointer related event handler is set on them `actor.on("pointerdown", () => {})` for example. * - * To opt-in, set [[Actor.enableCapturePointer]] to `true` and the [[Actor]] will + * To opt-in manually, set [[Actor.enableCapturePointer]] to `true` and the [[Actor]] will * start publishing `pointerup` and `pointerdown` events. `pointermove` events * will not be published by default due to performance implications. If you want * an actor to receive move events, set [[ICapturePointerConfig.captureMoveEvents]] to @@ -10471,14 +10980,14 @@ var ex; var i = 0, len = this._pointerUp.length; for (i; i < len; i++) { if (actor.contains(this._pointerUp[i].x, this._pointerUp[i].y, !isUIActor)) { - actor.eventDispatcher.publish('pointerup', this._pointerUp[i]); + actor.eventDispatcher.emit('pointerup', this._pointerUp[i]); } } i = 0; len = this._pointerDown.length; for (i; i < len; i++) { if (actor.contains(this._pointerDown[i].x, this._pointerDown[i].y, !isUIActor)) { - actor.eventDispatcher.publish('pointerdown', this._pointerDown[i]); + actor.eventDispatcher.emit('pointerdown', this._pointerDown[i]); } } if (actor.capturePointer.captureMoveEvents) { @@ -10486,7 +10995,7 @@ var ex; len = this._pointerMove.length; for (i; i < len; i++) { if (actor.contains(this._pointerMove[i].x, this._pointerMove[i].y, !isUIActor)) { - actor.eventDispatcher.publish('pointermove', this._pointerMove[i]); + actor.eventDispatcher.emit('pointermove', this._pointerMove[i]); } } } @@ -10494,7 +11003,7 @@ var ex; len = this._pointerCancel.length; for (i; i < len; i++) { if (actor.contains(this._pointerCancel[i].x, this._pointerCancel[i].y, !isUIActor)) { - actor.eventDispatcher.publish('pointercancel', this._pointerCancel[i]); + actor.eventDispatcher.emit('pointercancel', this._pointerCancel[i]); } } }; @@ -10507,7 +11016,7 @@ var ex; var transformedPoint = _this._engine.screenToWorldCoordinates(new ex.Point(x, y)); var pe = new PointerEvent(transformedPoint.x, transformedPoint.y, 0, PointerType.Mouse, e.button, e); eventArr.push(pe); - _this.at(0).eventDispatcher.publish(eventName, pe); + _this.at(0).eventDispatcher.emit(eventName, pe); }; }; Pointers.prototype._handleTouchEvent = function (eventName, eventArr) { @@ -10524,7 +11033,7 @@ var ex; var transformedPoint = _this._engine.screenToWorldCoordinates(new ex.Point(x, y)); var pe = new PointerEvent(transformedPoint.x, transformedPoint.y, index, PointerType.Touch, PointerButton.Unknown, e); eventArr.push(pe); - _this.at(index).eventDispatcher.publish(eventName, pe); + _this.at(index).eventDispatcher.emit(eventName, pe); // only with multi-pointer if (_this._pointers.length > 1) { if (eventName === 'up') { @@ -10553,7 +11062,7 @@ var ex; var transformedPoint = _this._engine.screenToWorldCoordinates(new ex.Point(x, y)); var pe = new PointerEvent(transformedPoint.x, transformedPoint.y, index, _this._stringToPointerType(e.pointerType), e.button, e); eventArr.push(pe); - _this.at(index).eventDispatcher.publish(eventName, pe); + _this.at(index).eventDispatcher.emit(eventName, pe); // only with multi-pointer if (_this._pointers.length > 1) { if (eventName === 'up') { @@ -10688,13 +11197,13 @@ var ex; * Keyboard input * * Working with the keyboard is easy in Excalibur. You can inspect - * whether a button is [[Keyboard.isKeyDown|down]], [[Keyboard.isKeyUp|up]], or - * [[Keyboard.isKeyPressed|pressed]]. Common keys are held in the [[Input.Keys]] + * whether a button was just [[Keyboard.wasPressed|pressed]] or [[Keyboard.wasReleased|released]] this frame, or + * if the key is currently being [[Keyboard.isHeld|held]] down. Common keys are held in the [[Input.Keys]] * enumeration but you can pass any character code to the methods. * * Excalibur subscribes to the browser events and keeps track of - * what keys are currently down, up, or pressed. A key can be pressed - * for multiple frames, but a key cannot be down or up for more than one + * what keys are currently held, released, or pressed. A key can be held + * for multiple frames, but a key cannot be pressed or released for more than one subsequent * update frame. * * ## Inspecting the keyboard @@ -10702,19 +11211,36 @@ var ex; * You can inspect [[Engine.input]] to see what the state of the keyboard * is during an update. * + * It is recommended that keyboard actions that directly effect actors be handled like so to improve code quality: * ```ts * class Player extends ex.Actor { * public update(engine, delta) { * - * if (engine.input.keyboard.isKeyPressed(ex.Input.Keys.W) || - * engine.input.keyboard.isKeyPressed(ex.Input.Keys.Up)) { + * if (engine.input.keyboard.isHeld(ex.Input.Keys.W) || + * engine.input.keyboard.isHeld(ex.Input.Keys.Up)) { * * player._moveForward(); * } * + * if (engine.input.keyboard.wasPressed(ex.Input.Keys.Right)) { + * player._fire(); + * } * } * } * ``` + * ## Events + * You can subscribe to keyboard events through `engine.input.keyboard.on`. A [[KeyEvent]] object is + * passed to your handler which offers information about the key that was part of the event. + * + * - `press` - When a key was just pressed this frame + * - `release` - When a key was just released this frame + * - `hold` - Whenever a key is in the down position + * + * ```ts + * engine.input.pointers.primary.on("press", (evt: KeyEvent) => {...}); + * engine.input.pointers.primary.on("release", (evt: KeyEvent) => {...}); + * engine.input.pointers.primary.on("hold", (evt: KeyEvent) => {...}); + * ``` */ var Keyboard = (function (_super) { __extends(Keyboard, _super); @@ -10739,7 +11265,9 @@ var ex; _this._keys.splice(key, 1); _this._keysUp.push(ev.keyCode); var keyEvent = new KeyEvent(ev.keyCode); - _this.eventDispatcher.publish('up', keyEvent); + // alias the old api, we may want to deprecate this in the future + _this.eventDispatcher.emit('up', keyEvent); + _this.eventDispatcher.emit('release', keyEvent); }); // key down is on window because canvas cannot have focus window.addEventListener('keydown', function (ev) { @@ -10747,7 +11275,8 @@ var ex; _this._keys.push(ev.keyCode); _this._keysDown.push(ev.keyCode); var keyEvent = new KeyEvent(ev.keyCode); - _this.eventDispatcher.publish('down', keyEvent); + _this.eventDispatcher.emit('down', keyEvent); + _this.eventDispatcher.emit('press', keyEvent); } }); }; @@ -10755,6 +11284,10 @@ var ex; // Reset keysDown and keysUp after update is complete this._keysDown.length = 0; this._keysUp.length = 0; + // Emit synthetic "hold" event + for (var i = 0; i < this._keys.length; i++) { + this.eventDispatcher.emit('hold', new KeyEvent(this._keys[i])); + } }; /** * Gets list of keys being pressed down @@ -10763,24 +11296,24 @@ var ex; return this._keys; }; /** - * Tests if a certain key is down. This is cleared at the end of the update frame. - * @param key Test wether a key is down + * Tests if a certain key was just pressed this frame. This is cleared at the end of the update frame. + * @param key Test wether a key was just pressed */ - Keyboard.prototype.isKeyDown = function (key) { + Keyboard.prototype.wasPressed = function (key) { return this._keysDown.indexOf(key) > -1; }; /** - * Tests if a certain key is pressed. This is persisted between frames. - * @param key Test wether a key is pressed + * Tests if a certain key is held down. This is persisted between frames. + * @param key Test wether a key is held down */ - Keyboard.prototype.isKeyPressed = function (key) { + Keyboard.prototype.isHeld = function (key) { return this._keys.indexOf(key) > -1; }; /** - * Tests if a certain key is up. This is cleared at the end of the update frame. - * @param key Test wether a key is up + * Tests if a certain key was just released this frame. This is cleared at the end of the update frame. + * @param key Test wether a key was just released */ - Keyboard.prototype.isKeyUp = function (key) { + Keyboard.prototype.wasReleased = function (key) { return this._keysUp.indexOf(key) > -1; }; return Keyboard; @@ -10801,11 +11334,60 @@ var ex; * You can query any [[Gamepad|Gamepads]] that are connected or listen to events ("button" and "axis"). * * You must opt-in to controller support ([[Gamepads.enabled]]) because it is a polling-based - * API, so we have to check it each update frame. + * API, so we have to check it each update frame. If an gamepad related event handler is set, you will + * automatically opt-in to controller polling. * - * Any number of gamepads are supported using the [[Gamepads.at]] method. If a [[Gamepad]] is + * HTML5 Gamepad API only supports a maximum of 4 gamepads. You can access them using the [[Gamepads.at]] method. If a [[Gamepad]] is * not connected, it will simply not throw events. * + * ## Gamepad Filtering + * + * Different browsers/devices are sometimes loose about the devices they consider Gamepads, you can set minimum device requirements with + * `engine.inpute.gamepads.setMinimumGamepadConfiguration` so that undesired devices are not reported to you (Touchpads, Mice, Web + * Cameras, etc.). + * ```js + * // ensures that only gamepads with at least 4 axis and 8 buttons are reported for events + * engine.input.gamepads.setMinimumGamepadConfiguration({ + * axis: 4, + * buttons: 8 + * }); + * ``` + * + * ## Events + * + * You can subscribe to gamepad connect and disconnect events through `engine.input.gamepads.on`. + * A [[GamepadConnectEvent]] or [[GamepadDisconnectEvent]] will be passed to you. + * + * - `connect` - When a gamepad connects it will fire this event and pass a [[GamepadConnectEvent]] with a reference to the gamepad. + * - `disconnect` - When a gamepad disconnects it will fire this event and pass a [[GamepadDisconnectEvent]] + * + * Once you have a reference to a gamepad you may listen to changes on that gamepad with `.on`. A [[GamepadButtonEvent]] or + * [[GamepadAxisEvent]] will be passed to you. + * - `button` - Whenever a button is pressed on the game + * - `axis` - Whenever an axis + * + * ```ts + * + * engine.input.gamepads.on('connect', (ce: ex.Input.GamepadConnectEvent) => { + * var newPlayer = CreateNewPlayer(); // pseudo-code for new player logic on gamepad connection + * console.log("Gamepad connected", ce); + * ce.gamepad.on('button', (be: ex.GamepadButtonEvent) => { + * if(be.button === ex.Input.Buttons.Face1) { + * newPlayer.jump(); + * } + * }); + * + * ce.gamepad.on('axis', (ae: ex.GamepadAxisEvent) => { + * if(ae.axis === ex.Input.Axis.LeftStickX && ae.value > .5){ + * newPlayer.moveRight(); + * } + * }) + * + * }); + * + * + * ``` + * * ## Responding to button input * * [[Buttons|Gamepad buttons]] typically have values between 0 and 1, however depending on @@ -10889,6 +11471,7 @@ var ex; this._pads = []; this._initSuccess = false; this._navigator = navigator; + this._minimumConfiguration = null; this._engine = engine; } Gamepads.prototype.init = function () { @@ -10905,6 +11488,55 @@ var ex; this._initSuccess = true; } }; + /** + * Sets the minimum gamepad configuration, for example {axis: 4, buttons: 4} means + * this game requires at minimum 4 axis inputs and 4 buttons, this is not restrictive + * all other controllers with more axis or buttons are valid as well. If no minimum + * configuration is set all pads are valid. + */ + Gamepads.prototype.setMinimumGamepadConfiguration = function (config) { + this._enableAndUpdate(); // if config is used, implicitely enable + this._minimumConfiguration = config; + }; + /** + * When implicitely enabled, set the enabled flag and run an update so information is updated + */ + Gamepads.prototype._enableAndUpdate = function () { + if (!this.enabled) { + this.enabled = true; + this.update(100); + } + }; + /** + * Checks a navigator gamepad against the minimum configuration if present. + */ + Gamepads.prototype._isGamepadValid = function (pad) { + if (!this._minimumConfiguration) { + return true; + } + ; + if (!pad) { + return false; + } + ; + var axesLength = pad.axes.filter(function (value, index, array) { + return (typeof value !== undefined); + }).length; + var buttonLength = pad.buttons.filter(function (value, index, array) { + return (typeof value !== undefined); + }).length; + return axesLength >= this._minimumConfiguration.axis && + buttonLength >= this._minimumConfiguration.buttons && + pad.connected; + }; + Gamepads.prototype.on = function (eventName, handler) { + this._enableAndUpdate(); // implicitly enable + _super.prototype.on.call(this, eventName, handler); + }; + Gamepads.prototype.off = function (eventName, handler) { + this._enableAndUpdate(); // implicitly enable + _super.prototype.off.call(this, eventName, handler); + }; /** * Updates Gamepad state and publishes Gamepad events */ @@ -10916,11 +11548,18 @@ var ex; var gamepads = this._navigator.getGamepads(); for (var i = 0; i < gamepads.length; i++) { if (!gamepads[i]) { + // If was connected, but now isn't emit the disconnect event + if (this.at(i).connected) { + this.eventDispatcher.emit('disconnect', new ex.GamepadDisconnectEvent(i)); + } // Reset connection status this.at(i).connected = false; continue; } else { + if (!this.at(i).connected && this._isGamepadValid(gamepads[i])) { + this.eventDispatcher.emit('connect', new ex.GamepadConnectEvent(i, this.at(i))); + } // Set connection status this.at(i).connected = true; } @@ -10930,6 +11569,8 @@ var ex; continue; } this._gamePadTimeStamps[i] = gamepads[i].timestamp; + // Add reference to navigator gamepad + this.at(i).navigatorGamepad = gamepads[i]; // Buttons var b, a, value, buttonIndex, axesIndex; for (b in Buttons) { @@ -10937,14 +11578,16 @@ var ex; continue; } buttonIndex = Buttons[b]; - value = gamepads[i].buttons[buttonIndex].value; - if (value !== this._oldPads[i].getButton(buttonIndex)) { - if (gamepads[i].buttons[buttonIndex].pressed) { - this.at(i).updateButton(buttonIndex, value); - this.at(i).eventDispatcher.publish('button', new GamepadButtonEvent(buttonIndex, value)); - } - else { - this.at(i).updateButton(buttonIndex, 0); + if (gamepads[i].buttons[buttonIndex]) { + value = gamepads[i].buttons[buttonIndex].value; + if (value !== this._oldPads[i].getButton(buttonIndex)) { + if (gamepads[i].buttons[buttonIndex].pressed) { + this.at(i).updateButton(buttonIndex, value); + this.at(i).eventDispatcher.publish('button', new ex.GamepadButtonEvent(buttonIndex, value)); + } + else { + this.at(i).updateButton(buttonIndex, 0); + } } } } @@ -10957,7 +11600,7 @@ var ex; value = gamepads[i].axes[axesIndex]; if (value !== this._oldPads[i].getAxes(axesIndex)) { this.at(i).updateAxes(axesIndex, value); - this.at(i).eventDispatcher.publish('axis', new GamepadAxisEvent(axesIndex, value)); + this.at(i).eventDispatcher.emit('axis', new ex.GamepadAxisEvent(axesIndex, value)); } } this._oldPads[i] = this._clonePad(gamepads[i]); @@ -10967,6 +11610,7 @@ var ex; * Safely retrieves a Gamepad at a specific index and creates one if it doesn't yet exist */ Gamepads.prototype.at = function (index) { + this._enableAndUpdate(); // implicitly enable gamepads when at() is called if (index >= this._pads.length) { // Ensure there is a pad to retrieve for (var i = this._pads.length - 1, max = index; i < max; i++) { @@ -10976,6 +11620,19 @@ var ex; } return this._pads[index]; }; + /** + * Returns a list of all valid gamepads that meet the minimum configuration requirment. + */ + Gamepads.prototype.getValidGamepads = function () { + this._enableAndUpdate(); + var result = []; + for (var i = 0; i < this._pads.length; i++) { + if (this._isGamepadValid(this.at(i).navigatorGamepad) && this.at(i).connected) { + result.push(this.at(i)); + } + } + return result; + }; /** * Gets the number of connected gamepads */ @@ -10999,7 +11656,9 @@ var ex; return clonedPad; } for (i = 0, len = pad.buttons.length; i < len; i++) { - clonedPad.updateButton(i, pad.buttons[i].value); + if (pad.buttons[i]) { + clonedPad.updateButton(i, pad.buttons[i].value); + } } for (i = 0, len = pad.axes.length; i < len; i++) { clonedPad.updateAxes(i, pad.axes[i]); @@ -11161,40 +11820,6 @@ var ex; Axes[Axes["RightStickY"] = 3] = "RightStickY"; })(Input.Axes || (Input.Axes = {})); var Axes = Input.Axes; - /** - * Gamepad button event. See [[Gamepads]] for information on responding to controller input. - */ - var GamepadButtonEvent = (function (_super) { - __extends(GamepadButtonEvent, _super); - /** - * @param button The Gamepad button - * @param value A numeric value between 0 and 1 - */ - function GamepadButtonEvent(button, value) { - _super.call(this); - this.button = button; - this.value = value; - } - return GamepadButtonEvent; - })(ex.GameEvent); - Input.GamepadButtonEvent = GamepadButtonEvent; - /** - * Gamepad axis event. See [[Gamepads]] for information on responding to controller input. - */ - var GamepadAxisEvent = (function (_super) { - __extends(GamepadAxisEvent, _super); - /** - * @param axis The Gamepad axis - * @param value A numeric value between -1 and 1 - */ - function GamepadAxisEvent(axis, value) { - _super.call(this); - this.axis = axis; - this.value = value; - } - return GamepadAxisEvent; - })(ex.GameEvent); - Input.GamepadAxisEvent = GamepadAxisEvent; })(Input = ex.Input || (ex.Input = {})); })(ex || (ex = {})); /// @@ -11239,7 +11864,7 @@ var ex; * * ## Where to Start * - * These are the core concepts of Excalibur that you should be + * These are the core concepts of Excalibur that you should become * familiar with. * * - [[Engine|Intro to the Engine]] @@ -11278,6 +11903,7 @@ var ex; * - [[Sound|Working with Sounds]] * - [[SpriteSheet|Working with SpriteSheets]] * - [[Animation|Working with Animations]] + * - [[TileMap|Working with TileMaps]] * * ## Effects and Particles * @@ -11286,6 +11912,7 @@ var ex; * * - [[Effects|Sprite Effects]] * - [[ParticleEmitter|Particle Emitters]] + * - [[IPostProcessor|Post Processors]] * * ## Math * @@ -11341,9 +11968,11 @@ var ex; * * The Excalibur engine uses a simple main loop. The engine updates and renders * the "scene graph" which is the [[Scene|scenes]] and the tree of [[Actor|actors]] within that - * scene. Only one [[Scene]] can be active at once, the engine does not update/draw any other + * scene. Only one [[Scene]] can be active at a time. The engine does not update/draw any other * scene, which means any actors will not be updated/drawn if they are part of a deactivated scene. * + * ![Engine Lifecycle](/assets/images/docs/EngineLifeCycle.png) + * * **Scene Graph** * * ``` @@ -11362,13 +11991,13 @@ var ex; * * ### Update Loop * - * The first operation run is the [[Engine.update|update]] loop. [[Actor]] and [[Scene]] both implement + * The first operation run is the [[Engine._update|update]] loop. [[Actor]] and [[Scene]] both implement * an overridable/extendable `update` method. Use it to perform any logic-based operations * in your game for a particular class. * * ### Draw Loop * - * The next step is the [[Engine.draw|draw]] loop. A [[Scene]] loops through its child [[Actor|actors]] and + * The next step is the [[Engine._draw|draw]] loop. A [[Scene]] loops through its child [[Actor|actors]] and * draws each one. You can override the `draw` method on an actor to customize its drawing. * You should **not** perform any logic in a draw call, it should only relate to drawing. * @@ -11615,6 +12244,8 @@ var ex; * the [[currentScene]] may be drawn or updated. * * @param actor The actor to add to the [[currentScene]] + * + * @obsolete Use [[add]] instead. */ Engine.prototype.addChild = function (actor) { this.currentScene.addChild(actor); @@ -11741,17 +12372,17 @@ var ex; // only deactivate when initialized if (this.currentScene.isInitialized) { this.currentScene.onDeactivate.call(this.currentScene); - this.currentScene.eventDispatcher.publish('deactivate', new ex.DeactivateEvent(newScene)); + this.currentScene.eventDispatcher.emit('deactivate', new ex.DeactivateEvent(newScene)); } // set current scene to new one this.currentScene = newScene; if (!this.currentScene.isInitialized) { this.currentScene.onInitialize.call(this.currentScene, this); - this.currentScene.eventDispatcher.publish('initialize', new ex.InitializeEvent(this)); + this.currentScene.eventDispatcher.emit('initialize', new ex.InitializeEvent(this)); this.currentScene.isInitialized = true; } this.currentScene.onActivate.call(this.currentScene); - this.currentScene.eventDispatcher.publish('activate', new ex.ActivateEvent(oldScene)); + this.currentScene.eventDispatcher.emit('activate', new ex.ActivateEvent(oldScene)); } else { this._logger.error('Scene', key, 'does not exist!'); @@ -11861,11 +12492,11 @@ var ex; // https://developer.mozilla.org/en-US/docs/Web/Guide/User_experience/Using_the_Page_Visibility_API document.addEventListener('visibilitychange', function () { if (document.hidden || document.msHidden) { - _this.eventDispatcher.publish('hidden', new ex.HiddenEvent()); + _this.eventDispatcher.emit('hidden', new ex.HiddenEvent()); _this._logger.debug('Window hidden'); } else { - _this.eventDispatcher.publish('visible', new ex.VisibleEvent()); + _this.eventDispatcher.emit('visible', new ex.VisibleEvent()); _this._logger.debug('Window visible'); } }); @@ -11914,6 +12545,7 @@ var ex; // suspend updates untill loading is finished return; } + this.emit('preupdate', new ex.PreUpdateEvent(this, delta, this)); // process engine level events this.currentScene.update(this, delta); // update animations @@ -11925,7 +12557,8 @@ var ex; this.input.pointers.update(delta); this.input.gamepads.update(delta); // Publish update event - this.eventDispatcher.publish(ex.EventType[ex.EventType.Update], new ex.UpdateEvent(delta)); + this.eventDispatcher.emit('update', new ex.UpdateEvent(delta)); + this.emit('postupdate', new ex.PreUpdateEvent(this, delta, this)); }; /** * Draws the entire game @@ -11933,6 +12566,7 @@ var ex; */ Engine.prototype._draw = function (delta) { var ctx = this.ctx; + this.emit('predraw', new ex.PreDrawEvent(ctx, delta, this)); if (this._isLoading) { ctx.fillStyle = 'black'; ctx.fillRect(0, 0, this.width, this.height); @@ -11964,7 +12598,7 @@ var ex; for (var i = 0; i < this.postProcessors.length; i++) { this.postProcessors[i].process(this.ctx.getImageData(0, 0, this.width, this.height), this.ctx); } - //ctx.drawImage(currentImage, 0, 0, this.width, this.height); + this.emit('postdraw', new ex.PreDrawEvent(ctx, delta, this)); }; /** * Starts the internal game loop for Excalibur after loading @@ -12143,7 +12777,7 @@ var ex; return AnimationNode; })(); })(ex || (ex = {})); -//# sourceMappingURL=excalibur-0.5.1.js.map +//# sourceMappingURL=excalibur-0.6.0.js.map ; // Concatenated onto excalibur after build // Exports the excalibur module so it can be used with browserify diff --git a/dist/Excalibur.min.js b/dist/Excalibur.min.js index 3113751bd..dba61a9b9 100644 --- a/dist/Excalibur.min.js +++ b/dist/Excalibur.min.js @@ -1,12 +1,12 @@ -/*! excalibur - v0.5.1 - 2015-09-14 +/*! excalibur - v0.6.0 - 2016-01-19 * https://github.com/excaliburjs/Excalibur -* Copyright (c) 2015 ; Licensed BSD-2-Clause*/ -"undefined"==typeof window&&(window={audioContext:function(){}}),"undefined"==typeof window||window.requestAnimationFrame||(window.requestAnimationFrame=window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||function(t){window.setInterval(t,1e3/60)}),"undefined"==typeof window||window.cancelAnimationFrame||(window.cancelAnimationFrame=window.webkitCancelAnimationFrame||window.mozCancelAnimationFrame||function(){}),"undefined"==typeof window||window.AudioContext||(window.AudioContext=window.AudioContext||window.webkitAudioContext||window.mozAudioContext||window.msAudioContext||window.oAudioContext),Array.prototype.forEach||(Array.prototype.forEach=function(t,e){var i,n;if(null==this)throw new TypeError(" this is null or not defined");var s=Object(this),o=s.length>>>0;if("function"!=typeof t)throw new TypeError(t+" is not a function");for(arguments.length>1&&(i=e),n=0;o>n;){var r;n in s&&(r=s[n],t.call(i,r,n,s)),n++}}),Array.prototype.some||(Array.prototype.some=function(t){"use strict";if(void 0===this||null===this)throw new TypeError;var e=Object(this),i=e.length>>>0;if("function"!=typeof t)throw new TypeError;for(var n=arguments.length>=2?arguments[1]:void 0,s=0;i>s;s++)if(s in e&&t.call(n,e[s],s,e))return!0;return!1}),Function.prototype.bind||(Function.prototype.bind=function(t){if("function"!=typeof this)throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");var e=Array.prototype.slice.call(arguments,1),i=this,n=function(){},s=function(){return i.apply(this instanceof n&&t?this:t,e.concat(Array.prototype.slice.call(arguments)))};return n.prototype=this.prototype,s.prototype=new n,s});var ex;(function(t){var e;(function(e){var i=function(){function t(){}return t.prototype.updatePixel=function(t,e,i){var n=4*(t+e*i.width),s=i.data,o=(s[n+0]+s[n+1]+s[n+2])/3;s[n+0]=o,s[n+1]=o,s[n+2]=o},t}();e.Grayscale=i;var n=function(){function t(){}return t.prototype.updatePixel=function(t,e,i){var n=4*(t+e*i.width),s=i.data;s[n+0]=255-s[n+0],s[n+1]=255-s[n+1],s[n+2]=255-s[n+2]},t}();e.Invert=n;var s=function(){function t(t){this.opacity=t}return t.prototype.updatePixel=function(t,e,i){var n=4*(t+e*i.width),s=i.data;0!==s[n+3]&&(s[n+3]=Math.round(255*this.opacity))},t}();e.Opacity=s;var o=function(){function t(t){this.color=t}return t.prototype.updatePixel=function(t,e,i){var n=4*(t+e*i.width),s=i.data;0!==s[n+3]&&(s[n+0]=(s[n+0]+this.color.r)/2,s[n+1]=(s[n+1]+this.color.g)/2,s[n+2]=(s[n+2]+this.color.b)/2)},t}();e.Colorize=o;var r=function(){function e(t){void 0===t&&(t=.1),this.factor=t}return e.prototype.updatePixel=function(e,i,n){var s=4*(e+i*n.width),o=n.data,r=t.Color.fromRGB(o[s+0],o[s+1],o[s+2],o[s+3]).lighten(this.factor);o[s+0]=r.r,o[s+1]=r.g,o[s+2]=r.b,o[s+3]=r.a},e}();e.Lighten=r;var h=function(){function e(t){void 0===t&&(t=.1),this.factor=t}return e.prototype.updatePixel=function(e,i,n){var s=4*(e+i*n.width),o=n.data,r=t.Color.fromRGB(o[s+0],o[s+1],o[s+2],o[s+3]).darken(this.factor);o[s+0]=r.r,o[s+1]=r.g,o[s+2]=r.b,o[s+3]=r.a},e}();e.Darken=h;var a=function(){function e(t){void 0===t&&(t=.1),this.factor=t}return e.prototype.updatePixel=function(e,i,n){var s=4*(e+i*n.width),o=n.data,r=t.Color.fromRGB(o[s+0],o[s+1],o[s+2],o[s+3]).saturate(this.factor);o[s+0]=r.r,o[s+1]=r.g,o[s+2]=r.b,o[s+3]=r.a},e}();e.Saturate=a;var c=function(){function e(t){void 0===t&&(t=.1),this.factor=t}return e.prototype.updatePixel=function(e,i,n){var s=4*(e+i*n.width),o=n.data,r=t.Color.fromRGB(o[s+0],o[s+1],o[s+2],o[s+3]).desaturate(this.factor);o[s+0]=r.r,o[s+1]=r.g,o[s+2]=r.b,o[s+3]=r.a},e}();e.Desaturate=c;var u=function(){function t(t){this.color=t}return t.prototype.updatePixel=function(t,e,i){var n=4*(t+e*i.width),s=i.data;0!==s[n+3]&&(s[n+0]=this.color.r,s[n+1]=this.color.g,s[n+2]=this.color.b)},t}();e.Fill=u})(e=t.Effects||(t.Effects={}))})(ex||(ex={}));var ex;(function(t){var e;(function(t){var e=function(){function t(){}return t.prototype.update=function(t,e,i){t.x+=t.dx*i/1e3,t.y+=t.dy*i/1e3,t.dx+=t.ax*i/1e3,t.dy+=t.ay*i/1e3,t.rotation+=t.rx*i/1e3,t.scale.x+=t.sx*i/1e3,t.scale.y+=t.sy*i/1e3},t}();t.Movement=e})(e=t.Traits||(t.Traits={}))})(ex||(ex={}));var ex;(function(t){var e=function(){function e(){this._topLeft=new t.Point(0,0),this._topRight=new t.Point(0,0),this._bottomLeft=new t.Point(0,0),this._bottomRight=new t.Point(0,0)}return e.prototype.isSpriteOffScreen=function(e,i){var n=e.currentDrawing.width*e.currentDrawing.scale.x,s=e.currentDrawing.height*e.currentDrawing.scale.y,o=e.rotation,r=e.getCenter().toPoint();this._topLeft.x=e.getWorldX()-n/2,this._topLeft.y=e.getWorldY()-s/2,this._topLeft=this._topLeft.rotate(o,r),this._topRight.x=e.getWorldX()+n/2,this._topRight.y=e.getWorldY()-s/2,this._topRight=this._topRight.rotate(o,r),this._bottomLeft.x=e.getWorldX()-n/2,this._bottomLeft.y=e.getWorldY()+s/2,this._bottomLeft=this._bottomLeft.rotate(o,r),this._bottomRight.x=e.getWorldX()+n/2,this._bottomRight.y=e.getWorldY()+s/2,this._bottomRight=this._bottomRight.rotate(o,r);var h=i.worldToScreenCoordinates(this._topLeft),a=i.worldToScreenCoordinates(this._topRight),c=i.worldToScreenCoordinates(this._bottomLeft),u=i.worldToScreenCoordinates(this._bottomRight);this._xCoords=[],this._yCoords=[],this._xCoords.push(h.x,a.x,c.x,u.x),this._yCoords.push(h.y,a.y,c.y,u.y),this._xMin=Math.min.apply(null,this._xCoords),this._yMin=Math.min.apply(null,this._yCoords),this._xMax=Math.max.apply(null,this._xCoords),this._yMax=Math.max.apply(null,this._yCoords);var l=i.screenToWorldCoordinates(new t.Point(this._xMin,this._yMin)),p=i.screenToWorldCoordinates(new t.Point(this._xMax,this._yMax));this._xMinWorld=l.x,this._yMinWorld=l.y,this._xMaxWorld=p.x,this._yMaxWorld=p.y;var d=[];d.push(new t.Point(this._xMin,this._yMin),new t.Point(this._xMax,this._yMin),new t.Point(this._xMin,this._yMax),new t.Point(this._xMax,this._yMax));for(var f=0;d.length>f;f++)if(d[f].x>0&&d[f].y>0&&d[f].x0&&a.y+h*c>0&&a.xa.x+r*c||0>a.y+h*c||a.x>i.width||a.y>i.height)&&u&&(n.publish("exitviewport",new t.ExitViewPortEvent),e.isOffScreen=!0)},e}();e.OffscreenCulling=i})(e=t.Traits||(t.Traits={}))})(ex||(ex={}));var ex;(function(t){var e;(function(t){var e=function(){function t(){}return t.prototype.update=function(t,e){t.enableCapturePointer&&(t.isKilled()||e.input.pointers.propogate(t))},t}();t.CapturePointer=e})(e=t.Traits||(t.Traits={}))})(ex||(ex={}));var ex;(function(t){var e;(function(e){var i=function(){function e(){}return e.prototype.update=function(e,i){var n=e.eventDispatcher;if(e.collisionType!==t.CollisionType.PreventCollision)for(var s=0;i.currentScene.tileMaps.length>s;s++)for(var o,r=i.currentScene.tileMaps[s],h=t.Side.None,a=2,c=!1;(o=r.collides(e))&&!(0>a--);)h=e.getSideFromIntersect(o),n.publish("collision",new t.CollisionEvent(e,null,h,o)),(e.collisionType===t.CollisionType.Active||e.collisionType===t.CollisionType.Elastic)&&(e.y+=o.y,e.x+=o.x,e.collisionType!==t.CollisionType.Elastic||c||(c=!0,h===t.Side.Left?e.dx=Math.abs(e.dx):h===t.Side.Right?e.dx=-Math.abs(e.dx):h===t.Side.Top?e.dy=Math.abs(e.dy):h===t.Side.Bottom&&(e.dy=-Math.abs(e.dy))))},e}();e.CollisionDetection=i})(e=t.Traits||(t.Traits={}))})(ex||(ex={}));var ex;(function(t){(function(t){t[t.None=0]="None",t[t.Top=1]="Top",t[t.Bottom=2]="Bottom",t[t.Left=3]="Left",t[t.Right=4]="Right"})(t.Side||(t.Side={})),t.Side})(ex||(ex={}));var __extends=this&&this.__extends||function(t,e){function i(){this.constructor=t}for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n]);i.prototype=e.prototype,t.prototype=new i},ex;(function(t){var e=function(){function e(t,e){this.x=t,this.y=e}return e.prototype.toVector=function(){return new i(this.x,this.y)},e.prototype.rotate=function(i,n){n||(n=new t.Point(0,0));var s=Math.sin(i),o=Math.cos(i),r=o*(this.x-n.x)-s*(this.y-n.y)+n.x,h=s*(this.x-n.x)+o*(this.y-n.y)+n.y;return new e(r,h)},e.prototype.add=function(t){return new e(this.x+t.x,this.y+t.y)},e.prototype.setTo=function(t,e){this.x=t,this.y=e},e.prototype.clone=function(){return new e(this.x,this.y)},e.prototype.equals=function(t){return this.x===t.x&&this.y===t.y},e}();t.Point=e;var i=function(t){function i(e,i){t.call(this,e,i),this.x=e,this.y=i}return __extends(i,t),i.fromAngle=function(t){return new i(Math.cos(t),Math.sin(t))},i.prototype.distance=function(t){return t||(t=new i(0,0)),Math.sqrt(Math.pow(this.x-t.x,2)+Math.pow(this.y-t.y,2))},i.prototype.normalize=function(){var t=this.distance();return t>0?new i(this.x/t,this.y/t):new i(0,1)},i.prototype.scale=function(t){return new i(this.x*t,this.y*t)},i.prototype.plus=function(t){return this.add(t)},i.prototype.add=function(t){return new i(this.x+t.x,this.y+t.y)},i.prototype.subtract=function(t){return this.minus(t)},i.prototype.minus=function(t){return new i(this.x-t.x,this.y-t.y)},i.prototype.dot=function(t){return this.x*t.x+this.y*t.y},i.prototype.cross=function(t){return this.x*t.y-this.y*t.x},i.prototype.perpendicular=function(){return new i(this.y,-this.x)},i.prototype.normal=function(){return this.perpendicular().normalize()},i.prototype.toAngle=function(){return Math.atan2(this.y,this.x)},i.prototype.toPoint=function(){return new e(this.x,this.y)},i.prototype.rotate=function(e,i){return t.prototype.rotate.call(this,e,i).toVector()},i.prototype.clone=function(){return new i(this.x,this.y)},i.Zero=new i(0,0),i}(e);t.Vector=i;var n=function(){function t(t,e){this.pos=t,this.dir=e.normalize()}return t.prototype.intersect=function(t){var e=t.begin.toVector().minus(this.pos.toVector());if(0===this.dir.cross(t.getSlope())&&0!==e.cross(this.dir))return-1;var i=this.dir.cross(t.getSlope());if(0===i)return-1;var n=e.cross(t.getSlope())/i;if(n>=0){var s=e.cross(this.dir)/i/t.getLength();if(s>=0&&1>=s)return n}return-1},t.prototype.getPoint=function(t){return this.pos.toVector().add(this.dir.scale(t)).toPoint()},t}();t.Ray=n;var s=function(){function t(t,e){this.begin=t,this.end=e}return t.prototype.getSlope=function(){var t=this.begin.toVector(),e=this.end.toVector(),i=t.distance(e);return e.minus(t).scale(1/i)},t.prototype.getLength=function(){var t=this.begin.toVector(),e=this.end.toVector(),i=t.distance(e);return i},t}();t.Line=s;var o=function(){function t(t,e){this.min=t,this.max=e}return t.prototype.overlaps=function(t){return this.max>t.min&&t.max>this.min},t.prototype.getOverlap=function(t){return this.overlaps(t)?this.max>t.max?t.max-this.min:this.max-t.min:0},t}();t.Projection=o})(ex||(ex={}));var ex;(function(t){var e;(function(e){function i(t){for(var e="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",i="",n=0;t.length>n;){var s,o,r=255&t.charCodeAt(n++),h=255&t.charCodeAt(n++),a=255&t.charCodeAt(n++),c=r>>2,u=(3&r)<<4|h>>4;isNaN(h)?s=o=64:(s=(15&h)<<2|a>>6,o=isNaN(a)?64:63&a),i+=e.charAt(c)+e.charAt(u)+e.charAt(s)+e.charAt(o)}return i}function n(t,e,i){return e>=t?e:t>=i?i:t}function s(t,e,i,n,s,o){t.beginPath(),t.strokeStyle=e,t.moveTo(i,n),t.lineTo(s,o),t.closePath(),t.stroke()}function o(t,e){return t+Math.random()*(e-t)}function r(t,e){return Math.round(o(t,e))}function h(t){var e=t;if(t>this.TwoPI)for(;e>this.TwoPI;)e-=this.TwoPI;if(0>t)for(;0>e;)e+=this.TwoPI;return e}function a(t){return 180/Math.PI*t}function c(t){return t/180*Math.PI}function u(e){var i=0,n=0,s=function(t){i+=t.offsetLeft,t.offsetParent&&s(t.offsetParent)},o=function(t){n+=t.offsetTop,t.offsetParent&&o(t.offsetParent)};return s(e),o(e),new t.Point(i,n)}function l(t,e){return-1===e.indexOf(t)?(e.push(t),!0):!1}function p(t,e){var i=-1;return(i=e.indexOf(t))>-1?(e.splice(i,1),!0):!1}function d(e){return e===t.Side.Top?t.Side.Bottom:e===t.Side.Bottom?t.Side.Top:e===t.Side.Left?t.Side.Right:e===t.Side.Right?t.Side.Left:t.Side.None}e.TwoPI=2*Math.PI,e.base64Encode=i,e.clamp=n,e.drawLine=s,e.randomInRange=o,e.randomIntInRange=r,e.canonicalizeAngle=h,e.toDegrees=a,e.toRadians=c,e.getPosition=u,e.addItemToArray=l,e.removeItemToArray=p,e.getOppositeSide=d;var f=function(){function t(e){void 0===e&&(e=t.DefaultSize),this._internalArray=null,this._endPointer=0,this._internalArray=Array(e)}return t.prototype._resize=function(){for(var t=2*this._internalArray.length,e=Array(t),i=this.count(),n=0;i>n;n++)e[n]=this._internalArray[n];delete this._internalArray,this._internalArray=e},t.prototype.push=function(t){return this._endPointer===this._internalArray.length&&this._resize(),this._internalArray[this._endPointer++]=t},t.prototype.pop=function(){return this._endPointer=0>this._endPointer-1?0:this._endPointer-1,this._internalArray[this._endPointer]},t.prototype.count=function(){return this._endPointer},t.prototype.clear=function(){this._endPointer=0},t.prototype.internalSize=function(){return this._internalArray.length},t.prototype.elementAt=function(t){return t>=this.count()?void 0:this._internalArray[t]},t.prototype.insert=function(t,e){return t>=this.count()&&this._resize(),this._internalArray[t]=e},t.prototype.remove=function(t){var e=this.count();if(0!==e){for(var i=this._internalArray[t],n=t;e>n;n++)this._internalArray[n]=this._internalArray[n+1];return this._endPointer--,i}},t.prototype.removeElement=function(t){var e=this._internalArray.indexOf(t);this.remove(e)},t.prototype.toArray=function(){return this._internalArray.slice(0,this._endPointer)},t.prototype.forEach=function(t){var e=0,i=this.count();for(e;i>e;e++)t.call(this,this._internalArray[e],e)},t.prototype.map=function(t){for(var e=this.count(),i=0;e>i;i++)this._internalArray[i]=t.call(this,this._internalArray[i],i)},t.DefaultSize=200,t}();e.Collection=f})(e=t.Util||(t.Util={}))})(ex||(ex={}));var ex;(function(t){var e=function(){function e(e,i,n,s,o){var r=this;this.sx=i,this.sy=n,this.swidth=s,this.sheight=o,this.rotation=0,this.anchor=new t.Point(0,0),this.scale=new t.Point(1,1),this.logger=t.Logger.getInstance(),this.flipVertical=!1,this.flipHorizontal=!1,this.width=0,this.height=0,this.effects=[],this.internalImage=new Image,this.naturalWidth=0,this.naturalHeight=0,this._spriteCanvas=null,this._spriteCtx=null,this._pixelData=null,this._pixelsLoaded=!1,this._dirtyEffect=!1,(0>i||0>n||0>s||0>o)&&this.logger.error("Sprite cannot have any negative dimensions x:",i,"y:",n,"width:",s,"height:",o),this._texture=e,this._spriteCanvas=document.createElement("canvas"),this._spriteCanvas.width=s,this._spriteCanvas.height=o,this._spriteCtx=this._spriteCanvas.getContext("2d"),this._texture.loaded.then(function(){r._spriteCanvas.width=r._spriteCanvas.width||r._texture.image.naturalWidth,r._spriteCanvas.height=r._spriteCanvas.height||r._texture.image.naturalHeight,r._loadPixels(),r._dirtyEffect=!0}).error(function(t){r.logger.error("Error loading texture ",r._texture.path,t)}),this.width=s,this.height=o,this.naturalWidth=s,this.naturalHeight=o}return e.prototype._loadPixels=function(){if(this._texture.isLoaded()&&!this._pixelsLoaded){var e=t.Util.clamp,i=this._texture.image.naturalWidth||0,n=this._texture.image.naturalHeight||0;this.swidth>i&&this.logger.warn("The sprite width",this.swidth,"exceeds the width",i,"of the backing texture",this._texture.path),this.sheight>n&&this.logger.warn("The sprite height",this.sheight,"exceeds the height",n,"of the backing texture",this._texture.path),this._spriteCtx.drawImage(this._texture.image,e(this.sx,0,i),e(this.sy,0,n),e(this.swidth,0,i),e(this.sheight,0,n),0,0,this.swidth,this.sheight),this.internalImage.src=this._spriteCanvas.toDataURL("image/png"),this._pixelsLoaded=!0}},e.prototype.opacity=function(e){this.addEffect(new t.Effects.Opacity(e))},e.prototype.grayscale=function(){this.addEffect(new t.Effects.Grayscale)},e.prototype.invert=function(){this.addEffect(new t.Effects.Invert)},e.prototype.fill=function(e){this.addEffect(new t.Effects.Fill(e))},e.prototype.colorize=function(e){this.addEffect(new t.Effects.Colorize(e))},e.prototype.lighten=function(e){void 0===e&&(e=.1),this.addEffect(new t.Effects.Lighten(e))},e.prototype.darken=function(e){void 0===e&&(e=.1),this.addEffect(new t.Effects.Darken(e))},e.prototype.saturate=function(e){void 0===e&&(e=.1),this.addEffect(new t.Effects.Saturate(e))},e.prototype.desaturate=function(e){void 0===e&&(e=.1),this.addEffect(new t.Effects.Desaturate(e))},e.prototype.addEffect=function(t){this.effects.push(t),this._texture.isLoaded()&&this._pixelsLoaded?this._applyEffects():this._dirtyEffect=!0},e.prototype.removeEffect=function(t){var e=null;e="number"==typeof t?t:this.effects.indexOf(t),this.effects.splice(e,1),this._texture.isLoaded()&&this._pixelsLoaded?this._applyEffects():this._dirtyEffect=!0},e.prototype._applyEffects=function(){var e=t.Util.clamp,i=this._texture.image.naturalWidth||0,n=this._texture.image.naturalHeight||0;this._spriteCtx.clearRect(0,0,this.swidth,this.sheight),this._spriteCtx.drawImage(this._texture.image,e(this.sx,0,i),e(this.sy,0,n),e(this.swidth,0,i),e(this.sheight,0,n),0,0,this.swidth,this.sheight),this._pixelData=this._spriteCtx.getImageData(0,0,this.swidth,this.sheight);var s=0,o=0,r=0,h=this.effects.length;for(s;h>s;s++)for(r=0;this.sheight>r;r++)for(o=0;this.swidth>o;o++)this.effects[s].updatePixel(o,r,this._pixelData);this._spriteCtx.clearRect(0,0,this.swidth,this.sheight),this._spriteCtx.putImageData(this._pixelData,0,0),this.internalImage.src=this._spriteCanvas.toDataURL("image/png")},e.prototype.clearEffects=function(){this.effects.length=0,this._applyEffects()},e.prototype.reset=function(){},e.prototype.debugDraw=function(e,i,n){e.save(),e.translate(i,n),e.rotate(this.rotation);var s=this.width*this.scale.x*this.anchor.x,o=this.height*this.scale.y*this.anchor.y;e.strokeStyle=t.Color.Black,e.strokeRect(-s,-o,this.width*this.scale.x,this.height*this.scale.y),e.restore()},e.prototype.draw=function(t,e,i){this._dirtyEffect&&(this._applyEffects(),this._dirtyEffect=!1),this.width=this.naturalWidth*this.scale.x,this.height=this.naturalHeight*this.scale.y,t.save();var n=this.width*this.anchor.x,s=this.height*this.anchor.y;t.translate(e,i),t.rotate(this.rotation),this.flipHorizontal&&(t.translate(this.swidth*this.scale.x,0),t.scale(-1,1)),this.flipVertical&&(t.translate(0,this.sheight*this.scale.y),t.scale(1,-1)),this.internalImage&&t.drawImage(this.internalImage,0,0,this.swidth,this.sheight,-n,-s,this.swidth*this.scale.x,this.sheight*this.scale.y),t.restore()},e.prototype.clone=function(){var t=new e(this._texture,this.sx,this.sy,this.swidth,this.sheight);t.scale=this.scale.clone(),t.rotation=this.rotation,t.flipHorizontal=this.flipHorizontal,t.flipVertical=this.flipVertical;var i=0,n=this.effects.length;for(i;n>i;i++)t.addEffect(this.effects[i]);return t},e}();t.Sprite=e})(ex||(ex={}));var ex;(function(t){var e=function(){function e(e,i,n,s,o){this.image=e,this.columns=i,this.rows=n,this.sprites=[],this._internalImage=e.image,this.sprites=Array(i*n);var r=0,h=0;for(r=0;n>r;r++)for(h=0;i>h;h++)this.sprites[h+r*i]=new t.Sprite(this.image,h*s,r*o,s,o)}return e.prototype.getAnimationByIndices=function(e,i,n){var s=this,o=i.map(function(t){return s.sprites[t]});return o=o.map(function(t){return t.clone()}),new t.Animation(e,o,n)},e.prototype.getAnimationBetween=function(e,i,n,s){var o=this.sprites.slice(i,n);return o=o.map(function(t){return t.clone()}),new t.Animation(e,o,s)},e.prototype.getAnimationForAll=function(e,i){var n=this.sprites.map(function(t){return t.clone()});return new t.Animation(e,n,i)},e.prototype.getSprite=function(t){return t>=0&&this.sprites.length>t?this.sprites[t]:void 0},e}();t.SpriteSheet=e;var i=function(e){function i(i,n,s,o,r,h,a){e.call(this,i,o,r,h,a),this.image=i,this.alphabet=n,this.caseInsensitive=s,this._spriteLookup={},this._colorLookup={},this._currentColor=t.Color.Black}return __extends(i,e),i.prototype.getTextSprites=function(){for(var t={},e=0;this.alphabet.length>e;e++){var i=this.alphabet[e];this.caseInsensitive&&(i=i.toLowerCase()),t[i]=this.sprites[e].clone()}return t},i}(e);t.SpriteFont=i})(ex||(ex={}));var ex;(function(t){var e=function(){function e(e,i,s,o,r,h){var a=this;this.x=e,this.y=i,this.cellWidth=s,this.cellHeight=o,this.rows=r,this.cols=h,this._collidingX=-1,this._collidingY=-1,this._onScreenXStart=0,this._onScreenXEnd=9999,this._onScreenYStart=0,this._onScreenYEnd=9999,this._spriteSheets={},this.logger=t.Logger.getInstance(),this.data=[],this.data=Array(r*h);for(var c=0;h>c;c++)for(var u=0;r>u;u++)(function(){var t=new n(c*s+e,u*o+i,s,o,c+u*h);a.data[c+u*h]=t})()}return e.prototype.registerSpriteSheet=function(t,e){this._spriteSheets[t]=e},e.prototype.collides=function(e){for(var i=e.x+e.getWidth(),n=e.y+e.getHeight(),s=e.getBounds(),o=[],r=s.left;i>=r;r+=Math.min(e.getWidth()/2,this.cellWidth/2))for(var h=s.top;n>=h;h+=Math.min(e.getHeight()/2,this.cellHeight/2)){var a=this.getCellByPoint(r,h);if(a&&a.solid){var c=s.collides(a.getBounds()),u=e.getCenter().minus(a.getCenter());c&&c.dot(u)>0&&o.push(c)}}if(0===o.length)return null;var l=o.reduce(function(e,i){var n=e.x,s=e.y;return Math.abs(e.x)t||0>e||t>=this.cols||e>=this.rows?null:this.data[t+e*this.cols]},e.prototype.getCellByPoint=function(t,e){t=Math.floor((t-this.x)/this.cellWidth),e=Math.floor((e-this.y)/this.cellHeight);var i=this.getCell(t,e);return t>=0&&e>=0&&this.cols>t&&this.rows>e&&i?i:null},e.prototype.update=function(e){var i=e.screenToWorldCoordinates(new t.Point(0,0)),n=e.screenToWorldCoordinates(new t.Point(e.canvas.clientWidth,e.canvas.clientHeight));this._onScreenXStart=Math.max(Math.floor(i.x/this.cellWidth)-2,0),this._onScreenYStart=Math.max(Math.floor((i.y-this.y)/this.cellHeight)-2,0),this._onScreenXEnd=Math.max(Math.floor(n.x/this.cellWidth)+2,0),this._onScreenYEnd=Math.max(Math.floor((n.y-this.y)/this.cellHeight)+2,0)},e.prototype.draw=function(t){t.save(),t.translate(this.x,this.y);var e,i,n,s=this._onScreenXStart,o=Math.min(this._onScreenXEnd,this.cols),r=this._onScreenYStart,h=Math.min(this._onScreenYEnd,this.rows);for(s;o>s;s++){for(r;h>r;r++)for(e=this.getCell(s,r).sprites.filter(function(t){return t.spriteId>-1}),i=0,n=e.length;n>i;i++){var a=this._spriteSheets[e[i].spriteSheetKey];if(a){var c=a.getSprite(e[i].spriteId);c?c.draw(t,s*this.cellWidth,r*this.cellHeight):this.logger.warn("Sprite does not exist for id",e[i].spriteId,"in sprite sheet",e[i].spriteSheetKey,c,a)}else this.logger.warn("Sprite sheet",e[i].spriteSheetKey,"does not exist",a)}r=this._onScreenYStart}t.restore()},e.prototype.debugDraw=function(e){var i=this.cols*this.cellWidth,n=this.rows*this.cellHeight;e.save(),e.strokeStyle=""+t.Color.Red;for(var s=0;this.cols+1>s;s++)e.beginPath(),e.moveTo(this.x+s*this.cellWidth,this.y),e.lineTo(this.x+s*this.cellWidth,this.y+n),e.stroke();for(var o=0;this.rows+1>o;o++)e.beginPath(),e.moveTo(this.x,this.y+o*this.cellHeight),e.lineTo(this.x+i,this.y+o*this.cellHeight),e.stroke();var r=t.Color.Red.clone();r.a=.3,this.data.filter(function(t){return t.solid}).forEach(function(t){e.fillStyle=""+r,e.fillRect(t.x,t.y,t.width,t.height)}),this._collidingY>-1&&this._collidingX>-1&&(e.fillStyle=""+t.Color.Cyan,e.fillRect(this.x+this._collidingX*this.cellWidth,this.y+this._collidingY*this.cellHeight,this.cellWidth,this.cellHeight)),e.restore()},e}();t.TileMap=e;var i=function(){function t(t,e){this.spriteSheetKey=t,this.spriteId=e}return t}();t.TileSprite=i;var n=function(){function e(e,i,n,s,o,r,h){void 0===r&&(r=!1),void 0===h&&(h=[]),this.x=e,this.y=i,this.width=n,this.height=s,this.index=o,this.solid=r,this.sprites=h,this._bounds=new t.BoundingBox(this.x,this.y,this.x+this.width,this.y+this.height)}return e.prototype.getBounds=function(){return this._bounds},e.prototype.getCenter=function(){return new t.Vector(this.x+this.width/2,this.y+this.height/2)},e.prototype.pushSprite=function(t){this.sprites.push(t)},e.prototype.removeSprite=function(t){var e=-1;(e=this.sprites.indexOf(t))>-1&&this.sprites.splice(e,1)},e.prototype.clearSprites=function(){this.sprites.length=0},e}();t.Cell=n})(ex||(ex={}));var ex;(function(t){(function(t){t[t.Naive=0]="Naive",t[t.DynamicAABBTree=1]="DynamicAABBTree",t[t.SeparatingAxis=2]="SeparatingAxis"})(t.CollisionStrategy||(t.CollisionStrategy={})),t.CollisionStrategy;var e=function(){function e(t,e,i,n){void 0===t&&(t=0),void 0===e&&(e=0),void 0===i&&(i=0),void 0===n&&(n=0),this.left=t,this.top=e,this.right=i,this.bottom=n}return e.prototype.getWidth=function(){return this.right-this.left},e.prototype.getHeight=function(){return this.bottom-this.top},e.prototype.getPerimeter=function(){var t=this.getWidth(),e=this.getHeight();return 2*(t+e)},e.prototype.contains=function(i){return i instanceof t.Point?this.left<=i.x&&this.top<=i.y&&this.bottom>=i.y&&this.right>=i.x:i instanceof e?this.left=n.left&&this.right<=n.right?n.left-this.right:n.right-this.left;var r=0;return r=this.top<=n.bottom&&this.top>=n.top?n.bottom-this.top:n.top-this.bottom,Math.abs(o)n;n++)e.push(new t.Line(this._points[n],this._points[(n+1)%i]));return e},e.prototype.getAxes=function(){for(var t=[],e=this._points.length,i=0;e>i;i++)t.push(this._points[i].minus(this._points[(i+1)%e]).normal());return t},e.prototype.project=function(e){for(var i=[],n=this._points.length,s=0;n>s;s++)i.push(this._points[s].dot(e));return new t.Projection(Math.min.apply(Math,i),Math.max.apply(Math,i))},e.prototype.getWidth=function(){var t=this._points.reduce(function(t,e){return Math.min(t,e.x)},1/0),e=this._points.reduce(function(t,e){return Math.max(t,e.x)},-1/0);return e-t},e.prototype.getHeight=function(){var t=this._points.reduce(function(t,e){return Math.min(t,e.y)},1/0),e=this._points.reduce(function(t,e){return Math.max(t,e.y)},-1/0);return t-e},e.prototype.contains=function(e){var i=new t.Ray(e,new t.Vector(1,0)),n=this.getSides().reduce(function(t,e){return i.intersect(e)>=0?t+1:t},0);return 0===n%2?!1:!0},e.prototype.collides=function(t){if(t instanceof e){var i=t,n=this.getAxes();n=i.getAxes().concat(n);for(var s=99999,o=null,r=0;n.length>r;r++){var h=this.project(n[r]),a=i.project(n[r]),c=h.getOverlap(a);if(0===c)return null;s>=c&&(s=c,o=n[r])}return o?o.normalize().scale(s):null}return null},e.prototype.debugDraw=function(e){e.beginPath(),e.lineWidth=2;var i=this._points[0];e.moveTo(i.x,i.y);var n=0,s=this._points.length;for(n;s>n;n++)e.lineTo(this._points[n].x,this._points[n].y);e.lineTo(i.x,i.y),e.closePath(),e.strokeStyle=""+t.Color.Blue,e.stroke()},e}();t.SATBoundingBox=i})(ex||(ex={}));var ex;(function(t){var e=function(){function e(){this.eventDispatcher=new t.EventDispatcher(this)}return e.prototype.addEventListener=function(t,e){this.eventDispatcher.subscribe(t,e)},e.prototype.removeEventListener=function(t,e){this.eventDispatcher.unsubscribe(t,e)},e.prototype.on=function(t,e){this.eventDispatcher.subscribe(t,e)},e.prototype.off=function(t,e){this.eventDispatcher.unsubscribe(t,e)},e.extend=function(t){var i,n=this;i=t&&t.hasOwnProperty("constructor")?t.constructor:function(){return n.apply(this,arguments)};var s=function(){this.constructor=i};if(s.prototype=n.prototype,i.prototype=new s,t)for(var o in t)t.hasOwnProperty(o)&&(i.prototype[o]=t[o]);return i.extend=e.extend,i},e}();t.Class=e})(ex||(ex={}));var ex;(function(t){var e=function(){function t(e,i,n){this.id=0,this.interval=10,this.fcn=function(){},this.repeats=!1,this._elapsedTime=0,this._totalTimeAlive=0,this.complete=!1,this.scene=null,this.id=t.id++,this.interval=i||this.interval,this.fcn=e||this.fcn,this.repeats=n||this.repeats}return t.prototype.update=function(t){this._totalTimeAlive+=t,this._elapsedTime+=t,this._elapsedTime>this.interval&&(this.fcn.call(this),this.repeats?this._elapsedTime=0:this.complete=!0)},t.prototype.getTimeRunning=function(){return this._totalTimeAlive},t.prototype.cancel=function(){this.scene&&this.scene.cancelTimer(this)},t.id=0,t}();t.Timer=e})(ex||(ex={}));var ex;(function(t){var e=function(){function e(){}return e.prototype.register=function(){},e.prototype.remove=function(){},e.prototype.evaluate=function(e){for(var i,n,s=e.filter(function(e){return!e.isKilled()&&e.collisionType!==t.CollisionType.PreventCollision}),o=[],r=0,h=s.length;h>r;r++){i=s[r];for(var a=r+1;h>a;a++){n=s[a];var c;if(c=i.collides(n)){var u=i.getSideFromIntersect(c),l=new t.CollisionPair(i,n,c,u);o.some(function(t){return t.equals(l)})||o.push(l)}}}var p=0,d=o.length;for(p;d>p;p++)o[p].evaluate();return o},e.prototype.update=function(){return 0},e.prototype.debugDraw=function(){},e}();t.NaiveCollisionResolver=e})(ex||(ex={}));var ex;(function(t){var e=function(){function e(e){this.parent=e,this.parent=e||null,this.actor=null,this.bounds=new t.BoundingBox,this.left=null,this.right=null,this.height=0}return e.prototype.isLeaf=function(){return!this.left&&!this.right},e}();t.TreeNode=e;var i=function(){function t(){this.root=null,this.nodes={}}return t.prototype.insert=function(t){if(null===this.root)return this.root=t,this.root.parent=null,void 0;for(var i=t.bounds,n=this.root;!n.isLeaf();){var s,o,r=n.left,h=n.right,a=n.bounds.getPerimeter(),c=n.bounds.combine(i),u=c.getPerimeter(),l=2*u,p=2*(u-a),d=0,f=i.combine(r.bounds);r.isLeaf()?d=f.getPerimeter()+p:(o=r.bounds.getPerimeter(),s=f.getPerimeter(),d=s-o+p);var g=0,_=i.combine(h.bounds);if(h.isLeaf()?g=_.getPerimeter()+p:(o=h.bounds.getPerimeter(),s=_.getPerimeter(),g=s-o+p),d>l&&g>l)break;n=g>d?r:h}var y=n.parent,A=new e(y);A.bounds=i.combine(n.bounds),A.height=n.height+1,null!==y?(y.left===n?y.left=A:y.right=A,A.left=n,A.right=t,n.parent=A,t.parent=A):(A.left=n,A.right=t,n.parent=A,t.parent=A,this.root=A);for(var v=t.parent;v;){if(v=this.balance(v),!v.left)throw Error("Parent of current leaf cannot have a null left child"+v);if(!v.right)throw Error("Parent of current leaf cannot have a null right child"+v);v.height=1+Math.max(v.left.height,v.right.height),v.bounds=v.left.bounds.combine(v.right.bounds),v=v.parent}},t.prototype.remove=function(t){if(t===this.root)return this.root=null,void 0; -var e,i=t.parent,n=i.parent;if(e=i.left===t?i.right:i.left,n){n.left===i?n.left=e:n.right=e,e.parent=n;for(var s=n;s;)s=this.balance(s),s.bounds=s.left.bounds.combine(s.right.bounds),s.height=1+Math.max(s.left.height,s.right.height),s=s.parent}else this.root=e,e.parent=null},t.prototype.registerActor=function(t){var i=new e;i.actor=t,i.bounds=t.getBounds(),i.bounds.left-=2,i.bounds.top-=2,i.bounds.right+=2,i.bounds.bottom+=2,this.nodes[t.id]=i,this.insert(i)},t.prototype.updateActor=function(t){var e=this.nodes[t.id];if(e){var i=t.getBounds();if(e.bounds.contains(i))return!1;this.remove(e),i.left-=5,i.top-=5,i.right+=5,i.bottom+=5;var n=2*t.dx,s=2*t.dy;return 0>n?i.left+=n:i.right+=n,0>s?i.top+=s:i.bottom+=s,e.bounds=i,this.insert(e),!0}},t.prototype.removeActor=function(t){var e=this.nodes[t.id];e&&(this.remove(e),this.nodes[t.id]=null,delete this.nodes[t.id])},t.prototype.balance=function(t){if(null===t)throw Error("Cannot balance at null node");if(t.isLeaf()||2>t.height)return t;var e=t.left,i=t.right,n=t,s=e,o=i,r=e.left,h=e.right,a=i.left,c=i.right,u=o.height-s.height;if(u>1)return o.left=n,o.parent=n.parent,n.parent=o,o.parent?o.parent.left===n?o.parent.left=o:o.parent.right=o:this.root=o,a.height>c.height?(o.right=a,n.right=c,c.parent=n,n.bounds=s.bounds.combine(c.bounds),o.bounds=n.bounds.combine(a.bounds),n.height=1+Math.max(s.height,c.height),o.height=1+Math.max(n.height,a.height)):(o.right=c,n.right=a,a.parent=n,n.bounds=s.bounds.combine(a.bounds),o.bounds=n.bounds.combine(c.bounds),n.height=1+Math.max(s.height,a.height),o.height=1+Math.max(n.height,c.height)),o;if(-1>u){if(s.left=n,s.parent=n.parent,n.parent=s,s.parent)if(s.parent.left===n)s.parent.left=s;else{if(s.parent.right!==n)throw"Error rotating Dynamic Tree";s.parent.right=s}else this.root=s;return r.height>h.height?(s.right=r,n.left=h,h.parent=n,n.bounds=o.bounds.combine(h.bounds),s.bounds=n.bounds.combine(r.bounds),n.height=1+Math.max(o.height,h.height),s.height=1+Math.max(n.height,r.height)):(s.right=h,n.left=r,r.parent=n,n.bounds=o.bounds.combine(r.bounds),s.bounds=n.bounds.combine(h.bounds),n.height=1+Math.max(o.height,r.height),s.height=1+Math.max(n.height,h.height)),s}return t},t.prototype.getHeight=function(){return null===this.root?0:this.root.height},t.prototype.query=function(t,e){var i=t.getBounds(),n=function(s){return s&&s.bounds.collides(i)?s.isLeaf()&&s.actor!==t?e.call(t,s.actor)?!0:void 0:n(s.left)||n(s.right):null};return n(this.root)},t.prototype.rayCast=function(){return null},t.prototype.getNodes=function(){var t=function(e){return e?[e].concat(t(e.left),t(e.right)):[]};return t(this.root)},t.prototype.debugDraw=function(t){var e=function(i){i&&(t.strokeStyle=i.isLeaf()?"green":"white",i.bounds.debugDraw(t),i.left&&e(i.left),i.right&&e(i.right))};e(this.root)},t}();t.DynamicTree=i})(ex||(ex={}));var ex;(function(t){var e=function(){function e(){this._dynamicCollisionTree=new t.DynamicTree}return e.prototype.register=function(t){this._dynamicCollisionTree.registerActor(t)},e.prototype.remove=function(t){this._dynamicCollisionTree.removeActor(t)},e.prototype.evaluate=function(e){for(var i,n=e.filter(function(e){return!e.isKilled()&&e.collisionType!==t.CollisionType.PreventCollision}),s=[],o=0,r=n.length;r>o;o++)i=n[o],this._dynamicCollisionTree.query(i,function(e){if(e.collisionType===t.CollisionType.PreventCollision||e.isKilled())return!1;var n;if(n=i.collides(e)){var o=i.getSideFromIntersect(n),r=new t.CollisionPair(i,e,n,o);return s.some(function(t){return t.equals(r)})||s.push(r),!0}return!1});var h=0,a=s.length;for(h;a>h;h++)s[h].evaluate();return s},e.prototype.update=function(t){var e=0,i=0,n=t.length;for(i;n>i;i++)this._dynamicCollisionTree.updateActor(t[i])&&e++;return e},e.prototype.debugDraw=function(t,e){this._dynamicCollisionTree.debugDraw(t,e)},e}();t.DynamicTreeCollisionResolver=e})(ex||(ex={}));var ex;(function(t){var e=function(){function e(t,e,i,n){this.left=t,this.right=e,this.intersect=i,this.side=n}return e.prototype.equals=function(t){return t.left===this.left&&t.right===this.right||t.right===this.left&&t.left===this.right},e.prototype.evaluate=function(){this.left.eventDispatcher.publish("collision",new t.CollisionEvent(this.left,this.right,this.side,this.intersect)),this.right.eventDispatcher.publish("collision",new t.CollisionEvent(this.right,this.left,t.Util.getOppositeSide(this.side),this.intersect.scale(-1)));var e=this.side;this.left.collisionType!==t.CollisionType.Active&&this.left.collisionType!==t.CollisionType.Elastic||this.right.collisionType===t.CollisionType.Passive||(this.left.y+=this.intersect.y,this.left.x+=this.intersect.x,this.left.collisionType===t.CollisionType.Elastic?e===t.Side.Left?this.left.dx=Math.abs(this.left.dx):e===t.Side.Right?this.left.dx=-Math.abs(this.left.dx):e===t.Side.Top?this.left.dy=Math.abs(this.left.dy):e===t.Side.Bottom&&(this.left.dy=-Math.abs(this.left.dy)):(0!==this.intersect.x&&(this.left.dx=0>=this.left.dx&&0>=this.right.dx?Math.max(this.left.dx,this.right.dx):this.left.dx>=0&&this.right.dx>=0?Math.min(this.left.dx,this.right.dx):0),0!==this.intersect.y&&(this.left.dy=0>=this.left.dy&&0>=this.right.dy?Math.max(this.left.dy,this.right.dy):this.left.dy>=0&&this.right.dy>=0?Math.min(this.left.dy,this.right.dy):0)));var i=t.Util.getOppositeSide(this.side),n=this.intersect.scale(-1);this.right.collisionType!==t.CollisionType.Active&&this.right.collisionType!==t.CollisionType.Elastic||this.left.collisionType===t.CollisionType.Passive||(this.right.y+=n.y,this.right.x+=n.x,this.right.collisionType===t.CollisionType.Elastic?i===t.Side.Left?this.right.dx=Math.abs(this.right.dx):i===t.Side.Right?this.right.dx=-Math.abs(this.right.dx):i===t.Side.Top?this.right.dy=Math.abs(this.right.dy):i===t.Side.Bottom&&(this.right.dy=-Math.abs(this.right.dy)):(0!==n.x&&(this.right.dx=0>=this.right.dx&&0>=this.left.dx?Math.max(this.left.dx,this.right.dx):this.left.dx>=0&&this.right.dx>=0?Math.min(this.left.dx,this.right.dx):0),0!==n.y&&(this.right.dy=0>=this.right.dy&&0>=this.left.dy?Math.max(this.left.dy,this.right.dy):this.left.dy>=0&&this.right.dy>=0?Math.min(this.left.dy,this.right.dy):0)))},e}();t.CollisionPair=e})(ex||(ex={}));var ex;(function(t){var e=function(){function e(){this._focus=new t.Point(0,0),this._lerp=!1,this._cameraMoving=!1,this._currentLerpTime=0,this._lerpDuration=1e3,this._totalLerpTime=0,this._lerpStart=null,this._lerpEnd=null,this._isShaking=!1,this._shakeMagnitudeX=0,this._shakeMagnitudeY=0,this._shakeDuration=0,this._elapsedShakeTime=0,this._isZooming=!1,this._currentZoomScale=1,this._maxZoomScale=1,this._zoomDuration=0,this._elapsedZoomTime=0,this._zoomIncrement=.01}return e.prototype._easeInOutCubic=function(t,e,i,n){return i-=e,t/=n/2,1>t?i/2*t*t*t+e:(t-=2,i/2*(t*t*t+2)+e)},e.prototype.setActorToFollow=function(t){this._follow=t},e.prototype.getFocus=function(){return this._focus},e.prototype.setFocus=function(e,i){this._follow||this._lerp||(this._focus.x=e,this._focus.y=i),this._lerp&&(this._lerpStart=this._focus.clone(),this._lerpEnd=new t.Point(e,i),this._currentLerpTime=0,this._cameraMoving=!0)},e.prototype.shake=function(t,e,i){this._isShaking=!0,this._shakeMagnitudeX=t,this._shakeMagnitudeY=e,this._shakeDuration=i},e.prototype.zoom=function(t,e){void 0===e&&(e=0),this._isZooming=!0,this._maxZoomScale=t,this._zoomDuration=e,e&&(this._zoomIncrement=1e3*(Math.abs(this._maxZoomScale-this._currentZoomScale)/e)),1>this._maxZoomScale?e?this._zoomIncrement=-1*this._zoomIncrement:(this._isZooming=!1,this._setCurrentZoomScale(this._maxZoomScale)):e||(this._isZooming=!1,this._setCurrentZoomScale(this._maxZoomScale))},e.prototype.getZoom=function(){return this._currentZoomScale},e.prototype._setCurrentZoomScale=function(t){this._currentZoomScale=t},e.prototype.update=function(t,e){var i=this.getFocus(),n=0,s=0,o=t.canvas.width,r=t.canvas.height,h=o/this.getZoom(),a=r/this.getZoom();this._lerp&&(this._currentLerpTime=this._shakeDuration},e.prototype._isDoneZooming=function(){return 0!==this._zoomDuration?this._elapsedZoomTime>=this._zoomDuration:1>this._maxZoomScale?this._currentZoomScale<=this._maxZoomScale:this._currentZoomScale>=this._maxZoomScale},e}();t.BaseCamera=e;var i=function(e){function i(){e.apply(this,arguments)}return __extends(i,e),i.prototype.getFocus=function(){return this._follow?new t.Point(this._follow.x+this._follow.getWidth()/2,this._focus.y):this._focus},i}(e);t.SideCamera=i;var n=function(e){function i(){e.apply(this,arguments)}return __extends(i,e),i.prototype.getFocus=function(){return this._follow?new t.Point(this._follow.x+this._follow.getWidth()/2,this._follow.y+this._follow.getHeight()/2):this._focus},i}(e);t.LockedCamera=n})(ex||(ex={}));var ex;(function(t){(function(t){t[t.ShortestPath=0]="ShortestPath",t[t.LongestPath=1]="LongestPath",t[t.Clockwise=2]="Clockwise",t[t.CounterClockwise=3]="CounterClockwise"})(t.RotationType||(t.RotationType={})),t.RotationType})(ex||(ex={}));var ex;(function(t){var e;(function(e){var i;(function(e){var i=function(){function e(e,i,n,s,o){this.actor=e,this.easingFcn=o,this._currentLerpTime=0,this._lerpDuration=1e3,this._lerpStart=new t.Point(0,0),this._lerpEnd=new t.Point(0,0),this._initialized=!1,this._stopped=!1,this._distance=0,this._lerpDuration=s,this._lerpEnd=new t.Point(i,n)}return e.prototype._initialize=function(){this._lerpStart=new t.Point(this.actor.x,this.actor.y),this._currentLerpTime=0,this._distance=this._lerpStart.toVector().distance(this._lerpEnd.toVector())},e.prototype.update=function(t){this._initialized||(this._initialize(),this._initialized=!0);var e=this.actor.x,i=this.actor.y;this._currentLerpTime=this._distance},e.prototype.reset=function(){this._initialized=!1},e.prototype.stop=function(){this._stopped=!0},e}();e.EaseTo=i;var n=function(){function e(e,i,n,s){this._started=!1,this._stopped=!1,this._actor=e,this._end=new t.Vector(i,n),this._speed=s}return e.prototype.update=function(){this._started||(this._started=!0,this._start=new t.Vector(this._actor.x,this._actor.y),this._distance=this._start.distance(this._end),this._dir=this._end.minus(this._start).normalize());var e=this._dir.scale(this._speed);this._actor.dx=e.x,this._actor.dy=e.y,this.isComplete(this._actor)&&(this._actor.x=this._end.x,this._actor.y=this._end.y,this._actor.dy=0,this._actor.dx=0)},e.prototype.isComplete=function(e){return this._stopped||new t.Vector(e.x,e.y).distance(this._start)>=this._distance},e.prototype.stop=function(){this._actor.dy=0,this._actor.dx=0,this._stopped=!0},e.prototype.reset=function(){this._started=!1},e}();e.MoveTo=n;var s=function(){function e(e,i,n,s){if(this._started=!1,this._stopped=!1,this._actor=e,this._end=new t.Vector(i,n),0>=s)throw t.Logger.getInstance().error("Attempted to moveBy time less than or equal to zero : "+s),Error("Cannot move in time <= 0");this._time=s}return e.prototype.update=function(){this._started||(this._started=!0,this._start=new t.Vector(this._actor.x,this._actor.y),this._distance=this._start.distance(this._end),this._dir=this._end.minus(this._start).normalize(),this._speed=this._distance/(this._time/1e3));var e=this._dir.scale(this._speed);this._actor.dx=e.x,this._actor.dy=e.y,this.isComplete(this._actor)&&(this._actor.x=this._end.x,this._actor.y=this._end.y,this._actor.dy=0,this._actor.dx=0)},e.prototype.isComplete=function(e){return this._stopped||new t.Vector(e.x,e.y).distance(this._start)>=this._distance},e.prototype.stop=function(){this._actor.dy=0,this._actor.dx=0,this._stopped=!0},e.prototype.reset=function(){this._started=!1},e}();e.MoveBy=s;var o=function(){function e(e,i,n){this._started=!1,this._stopped=!1,this._actor=e,this._actorToFollow=i,this._current=new t.Vector(this._actor.x,this._actor.y),this._end=new t.Vector(i.x,i.y),this._maximumDistance=void 0!==n?n:this._current.distance(this._end),this._speed=0}return e.prototype.update=function(){this._started||(this._started=!0,this._distanceBetween=this._current.distance(this._end),this._dir=this._end.minus(this._current).normalize());var t=Math.sqrt(Math.pow(this._actorToFollow.dx,2)+Math.pow(this._actorToFollow.dy,2));if(0!==t&&(this._speed=t),this._current.x=this._actor.x,this._current.y=this._actor.y,this._end.x=this._actorToFollow.x,this._end.y=this._actorToFollow.y,this._distanceBetween=this._current.distance(this._end),this._dir=this._end.minus(this._current).normalize(),this._distanceBetween>=this._maximumDistance){var e=this._dir.scale(this._speed);this._actor.dx=e.x,this._actor.dy=e.y}else this._actor.dx=0,this._actor.dy=0;this.isComplete(this._actor)&&(this._actor.x=this._end.x,this._actor.y=this._end.y,this._actor.dy=0,this._actor.dx=0)},e.prototype.stop=function(){this._actor.dy=0,this._actor.dx=0,this._stopped=!0},e.prototype.isComplete=function(){return this._stopped},e.prototype.reset=function(){this._started=!1},e}();e.Follow=o;var r=function(){function e(e,i,n){this._started=!1,this._stopped=!1,this._speedWasSpecified=!1,this._actor=e,this._actorToMeet=i,this._current=new t.Vector(this._actor.x,this._actor.y),this._end=new t.Vector(i.x,i.y),this._speed=n||0,void 0!==n&&(this._speedWasSpecified=!0)}return e.prototype.update=function(){this._started||(this._started=!0,this._distanceBetween=this._current.distance(this._end),this._dir=this._end.minus(this._current).normalize());var t=Math.sqrt(Math.pow(this._actorToMeet.dx,2)+Math.pow(this._actorToMeet.dy,2));0===t||this._speedWasSpecified||(this._speed=t),this._current.x=this._actor.x,this._current.y=this._actor.y,this._end.x=this._actorToMeet.x,this._end.y=this._actorToMeet.y,this._distanceBetween=this._current.distance(this._end),this._dir=this._end.minus(this._current).normalize();var e=this._dir.scale(this._speed);this._actor.dx=e.x,this._actor.dy=e.y,this.isComplete(this._actor)&&(this._actor.x=this._end.x,this._actor.y=this._end.y,this._actor.dy=0,this._actor.dx=0)},e.prototype.isComplete=function(){return this._stopped||1>=this._distanceBetween},e.prototype.stop=function(){this._actor.dy=0,this._actor.dx=0,this._stopped=!0},e.prototype.reset=function(){this._started=!1},e}();e.Meet=r;var h=function(){function e(e,i,n,s){this._started=!1,this._stopped=!1,this._actor=e,this._end=i,this._speed=n,this._rotationType=s||t.RotationType.ShortestPath}return e.prototype.update=function(){if(!this._started){this._started=!0,this._start=this._actor.rotation;var e=Math.abs(this._end-this._start),i=t.Util.TwoPI-e;switch(e>i?(this._shortDistance=i,this._longDistance=e):(this._shortDistance=e,this._longDistance=i),this._shortestPathIsPositive=(this._start-this._end+t.Util.TwoPI)%t.Util.TwoPI>=Math.PI,this._rotationType){case t.RotationType.ShortestPath:this._distance=this._shortDistance,this._direction=this._shortestPathIsPositive?1:-1;break;case t.RotationType.LongestPath:this._distance=this._longDistance,this._direction=this._shortestPathIsPositive?-1:1;break;case t.RotationType.Clockwise:this._direction=1,this._distance=this._shortestPathIsPositive?this._shortDistance:this._longDistance;break;case t.RotationType.CounterClockwise:this._direction=-1,this._distance=this._shortestPathIsPositive?this._longDistance:this._shortDistance}}this._actor.rx=this._direction*this._speed,this.isComplete(this._actor)&&(this._actor.rotation=this._end,this._actor.rx=0,this._stopped=!0)},e.prototype.isComplete=function(){var t=Math.abs(this._actor.rotation-this._start);return this._stopped||t>=Math.abs(this._distance)},e.prototype.stop=function(){this._actor.rx=0,this._stopped=!0},e.prototype.reset=function(){this._started=!1},e}();e.RotateTo=h;var a=function(){function e(e,i,n,s){this._started=!1,this._stopped=!1,this._actor=e,this._end=i,this._time=n,this._rotationType=s||t.RotationType.ShortestPath}return e.prototype.update=function(){if(!this._started){this._started=!0,this._start=this._actor.rotation;var e=Math.abs(this._end-this._start),i=t.Util.TwoPI-e;switch(e>i?(this._shortDistance=i,this._longDistance=e):(this._shortDistance=e,this._longDistance=i),this._shortestPathIsPositive=(this._start-this._end+t.Util.TwoPI)%t.Util.TwoPI>=Math.PI,this._rotationType){case t.RotationType.ShortestPath:this._distance=this._shortDistance,this._direction=this._shortestPathIsPositive?1:-1;break;case t.RotationType.LongestPath:this._distance=this._longDistance,this._direction=this._shortestPathIsPositive?-1:1;break;case t.RotationType.Clockwise:this._direction=1,this._distance=this._shortDistance>=0?this._shortDistance:this._longDistance;break;case t.RotationType.CounterClockwise:this._direction=-1,this._distance=0>=this._shortDistance?this._shortDistance:this._longDistance}this._speed=Math.abs(1e3*(this._distance/this._time))}this._actor.rx=this._direction*this._speed,this.isComplete(this._actor)&&(this._actor.rotation=this._end,this._actor.rx=0,this._stopped=!0)},e.prototype.isComplete=function(){var t=Math.abs(this._actor.rotation-this._start);return this._stopped||t>=Math.abs(this._distance)},e.prototype.stop=function(){this._actor.rx=0,this._stopped=!0},e.prototype.reset=function(){this._started=!1},e}();e.RotateBy=a;var c=function(){function t(t,e,i,n,s){this._started=!1,this._stopped=!1,this._actor=t,this._endX=e,this._endY=i,this._speedX=n,this._speedY=s}return t.prototype.update=function(){if(this._started||(this._started=!0,this._startX=this._actor.scale.x,this._startY=this._actor.scale.y,this._distanceX=Math.abs(this._endX-this._startX),this._distanceY=Math.abs(this._endY-this._startY)),Math.abs(this._actor.scale.x-this._startX)>=this._distanceX)this._actor.sx=0;else{var t=this._endY=this._distanceY)this._actor.sy=0;else{var e=this._endY=this._distanceX&&Math.abs(this._actor.scale.y-this._startY)>=this._distanceY},t.prototype.stop=function(){this._actor.sx=0,this._actor.sy=0,this._stopped=!0},t.prototype.reset=function(){this._started=!1},t}();e.ScaleTo=c;var u=function(){function t(t,e,i,n){this._started=!1,this._stopped=!1,this._actor=t,this._endX=e,this._endY=i,this._time=n,this._speedX=1e3*((this._endX-this._actor.scale.x)/n),this._speedY=1e3*((this._endY-this._actor.scale.y)/n)}return t.prototype.update=function(){this._started||(this._started=!0,this._startX=this._actor.scale.x,this._startY=this._actor.scale.y,this._distanceX=Math.abs(this._endX-this._startX),this._distanceY=Math.abs(this._endY-this._startY));var t=this._endX=this._distanceX&&Math.abs(this._actor.scale.y-this._startY)>=this._distanceY},t.prototype.stop=function(){this._actor.sx=0,this._actor.sy=0,this._stopped=!0},t.prototype.reset=function(){this._started=!1},t}();e.ScaleBy=u;var l=function(){function t(t,e){this._elapsedTime=0,this._started=!1,this._stopped=!1,this._actor=t,this._delay=e}return t.prototype.update=function(t){this._started||(this._started=!0),this.x=this._actor.x,this.y=this._actor.y,this._elapsedTime+=t},t.prototype.isComplete=function(){return this._stopped||this._elapsedTime>=this._delay},t.prototype.stop=function(){this._stopped=!0},t.prototype.reset=function(){this._elapsedTime=0,this._started=!1},t}();e.Delay=l;var p=function(){function t(t,e,i,n){void 0===n&&(n=1),this._timeVisible=0,this._timeNotVisible=0,this._elapsedTime=0,this._totalTime=0,this._stopped=!1,this._started=!1,this._actor=t,this._timeVisible=e,this._timeNotVisible=i,this._duration=(e+i)*n}return t.prototype.update=function(t){this._started||(this._started=!0),this._elapsedTime+=t,this._totalTime+=t,this._actor.visible&&this._elapsedTime>=this._timeVisible&&(this._actor.visible=!1,this._elapsedTime=0),!this._actor.visible&&this._elapsedTime>=this._timeNotVisible&&(this._actor.visible=!0,this._elapsedTime=0),this.isComplete(this._actor)&&(this._actor.visible=!0)},t.prototype.isComplete=function(){return this._stopped||this._totalTime>=this._duration},t.prototype.stop=function(){this._actor.visible=!0,this._stopped=!0},t.prototype.reset=function(){this._started=!1,this._elapsedTime=0,this._totalTime=0},t}();e.Blink=p;var d=function(){function e(t,e,i){this._multiplyer=1,this._started=!1,this._stopped=!1,this._actor=t,this._endOpacity=e,this._speed=i,t.opacity>e&&(this._multiplyer=-1)}return e.prototype.update=function(e){this._started||(this._started=!0),this._speed>0&&(this._actor.opacity+=this._multiplyer*Math.abs(this._actor.opacity-this._endOpacity)*e/this._speed),this._speed-=e,t.Logger.getInstance().debug("actor opacity: "+this._actor.opacity),this.isComplete(this._actor)&&(this._actor.opacity=this._endOpacity)},e.prototype.isComplete=function(){return this._stopped||.05>Math.abs(this._actor.opacity-this._endOpacity)},e.prototype.stop=function(){this._stopped=!0},e.prototype.reset=function(){this._started=!1},e}();e.Fade=d;var f=function(){function t(t){this._started=!1,this._stopped=!1,this._actor=t}return t.prototype.update=function(){this._actor.actionQueue.clearActions(),this._actor.kill(),this._stopped=!0},t.prototype.isComplete=function(){return this._stopped},t.prototype.stop=function(){},t.prototype.reset=function(){},t}();e.Die=f;var g=function(){function t(t,e){this._method=null,this._actor=null,this._hasBeenCalled=!1,this._actor=t,this._method=e}return t.prototype.update=function(){this._method.call(this._actor),this._hasBeenCalled=!0},t.prototype.isComplete=function(){return this._hasBeenCalled},t.prototype.reset=function(){this._hasBeenCalled=!1},t.prototype.stop=function(){this._hasBeenCalled=!0},t}();e.CallMethod=g;var _=function(){function t(t,e,i){this._stopped=!1,this._actor=t,this._actionQueue=new A(t),this._repeat=e,this._originalRepeat=e;var n=0,s=i.length;for(n;s>n;n++)i[n].reset(),this._actionQueue.add(i[n])}return t.prototype.update=function(t){this.x=this._actor.x,this.y=this._actor.y,this._actionQueue.hasNext()||(this._actionQueue.reset(),this._repeat--),this._actionQueue.update(t)},t.prototype.isComplete=function(){return this._stopped||0>=this._repeat},t.prototype.stop=function(){this._stopped=!0},t.prototype.reset=function(){this._repeat=this._originalRepeat},t}();e.Repeat=_;var y=function(){function t(t,e){this._stopped=!1,this._actor=t,this._actionQueue=new A(t);var i=0,n=e.length;for(i;n>i;i++)e[i].reset(),this._actionQueue.add(e[i])}return t.prototype.update=function(t){this.x=this._actor.x,this.y=this._actor.y,this._stopped||(this._actionQueue.hasNext()||this._actionQueue.reset(),this._actionQueue.update(t))},t.prototype.isComplete=function(){return this._stopped},t.prototype.stop=function(){this._stopped=!0,this._actionQueue.clearActions()},t.prototype.reset=function(){},t}();e.RepeatForever=y;var A=function(){function t(t){this._actions=[],this._completedActions=[],this._actor=t}return t.prototype.add=function(t){this._actions.push(t)},t.prototype.remove=function(t){var e=this._actions.indexOf(t);this._actions.splice(e,1)},t.prototype.clearActions=function(){this._actions.length=0,this._completedActions.length=0,this._currentAction&&this._currentAction.stop()},t.prototype.getActions=function(){return this._actions.concat(this._completedActions)},t.prototype.hasNext=function(){return this._actions.length>0},t.prototype.reset=function(){this._actions=this.getActions();var t=0,e=this._actions.length;for(t;e>t;t++)this._actions[t].reset();this._completedActions=[]},t.prototype.update=function(t){this._actions.length>0&&(this._currentAction=this._actions[0],this._currentAction.update(t),this._currentAction.isComplete(this._actor)&&this._completedActions.push(this._actions.shift()))},t}();e.ActionQueue=A})(i=e.Actions||(e.Actions={}))})(e=t.Internal||(t.Internal={}))})(ex||(ex={}));var ex;(function(t){var e=function(){function e(){this._actors=[],this._queues=[],null!==arguments&&(this._actors=Array.prototype.slice.call(arguments,0),this._queues=this._actors.map(function(t){return t.actionQueue}))}return e.prototype.clearActions=function(){var t=0,e=this._queues.length;for(t;e>t;t++)this._queues[t].clearActions()},e.prototype.addActorToContext=function(t){this._actors.push(t),this._queues.push(t.actionQueue)},e.prototype.removeActorFromContext=function(t){var e=this._actors.indexOf(t);e>-1&&(this._actors.splice(e,1),this._queues.splice(e,1))},e.prototype.moveTo=function(e,i,n){var s=0,o=this._queues.length;for(s;o>s;s++)this._queues[s].add(new t.Internal.Actions.MoveTo(this._actors[s],e,i,n));return this},e.prototype.moveBy=function(e,i,n){var s=0,o=this._queues.length;for(s;o>s;s++)this._queues[s].add(new t.Internal.Actions.MoveBy(this._actors[s],e,i,n));return this},e.prototype.rotateTo=function(e,i){var n=0,s=this._queues.length;for(n;s>n;n++)this._queues[n].add(new t.Internal.Actions.RotateTo(this._actors[n],e,i));return this},e.prototype.rotateBy=function(e,i){var n=0,s=this._queues.length;for(n;s>n;n++)this._queues[n].add(new t.Internal.Actions.RotateBy(this._actors[n],e,i));return this},e.prototype.scaleTo=function(e,i,n,s){var o=0,r=this._queues.length;for(o;r>o;o++)this._queues[o].add(new t.Internal.Actions.ScaleTo(this._actors[o],e,i,n,s));return this},e.prototype.scaleBy=function(e,i,n){var s=0,o=this._queues.length;for(s;o>s;s++)this._queues[s].add(new t.Internal.Actions.ScaleBy(this._actors[s],e,i,n));return this},e.prototype.blink=function(e,i,n){void 0===n&&(n=1);var s=0,o=this._queues.length;for(s;o>s;s++)this._queues[s].add(new t.Internal.Actions.Blink(this._actors[s],e,i,n));return this},e.prototype.fade=function(e,i){var n=0,s=this._queues.length;for(n;s>n;n++)this._queues[n].add(new t.Internal.Actions.Fade(this._actors[n],e,i));return this},e.prototype.delay=function(e){var i=0,n=this._queues.length;for(i;n>i;i++)this._queues[i].add(new t.Internal.Actions.Delay(this._actors[i],e));return this},e.prototype.die=function(){var e=0,i=this._queues.length;for(e;i>e;e++)this._queues[e].add(new t.Internal.Actions.Die(this._actors[e]));return this},e.prototype.callMethod=function(e){var i=0,n=this._queues.length;for(i;n>i;i++)this._queues[i].add(new t.Internal.Actions.CallMethod(this._actors[i],e));return this},e.prototype.repeat=function(e){if(!e)return this.repeatForever(),this;var i=0,n=this._queues.length;for(i;n>i;i++)this._queues[i].add(new t.Internal.Actions.Repeat(this._actors[i],e,this._actors[i].actionQueue.getActions()));return this},e.prototype.repeatForever=function(){var e=0,i=this._queues.length;for(e;i>e;e++)this._queues[e].add(new t.Internal.Actions.RepeatForever(this._actors[e],this._actors[e].actionQueue.getActions()));return this},e.prototype.follow=function(e,i){var n=0,s=this._queues.length;for(n;s>n;n++)void 0===i?this._queues[n].add(new t.Internal.Actions.Follow(this._actors[n],e)):this._queues[n].add(new t.Internal.Actions.Follow(this._actors[n],e,i));return this},e.prototype.meet=function(e,i){var n=0,s=this._queues.length;for(n;s>n;n++)void 0===i?this._queues[n].add(new t.Internal.Actions.Meet(this._actors[n],e)):this._queues[n].add(new t.Internal.Actions.Meet(this._actors[n],e,i));return this},e.prototype.asPromise=function(){var e=this,i=this._queues.map(function(i,n){var s=new t.Promise;return i.add(new t.Internal.Actions.CallMethod(e._actors[n],function(){s.resolve()})),s});return t.Promise.join.apply(this,i)},e}();t.ActionContext=e})(ex||(ex={}));var ex;(function(t){var e=function(e){function i(i,n){if(e.call(this),this.name=i,this.scene=n,this._logger=t.Logger.getInstance(),this._members=[],this.actions=new t.ActionContext,null==n)this._logger.error("Invalid constructor arguments passed to Group: ",i,", scene must not be null!");else{var s=n.groups[i];s&&this._logger.warn("Group with name",i,"already exists. This new group will replace it."),n.groups[i]=this}}return __extends(i,e),i.prototype.add=function(e){e instanceof t.Actor&&(e=[].concat(e));var i,n=0,s=e.length;for(n;s>n;n++)i=this.getMembers().indexOf(e[n]),-1===i&&(this._members.push(e[n]),this.scene.add(e[n]),this.actions.addActorToContext(e[n]),this.eventDispatcher.wire(e[n].eventDispatcher))},i.prototype.remove=function(t){var e=this._members.indexOf(t);e>-1&&(this._members.splice(e,1),this.actions.removeActorFromContext(t),this.eventDispatcher.unwire(t.eventDispatcher))},i.prototype.move=function(e){var i=0,n=this.getMembers(),s=n.length;if(1===arguments.length&&e instanceof t.Vector)for(i;s>i;i++)n[i].x+=e.x,n[i].y+=e.y;else if("number"==typeof arguments[0]&&"number"==typeof arguments[1]){var o=arguments[0],r=arguments[1];for(i;s>i;i++)n[i].x+=o,n[i].y+=r}else this._logger.error("Invalid arguments passed to group move",this.name,"args:",arguments)},i.prototype.rotate=function(){if("number"==typeof arguments[0]){var t=arguments[0],e=0,i=this.getMembers(),n=i.length;for(e;n>e;e++)i[e].rotation+=t}else this._logger.error("Invalid arguments passed to group rotate",this.name,"args:",arguments)},i.prototype.on=function(t,e){this.eventDispatcher.subscribe(t,e)},i.prototype.off=function(t,e){this.eventDispatcher.unsubscribe(t,e)},i.prototype.emit=function(t,e){this.eventDispatcher.emit(t,e)},i.prototype.contains=function(t){return this.getMembers().indexOf(t)>-1},i.prototype.getMembers=function(){return this._members},i.prototype.getRandomMember=function(){return this._members[Math.floor(Math.random()*this._members.length)] -},i.prototype.getBounds=function(){return this.getMembers().map(function(t){return t.getBounds()}).reduce(function(t,e){return t.combine(e)})},i}(t.Class);t.Group=e})(ex||(ex={}));var ex;(function(t){var e=function(){function t(t){this._getComparable=t}return t.prototype.find=function(t){return this._find(this._root,t)},t.prototype._find=function(t,e){return null==t?!1:this._getComparable.call(e)===t.getKey()?t.getData().indexOf(e)>-1?!0:!1:this._getComparable.call(e)e?this._get(t.getLeft(),e):this._get(t.getRight(),e)},t.prototype.add=function(t){return null==this._root?(this._root=new i(this._getComparable.call(t),[t],null,null),!0):this._insert(this._root,t)},t.prototype._insert=function(t,e){return null!=t?this._getComparable.call(e)===t.getKey()?t.getData().indexOf(e)>-1?!1:(t.getData().push(e),!0):this._getComparable.call(e)-1){if(t.getData().splice(i,1),0===t.getData().length){if(null==t.getLeft()&&null==t.getRight())return null;if(null==t.getLeft())return t.getRight();if(null==t.getRight())return t.getLeft();var n=this._findMinNode(t.getRight());return t.setKey(n.getKey()),t.setData(n.getData()),t.setRight(this._cleanup(t.getRight(),n)),t}return t}},t.prototype._cleanup=function(t,e){var i=e.getKey();if(null==t)return null;if(i===t.getKey()){if(null==t.getLeft()&&null==t.getRight())return null;if(null==t.getLeft())return t.getRight();if(null==t.getRight())return t.getLeft();var n=this._findMinNode(t.getRight());return t.setKey(n.getKey()),t.setData(n.getData()),t.setRight(this._cleanup(t.getRight(),n)),t}return this._getComparable.call(e)i;i++)this.children[i].triggerEvent(t,e)},i.prototype.update=function(t,e){var i,n;for(i=0,n=this.uiActors.length;n>i;i++)this.uiActors[i].update(t,e);for(i=0,n=this.tileMaps.length;n>i;i++)this.tileMaps[i].update(t,e);for(i=0,n=this.children.length;n>i;i++)this.children[i].update(t,e);this._collisionResolver&&(this._collisionResolver.update(this.children),this._collisionResolver.evaluate(this.children));var s;for(i=0,n=this._killQueue.length;n>i;i++)s=this.children.indexOf(this._killQueue[i]),s>-1&&(this._sortedDrawingTree.removeByComparable(this._killQueue[i]),this.children.splice(s,1));for(this._killQueue.length=0,i=0,n=this._cancelQueue.length;n>i;i++)this.removeTimer(this._cancelQueue[i]);this._cancelQueue.length=0,this._timers=this._timers.filter(function(t){return t.update(e),!t.complete})},i.prototype.draw=function(t,e){t.save(),this.camera&&this.camera.update(t,e);var i,n;for(i=0,n=this.tileMaps.length;n>i;i++)this.tileMaps[i].draw(t,e);var s=this._sortedDrawingTree.list();for(i=0,n=s.length;n>i;i++)s[i].visible&&!s[i].isOffScreen&&s[i].draw(t,e);for(this.engine&&this.engine.isDebug&&(t.strokeStyle="yellow",this.debugDraw(t)),t.restore(),i=0,n=this.uiActors.length;n>i;i++)this.uiActors[i].visible&&this.uiActors[i].draw(t,e);if(this.engine&&this.engine.isDebug)for(i=0,n=this.uiActors.length;n>i;i++)this.uiActors[i].debugDraw(t)},i.prototype.debugDraw=function(t){var e,i;for(e=0,i=this.tileMaps.length;i>e;e++)this.tileMaps[e].debugDraw(t);for(e=0,i=this.children.length;i>e;e++)this.children[e].debugDraw(t);this.camera.debugDraw(t)},i.prototype.contains=function(t){return this.children.indexOf(t)>-1},i.prototype.add=function(e){return e instanceof t.UIActor?(this.addUIActor(e),void 0):(e instanceof t.Actor&&(this.addChild(e),this._sortedDrawingTree.add(e)),e instanceof t.Timer&&this.addTimer(e),e instanceof t.TileMap&&this.addTileMap(e),void 0)},i.prototype.remove=function(e){return e instanceof t.UIActor?(this.removeUIActor(e),void 0):(e instanceof t.Actor&&(this._collisionResolver.remove(e),this.removeChild(e)),e instanceof t.Timer&&this.removeTimer(e),e instanceof t.TileMap&&this.removeTileMap(e),void 0)},i.prototype.addUIActor=function(t){this.uiActors.push(t),t.scene=this},i.prototype.removeUIActor=function(t){var e=this.uiActors.indexOf(t);e>-1&&this.uiActors.splice(e,1)},i.prototype.addChild=function(t){this._collisionResolver.register(t),t.scene=this,this.children.push(t),this._sortedDrawingTree.add(t),t.parent=this.actor},i.prototype.addTileMap=function(t){this.tileMaps.push(t)},i.prototype.removeTileMap=function(t){var e=this.tileMaps.indexOf(t);e>-1&&this.tileMaps.splice(e,1)},i.prototype.removeChild=function(t){this._collisionResolver.remove(t),this._killQueue.push(t),t.parent=null},i.prototype.addTimer=function(t){return this._timers.push(t),t.scene=this,t},i.prototype.removeTimer=function(t){var e=this._timers.indexOf(t);return-1!==e&&this._timers.splice(e,1),t},i.prototype.cancelTimer=function(t){return this._cancelQueue.push(t),t},i.prototype.isTimerActive=function(t){return this._timers.indexOf(t)>-1},i.prototype.createGroup=function(e){return new t.Group(e,this)},i.prototype.getGroup=function(t){return this.groups[t]},i.prototype.removeGroup=function(e){"string"==typeof e?delete this.groups[e]:e instanceof t.Group?delete this.groups[e.name]:this._logger.error("Invalid arguments to removeGroup",e)},i.prototype.cleanupDrawTree=function(t){this._sortedDrawingTree.removeByComparable(t)},i.prototype.updateDrawTree=function(t){this._sortedDrawingTree.add(t)},i}(t.Class);t.Scene=e})(ex||(ex={}));var ex;(function(t){var e=function(){function t(){}return t.Linear=function(t,e,i,n){return i-=e,i*t/n+e},t.EaseInQuad=function(t,e,i,n){t/=n},t.EaseOutQuad=function(t,e,i,n){return t/=n,-i*t*(t-2)+e},t.EaseInOutQuad=function(t,e,i,n){return i-=e,t/=n/2,1>t?i/2*t*t+e:(t--,-i/2*(t*(t-2)-1)+e)},t.EaseInCubic=function(t,e,i,n){return i-=e,t/=n,i*t*t*t+e},t.EaseOutCubic=function(t,e,i,n){return i-=e,t/=n,i*(t*t*t+1)+e},t.EaseInOutCubic=function(t,e,i,n){return i-=e,t/=n/2,1>t?i/2*t*t*t+e:(t-=2,i/2*(t*t*t+2)+e)},t}();t.EasingFunctions=e})(ex||(ex={}));var ex;(function(t){var e=function(e){function n(s,o,r,h,a){e.call(this),this.id=n.maxId++,this.x=0,this.y=0,this._height=0,this._width=0,this.rotation=0,this.rx=0,this.scale=new t.Vector(1,1),this.sx=0,this.sy=0,this.dx=0,this.dy=0,this.ax=0,this.ay=0,this.isOffScreen=!1,this.visible=!0,this.opacity=1,this.previousOpacity=1,this.actions=new t.ActionContext(this),this.logger=t.Logger.getInstance(),this.scene=null,this.parent=null,this.children=[],this.collisionType=i.PreventCollision,this.collisionGroups=[],this._collisionHandlers={},this._isInitialized=!1,this.frames={},this.currentDrawing=null,this.centerDrawingX=!0,this.centerDrawingY=!0,this.traits=[],this.enableCapturePointer=!1,this.capturePointer={captureMoveEvents:!1},this._zIndex=0,this._isKilled=!1,this.x=s||0,this.y=o||0,this._width=r||0,this._height=h||0,a&&(this.color=a.clone(),this.opacity=a.a),this.traits.push(new t.Traits.Movement),this.traits.push(new t.Traits.OffscreenCulling),this.traits.push(new t.Traits.CapturePointer),this.actionQueue=new t.Internal.Actions.ActionQueue(this),this.anchor=new t.Point(.5,.5)}return __extends(n,e),n.prototype.onInitialize=function(){},n.prototype._checkForPointerOptIn=function(t){!t||"pointerdown"!==t.toLowerCase()&&"pointerdown"!==t.toLowerCase()&&"pointermove"!==t.toLowerCase()||(this.enableCapturePointer=!0,"pointermove"===t.toLowerCase()&&(this.capturePointer.captureMoveEvents=!0))},n.prototype.addEventListener=function(t,i){this._checkForPointerOptIn(t),e.prototype.addEventListener.call(this,t,i)},n.prototype.on=function(t,e){this._checkForPointerOptIn(t),this.eventDispatcher.subscribe(t,e)},n.prototype.kill=function(){this.scene?(this.scene.remove(this),this._isKilled=!0):this.logger.warn("Cannot kill actor, it was never added to the Scene")},n.prototype.isKilled=function(){return this._isKilled},n.prototype.addChild=function(e){e.collisionType=i.PreventCollision,t.Util.addItemToArray(e,this.children)&&(e.parent=this)},n.prototype.removeChild=function(e){t.Util.removeItemToArray(e,this.children)&&(e.parent=null)},n.prototype.setDrawing=function(e){e=""+e,this.currentDrawing!==this.frames[e]&&(null!=this.frames[e]?(this.frames[e].reset(),this.currentDrawing=this.frames[e]):t.Logger.getInstance().error("the specified drawing key '"+e+"' does not exist"))},n.prototype.addDrawing=function(){2===arguments.length?(this.frames[arguments[0]]=arguments[1],this.currentDrawing||(this.currentDrawing=arguments[1])):(arguments[0]instanceof t.Sprite&&this.addDrawing("default",arguments[0]),arguments[0]instanceof t.Texture&&this.addDrawing("default",arguments[0].asSprite()))},n.prototype.getZIndex=function(){return this._zIndex},n.prototype.setZIndex=function(t){this.scene.cleanupDrawTree(this),this._zIndex=t,this.scene.updateDrawTree(this)},n.prototype.triggerEvent=function(t,e){this.eventDispatcher.publish(t,e)},n.prototype.addCollisionGroup=function(t){this.collisionGroups.push(t)},n.prototype.removeCollisionGroup=function(t){var e=this.collisionGroups.indexOf(t);-1!==e&&this.collisionGroups.splice(e,1)},n.prototype.getCenter=function(){return new t.Vector(this.x+this.getWidth()/2-this.anchor.x*this.getWidth(),this.y+this.getHeight()/2-this.anchor.y*this.getHeight())},n.prototype.getWidth=function(){return this._width*this.scale.x},n.prototype.setWidth=function(t){this._width=t/this.scale.x},n.prototype.getHeight=function(){return this._height*this.scale.y},n.prototype.setHeight=function(t){this._height=t/this.scale.y},n.prototype.setCenterDrawing=function(t){this.centerDrawingY=t,this.centerDrawingX=t},n.prototype.getLeft=function(){return this.x},n.prototype.getRight=function(){return this.x+this.getWidth()},n.prototype.getTop=function(){return this.y},n.prototype.getBottom=function(){return this.y+this.getHeight()},n.prototype.getWorldX=function(){return this.parent?this.x*this.parent.scale.x+this.parent.getWorldX():this.x},n.prototype.getWorldY=function(){return this.parent?this.y*this.parent.scale.y+this.parent.getWorldY():this.y},n.prototype.getGlobalScale=function(){if(!this.parent)return new t.Point(this.scale.x,this.scale.y);var e=this.parent.getGlobalScale();return new t.Point(this.scale.x*e.x,this.scale.y*e.y)},n.prototype.getBounds=function(){var e=this._getCalculatedAnchor();return new t.BoundingBox(this.getWorldX()-e.x,this.getWorldY()-e.y,this.getWorldX()+this.getWidth()-e.x,this.getWorldY()+this.getHeight()-e.y)},n.prototype.contains=function(e,i,n){void 0===n&&(n=!1);var s=this.getBounds().contains(new t.Point(e,i));return n?s||this.children.some(function(t){return t.contains(e,i,!0)}):s},n.prototype.getSideFromIntersect=function(e){return e?Math.abs(e.x)>Math.abs(e.y)?0>e.x?t.Side.Right:t.Side.Left:0>e.y?t.Side.Bottom:t.Side.Top:t.Side.None},n.prototype.collidesWithSide=function(e){var i=this.collides(e);return i?Math.abs(i.x)>Math.abs(i.y)?this.x=Math.sqrt(Math.pow(this.x-t.x,2)+Math.pow(this.y-t.y,2))},n.prototype.clearActions=function(){this.actionQueue.clearActions()},n.prototype.easeTo=function(e,i,n,s){return void 0===s&&(s=t.EasingFunctions.Linear),this.actionQueue.add(new t.Internal.Actions.EaseTo(this,e,i,n,s)),this},n.prototype.moveTo=function(e,i,n){return this.actionQueue.add(new t.Internal.Actions.MoveTo(this,e,i,n)),this},n.prototype.moveBy=function(e,i,n){return this.actionQueue.add(new t.Internal.Actions.MoveBy(this,e,i,n)),this},n.prototype.rotateTo=function(e,i,n){return this.actionQueue.add(new t.Internal.Actions.RotateTo(this,e,i,n)),this},n.prototype.rotateBy=function(e,i,n){return this.actionQueue.add(new t.Internal.Actions.RotateBy(this,e,i,n)),this},n.prototype.scaleTo=function(e,i,n,s){return this.actionQueue.add(new t.Internal.Actions.ScaleTo(this,e,i,n,s)),this},n.prototype.scaleBy=function(e,i,n){return this.actionQueue.add(new t.Internal.Actions.ScaleBy(this,e,i,n)),this},n.prototype.blink=function(e,i,n){return void 0===n&&(n=1),this.actionQueue.add(new t.Internal.Actions.Blink(this,e,i,n)),this},n.prototype.fade=function(e,i){return this.actionQueue.add(new t.Internal.Actions.Fade(this,e,i)),this},n.prototype.delay=function(e){return this.actionQueue.add(new t.Internal.Actions.Delay(this,e)),this},n.prototype.die=function(){return this.actionQueue.add(new t.Internal.Actions.Die(this)),this},n.prototype.callMethod=function(e){return this.actionQueue.add(new t.Internal.Actions.CallMethod(this,e)),this},n.prototype.repeat=function(e){return e?(this.actionQueue.add(new t.Internal.Actions.Repeat(this,e,this.actionQueue.getActions())),this):(this.repeatForever(),this)},n.prototype.repeatForever=function(){return this.actionQueue.add(new t.Internal.Actions.RepeatForever(this,this.actionQueue.getActions())),this},n.prototype.follow=function(e,i){return i===void 0?this.actionQueue.add(new t.Internal.Actions.Follow(this,e)):this.actionQueue.add(new t.Internal.Actions.Follow(this,e,i)),this},n.prototype.meet=function(e,i){return i===void 0?this.actionQueue.add(new t.Internal.Actions.Meet(this,e)):this.actionQueue.add(new t.Internal.Actions.Meet(this,e,i)),this},n.prototype.asPromise=function(){var e=new t.Promise;return this.callMethod(function(){e.resolve()}),e},n.prototype._getCalculatedAnchor=function(){return new t.Point(this.getWidth()*this.anchor.x,this.getHeight()*this.anchor.y)},n.prototype.update=function(e,i){this._isInitialized||(this.onInitialize(e),this.eventDispatcher.publish("initialize",new t.InitializeEvent(e)),this._isInitialized=!0);var n=this.eventDispatcher;this.actionQueue.update(i),this.color&&(this.color.a=this.opacity);for(var s=0;this.traits.length>s;s++)this.traits[s].update(this,e,i);n.publish(t.EventType[t.EventType.Update],new t.UpdateEvent(i))},n.prototype.draw=function(e,i){var n=this._getCalculatedAnchor();if(e.save(),e.scale(this.scale.x,this.scale.y),e.translate(this.x,this.y),e.rotate(this.rotation),this.previousOpacity!==this.opacity){for(var s in this.frames)this.frames[s].addEffect(new t.Effects.Opacity(this.opacity));this.previousOpacity=this.opacity}if(this.currentDrawing){var o=0,r=0;this.centerDrawingX&&(o=(this.currentDrawing.naturalWidth*this.currentDrawing.scale.x-this.getWidth())/2-this.currentDrawing.naturalWidth*this.currentDrawing.scale.x*this.currentDrawing.anchor.x),this.centerDrawingY&&(r=(this.currentDrawing.naturalHeight*this.currentDrawing.scale.y-this.getHeight())/2-this.currentDrawing.naturalHeight*this.currentDrawing.scale.y*this.currentDrawing.anchor.y),this.currentDrawing.draw(e,-n.x-o,-n.y-r)}else this.color&&(e.fillStyle=""+this.color,e.fillRect(-n.x,-n.y,this._width,this._height));for(var h=0;this.children.length>h;h++)this.children[h].draw(e,i);e.restore()},n.prototype.debugDraw=function(e){var i=this.getBounds();i.debugDraw(e),e.fillText("id: "+this.id,i.left+3,i.top+10),e.fillStyle=""+t.Color.Yellow,e.beginPath(),e.arc(this.getWorldX(),this.getWorldY(),3,0,2*Math.PI),e.closePath(),e.fill();for(var n=0;this.traits.length>n;n++)this.traits[n]instanceof t.Traits.OffscreenCulling&&this.traits[n].cullingBox.debugDraw(e);e.strokeStyle=""+t.Color.Yellow,e.beginPath();var s=Math.min(this.getWidth(),this.getHeight());e.arc(this.getWorldX(),this.getWorldY(),s,0,2*Math.PI),e.closePath(),e.stroke();var o={"0 Pi":0,"Pi/2":Math.PI/2,Pi:Math.PI,"3/2 Pi":3*Math.PI/2},r=e.font;for(var h in o)e.fillStyle=""+t.Color.Yellow,e.font="14px",e.textAlign="center",e.fillText(h,this.getWorldX()+Math.cos(o[h])*(s+10),this.getWorldY()+Math.sin(o[h])*(s+10));e.font=r,e.save(),e.translate(this.x,this.y),e.rotate(this.rotation);for(var a=0;this.children.length>a;a++)this.children[a].debugDraw(e);e.restore()},n.maxId=0,n}(t.Class);t.Actor=e,function(t){t[t.PreventCollision=0]="PreventCollision",t[t.Passive=1]="Passive",t[t.Active=2]="Active",t[t.Elastic=3]="Elastic",t[t.Fixed=4]="Fixed"}(t.CollisionType||(t.CollisionType={}));var i=t.CollisionType})(ex||(ex={}));var ex;(function(t){(function(t){t[t.Debug=0]="Debug",t[t.Info=1]="Info",t[t.Warn=2]="Warn",t[t.Error=3]="Error",t[t.Fatal=4]="Fatal"})(t.LogLevel||(t.LogLevel={}));var e=t.LogLevel,i=function(){function t(){if(this._appenders=[],this.defaultLevel=e.Info,t._instance)throw Error("Logger is a singleton");return t._instance=this,t._instance.addAppender(new n),t._instance}return t.getInstance=function(){return null==t._instance&&(t._instance=new t),t._instance},t.prototype.addAppender=function(t){this._appenders.push(t)},t.prototype.clearAppenders=function(){this._appenders.length=0},t.prototype._log=function(t,e){null==t&&(t=this.defaultLevel);var i=0,n=this._appenders.length;for(i;n>i;i++)t>=this.defaultLevel&&this._appenders[i].log(t,e)},t.prototype.debug=function(){for(var t=[],i=0;arguments.length>i;i++)t[i-0]=arguments[i];this._log(e.Debug,t)},t.prototype.info=function(){for(var t=[],i=0;arguments.length>i;i++)t[i-0]=arguments[i];this._log(e.Info,t)},t.prototype.warn=function(){for(var t=[],i=0;arguments.length>i;i++)t[i-0]=arguments[i];this._log(e.Warn,t)},t.prototype.error=function(){for(var t=[],i=0;arguments.length>i;i++)t[i-0]=arguments[i];this._log(e.Error,t)},t.prototype.fatal=function(){for(var t=[],i=0;arguments.length>i;i++)t[i-0]=arguments[i];this._log(e.Fatal,t)},t._instance=null,t}();t.Logger=i;var n=function(){function t(){}return t.prototype.log=function(t,i){if(console||console.log||!console.warn||!console.error){var n=[];n.unshift.apply(n,i),n.unshift("["+e[t]+"] : "),e.Warn>t?console.log.apply?console.log.apply(console,n):console.log(n.join(" ")):e.Error>t?console.warn.apply?console.warn.apply(console,n):console.warn(n.join(" ")):console.error.apply?console.error.apply(console,n):console.error(n.join(" "))}},t}();t.ConsoleAppender=n;var s=function(){function t(t,e){this._messages=[],this._canvas=document.createElement("canvas"),this._canvas.width=t||window.innerWidth,this._canvas.height=e||window.innerHeight,this._canvas.style.position="absolute",this._ctx=this._canvas.getContext("2d"),document.body.appendChild(this._canvas)}return t.prototype.log=function(t,i){var n=i.join(",");this._ctx.clearRect(0,0,this._canvas.width,this._canvas.height),this._messages.unshift("["+e[t]+"] : "+n);for(var s=10,o=1,r=0;this._messages.length>r;r++)this._ctx.fillStyle="rgba(255,255,255,"+o.toFixed(2)+")",this._ctx.fillText(this._messages[r],200,s),s+=10,o=o>0?o-.05:0},t}();t.ScreenAppender=s})(ex||(ex={}));var ex;(function(t){(function(t){t[t.Collision=0]="Collision",t[t.EnterViewPort=1]="EnterViewPort",t[t.ExitViewPort=2]="ExitViewPort",t[t.Blur=3]="Blur",t[t.Focus=4]="Focus",t[t.Update=5]="Update",t[t.Activate=6]="Activate",t[t.Deactivate=7]="Deactivate",t[t.Initialize=8]="Initialize"})(t.EventType||(t.EventType={})),t.EventType;var e=function(){function t(){}return t}();t.GameEvent=e;var i=function(t){function e(e,i){t.call(this),this.topic=e,this.handler=i}return __extends(e,t),e}(e);t.SubscribeEvent=i;var n=function(t){function e(e,i){t.call(this),this.topic=e,this.handler=i}return __extends(e,t),e}(e);t.UnsubscribeEvent=n;var s=function(t){function e(){t.call(this)}return __extends(e,t),e}(e);t.VisibleEvent=s;var o=function(t){function e(){t.call(this)}return __extends(e,t),e}(e);t.HiddenEvent=o;var r=function(t){function e(e,i,n,s){t.call(this),this.actor=e,this.other=i,this.side=n,this.intersection=s}return __extends(e,t),e}(e);t.CollisionEvent=r;var h=function(t){function e(e){t.call(this),this.delta=e}return __extends(e,t),e}(e);t.UpdateEvent=h;var a=function(t){function e(e){t.call(this),this.engine=e}return __extends(e,t),e}(e);t.InitializeEvent=a;var c=function(t){function e(e){t.call(this),this.oldScene=e}return __extends(e,t),e}(e);t.ActivateEvent=c;var u=function(t){function e(e){t.call(this),this.newScene=e}return __extends(e,t),e}(e);t.DeactivateEvent=u;var l=function(t){function e(){t.call(this)}return __extends(e,t),e}(e);t.ExitViewPortEvent=l;var p=function(t){function e(){t.call(this)}return __extends(e,t),e}(e);t.EnterViewPortEvent=p})(ex||(ex={}));var ex;(function(t){var e=function(){function e(e){this._handlers={},this._wiredEventDispatchers=[],this._log=t.Logger.getInstance(),this._target=e}return e.prototype.publish=function(e,i){if(e){e=e.toLowerCase();var n=this._target;i||(i=new t.GameEvent),i.target=n;var s,o;if(this._handlers[e])for(s=0,o=this._handlers[e].length,s;o>s;s++)this._handlers[e][s].call(n,i);for(s=0,o=this._wiredEventDispatchers.length,s;o>s;s++)this._wiredEventDispatchers[s].publish(e,i)}},e.prototype.emit=function(t,e){this.publish(t,e)},e.prototype.subscribe=function(e,i){e=e.toLowerCase(),this._handlers[e]||(this._handlers[e]=[]),this._handlers[e].push(i),"unsubscribe"!==e&&"subscribe"!==e&&this.emit("subscribe",new t.SubscribeEvent(e,i))},e.prototype.unsubscribe=function(e,i){e=e.toLowerCase();var n=this._handlers[e];if(n)if(i){var s=n.indexOf(i);this._handlers[e].splice(s,1)}else this._handlers[e].length=0;"unsubscribe"!==e&&"subscribe"!==e&&this.emit("unsubscribe",new t.UnsubscribeEvent(e,i))},e.prototype.wire=function(t){t._wiredEventDispatchers.push(this)},e.prototype.unwire=function(t){var e=t._wiredEventDispatchers.indexOf(this);e>-1&&t._wiredEventDispatchers.splice(e,1)},e}();t.EventDispatcher=e})(ex||(ex={}));var ex;(function(t){var e=function(){function t(t,e,i,n){this.r=t,this.g=e,this.b=i,this.a=null!=n?n:1}return t.fromRGB=function(e,i,n,s){return new t(e,i,n,s)},t.fromHex=function(e){var i=/^#?([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})?$/i,n=null;if(n=e.match(i)){var s=parseInt(n[1],16),o=parseInt(n[2],16),r=parseInt(n[3],16),h=1;return n[4]&&(h=parseInt(n[4],16)/255),new t(s,o,r,h)}throw Error("Invalid hex string: "+e)},t.fromHSL=function(t,e,n,s){void 0===s&&(s=1);var o=new i(t,e,n,s);return o.toRGBA()},t.prototype.lighten=function(t){void 0===t&&(t=.1);var e=i.fromRGBA(this.r,this.g,this.b,this.a);return e.l+=e.l*t,e.toRGBA()},t.prototype.darken=function(t){void 0===t&&(t=.1);var e=i.fromRGBA(this.r,this.g,this.b,this.a);return e.l-=e.l*t,e.toRGBA()},t.prototype.saturate=function(t){void 0===t&&(t=.1);var e=i.fromRGBA(this.r,this.g,this.b,this.a);return e.s+=e.s*t,e.toRGBA()},t.prototype.desaturate=function(t){void 0===t&&(t=.1);var e=i.fromRGBA(this.r,this.g,this.b,this.a);return e.s-=e.s*t,e.toRGBA()},t.prototype.mulitiply=function(e){var i=255*(e.r/255*this.r/255),n=255*(e.g/255*this.g/255),s=255*(e.b/255*this.b/255),o=e.a*this.a;return new t(i,n,s,o)},t.prototype.screen=function(t){var e=t.invert(),i=t.invert();return e.mulitiply(i).invert()},t.prototype.invert=function(){return new t(255-this.r,255-this.g,255-this.b,1-this.a)},t.prototype.average=function(e){var i=(e.r+this.r)/2,n=(e.g+this.g)/2,s=(e.b+this.b)/2,o=(e.a+this.a)/2;return new t(i,n,s,o)},t.prototype.toString=function(){var t=this.r.toFixed(0)+""+", "+(this.g.toFixed(0)+"")+", "+(this.b.toFixed(0)+"");return void 0!==this.a||null!==this.a?"rgba("+t+", "+(this.a+"")+")":"rgb("+t+")"},t.prototype.fillStyle=function(){return""+this},t.prototype.clone=function(){return new t(this.r,this.g,this.b,this.a)},t.Black=t.fromHex("#000000"),t.White=t.fromHex("#FFFFFF"),t.Gray=t.fromHex("#808080"),t.LightGray=t.fromHex("#D3D3D3"),t.DarkGray=t.fromHex("#A9A9A9"),t.Yellow=t.fromHex("#FFFF00"),t.Orange=t.fromHex("#FFA500"),t.Red=t.fromHex("#FF0000"),t.Vermillion=t.fromHex("#FF5B31"),t.Rose=t.fromHex("#FF007F"),t.Magenta=t.fromHex("#FF00FF"),t.Violet=t.fromHex("#7F00FF"),t.Blue=t.fromHex("#0000FF"),t.Azure=t.fromHex("#007FFF"),t.Cyan=t.fromHex("#00FFFF"),t.Viridian=t.fromHex("#59978F"),t.Green=t.fromHex("#00FF00"),t.Chartreuse=t.fromHex("#7FFF00"),t.Transparent=t.fromHex("#FFFFFF00"),t}();t.Color=e;var i=function(){function t(t,e,i,n){this.h=t,this.s=e,this.l=i,this.a=n}return t.fromRGBA=function(e,i,n,s){e/=255,i/=255,n/=255;var o,r,h=Math.max(e,i,n),a=Math.min(e,i,n),c=(h+a)/2;if(h===a)o=r=0;else{var u=h-a;switch(r=c>.5?u/(2-h-a):u/(h+a),h){case e:o=(i-n)/u+(n>i?6:0);break;case i:o=(n-e)/u+2;break;case n:o=(e-i)/u+4}o/=6}return new t(o,r,c,s)},t.prototype.toRGBA=function(){function t(t,e,i){return 0>i&&(i+=1),i>1&&(i-=1),1/6>i?t+6*(e-t)*i:.5>i?e:2/3>i?t+6*(e-t)*(2/3-i):t}var i,n,s;if(0===this.s)i=n=s=this.l;else{var o=.5>this.l?this.l*(1+this.s):this.l+this.s-this.l*this.s,r=2*this.l-o;i=t(r,o,this.h+1/3),n=t(r,o,this.h),s=t(r,o,this.h-1/3)}return new e(255*i,255*n,255*s,this.a)},t}()})(ex||(ex={}));var ex;(function(t){var e=function(e){function i(i,n,s,o){e.call(this,i,n,s,o),this.traits=[],this.traits.push(new t.Traits.Movement),this.traits.push(new t.Traits.CapturePointer),this.anchor.setTo(0,0),this.collisionType=t.CollisionType.PreventCollision,this.enableCapturePointer=!0}return __extends(i,e),i.prototype.onInitialize=function(t){this._engine=t},i.prototype.contains=function(i,n,s){if(void 0===s&&(s=!0),s)return e.prototype.contains.call(this,i,n);var o=this._engine.worldToScreenCoordinates(new t.Point(i,n));return e.prototype.contains.call(this,o.x,o.y)},i}(t.Actor);t.UIActor=e})(ex||(ex={}));var ex;(function(t){var e=function(e){function i(i,n,s,o,r,h){e.call(this,i,n,s,o),this._action=function(){},this.repeats=1,this.target=null,this.repeats=h||this.repeats,this._action=r||this._action,this.collisionType=t.CollisionType.PreventCollision,this.eventDispatcher=new t.EventDispatcher(this),this.actionQueue=new t.Internal.Actions.ActionQueue(this)}return __extends(i,e),i.prototype.update=function(e,i){if(this.actionQueue.update(i),this.x+=this.dx*i/1e3,this.y+=this.dy*i/1e3,this.rotation+=this.rx*i/1e3,this.scale.x+=this.sx*i/1e3,this.scale.y+=this.sy*i/1e3,this.target)this.collides(this.target)&&this._dispatchAction();else for(var n=0;e.currentScene.children.length>n;n++){var s=e.currentScene.children[n];s!==this&&s.collisionType!==t.CollisionType.PreventCollision&&this.collides(s)&&this._dispatchAction()}0===this.repeats&&this.kill()},i.prototype._dispatchAction=function(){this._action.call(this),this.repeats--},i.prototype.draw=function(){},i.prototype.debugDraw=function(i){e.prototype.debugDraw.call(this,i),i.save(),i.translate(this.x,this.y);var n=this.getBounds();n.left=n.left-this.getWorldX(),n.right=n.right-this.getWorldX(),n.top=n.top-this.getWorldY(),n.bottom=n.bottom-this.getWorldY(),i.fillStyle=""+t.Color.Violet,i.strokeStyle=""+t.Color.Violet,i.fillText("Trigger",10,10),n.debugDraw(i),i.restore()},i}(t.Actor);t.Trigger=e})(ex||(ex={}));var ex;(function(t){(function(t){t[t.Circle=0]="Circle",t[t.Rectangle=1]="Rectangle"})(t.EmitterType||(t.EmitterType={}));var e=t.EmitterType,i=function(){function e(e,i,n,s,o,r,h,a,c,u){this.position=new t.Vector(0,0),this.velocity=new t.Vector(0,0),this.acceleration=new t.Vector(0,0),this.particleRotationalVelocity=0,this.currentRotation=0,this.focus=null,this.focusAccel=0,this.opacity=1,this.beginColor=t.Color.White.clone(),this.endColor=t.Color.White.clone(),this.life=300,this.fadeFlag=!1,this._rRate=1,this._gRate=1,this._bRate=1,this._aRate=0,this._currentColor=t.Color.White.clone(),this.emitter=null,this.particleSize=5,this.particleSprite=null,this.sizeRate=0,this.elapsedMultiplier=0,this.emitter=e,this.life=i||this.life,this.opacity=n||this.opacity,this.endColor=o||this.endColor.clone(),this.beginColor=s||this.beginColor.clone(),this._currentColor=this.beginColor.clone(),this.position=r||this.position,this.velocity=h||this.velocity,this.acceleration=a||this.acceleration,this._rRate=(this.endColor.r-this.beginColor.r)/this.life,this._gRate=(this.endColor.g-this.beginColor.g)/this.life,this._bRate=(this.endColor.b-this.beginColor.b)/this.life,this._aRate=this.opacity/this.life,this.startSize=c||0,this.endSize=u||0,this.endSize>0&&this.startSize>0&&(this.sizeRate=(this.endSize-this.startSize)/this.life,this.particleSize=this.startSize)}return e.prototype.kill=function(){this.emitter.removeParticle(this)},e.prototype.update=function(e){if(this.life=this.life-e,this.elapsedMultiplier=this.elapsedMultiplier+e,0>this.life&&this.kill(),this.fadeFlag&&(this.opacity=t.Util.clamp(this._aRate*this.life,1e-4,1)),this.startSize>0&&this.endSize>0&&(this.particleSize=t.Util.clamp(this.sizeRate*e+this.particleSize,Math.min(this.startSize,this.endSize),Math.max(this.startSize,this.endSize))),this._currentColor.r=t.Util.clamp(this._currentColor.r+this._rRate*e,0,255),this._currentColor.g=t.Util.clamp(this._currentColor.g+this._gRate*e,0,255),this._currentColor.b=t.Util.clamp(this._currentColor.b+this._bRate*e,0,255),this._currentColor.a=t.Util.clamp(this.opacity,1e-4,1),this.focus){var i=this.focus.minus(this.position).normalize().scale(this.focusAccel).scale(e/1e3);this.velocity=this.velocity.add(i)}else this.velocity=this.velocity.add(this.acceleration.scale(e/1e3));this.position=this.position.add(this.velocity.scale(e/1e3)),this.particleRotationalVelocity&&(this.currentRotation=(this.currentRotation+this.particleRotationalVelocity*e/1e3)%(2*Math.PI))},e.prototype.draw=function(e){return this.particleSprite?(this.particleSprite.rotation=this.currentRotation,this.particleSprite.scale.setTo(this.particleSize,this.particleSize),this.particleSprite.draw(e,this.position.x,this.position.y),void 0):(this._currentColor.a=t.Util.clamp(this.opacity,1e-4,1),e.fillStyle=""+this._currentColor,e.beginPath(),e.arc(this.position.x,this.position.y,this.particleSize,0,2*Math.PI),e.fill(),e.closePath(),void 0) -},e}();t.Particle=i;var n=function(n){function s(i,s,o,r){n.call(this,i,s,o,r,t.Color.White),this._particlesToEmit=0,this.numParticles=0,this.isEmitting=!0,this.particles=null,this.deadParticles=null,this.minVel=0,this.maxVel=0,this.acceleration=new t.Vector(0,0),this.minAngle=0,this.maxAngle=0,this.emitRate=1,this.particleLife=2e3,this.opacity=1,this.fadeFlag=!1,this.focus=null,this.focusAccel=1,this.startSize=null,this.endSize=null,this.minSize=5,this.maxSize=5,this.beginColor=t.Color.White,this.endColor=t.Color.White,this.particleSprite=null,this.emitterType=e.Rectangle,this.radius=0,this.particleRotationalVelocity=0,this.randomRotation=!1,this.collisionType=t.CollisionType.PreventCollision,this.particles=new t.Util.Collection,this.deadParticles=new t.Util.Collection;for(var h in this.traits)this.traits[h]instanceof t.Traits.OffscreenCulling&&this.traits.splice(h,1)}return __extends(s,n),s.prototype.removeParticle=function(t){this.deadParticles.push(t)},s.prototype.emit=function(t){for(var e=0;t>e;e++)this.particles.push(this._createParticle())},s.prototype.clearParticles=function(){this.particles.clear()},s.prototype._createParticle=function(){var n=0,s=0,o=t.Util.randomInRange(this.minAngle,this.maxAngle),r=t.Util.randomInRange(this.minVel,this.maxVel),h=this.startSize||t.Util.randomInRange(this.minSize,this.maxSize),a=r*Math.cos(o),c=r*Math.sin(o);if(this.emitterType===e.Rectangle)n=t.Util.randomInRange(this.x,this.x+this.getWidth()),s=t.Util.randomInRange(this.y,this.y+this.getHeight());else if(this.emitterType===e.Circle){var u=t.Util.randomInRange(0,this.radius);n=u*Math.cos(o)+this.x,s=u*Math.sin(o)+this.y}var l=new i(this,this.particleLife,this.opacity,this.beginColor,this.endColor,new t.Vector(n,s),new t.Vector(a,c),this.acceleration,this.startSize,this.endSize);return l.fadeFlag=this.fadeFlag,l.particleSize=h,this.particleSprite&&(l.particleSprite=this.particleSprite),l.particleRotationalVelocity=this.particleRotationalVelocity,this.randomRotation&&(l.currentRotation=t.Util.randomInRange(0,2*Math.PI)),this.focus&&(l.focus=this.focus.add(new t.Vector(this.x,this.y)),l.focusAccel=this.focusAccel),l},s.prototype.update=function(t,e){var i=this;n.prototype.update.call(this,t,e),this.isEmitting&&(this._particlesToEmit+=this.emitRate*(e/1e3),this._particlesToEmit>1&&(this.emit(Math.floor(this._particlesToEmit)),this._particlesToEmit=this._particlesToEmit-Math.floor(this._particlesToEmit))),this.particles.forEach(function(t){return t.update(e)}),this.deadParticles.forEach(function(t){return i.particles.removeElement(t)}),this.deadParticles.clear()},s.prototype.draw=function(t){this.particles.forEach(function(e){return e.draw(t)})},s.prototype.debugDraw=function(e){n.prototype.debugDraw.call(this,e),e.fillStyle=""+t.Color.Black,e.fillText("Particles: "+this.particles.count(),this.x,this.y+20),this.focus&&(e.fillRect(this.focus.x+this.x,this.focus.y+this.y,3,3),t.Util.drawLine(e,"yellow",this.focus.x+this.x,this.focus.y+this.y,n.prototype.getCenter.call(this).x,n.prototype.getCenter.call(this).y),e.fillText("Focus",this.focus.x+this.x,this.focus.y+this.y))},s}(t.Actor);t.ParticleEmitter=n})(ex||(ex={}));var ex;(function(t){var e=function(){function e(e,i,n,s){this.currentFrame=0,this._oldTime=Date.now(),this.anchor=new t.Point(0,0),this.rotation=0,this.scale=new t.Point(1,1),this.loop=!1,this.freezeFrame=-1,this.flipVertical=!1,this.flipHorizontal=!1,this.width=0,this.height=0,this.naturalWidth=0,this.naturalHeight=0,this.sprites=i,this.speed=n,this._engine=e,null!=s&&(this.loop=s),i&&i[0]&&(this.height=i[0]?i[0].height:0,this.width=i[0]?i[0].width:0,this.naturalWidth=i[0]?i[0].naturalWidth:0,this.naturalHeight=i[0]?i[0].naturalHeight:0)}return e.prototype.opacity=function(e){this.addEffect(new t.Effects.Opacity(e))},e.prototype.grayscale=function(){this.addEffect(new t.Effects.Grayscale)},e.prototype.invert=function(){this.addEffect(new t.Effects.Invert)},e.prototype.fill=function(e){this.addEffect(new t.Effects.Fill(e))},e.prototype.colorize=function(e){this.addEffect(new t.Effects.Colorize(e))},e.prototype.lighten=function(e){void 0===e&&(e=.1),this.addEffect(new t.Effects.Lighten(e))},e.prototype.darken=function(e){void 0===e&&(e=.1),this.addEffect(new t.Effects.Darken(e))},e.prototype.saturate=function(e){void 0===e&&(e=.1),this.addEffect(new t.Effects.Saturate(e))},e.prototype.desaturate=function(e){void 0===e&&(e=.1),this.addEffect(new t.Effects.Desaturate(e))},e.prototype.addEffect=function(t){for(var e in this.sprites)this.sprites[e].addEffect(t)},e.prototype.removeEffect=function(t){for(var e in this.sprites)this.sprites[e].removeEffect(t)},e.prototype.clearEffects=function(){for(var t in this.sprites)this.sprites[t].clearEffects()},e.prototype._setAnchor=function(t){for(var e in this.sprites)this.sprites[e].anchor.setTo(t.x,t.y)},e.prototype._setRotation=function(t){for(var e in this.sprites)this.sprites[e].rotation=t},e.prototype._setScale=function(t){for(var e in this.sprites)this.sprites[e].scale=t},e.prototype.reset=function(){this.currentFrame=0},e.prototype.isDone=function(){return!this.loop&&this.currentFrame>=this.sprites.length},e.prototype.tick=function(){var t=Date.now();t-this._oldTime>this.speed&&(this.currentFrame=this.loop?(this.currentFrame+1)%this.sprites.length:this.currentFrame+1,this._oldTime=t)},e.prototype._updateValues=function(){this._setAnchor(this.anchor),this._setRotation(this.rotation),this._setScale(this.scale)},e.prototype.skip=function(t){this.currentFrame=(this.currentFrame+t)%this.sprites.length},e.prototype.draw=function(e,i,n){this.tick(),this._updateValues();var s;this.currentFrame=this.sprites.length&&(s=this.sprites[t.Util.clamp(this.freezeFrame,0,this.sprites.length-1)],s.draw(e,i,n)),s&&(this.width=s.width,this.height=s.height)},e.prototype.play=function(t,e){this.reset(),this._engine.playAnimation(this,t,e)},e}();t.Animation=e})(ex||(ex={}));var ex;(function(t){var e;(function(e){var i=function(){function e(e,i){this._log=t.Logger.getInstance(),this.onload=function(){},this.onprogress=function(){},this.onerror=function(){},window.AudioContext?(this._log.debug("Using new Web Audio Api for "+e),this._soundImpl=new o(e,i)):(this._log.debug("Falling back to Audio Element for "+e),this._soundImpl=new n(e,i))}return e.prototype.setVolume=function(t){this._soundImpl.setVolume(t)},e.prototype.setLoop=function(t){this._soundImpl.setLoop(t)},e.prototype.load=function(){this._soundImpl.onload=this.onload,this._soundImpl.onprogress=this.onprogress,this._soundImpl.onerror=this.onerror,this._soundImpl.load()},e.prototype.isPlaying=function(){return this._soundImpl.isPlaying()},e.prototype.play=function(){return this._soundImpl.play()},e.prototype.pause=function(){this._soundImpl.pause()},e.prototype.stop=function(){this._soundImpl.stop()},e}();e.FallbackAudio=i;var n=function(){function e(e,i){var n=this;this.path=e,this._audioElements=Array(5),this._loadedAudio=null,this._isLoaded=!1,this._index=0,this._log=t.Logger.getInstance(),this._isPlaying=!1,this._currentOffset=0,this.onload=function(){},this.onprogress=function(){},this.onerror=function(){};for(var s=0;this._audioElements.length>s;s++)(function(t){n._audioElements[t]=new Audio})(s);i?this.setVolume(t.Util.clamp(i,0,1)):this.setVolume(1)}return e.prototype.isPlaying=function(){return this._isPlaying},e.prototype._audioLoaded=function(){this._isLoaded=!0},e.prototype.setVolume=function(t){var e=0,i=this._audioElements.length;for(e;i>e;e++)this._audioElements[e].volume=t},e.prototype.setLoop=function(t){var e=0,i=this._audioElements.length;for(e;i>e;e++)this._audioElements[e].loop=t},e.prototype.getLoop=function(){this._audioElements.some(function(t){return t.loop})},e.prototype.load=function(){var t=this,e=new XMLHttpRequest;e.open("GET",this.path,!0),e.responseType="blob",e.onprogress=this.onprogress,e.onerror=this.onerror,e.onload=function(i){return 200!==e.status?(t._log.error("Failed to load audio resource ",t.path," server responded with error code",e.status),t.onerror(e.response),t._isLoaded=!1,void 0):(t._loadedAudio=URL.createObjectURL(e.response),t._audioElements.forEach(function(e){e.src=t._loadedAudio}),t.onload(i),void 0)},e.send()},e.prototype.play=function(){var e=this;this._audioElements[this._index].load(),this._audioElements[this._index].play(),this._currentOffset=0;var i=new t.Promise;return this._isPlaying=!0,this.getLoop()||this._audioElements[this._index].addEventListener("ended",function(){e._isPlaying=!1,i.resolve(!0)}),this._index=(this._index+1)%this._audioElements.length,i},e.prototype.pause=function(){this._index=(this._index-1+this._audioElements.length)%this._audioElements.length,this._currentOffset=this._audioElements[this._index].currentTime,this._audioElements.forEach(function(t){t.pause()}),this._isPlaying=!1},e.prototype.stop=function(){this._audioElements.forEach(function(t){t.pause()}),this._isPlaying=!1},e}();if(e.AudioTag=n,window.AudioContext)var s=new window.AudioContext;var o=function(){function e(e,i){this._context=s,this._volume=this._context.createGain(),this._buffer=null,this._sound=null,this._path="",this._isLoaded=!1,this._loop=!1,this._isPlaying=!1,this._isPaused=!1,this._currentOffset=0,this._logger=t.Logger.getInstance(),this.onload=function(){},this.onprogress=function(){},this.onerror=function(){},this._path=e,this._volume.gain.value=i?t.Util.clamp(i,0,1):1}return e.prototype.setVolume=function(t){this._volume.gain.value=t},e.prototype.load=function(){var t=this,e=new XMLHttpRequest;e.open("GET",this._path),e.responseType="arraybuffer",e.onprogress=this.onprogress,e.onerror=this.onerror,e.onload=function(){return 200!==e.status?(t._logger.error("Failed to load audio resource ",t._path," server responded with error code",e.status),t.onerror(e.response),t._isLoaded=!1,void 0):(t._context.decodeAudioData(e.response,function(e){t._buffer=e,t._isLoaded=!0,t.onload(t)},function(){t._logger.error("Unable to decode "+t._path+" this browser may not fully support this format, or the file may be corrupt, "+"if this is an mp3 try removing id3 tags and album art from the file."),t._isLoaded=!1,t.onload(t)}),void 0)};try{e.send()}catch(i){console.error("Error loading sound! If this is a cross origin error, you must host your sound with your html and javascript.")}},e.prototype.setLoop=function(t){this._loop=t},e.prototype.isPlaying=function(){return this._isPlaying},e.prototype.play=function(){var e=this;if(this._isLoaded){this._sound=this._context.createBufferSource(),this._sound.buffer=this._buffer,this._sound.loop=this._loop,this._sound.connect(this._volume),this._volume.connect(this._context.destination),this._sound.start(0,this._currentOffset%this._buffer.duration),this._currentOffset=0;var i;return i=this._isPaused&&this._playPromise?this._playPromise:new t.Promise,this._isPaused=!1,this._isPlaying=!0,this._loop||(this._sound.onended=function(){e._isPlaying=!1,e._isPaused||i.resolve(!0)}.bind(this)),this._playPromise=i,i}return t.Promise.wrap(!0)},e.prototype.pause=function(){if(this._isPlaying)try{window.clearTimeout(this._playingTimer),this._sound.stop(0),this._currentOffset=this._context.currentTime,this._isPlaying=!1,this._isPaused=!0}catch(t){this._logger.warn("The sound clip",this._path,"has already been paused!")}},e.prototype.stop=function(){if(this._sound)try{window.clearTimeout(this._playingTimer),this._currentOffset=0,this._sound.stop(0),this._isPlaying=!1,this._isPaused=!1}catch(t){this._logger.warn("The sound clip",this._path,"has already been stopped!")}},e}();e.WebAudio=o})(e=t.Internal||(t.Internal={}))})(ex||(ex={}));var ex;(function(t){(function(t){t[t.Resolved=0]="Resolved",t[t.Rejected=1]="Rejected",t[t.Pending=2]="Pending"})(t.PromiseState||(t.PromiseState={}));var e=t.PromiseState,i=function(){function i(){this._state=e.Pending,this._successCallbacks=[],this._rejectCallback=function(){},this._logger=t.Logger.getInstance()}return i.wrap=function(t){var e=(new i).resolve(t);return e},i.join=function(){for(var t=[],e=0;arguments.length>e;e++)t[e-0]=arguments[e];var n=new i;if(!t||!t.length)return n.resolve();var s=t.length,o=0,r=0,h=[];return t.forEach(function(t){t.then(function(){o+=1,o===s?n.resolve():o+r+h.length===s&&n.reject(h)},function(){r+=1,o+r+h.length===s&&n.reject(h)}).error(function(t){h.push(t),h.length+o+r===s&&n.reject(h)})}),n},i.prototype.then=function(t,i){if(t&&(this._successCallbacks.push(t),this.state()===e.Resolved))try{t.call(this,this._value)}catch(n){this._handleError(n)}if(i&&(this._rejectCallback=i,this.state()===e.Rejected))try{i.call(this,this._value)}catch(n){this._handleError(n)}return this},i.prototype.error=function(t){return t&&(this._errorCallback=t),this},i.prototype.resolve=function(t){var i=this;if(this._state!==e.Pending)throw Error("Cannot resolve a promise that is not in a pending state!");this._value=t;try{this._state=e.Resolved,this._successCallbacks.forEach(function(t){t.call(i,i._value)})}catch(n){this._handleError(n)}return this},i.prototype.reject=function(t){if(this._state!==e.Pending)throw Error("Cannot reject a promise that is not in a pending state!");this._value=t;try{this._state=e.Rejected,this._rejectCallback.call(this,this._value)}catch(i){this._handleError(i)}return this},i.prototype.state=function(){return this._state},i.prototype._handleError=function(t){if(!this._errorCallback)throw t;this._errorCallback.call(this,t)},i}();t.Promise=i})(ex||(ex={}));var ex;(function(t){var e=function(){function e(e,i,n){void 0===n&&(n=!0),this.path=e,this.responseType=i,this.bustCache=n,this.data=null,this.logger=t.Logger.getInstance(),this.onprogress=function(){},this.oncomplete=function(){},this.onerror=function(){}}return e.prototype.isLoaded=function(){return!!this.data},e.prototype.wireEngine=function(t){this._engine=t},e.prototype._cacheBust=function(t){var e=/\?\w*=\w*/;return t+=e.test(t)?"&__="+Date.now():"?__="+Date.now()},e.prototype._start=function(){this.logger.debug("Started loading resource "+this.path)},e.prototype.load=function(){var e=this,i=new t.Promise,n=new XMLHttpRequest;return n.open("GET",this.bustCache?this._cacheBust(this.path):this.path,!0),n.responseType=this.responseType,n.onloadstart=function(t){e._start(t)},n.onprogress=this.onprogress,n.onerror=this.onerror,n.onload=function(){return 200!==n.status?(e.logger.error("Failed to load resource ",e.path," server responded with error code",n.status),e.onerror(n.response),i.resolve(n.response),void 0):(e.data=e.processDownload(n.response),e.oncomplete(),e.logger.debug("Completed loading resource",e.path),i.resolve(e.data),void 0)},n.send(),i},e.prototype.getData=function(){return this.data},e.prototype.processDownload=function(t){return URL.createObjectURL(t)},e}();t.Resource=e})(ex||(ex={}));var ex;(function(t){var e=function(e){function i(i,n){void 0===n&&(n=!0),e.call(this,i,"blob",n),this.path=i,this.bustCache=n,this.loaded=new t.Promise,this._isLoaded=!1,this._sprite=null,this._sprite=new t.Sprite(this,0,0,0,0)}return __extends(i,e),i.prototype.isLoaded=function(){return this._isLoaded},i.prototype.load=function(){var i=this,n=new t.Promise,s=e.prototype.load.call(this);return s.then(function(){i.image=new Image,i.image.addEventListener("load",function(){i._isLoaded=!0,i.width=i._sprite.swidth=i._sprite.naturalWidth=i._sprite.width=i.image.naturalWidth,i.height=i._sprite.sheight=i._sprite.naturalHeight=i._sprite.height=i.image.naturalHeight,i.loaded.resolve(i.image),n.resolve(i.image)}),i.image.src=e.prototype.getData.call(i)},function(){n.reject("Error loading texture.")}),n},i.prototype.asSprite=function(){return this._sprite},i}(t.Resource);t.Texture=e;var i=function(){function e(){for(var i=[],n=0;arguments.length>n;n++)i[n-0]=arguments[n];this._logger=t.Logger.getInstance(),this.onprogress=function(){},this.oncomplete=function(){},this.onerror=function(){},this.onload=function(){},this._isLoaded=!1,this._selectedFile="",this._wasPlayingOnHidden=!1,this._selectedFile="";for(var s=0;i.length>s;s++)if(e.canPlayFile(i[s])){this._selectedFile=i[s];break}this._selectedFile||(this._logger.warn("This browser does not support any of the audio files specified:",i.join(", ")),this._logger.warn("Attempting to use",i[0]),this._selectedFile=i[0]),this.sound=new t.Internal.FallbackAudio(this._selectedFile,1)}return e.canPlayFile=function(e){try{var i=new Audio,n=/.*\.([A-Za-z0-9]+)$/,s=e.match(n)[1];return i.canPlayType("audio/"+s)?!0:!1}catch(o){return t.Logger.getInstance().warn("Cannot determine audio support, assuming no support for the Audio Tag",o),!1}},e.prototype.wireEngine=function(t){var e=this;t&&(this._engine=t,this._engine.on("hidden",function(){t.pauseAudioWhenHidden&&e.isPlaying()&&(e._wasPlayingOnHidden=!0,e.pause())}),this._engine.on("visible",function(){t.pauseAudioWhenHidden&&e._wasPlayingOnHidden&&(e.play(),e._wasPlayingOnHidden=!1)}))},e.prototype.setVolume=function(t){this.sound&&this.sound.setVolume(t)},e.prototype.setLoop=function(t){this.sound&&this.sound.setLoop(t)},e.prototype.isPlaying=function(){return this.sound?this.sound.isPlaying():void 0},e.prototype.play=function(){return this.sound?this.sound.play():void 0},e.prototype.pause=function(){this.sound&&this.sound.pause()},e.prototype.stop=function(){this.sound&&this.sound.stop()},e.prototype.isLoaded=function(){return this._isLoaded},e.prototype.load=function(){var e=this,i=new t.Promise;return this._logger.debug("Started loading sound",this._selectedFile),this.sound.onprogress=this.onprogress,this.sound.onload=function(){e.oncomplete(),e._isLoaded=!0,e._logger.debug("Completed loading sound",e._selectedFile),i.resolve(e.sound)},this.sound.onerror=function(t){e.onerror(t),i.resolve(t)},this.sound.load(),i},e}();t.Sound=i;var n=function(){function e(t){this._resourceList=[],this._index=0,this._resourceCount=0,this._numLoaded=0,this._progressCounts={},this._totalCounts={},this.onprogress=function(){},this.oncomplete=function(){},this.onerror=function(){},t&&this.addResources(t)}return e.prototype.wireEngine=function(t){this._engine=t},e.prototype.addResource=function(t){var e=this._index++;this._resourceList.push(t),this._progressCounts[e]=0,this._totalCounts[e]=1,this._resourceCount++},e.prototype.addResources=function(t){var e=0,i=t.length;for(e;i>e;e++)this.addResource(t[e])},e.prototype._sumCounts=function(t){var e=0;for(var i in t)e+=0|t[i];return e},e.prototype.isLoaded=function(){return this._numLoaded===this._resourceCount},e.prototype.load=function(){function e(t,i){t[i]&&t[i].load().then(function(){e(t,i+1)})}var i=this,n=new t.Promise,s=this;if(0===this._resourceList.length)return s.oncomplete.call(s),n;var o=Array(this._resourceList.length),r=this._resourceList.length;return this._resourceList.forEach(function(t,e){i._engine&&t.wireEngine(i._engine),t.onprogress=function(t){var i=t.total,n=t.loaded;o[e]={loaded:n/i*(100/r),total:100};var h=o.reduce(function(t,e){return{loaded:t.loaded+e.loaded,total:100}},{loaded:0,total:100});s.onprogress.call(s,h)},t.oncomplete=t.onerror=function(){s._numLoaded++,s._numLoaded===s._resourceCount&&(s.onprogress.call(s,{loaded:100,total:100}),s.oncomplete.call(s),n.resolve())}}),e(this._resourceList,0),n},e}();t.Loader=n})(ex||(ex={}));var ex;(function(t){var e=function(){function e(){this.failedTests=[],this._criticalTests={canvasSupport:function(){var t=document.createElement("canvas");return!(!t.getContext||!t.getContext("2d"))},arrayBufferSupport:function(){var t=new XMLHttpRequest;t.open("GET","/");try{t.responseType="arraybuffer"}catch(e){return!1}return"arraybuffer"===t.responseType},dataUrlSupport:function(){var t=document.createElement("canvas");return 0===t.toDataURL("image/png").indexOf("data:image/png")},objectUrlSupport:function(){return"URL"in window&&"revokeObjectURL"in URL&&"createObjectURL"in URL},rgbaSupport:function(){var t=document.createElement("a").style;return t.cssText="background-color:rgba(150,255,150,.5)",(""+t.backgroundColor).indexOf("rgba")>-1}},this._warningTest={webAudioSupport:function(){return!!(window.AudioContext||window.webkitAudioContext||window.mozAudioContext||window.msAudioContext||window.oAudioContext)},webglSupport:function(){var t=document.createElement("canvas");return!(!t.getContext||!t.getContext("webgl"))}}}return e.prototype.test=function(){var e=!1;for(var i in this._criticalTests)this._criticalTests[i]()||(this.failedTests.push(i),t.Logger.getInstance().error("Critical browser feature missing, Excalibur requires:",i),e=!0);if(e)return!1;for(var n in this._warningTest)this._warningTest[n]()||t.Logger.getInstance().warn("Warning browser feature missing, Excalibur will have reduced performance:",n);return!0},e}();t.Detector=e})(ex||(ex={}));var ex;(function(t){var e=function(){function e(e){this.path=e,this._isLoaded=!1,this.logger=t.Logger.getInstance(),this.onprogress=function(){},this.oncomplete=function(){},this.onerror=function(){},this._innerElement=document.createElement("div"),this._innerElement.className="excalibur-template"}return e.prototype.wireEngine=function(t){this._engine=t},e.prototype.getTemplateString=function(){return this._isLoaded?this._htmlString:""},e.prototype._compile=function(){this._innerElement.innerHTML=this._htmlString,this._styleElements=this._innerElement.querySelectorAll("[data-style]"),this._textElements=this._innerElement.querySelectorAll("[data-text]")},e.prototype._evaluateExpresion=function(t,e){var i=Function("return "+t+";"),n=i.call(e);return n},e.prototype.apply=function(t){for(var e=this,i=0;this._styleElements.length>i;i++)(function(){var n={};e._styleElements[i].dataset.style.split(";").forEach(function(t){if(t){var e=t.split(":");n[e[0].trim()]=e[1].trim()}});for(var s in n)(function(){var o=n[s];e._styleElements[i].style[s]=e._evaluateExpresion(o,t)})()})();for(var n=0;this._textElements.length>n;n++)(function(){var i=e._textElements[n].dataset.text;e._textElements[n].innerText=e._evaluateExpresion(i,t)})();return 1===this._innerElement.children.length&&(this._innerElement=this._innerElement.firstChild),this._innerElement},e.prototype.load=function(){var e=this,i=new t.Promise,n=new XMLHttpRequest;return n.open("GET",this.path,!0),n.responseType="text",n.onprogress=this.onprogress,n.onerror=this.onerror,n.onload=function(){return 200!==n.status?(e.logger.error("Failed to load html template resource ",e.path," server responded with error code",n.status),e.onerror(n.response),e._isLoaded=!1,i.resolve("error"),void 0):(e._htmlString=n.response,e.oncomplete(),e.logger.debug("Completed loading template",e.path),e._compile(),e._isLoaded=!0,i.resolve(e._htmlString),void 0)},n.overrideMimeType&&n.overrideMimeType("text/plain; charset=x-user-defined"),n.send(),i},e.prototype.isLoaded=function(){return this._isLoaded},e}();t.Template=e;var i=function(){function t(t,e,i){this.parent=document.getElementById(t),this.template=e,this._ctx=i,this.update()}return t.prototype.listen=function(t,e,i){var n=this;i||(i=function(){n.update()}),t.addEventListener&&e.forEach(function(e){t.addEventListener(e,i)})},t.prototype.update=function(){var t=this._applyTemplate(this.template,this._ctx);t instanceof String&&(this.parent.innerHTML=t),t instanceof Node&&this.parent.lastChild!==t&&this.parent.appendChild(t)},t.prototype._applyTemplate=function(t,e){return t.isLoaded()?t.apply(e):void 0},t}();t.Binding=i})(ex||(ex={}));var ex;(function(t){(function(t){t[t.Left=0]="Left",t[t.Right=1]="Right",t[t.Center=2]="Center",t[t.Start=3]="Start",t[t.End=4]="End"})(t.TextAlign||(t.TextAlign={}));var e=t.TextAlign;(function(t){t[t.Top=0]="Top",t[t.Hanging=1]="Hanging",t[t.Middle=2]="Middle",t[t.Alphabetic=3]="Alphabetic",t[t.Ideographic=4]="Ideographic",t[t.Bottom=5]="Bottom"})(t.BaseAlign||(t.BaseAlign={}));var i=t.BaseAlign,n=function(n){function s(e,i,s,o,r){n.call(this,i,s),this.letterSpacing=0,this.caseInsensitive=!0,this._textShadowOn=!1,this._shadowOffsetX=0,this._shadowOffsetY=0,this._shadowColor=t.Color.Black.clone(),this._shadowColorDirty=!1,this._textSprites={},this._shadowSprites={},this._color=t.Color.Black.clone(),this.text=e||"",this.color=t.Color.Black.clone(),this.spriteFont=r,this.collisionType=t.CollisionType.PreventCollision,this.font=o||"10px sans-serif",r&&(this._textSprites=r.getTextSprites())}return __extends(s,n),s.prototype.getTextWidth=function(t){var e=t.font;t.font=this.font;var i=t.measureText(this.text).width;return t.font=e,i},s.prototype._lookupTextAlign=function(t){switch(t){case e.Left:return"left";case e.Right:return"right";case e.Center:return"center";case e.End:return"end";case e.Start:return"start";default:return"start"}},s.prototype._lookupBaseAlign=function(t){switch(t){case i.Alphabetic:return"alphabetic";case i.Bottom:return"bottom";case i.Hanging:return"hangin";case i.Ideographic:return"ideographic";case i.Middle:return"middle";case i.Top:return"top";default:return"alphabetic"}},s.prototype.setTextShadow=function(t,e,i){this._textShadowOn=!0,this._shadowOffsetX=t,this._shadowOffsetY=e,this._shadowColor=i.clone(),this._shadowColorDirty=!0;for(var n in this._textSprites)this._shadowSprites[n]=this._textSprites[n].clone()},s.prototype.clearTextShadow=function(){this._textShadowOn=!1,this._shadowOffsetX=0,this._shadowOffsetY=0,this._shadowColor=t.Color.Black.clone()},s.prototype.update=function(e,i){if(n.prototype.update.call(this,e,i),this.spriteFont&&(this._color!==this.color||this.previousOpacity!==this.opacity)){for(var s in this._textSprites)this._textSprites[s].clearEffects(),this._textSprites[s].fill(this.color.clone()),this._textSprites[s].opacity(this.opacity);this._color=this.color,this.previousOpacity=this.opacity}if(this.spriteFont&&this._textShadowOn&&this._shadowColorDirty&&this._shadowColor){for(var o in this._shadowSprites)this._shadowSprites[o].clearEffects(),this._shadowSprites[o].addEffect(new t.Effects.Fill(this._shadowColor.clone()));this._shadowColorDirty=!1}},s.prototype.draw=function(t,e){t.save(),t.translate(this.x,this.y),t.scale(this.scale.x,this.scale.y),t.rotate(this.rotation),this._textShadowOn&&(t.save(),t.translate(this._shadowOffsetX,this._shadowOffsetY),this._fontDraw(t,e,this._shadowSprites),t.restore()),this._fontDraw(t,e,this._textSprites),n.prototype.draw.call(this,t,e),t.restore()},s.prototype._fontDraw=function(e,i,n){if(this.spriteFont)for(var s=0,o=0;this.text.length>o;o++){var r=this.text[o];this.caseInsensitive&&(r=r.toLowerCase());try{var h=n[r];h.draw(e,s,0),s+=h.swidth+this.letterSpacing}catch(a){t.Logger.getInstance().error("SpriteFont Error drawing char "+r)}}else{var c=e.textAlign,u=e.textBaseline;e.textAlign=this._lookupTextAlign(this.textAlign),e.textBaseline=this._lookupBaseAlign(this.baseAlign),this.color&&(this.color.a=this.opacity),e.fillStyle=""+this.color,e.font=this.font,this.maxWidth?e.fillText(this.text,0,0,this.maxWidth):e.fillText(this.text,0,0),e.textAlign=c,e.textBaseline=u}},s.prototype.debugDraw=function(t){n.prototype.debugDraw.call(this,t)},s}(t.Actor);t.Label=n})(ex||(ex={}));var ex;(function(t){var e;(function(e){(function(t){t[t.Touch=0]="Touch",t[t.Mouse=1]="Mouse",t[t.Pen=2]="Pen",t[t.Unknown=3]="Unknown"})(e.PointerType||(e.PointerType={}));var i=e.PointerType;(function(t){t[t.Left=0]="Left",t[t.Middle=1]="Middle",t[t.Right=2]="Right",t[t.Unknown=3]="Unknown"})(e.PointerButton||(e.PointerButton={}));var n=e.PointerButton;(function(t){t[t.Canvas=0]="Canvas",t[t.Document=1]="Document"})(e.PointerScope||(e.PointerScope={}));var s=e.PointerScope,o=function(t){function e(e,i,n,s,o,r){t.call(this),this.x=e,this.y=i,this.index=n,this.pointerType=s,this.button=o,this.ev=r}return __extends(e,t),e}(t.GameEvent);e.PointerEvent=o;var r=function(e){function r(t){e.call(this),this._pointerDown=[],this._pointerUp=[],this._pointerMove=[],this._pointerCancel=[],this._pointers=[],this._activePointers=[],this._engine=t,this._pointers.push(new h),this._activePointers=[-1],this.primary=this._pointers[0]}return __extends(r,e),r.prototype.init=function(t){void 0===t&&(t=s.Document);var e=document;e=t===s.Document?document:this._engine.canvas,e.addEventListener("touchstart",this._handleTouchEvent("down",this._pointerDown)),e.addEventListener("touchend",this._handleTouchEvent("up",this._pointerUp)),e.addEventListener("touchmove",this._handleTouchEvent("move",this._pointerMove)),e.addEventListener("touchcancel",this._handleTouchEvent("cancel",this._pointerCancel)),window.PointerEvent?(this._engine.canvas.style.touchAction="none",e.addEventListener("pointerdown",this._handlePointerEvent("down",this._pointerDown)),e.addEventListener("pointerup",this._handlePointerEvent("up",this._pointerUp)),e.addEventListener("pointermove",this._handlePointerEvent("move",this._pointerMove)),e.addEventListener("pointercancel",this._handlePointerEvent("cancel",this._pointerMove))):window.MSPointerEvent?(this._engine.canvas.style.msTouchAction="none",e.addEventListener("MSPointerDown",this._handlePointerEvent("down",this._pointerDown)),e.addEventListener("MSPointerUp",this._handlePointerEvent("up",this._pointerUp)),e.addEventListener("MSPointerMove",this._handlePointerEvent("move",this._pointerMove)),e.addEventListener("MSPointerCancel",this._handlePointerEvent("cancel",this._pointerMove))):(e.addEventListener("mousedown",this._handleMouseEvent("down",this._pointerDown)),e.addEventListener("mouseup",this._handleMouseEvent("up",this._pointerUp)),e.addEventListener("mousemove",this._handleMouseEvent("move",this._pointerMove)))},r.prototype.update=function(){this._pointerUp.length=0,this._pointerDown.length=0,this._pointerMove.length=0,this._pointerCancel.length=0},r.prototype.at=function(t){if(t>=this._pointers.length)for(var e=this._pointers.length-1,i=t;i>e;e++)this._pointers.push(new h),this._activePointers.push(-1);return this._pointers[t]},r.prototype.count=function(){return this._pointers.length},r.prototype.propogate=function(e){var i=e instanceof t.UIActor,n=0,s=this._pointerUp.length;for(n;s>n;n++)e.contains(this._pointerUp[n].x,this._pointerUp[n].y,!i)&&e.eventDispatcher.publish("pointerup",this._pointerUp[n]);for(n=0,s=this._pointerDown.length,n;s>n;n++)e.contains(this._pointerDown[n].x,this._pointerDown[n].y,!i)&&e.eventDispatcher.publish("pointerdown",this._pointerDown[n]);if(e.capturePointer.captureMoveEvents)for(n=0,s=this._pointerMove.length,n;s>n;n++)e.contains(this._pointerMove[n].x,this._pointerMove[n].y,!i)&&e.eventDispatcher.publish("pointermove",this._pointerMove[n]);for(n=0,s=this._pointerCancel.length,n;s>n;n++)e.contains(this._pointerCancel[n].x,this._pointerCancel[n].y,!i)&&e.eventDispatcher.publish("pointercancel",this._pointerCancel[n])},r.prototype._handleMouseEvent=function(e,n){var s=this;return function(r){r.preventDefault();var h=r.pageX-t.Util.getPosition(s._engine.canvas).x,a=r.pageY-t.Util.getPosition(s._engine.canvas).y,c=s._engine.screenToWorldCoordinates(new t.Point(h,a)),u=new o(c.x,c.y,0,i.Mouse,r.button,r);n.push(u),s.at(0).eventDispatcher.publish(e,u)}},r.prototype._handleTouchEvent=function(e,s){var r=this;return function(h){h.preventDefault();for(var a=0,c=h.changedTouches.length;c>a;a++){var u=r._pointers.length>1?r._getPointerIndex(h.changedTouches[a].identifier):0;if(-1!==u){var l=h.changedTouches[a].pageX-t.Util.getPosition(r._engine.canvas).x,p=h.changedTouches[a].pageY-t.Util.getPosition(r._engine.canvas).y,d=r._engine.screenToWorldCoordinates(new t.Point(l,p)),f=new o(d.x,d.y,u,i.Touch,n.Unknown,h);s.push(f),r.at(u).eventDispatcher.publish(e,f),r._pointers.length>1&&("up"===e?r._activePointers[u]=-1:"down"===e&&(r._activePointers[u]=h.changedTouches[a].identifier))}}}},r.prototype._handlePointerEvent=function(e,i){var n=this;return function(s){s.preventDefault();var r=n._pointers.length>1?n._getPointerIndex(s.pointerId):0;if(-1!==r){var h=s.pageX-t.Util.getPosition(n._engine.canvas).x,a=s.pageY-t.Util.getPosition(n._engine.canvas).y,c=n._engine.screenToWorldCoordinates(new t.Point(h,a)),u=new o(c.x,c.y,r,n._stringToPointerType(s.pointerType),s.button,s); -i.push(u),n.at(r).eventDispatcher.publish(e,u),n._pointers.length>1&&("up"===e?n._activePointers[r]=-1:"down"===e&&(n._activePointers[r]=s.pointerId))}}},r.prototype._getPointerIndex=function(t){var e;if((e=this._activePointers.indexOf(t))>-1)return e;for(var i=0;this._activePointers.length>i;i++)if(-1===this._activePointers[i])return i;return-1},r.prototype._stringToPointerType=function(t){switch(t){case"touch":return i.Touch;case"mouse":return i.Mouse;case"pen":return i.Pen;default:return i.Unknown}},r}(t.Class);e.Pointers=r;var h=function(t){function e(){t.apply(this,arguments)}return __extends(e,t),e}(t.Class);e.Pointer=h})(e=t.Input||(t.Input={}))})(ex||(ex={}));var ex;(function(t){var e;(function(e){(function(t){t[t.Num1=97]="Num1",t[t.Num2=98]="Num2",t[t.Num3=99]="Num3",t[t.Num4=100]="Num4",t[t.Num5=101]="Num5",t[t.Num6=102]="Num6",t[t.Num7=103]="Num7",t[t.Num8=104]="Num8",t[t.Num9=105]="Num9",t[t.Num0=96]="Num0",t[t.Numlock=144]="Numlock",t[t.Semicolon=186]="Semicolon",t[t.A=65]="A",t[t.B=66]="B",t[t.C=67]="C",t[t.D=68]="D",t[t.E=69]="E",t[t.F=70]="F",t[t.G=71]="G",t[t.H=72]="H",t[t.I=73]="I",t[t.J=74]="J",t[t.K=75]="K",t[t.L=76]="L",t[t.M=77]="M",t[t.N=78]="N",t[t.O=79]="O",t[t.P=80]="P",t[t.Q=81]="Q",t[t.R=82]="R",t[t.S=83]="S",t[t.T=84]="T",t[t.U=85]="U",t[t.V=86]="V",t[t.W=87]="W",t[t.X=88]="X",t[t.Y=89]="Y",t[t.Z=90]="Z",t[t.Shift=16]="Shift",t[t.Alt=18]="Alt",t[t.Up=38]="Up",t[t.Down=40]="Down",t[t.Left=37]="Left",t[t.Right=39]="Right",t[t.Space=32]="Space",t[t.Esc=27]="Esc"})(e.Keys||(e.Keys={})),e.Keys;var i=function(t){function e(e){t.call(this),this.key=e}return __extends(e,t),e}(t.GameEvent);e.KeyEvent=i;var n=function(t){function e(e){t.call(this),this._keys=[],this._keysUp=[],this._keysDown=[],this._engine=e}return __extends(e,t),e.prototype.init=function(){var t=this;window.addEventListener("blur",function(){t._keys.length=0}),window.addEventListener("keyup",function(e){var n=t._keys.indexOf(e.keyCode);t._keys.splice(n,1),t._keysUp.push(e.keyCode);var s=new i(e.keyCode);t.eventDispatcher.publish("up",s)}),window.addEventListener("keydown",function(e){if(-1===t._keys.indexOf(e.keyCode)){t._keys.push(e.keyCode),t._keysDown.push(e.keyCode);var n=new i(e.keyCode);t.eventDispatcher.publish("down",n)}})},e.prototype.update=function(){this._keysDown.length=0,this._keysUp.length=0},e.prototype.getKeys=function(){return this._keys},e.prototype.isKeyDown=function(t){return this._keysDown.indexOf(t)>-1},e.prototype.isKeyPressed=function(t){return this._keys.indexOf(t)>-1},e.prototype.isKeyUp=function(t){return this._keysUp.indexOf(t)>-1},e}(t.Class);e.Keyboard=n})(e=t.Input||(t.Input={}))})(ex||(ex={}));var ex;(function(t){var e;(function(e){var i=function(t){function e(e){t.call(this),this.enabled=!1,this.supported=!!navigator.getGamepads,this._gamePadTimeStamps=[0,0,0,0],this._oldPads=[],this._pads=[],this._initSuccess=!1,this._navigator=navigator,this._engine=e}return __extends(e,t),e.prototype.init=function(){this.supported&&(this._initSuccess||(this._oldPads=this._clonePads(this._navigator.getGamepads()),this._oldPads.length&&this._oldPads[0]&&(this._initSuccess=!0)))},e.prototype.update=function(){if(this.enabled&&this.supported){this.init();for(var t=this._navigator.getGamepads(),e=0;t.length>e;e++)if(t[e]){if(this.at(e).connected=!0,!t[e].timestamp||t[e].timestamp!==this._gamePadTimeStamps[e]){this._gamePadTimeStamps[e]=t[e].timestamp;var i,n,a,c,u;for(i in s)"number"==typeof s[i]&&(c=s[i],a=t[e].buttons[c].value,a!==this._oldPads[e].getButton(c)&&(t[e].buttons[c].pressed?(this.at(e).updateButton(c,a),this.at(e).eventDispatcher.publish("button",new r(c,a))):this.at(e).updateButton(c,0)));for(n in o)"number"==typeof o[n]&&(u=o[n],a=t[e].axes[u],a!==this._oldPads[e].getAxes(u)&&(this.at(e).updateAxes(u,a),this.at(e).eventDispatcher.publish("axis",new h(u,a))));this._oldPads[e]=this._clonePad(t[e])}}else this.at(e).connected=!1}},e.prototype.at=function(t){if(t>=this._pads.length)for(var e=this._pads.length-1,i=t;i>e;e++)this._pads.push(new n),this._oldPads.push(new n);return this._pads[t]},e.prototype.count=function(){return this._pads.filter(function(t){return t.connected}).length},e.prototype._clonePads=function(t){for(var e=[],i=0,n=t.length;n>i;i++)e.push(this._clonePad(t[i]));return e},e.prototype._clonePad=function(t){var e,i,s=new n;if(!t)return s;for(e=0,i=t.buttons.length;i>e;e++)s.updateButton(e,t.buttons[e].value);for(e=0,i=t.axes.length;i>e;e++)s.updateAxes(e,t.axes[e]);return s},e.MinAxisMoveThreshold=.05,e}(t.Class);e.Gamepads=i;var n=function(t){function e(){t.call(this),this.connected=!1,this._buttons=Array(16),this._axes=Array(4);var e;for(e=0;this._buttons.length>e;e++)this._buttons[e]=0;for(e=0;this._axes.length>e;e++)this._axes[e]=0}return __extends(e,t),e.prototype.isButtonPressed=function(t,e){return void 0===e&&(e=1),this._buttons[t]>=e},e.prototype.getButton=function(t){return this._buttons[t]},e.prototype.getAxes=function(t){var e=this._axes[t];return Math.abs(e)n;n++)this._animations[n].animation.draw(i,this._animations[n].x,this._animations[n].y);if(this.fps=1/(e/1e3),this.isDebug){this.ctx.font="Consolas",this.ctx.fillStyle=""+this.debugColor;for(var o=this.input.keyboard.getKeys(),r=0;o.length>r;r++)this.ctx.fillText(""+o[r]+" : "+(t.Input.Keys[o[r]]?t.Input.Keys[o[r]]:"Not Mapped"),100,10*r+10);this.ctx.fillText("FPS:"+(""+this.fps.toFixed(2)),10,10)}for(var h=0;this.postProcessors.length>h;h++)this.postProcessors[h].process(this.ctx.getImageData(0,0,this.width,this.height),this.ctx)},s.prototype.start=function(e){if(!this._compatible){var i=new t.Promise;return i.reject("Excalibur is incompatible with your browser")}var n;if(e?(e.wireEngine(this),n=this.load(e)):n=t.Promise.wrap(),!this._hasStarted){this._hasStarted=!0,this._logger.debug("Starting game...");var s=Date.now(),o=this;(function r(){if(o._hasStarted)try{o._requestId=window.requestAnimationFrame(r);var t=Date.now(),e=Math.floor(t-s)||1;e>200&&(e=1),o._update(e),o._draw(e),s=t}catch(i){window.cancelAnimationFrame(o._requestId),o.stop(),o.onFatalException(i)}})(),this._logger.debug("Game started")}return n},s.prototype.stop=function(){this._hasStarted&&(this._hasStarted=!1,this._logger.debug("Game stopped"))},s.prototype.screenshot=function(){var t=new Image,e=this.canvas.toDataURL("image/png");return t.src=e,t},s.prototype._drawLoadingBar=function(t,e,i){if(this._loadingDraw)return this._loadingDraw(t,e,i),void 0;var n=this.canvas.height/2,s=this.canvas.width/3,o=s,r=new Image;r.src="data:image/png;base64,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"; -var h=3*s/8,a=this.getAntialiasing();this.setAntialiasing(!0),t.drawImage(r,0,0,800,300,o,n-h-20,s,h),t.strokeStyle="white",t.lineWidth=2,t.strokeRect(o,n,s,20);var c=s*(e/i);t.fillStyle="white";var u=5,l=c-2*u,p=20-2*u;t.fillRect(o+u,n+u,l>0?l:0,p),this.setAntialiasing(a)},s.prototype.setLoadingDrawFunction=function(t){this._loadingDraw=t},s.prototype.load=function(e){var i=this,n=new t.Promise;return this._isLoading=!0,e.onprogress=function(t){i._progress=t.loaded,i._total=t.total,i._logger.debug("Loading "+(100*i._progress/i._total).toFixed(0))},e.oncomplete=function(){setTimeout(function(){i._isLoading=!1,n.resolve()},500)},e.load(),n},s}(t.Class);t.Engine=e,function(t){t[t.FullScreen=0]="FullScreen",t[t.Container=1]="Container",t[t.Fixed=2]="Fixed"}(t.DisplayMode||(t.DisplayMode={}));var i=t.DisplayMode,n=function(){function t(t,e,i){this.animation=t,this.x=e,this.y=i}return t}()})(ex||(ex={})); +* Copyright (c) 2016 ; Licensed BSD-2-Clause*/ +"undefined"==typeof window&&(window={audioContext:function(){}}),"undefined"==typeof window||window.requestAnimationFrame||(window.requestAnimationFrame=window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||function(t){window.setInterval(t,1e3/60)}),"undefined"==typeof window||window.cancelAnimationFrame||(window.cancelAnimationFrame=window.webkitCancelAnimationFrame||window.mozCancelAnimationFrame||function(){}),"undefined"==typeof window||window.AudioContext||(window.AudioContext=window.AudioContext||window.webkitAudioContext||window.mozAudioContext||window.msAudioContext||window.oAudioContext),Array.prototype.forEach||(Array.prototype.forEach=function(t,e){var i,n;if(null==this)throw new TypeError(" this is null or not defined");var s=Object(this),o=s.length>>>0;if("function"!=typeof t)throw new TypeError(t+" is not a function");for(arguments.length>1&&(i=e),n=0;o>n;){var r;n in s&&(r=s[n],t.call(i,r,n,s)),n++}}),Array.prototype.some||(Array.prototype.some=function(t){"use strict";if(void 0===this||null===this)throw new TypeError;var e=Object(this),i=e.length>>>0;if("function"!=typeof t)throw new TypeError;for(var n=arguments.length>=2?arguments[1]:void 0,s=0;i>s;s++)if(s in e&&t.call(n,e[s],s,e))return!0;return!1}),Function.prototype.bind||(Function.prototype.bind=function(t){if("function"!=typeof this)throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");var e=Array.prototype.slice.call(arguments,1),i=this,n=function(){},s=function(){return i.apply(this instanceof n&&t?this:t,e.concat(Array.prototype.slice.call(arguments)))};return n.prototype=this.prototype,s.prototype=new n,s});var ex;(function(t){var e;(function(e){var i=function(){function t(){}return t.prototype.updatePixel=function(t,e,i){var n=4*(t+e*i.width),s=i.data,o=(s[n+0]+s[n+1]+s[n+2])/3;s[n+0]=o,s[n+1]=o,s[n+2]=o},t}();e.Grayscale=i;var n=function(){function t(){}return t.prototype.updatePixel=function(t,e,i){var n=4*(t+e*i.width),s=i.data;s[n+0]=255-s[n+0],s[n+1]=255-s[n+1],s[n+2]=255-s[n+2]},t}();e.Invert=n;var s=function(){function t(t){this.opacity=t}return t.prototype.updatePixel=function(t,e,i){var n=4*(t+e*i.width),s=i.data;0!==s[n+3]&&(s[n+3]=Math.round(255*this.opacity))},t}();e.Opacity=s;var o=function(){function t(t){this.color=t}return t.prototype.updatePixel=function(t,e,i){var n=4*(t+e*i.width),s=i.data;0!==s[n+3]&&(s[n+0]=(s[n+0]+this.color.r)/2,s[n+1]=(s[n+1]+this.color.g)/2,s[n+2]=(s[n+2]+this.color.b)/2)},t}();e.Colorize=o;var r=function(){function e(t){void 0===t&&(t=.1),this.factor=t}return e.prototype.updatePixel=function(e,i,n){var s=4*(e+i*n.width),o=n.data,r=t.Color.fromRGB(o[s+0],o[s+1],o[s+2],o[s+3]).lighten(this.factor);o[s+0]=r.r,o[s+1]=r.g,o[s+2]=r.b,o[s+3]=r.a},e}();e.Lighten=r;var h=function(){function e(t){void 0===t&&(t=.1),this.factor=t}return e.prototype.updatePixel=function(e,i,n){var s=4*(e+i*n.width),o=n.data,r=t.Color.fromRGB(o[s+0],o[s+1],o[s+2],o[s+3]).darken(this.factor);o[s+0]=r.r,o[s+1]=r.g,o[s+2]=r.b,o[s+3]=r.a},e}();e.Darken=h;var a=function(){function e(t){void 0===t&&(t=.1),this.factor=t}return e.prototype.updatePixel=function(e,i,n){var s=4*(e+i*n.width),o=n.data,r=t.Color.fromRGB(o[s+0],o[s+1],o[s+2],o[s+3]).saturate(this.factor);o[s+0]=r.r,o[s+1]=r.g,o[s+2]=r.b,o[s+3]=r.a},e}();e.Saturate=a;var c=function(){function e(t){void 0===t&&(t=.1),this.factor=t}return e.prototype.updatePixel=function(e,i,n){var s=4*(e+i*n.width),o=n.data,r=t.Color.fromRGB(o[s+0],o[s+1],o[s+2],o[s+3]).desaturate(this.factor);o[s+0]=r.r,o[s+1]=r.g,o[s+2]=r.b,o[s+3]=r.a},e}();e.Desaturate=c;var l=function(){function t(t){this.color=t}return t.prototype.updatePixel=function(t,e,i){var n=4*(t+e*i.width),s=i.data;0!==s[n+3]&&(s[n+0]=this.color.r,s[n+1]=this.color.g,s[n+2]=this.color.b)},t}();e.Fill=l})(e=t.Effects||(t.Effects={}))})(ex||(ex={}));var ex;(function(t){var e;(function(t){var e=function(){function t(){}return t.prototype.update=function(t,e,i){t.x+=t.dx*i/1e3,t.y+=t.dy*i/1e3,t.dx+=t.ax*i/1e3,t.dy+=t.ay*i/1e3,t.rotation+=t.rx*i/1e3,t.scale.x+=t.sx*i/1e3,t.scale.y+=t.sy*i/1e3},t}();t.Movement=e})(e=t.Traits||(t.Traits={}))})(ex||(ex={}));var ex;(function(t){var e=function(){function e(){this._topLeft=new t.Point(0,0),this._topRight=new t.Point(0,0),this._bottomLeft=new t.Point(0,0),this._bottomRight=new t.Point(0,0)}return e.prototype.isSpriteOffScreen=function(e,i){var n=e.currentDrawing.width*e.currentDrawing.scale.x,s=e.currentDrawing.height*e.currentDrawing.scale.y,o=e.rotation,r=e.getCenter().toPoint();this._topLeft.x=e.getWorldX()-n/2,this._topLeft.y=e.getWorldY()-s/2,this._topLeft=this._topLeft.rotate(o,r),this._topRight.x=e.getWorldX()+n/2,this._topRight.y=e.getWorldY()-s/2,this._topRight=this._topRight.rotate(o,r),this._bottomLeft.x=e.getWorldX()-n/2,this._bottomLeft.y=e.getWorldY()+s/2,this._bottomLeft=this._bottomLeft.rotate(o,r),this._bottomRight.x=e.getWorldX()+n/2,this._bottomRight.y=e.getWorldY()+s/2,this._bottomRight=this._bottomRight.rotate(o,r);var h=i.worldToScreenCoordinates(this._topLeft),a=i.worldToScreenCoordinates(this._topRight),c=i.worldToScreenCoordinates(this._bottomLeft),l=i.worldToScreenCoordinates(this._bottomRight);this._xCoords=[],this._yCoords=[],this._xCoords.push(h.x,a.x,c.x,l.x),this._yCoords.push(h.y,a.y,c.y,l.y),this._xMin=Math.min.apply(null,this._xCoords),this._yMin=Math.min.apply(null,this._yCoords),this._xMax=Math.max.apply(null,this._xCoords),this._yMax=Math.max.apply(null,this._yCoords);var u=i.screenToWorldCoordinates(new t.Point(this._xMin,this._yMin)),p=i.screenToWorldCoordinates(new t.Point(this._xMax,this._yMax));this._xMinWorld=u.x,this._yMinWorld=u.y,this._xMaxWorld=p.x,this._yMaxWorld=p.y;var d=[];d.push(new t.Point(this._xMin,this._yMin),new t.Point(this._xMax,this._yMin),new t.Point(this._xMin,this._yMax),new t.Point(this._xMax,this._yMax));for(var f=0;d.length>f;f++)if(d[f].x>0&&d[f].y>0&&d[f].x0&&a.y+h*c>0&&a.xa.x+r*c||0>a.y+h*c||a.x>i.width||a.y>i.height)&&l&&(n.emit("exitviewport",new t.ExitViewPortEvent),e.isOffScreen=!0)},e}();e.OffscreenCulling=i})(e=t.Traits||(t.Traits={}))})(ex||(ex={}));var ex;(function(t){var e;(function(t){var e=function(){function t(){}return t.prototype.update=function(t,e){t.enableCapturePointer&&(t.isKilled()||e.input.pointers.propogate(t))},t}();t.CapturePointer=e})(e=t.Traits||(t.Traits={}))})(ex||(ex={}));var ex;(function(t){var e;(function(e){var i=function(){function e(){}return e.prototype.update=function(e,i){var n=e.eventDispatcher;if(e.collisionType!==t.CollisionType.PreventCollision&&i.currentScene&&i.currentScene.tileMaps)for(var s=0;i.currentScene.tileMaps.length>s;s++)for(var o,r=i.currentScene.tileMaps[s],h=t.Side.None,a=2,c=!1;(o=r.collides(e))&&!(0>a--);)h=e.getSideFromIntersect(o),n.emit("collision",new t.CollisionEvent(e,null,h,o)),(e.collisionType===t.CollisionType.Active||e.collisionType===t.CollisionType.Elastic)&&(e.y+=o.y,e.x+=o.x,e.collisionType!==t.CollisionType.Elastic||c||(c=!0,h===t.Side.Left?e.dx=Math.abs(e.dx):h===t.Side.Right?e.dx=-Math.abs(e.dx):h===t.Side.Top?e.dy=Math.abs(e.dy):h===t.Side.Bottom&&(e.dy=-Math.abs(e.dy))))},e}();e.CollisionDetection=i})(e=t.Traits||(t.Traits={}))})(ex||(ex={}));var ex;(function(t){(function(t){t[t.None=0]="None",t[t.Top=1]="Top",t[t.Bottom=2]="Bottom",t[t.Left=3]="Left",t[t.Right=4]="Right"})(t.Side||(t.Side={})),t.Side})(ex||(ex={}));var __extends=this&&this.__extends||function(t,e){function i(){this.constructor=t}for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n]);t.prototype=null===e?Object.create(e):(i.prototype=e.prototype,new i)},ex;(function(t){var e=function(){function e(t,e){this.x=t,this.y=e}return e.prototype.toVector=function(){return new i(this.x,this.y)},e.prototype.rotate=function(i,n){n||(n=new t.Point(0,0));var s=Math.sin(i),o=Math.cos(i),r=o*(this.x-n.x)-s*(this.y-n.y)+n.x,h=s*(this.x-n.x)+o*(this.y-n.y)+n.y;return new e(r,h)},e.prototype.add=function(t){return new e(this.x+t.x,this.y+t.y)},e.prototype.setTo=function(t,e){this.x=t,this.y=e},e.prototype.clone=function(){return new e(this.x,this.y)},e.prototype.equals=function(t){return this.x===t.x&&this.y===t.y},e}();t.Point=e;var i=function(t){function i(e,i){t.call(this,e,i),this.x=e,this.y=i}return __extends(i,t),i.fromAngle=function(t){return new i(Math.cos(t),Math.sin(t))},i.prototype.distance=function(t){return t||(t=new i(0,0)),Math.sqrt(Math.pow(this.x-t.x,2)+Math.pow(this.y-t.y,2))},i.prototype.normalize=function(){var t=this.distance();return t>0?new i(this.x/t,this.y/t):new i(0,1)},i.prototype.scale=function(t){return new i(this.x*t,this.y*t)},i.prototype.plus=function(t){return this.add(t)},i.prototype.add=function(t){return new i(this.x+t.x,this.y+t.y)},i.prototype.subtract=function(t){return this.minus(t)},i.prototype.minus=function(t){return new i(this.x-t.x,this.y-t.y)},i.prototype.dot=function(t){return this.x*t.x+this.y*t.y},i.prototype.cross=function(t){return this.x*t.y-this.y*t.x},i.prototype.perpendicular=function(){return new i(this.y,-this.x)},i.prototype.normal=function(){return this.perpendicular().normalize()},i.prototype.toAngle=function(){return Math.atan2(this.y,this.x)},i.prototype.toPoint=function(){return new e(this.x,this.y)},i.prototype.rotate=function(e,i){return t.prototype.rotate.call(this,e,i).toVector()},i.prototype.clone=function(){return new i(this.x,this.y)},i.Zero=new i(0,0),i}(e);t.Vector=i;var n=function(){function t(t,e){this.pos=t,this.dir=e.normalize()}return t.prototype.intersect=function(t){var e=t.begin.toVector().minus(this.pos.toVector());if(0===this.dir.cross(t.getSlope())&&0!==e.cross(this.dir))return-1;var i=this.dir.cross(t.getSlope());if(0===i)return-1;var n=e.cross(t.getSlope())/i;if(n>=0){var s=e.cross(this.dir)/i/t.getLength();if(s>=0&&1>=s)return n}return-1},t.prototype.getPoint=function(t){return this.pos.toVector().add(this.dir.scale(t)).toPoint()},t}();t.Ray=n;var s=function(){function t(t,e){this.begin=t,this.end=e}return t.prototype.getSlope=function(){var t=this.begin.toVector(),e=this.end.toVector(),i=t.distance(e);return e.minus(t).scale(1/i)},t.prototype.getLength=function(){var t=this.begin.toVector(),e=this.end.toVector(),i=t.distance(e);return i},t}();t.Line=s;var o=function(){function t(t,e){this.min=t,this.max=e}return t.prototype.overlaps=function(t){return this.max>t.min&&t.max>this.min},t.prototype.getOverlap=function(t){return this.overlaps(t)?this.max>t.max?t.max-this.min:this.max-t.min:0},t}();t.Projection=o})(ex||(ex={}));var ex;(function(t){var e;(function(e){function i(t){for(var e="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",i="",n=0;t.length>n;){var s,o,r=255&t.charCodeAt(n++),h=255&t.charCodeAt(n++),a=255&t.charCodeAt(n++),c=r>>2,l=(3&r)<<4|h>>4;isNaN(h)?s=o=64:(s=(15&h)<<2|a>>6,o=isNaN(a)?64:63&a),i+=e.charAt(c)+e.charAt(l)+e.charAt(s)+e.charAt(o)}return i}function n(t,e,i){return e>=t?e:t>=i?i:t}function s(t,e,i,n,s,o){t.beginPath(),t.strokeStyle=e,t.moveTo(i,n),t.lineTo(s,o),t.closePath(),t.stroke()}function o(t,e){return t+Math.random()*(e-t)}function r(t,e){return Math.round(o(t,e))}function h(t){var e=t;if(t>this.TwoPI)for(;e>this.TwoPI;)e-=this.TwoPI;if(0>t)for(;0>e;)e+=this.TwoPI;return e}function a(t){return 180/Math.PI*t}function c(t){return t/180*Math.PI}function l(e){var i=0,n=0,s=function(t){i+=t.offsetLeft,t.offsetParent&&s(t.offsetParent)},o=function(t){n+=t.offsetTop,t.offsetParent&&o(t.offsetParent)};return s(e),o(e),new t.Point(i,n)}function u(t,e){return-1===e.indexOf(t)?(e.push(t),!0):!1}function p(t,e){var i=-1;return(i=e.indexOf(t))>-1?(e.splice(i,1),!0):!1}function d(t,e){for(var i=0;t.length>i;i++)if(t[i]===e)return!0;return!1}function f(e){return e===t.Side.Top?t.Side.Bottom:e===t.Side.Bottom?t.Side.Top:e===t.Side.Left?t.Side.Right:e===t.Side.Right?t.Side.Left:t.Side.None}e.TwoPI=2*Math.PI,e.base64Encode=i,e.clamp=n,e.drawLine=s,e.randomInRange=o,e.randomIntInRange=r,e.canonicalizeAngle=h,e.toDegrees=a,e.toRadians=c,e.getPosition=l,e.addItemToArray=u,e.removeItemToArray=p,e.contains=d,e.getOppositeSide=f;var g=function(){function t(e){void 0===e&&(e=t.DefaultSize),this._internalArray=null,this._endPointer=0,this._internalArray=Array(e)}return t.prototype._resize=function(){for(var t=2*this._internalArray.length,e=Array(t),i=this.count(),n=0;i>n;n++)e[n]=this._internalArray[n];delete this._internalArray,this._internalArray=e},t.prototype.push=function(t){return this._endPointer===this._internalArray.length&&this._resize(),this._internalArray[this._endPointer++]=t},t.prototype.pop=function(){return this._endPointer=0>this._endPointer-1?0:this._endPointer-1,this._internalArray[this._endPointer]},t.prototype.count=function(){return this._endPointer},t.prototype.clear=function(){this._endPointer=0},t.prototype.internalSize=function(){return this._internalArray.length},t.prototype.elementAt=function(t){return t>=this.count()?void 0:this._internalArray[t]},t.prototype.insert=function(t,e){return t>=this.count()&&this._resize(),this._internalArray[t]=e},t.prototype.remove=function(t){var e=this.count();if(0!==e){for(var i=this._internalArray[t],n=t;e>n;n++)this._internalArray[n]=this._internalArray[n+1];return this._endPointer--,i}},t.prototype.removeElement=function(t){var e=this._internalArray.indexOf(t);this.remove(e)},t.prototype.toArray=function(){return this._internalArray.slice(0,this._endPointer)},t.prototype.forEach=function(t){var e=0,i=this.count();for(e;i>e;e++)t.call(this,this._internalArray[e],e)},t.prototype.map=function(t){for(var e=this.count(),i=0;e>i;i++)this._internalArray[i]=t.call(this,this._internalArray[i],i)},t.DefaultSize=200,t}();e.Collection=g})(e=t.Util||(t.Util={}))})(ex||(ex={}));var ex;(function(t){var e=function(){function e(e,i,n,s,o){var r=this;this.sx=i,this.sy=n,this.swidth=s,this.sheight=o,this.rotation=0,this.anchor=new t.Point(0,0),this.scale=new t.Point(1,1),this.logger=t.Logger.getInstance(),this.flipVertical=!1,this.flipHorizontal=!1,this.width=0,this.height=0,this.effects=[],this.internalImage=new Image,this.naturalWidth=0,this.naturalHeight=0,this._spriteCanvas=null,this._spriteCtx=null,this._pixelData=null,this._pixelsLoaded=!1,this._dirtyEffect=!1,(0>i||0>n||0>s||0>o)&&this.logger.error("Sprite cannot have any negative dimensions x:",i,"y:",n,"width:",s,"height:",o),this._texture=e,this._spriteCanvas=document.createElement("canvas"),this._spriteCanvas.width=s,this._spriteCanvas.height=o,this._spriteCtx=this._spriteCanvas.getContext("2d"),this._texture.loaded.then(function(){r._spriteCanvas.width=r._spriteCanvas.width||r._texture.image.naturalWidth,r._spriteCanvas.height=r._spriteCanvas.height||r._texture.image.naturalHeight,r._loadPixels(),r._dirtyEffect=!0}).error(function(t){r.logger.error("Error loading texture ",r._texture.path,t)}),this.width=s,this.height=o,this.naturalWidth=s,this.naturalHeight=o}return e.prototype._loadPixels=function(){if(this._texture.isLoaded()&&!this._pixelsLoaded){var e=t.Util.clamp,i=this._texture.image.naturalWidth||0,n=this._texture.image.naturalHeight||0;this.swidth>i&&this.logger.warn("The sprite width",this.swidth,"exceeds the width",i,"of the backing texture",this._texture.path),this.sheight>n&&this.logger.warn("The sprite height",this.sheight,"exceeds the height",n,"of the backing texture",this._texture.path),this._spriteCtx.drawImage(this._texture.image,e(this.sx,0,i),e(this.sy,0,n),e(this.swidth,0,i),e(this.sheight,0,n),0,0,this.swidth,this.sheight),this.internalImage.src=this._spriteCanvas.toDataURL("image/png"),this._pixelsLoaded=!0}},e.prototype.opacity=function(e){this.addEffect(new t.Effects.Opacity(e))},e.prototype.grayscale=function(){this.addEffect(new t.Effects.Grayscale)},e.prototype.invert=function(){this.addEffect(new t.Effects.Invert)},e.prototype.fill=function(e){this.addEffect(new t.Effects.Fill(e))},e.prototype.colorize=function(e){this.addEffect(new t.Effects.Colorize(e))},e.prototype.lighten=function(e){void 0===e&&(e=.1),this.addEffect(new t.Effects.Lighten(e))},e.prototype.darken=function(e){void 0===e&&(e=.1),this.addEffect(new t.Effects.Darken(e))},e.prototype.saturate=function(e){void 0===e&&(e=.1),this.addEffect(new t.Effects.Saturate(e))},e.prototype.desaturate=function(e){void 0===e&&(e=.1),this.addEffect(new t.Effects.Desaturate(e))},e.prototype.addEffect=function(t){this.effects.push(t),this._texture.isLoaded()&&this._pixelsLoaded?this._applyEffects():this._dirtyEffect=!0},e.prototype.removeEffect=function(t){var e=null;e="number"==typeof t?t:this.effects.indexOf(t),this.effects.splice(e,1),this._texture.isLoaded()&&this._pixelsLoaded?this._applyEffects():this._dirtyEffect=!0},e.prototype._applyEffects=function(){var e=t.Util.clamp,i=this._texture.image.naturalWidth||0,n=this._texture.image.naturalHeight||0;this._spriteCtx.clearRect(0,0,this.swidth,this.sheight),this._spriteCtx.drawImage(this._texture.image,e(this.sx,0,i),e(this.sy,0,n),e(this.swidth,0,i),e(this.sheight,0,n),0,0,this.swidth,this.sheight),this._pixelData=this._spriteCtx.getImageData(0,0,this.swidth,this.sheight);var s=0,o=0,r=0,h=this.effects.length;for(s;h>s;s++)for(r=0;this.sheight>r;r++)for(o=0;this.swidth>o;o++)this.effects[s].updatePixel(o,r,this._pixelData);this._spriteCtx.clearRect(0,0,this.swidth,this.sheight),this._spriteCtx.putImageData(this._pixelData,0,0),this.internalImage.src=this._spriteCanvas.toDataURL("image/png")},e.prototype.clearEffects=function(){this.effects.length=0,this._applyEffects()},e.prototype.reset=function(){},e.prototype.debugDraw=function(e,i,n){e.save(),e.translate(i,n),e.rotate(this.rotation);var s=this.width*this.scale.x*this.anchor.x,o=this.height*this.scale.y*this.anchor.y;e.strokeStyle=t.Color.Black,e.strokeRect(-s,-o,this.width*this.scale.x,this.height*this.scale.y),e.restore()},e.prototype.draw=function(t,e,i){this._dirtyEffect&&(this._applyEffects(),this._dirtyEffect=!1),this.width=this.naturalWidth*this.scale.x,this.height=this.naturalHeight*this.scale.y,t.save();var n=this.width*this.anchor.x,s=this.height*this.anchor.y;t.translate(e,i),t.rotate(this.rotation),this.flipHorizontal&&(t.translate(this.swidth*this.scale.x,0),t.scale(-1,1)),this.flipVertical&&(t.translate(0,this.sheight*this.scale.y),t.scale(1,-1)),this.internalImage&&t.drawImage(this.internalImage,0,0,this.swidth,this.sheight,-n,-s,this.swidth*this.scale.x,this.sheight*this.scale.y),t.restore()},e.prototype.clone=function(){var t=new e(this._texture,this.sx,this.sy,this.swidth,this.sheight);t.scale=this.scale.clone(),t.rotation=this.rotation,t.flipHorizontal=this.flipHorizontal,t.flipVertical=this.flipVertical;var i=0,n=this.effects.length;for(i;n>i;i++)t.addEffect(this.effects[i]);return t},e}();t.Sprite=e})(ex||(ex={}));var ex;(function(t){var e=function(){function e(e,i,n,s,o){this.image=e,this.columns=i,this.rows=n,this.sprites=[],this._internalImage=e.image,this.sprites=Array(i*n);var r=0,h=0;for(r=0;n>r;r++)for(h=0;i>h;h++)this.sprites[h+r*i]=new t.Sprite(this.image,h*s,r*o,s,o)}return e.prototype.getAnimationByIndices=function(e,i,n){var s=this,o=i.map(function(t){return s.sprites[t]});return o=o.map(function(t){return t.clone()}),new t.Animation(e,o,n)},e.prototype.getAnimationBetween=function(e,i,n,s){var o=this.sprites.slice(i,n);return o=o.map(function(t){return t.clone()}),new t.Animation(e,o,s)},e.prototype.getAnimationForAll=function(e,i){var n=this.sprites.map(function(t){return t.clone()});return new t.Animation(e,n,i)},e.prototype.getSprite=function(t){return t>=0&&this.sprites.length>t?this.sprites[t]:void 0},e}();t.SpriteSheet=e;var i=function(e){function i(i,n,s,o,r,h,a){e.call(this,i,o,r,h,a),this.image=i,this.alphabet=n,this.caseInsensitive=s,this.spWidth=h,this.spHeight=a,this._spriteLookup={},this._colorLookup={},this._currentColor=t.Color.Black.clone(),this._currentOpacity=1,this._sprites={},this._textShadowOn=!1,this._textShadowDirty=!0,this._textShadowColor=t.Color.Black.clone(),this._textShadowSprites={},this._shadowOffsetX=5,this._shadowOffsetY=5,this._sprites=this.getTextSprites()}return __extends(i,e),i.prototype.getTextSprites=function(){for(var t={},e=0;this.alphabet.length>e;e++){var i=this.alphabet[e];this.caseInsensitive&&(i=i.toLowerCase()),t[i]=this.sprites[e].clone()}return t},i.prototype.setTextShadow=function(t,e,i){this._textShadowOn=!0,this._shadowOffsetX=t,this._shadowOffsetY=e,this._textShadowColor=i.clone(),this._textShadowDirty=!0;for(var n in this._sprites)this._textShadowSprites[n]=this._sprites[n].clone()},i.prototype.useTextShadow=function(t){this._textShadowOn=t,t&&this.setTextShadow(5,5,this._textShadowColor)},i.prototype.draw=function(e,i,n,s,o){if(o=this._parseOptions(o),""+this._currentColor!=""+o.color||this._currentOpacity!==o.opacity){this._currentOpacity=o.opacity,this._currentColor=o.color;for(var r in this._sprites)this._sprites[r].clearEffects(),this._sprites[r].fill(o.color),this._sprites[r].opacity(o.opacity)}if(this._textShadowOn&&this._textShadowDirty&&this._textShadowColor){for(var h in this._textShadowSprites)this._textShadowSprites[h].clearEffects(),this._textShadowSprites[h].addEffect(new t.Effects.Fill(this._textShadowColor.clone()));this._textShadowDirty=!1}var a=this.sprites[0],c=a.sheight,l=o.fontSize/c,u=i.length*a.swidth*l+i.length*o.letterSpacing,p=n;o.textAlign===t.TextAlign.Left||o.textAlign===t.TextAlign.Start?p=n:o.textAlign===t.TextAlign.Right||o.textAlign===t.TextAlign.End?p=n-u:o.textAlign===t.TextAlign.Center&&(p=n-u/2);var d=s-c*l;o.baseAlign===t.BaseAlign.Top||o.baseAlign===t.BaseAlign.Hanging?d=s:o.baseAlign===t.BaseAlign.Ideographic||o.baseAlign===t.BaseAlign.Bottom||o.baseAlign===t.BaseAlign.Alphabetic?d=s-c*l:o.baseAlign===t.BaseAlign.Middle&&(d=s-c*l/2);for(var f=0;i.length>f;f++){var g=i[f];this.caseInsensitive&&(g=g.toLowerCase());try{this._textShadowOn&&(this._textShadowSprites[g].scale.x=l,this._textShadowSprites[g].scale.y=l,this._textShadowSprites[g].draw(e,p+this._shadowOffsetX,d+this._shadowOffsetY));var _=this._sprites[g];_.scale.x=l,_.scale.y=l,_.draw(e,p,d),p+=_.width+o.letterSpacing}catch(y){t.Logger.getInstance().error("SpriteFont Error drawing char "+g)}}},i.prototype._parseOptions=function(e){return{fontSize:e.fontSize||10,letterSpacing:e.letterSpacing||0,color:e.color||t.Color.Black.clone(),textAlign:void 0===typeof e.textAlign?t.TextAlign.Left:e.textAlign,baseAlign:void 0===typeof e.baseAlign?t.BaseAlign.Bottom:e.baseAlign,maxWidth:e.maxWidth||-1,opacity:e.opacity||0}},i}(e);t.SpriteFont=i})(ex||(ex={}));var ex;(function(t){var e=function(){function e(e,i,s,o,r,h){var a=this;this.x=e,this.y=i,this.cellWidth=s,this.cellHeight=o,this.rows=r,this.cols=h,this._collidingX=-1,this._collidingY=-1,this._onScreenXStart=0,this._onScreenXEnd=9999,this._onScreenYStart=0,this._onScreenYEnd=9999,this._spriteSheets={},this.logger=t.Logger.getInstance(),this.data=[],this.data=Array(r*h);for(var c=0;h>c;c++)for(var l=0;r>l;l++)(function(){var t=new n(c*s+e,l*o+i,s,o,c+l*h);a.data[c+l*h]=t})()}return e.prototype.registerSpriteSheet=function(t,e){this._spriteSheets[t]=e},e.prototype.collides=function(e){for(var i=e.x+e.getWidth(),n=e.y+e.getHeight(),s=e.getBounds(),o=[],r=s.left;i>=r;r+=Math.min(e.getWidth()/2,this.cellWidth/2))for(var h=s.top;n>=h;h+=Math.min(e.getHeight()/2,this.cellHeight/2)){var a=this.getCellByPoint(r,h);if(a&&a.solid){var c=s.collides(a.getBounds()),l=e.getCenter().minus(a.getCenter());c&&c.dot(l)>0&&o.push(c)}}if(0===o.length)return null;var u=o.reduce(function(e,i){var n=e.x,s=e.y;return Math.abs(e.x)t||0>e||t>=this.cols||e>=this.rows?null:this.data[t+e*this.cols]},e.prototype.getCellByPoint=function(t,e){t=Math.floor((t-this.x)/this.cellWidth),e=Math.floor((e-this.y)/this.cellHeight);var i=this.getCell(t,e);return t>=0&&e>=0&&this.cols>t&&this.rows>e&&i?i:null},e.prototype.update=function(e){var i=e.screenToWorldCoordinates(new t.Point(0,0)),n=e.screenToWorldCoordinates(new t.Point(e.canvas.clientWidth,e.canvas.clientHeight));this._onScreenXStart=Math.max(Math.floor(i.x/this.cellWidth)-2,0),this._onScreenYStart=Math.max(Math.floor((i.y-this.y)/this.cellHeight)-2,0),this._onScreenXEnd=Math.max(Math.floor(n.x/this.cellWidth)+2,0),this._onScreenYEnd=Math.max(Math.floor((n.y-this.y)/this.cellHeight)+2,0)},e.prototype.draw=function(t){t.save(),t.translate(this.x,this.y);var e,i,n,s=this._onScreenXStart,o=Math.min(this._onScreenXEnd,this.cols),r=this._onScreenYStart,h=Math.min(this._onScreenYEnd,this.rows);for(s;o>s;s++){for(r;h>r;r++)for(e=this.getCell(s,r).sprites.filter(function(t){return t.spriteId>-1}),i=0,n=e.length;n>i;i++){var a=this._spriteSheets[e[i].spriteSheetKey];if(a){var c=a.getSprite(e[i].spriteId);c?c.draw(t,s*this.cellWidth,r*this.cellHeight):this.logger.warn("Sprite does not exist for id",e[i].spriteId,"in sprite sheet",e[i].spriteSheetKey,c,a)}else this.logger.warn("Sprite sheet",e[i].spriteSheetKey,"does not exist",a)}r=this._onScreenYStart}t.restore()},e.prototype.debugDraw=function(e){var i=this.cols*this.cellWidth,n=this.rows*this.cellHeight;e.save(),e.strokeStyle=""+t.Color.Red;for(var s=0;this.cols+1>s;s++)e.beginPath(),e.moveTo(this.x+s*this.cellWidth,this.y),e.lineTo(this.x+s*this.cellWidth,this.y+n),e.stroke();for(var o=0;this.rows+1>o;o++)e.beginPath(),e.moveTo(this.x,this.y+o*this.cellHeight),e.lineTo(this.x+i,this.y+o*this.cellHeight),e.stroke();var r=t.Color.Red.clone();r.a=.3,this.data.filter(function(t){return t.solid}).forEach(function(t){e.fillStyle=""+r,e.fillRect(t.x,t.y,t.width,t.height)}),this._collidingY>-1&&this._collidingX>-1&&(e.fillStyle=""+t.Color.Cyan,e.fillRect(this.x+this._collidingX*this.cellWidth,this.y+this._collidingY*this.cellHeight,this.cellWidth,this.cellHeight)),e.restore()},e}();t.TileMap=e;var i=function(){function t(t,e){this.spriteSheetKey=t,this.spriteId=e}return t}();t.TileSprite=i;var n=function(){function e(e,i,n,s,o,r,h){void 0===r&&(r=!1),void 0===h&&(h=[]),this.x=e,this.y=i,this.width=n,this.height=s,this.index=o,this.solid=r,this.sprites=h,this._bounds=new t.BoundingBox(this.x,this.y,this.x+this.width,this.y+this.height)}return e.prototype.getBounds=function(){return this._bounds},e.prototype.getCenter=function(){return new t.Vector(this.x+this.width/2,this.y+this.height/2)},e.prototype.pushSprite=function(t){this.sprites.push(t)},e.prototype.removeSprite=function(t){var e=-1;(e=this.sprites.indexOf(t))>-1&&this.sprites.splice(e,1)},e.prototype.clearSprites=function(){this.sprites.length=0},e}();t.Cell=n})(ex||(ex={}));var ex;(function(t){(function(t){t[t.Naive=0]="Naive",t[t.DynamicAABBTree=1]="DynamicAABBTree",t[t.SeparatingAxis=2]="SeparatingAxis"})(t.CollisionStrategy||(t.CollisionStrategy={})),t.CollisionStrategy;var e=function(){function e(t,e,i,n){void 0===t&&(t=0),void 0===e&&(e=0),void 0===i&&(i=0),void 0===n&&(n=0),this.left=t,this.top=e,this.right=i,this.bottom=n}return e.prototype.getWidth=function(){return this.right-this.left},e.prototype.getHeight=function(){return this.bottom-this.top},e.prototype.getPerimeter=function(){var t=this.getWidth(),e=this.getHeight();return 2*(t+e)},e.prototype.contains=function(i){return i instanceof t.Point?this.left<=i.x&&this.top<=i.y&&this.bottom>=i.y&&this.right>=i.x:i instanceof e?this.left=n.left&&this.right<=n.right?n.left-this.right:n.right-this.left;var r=0;return r=this.top<=n.bottom&&this.top>=n.top?n.bottom-this.top:n.top-this.bottom,Math.abs(o)n;n++)e.push(new t.Line(this._points[n],this._points[(n+1)%i]));return e},e.prototype.getAxes=function(){for(var t=[],e=this._points.length,i=0;e>i;i++)t.push(this._points[i].minus(this._points[(i+1)%e]).normal());return t},e.prototype.project=function(e){for(var i=[],n=this._points.length,s=0;n>s;s++)i.push(this._points[s].dot(e));return new t.Projection(Math.min.apply(Math,i),Math.max.apply(Math,i))},e.prototype.getWidth=function(){var t=this._points.reduce(function(t,e){return Math.min(t,e.x)},1/0),e=this._points.reduce(function(t,e){return Math.max(t,e.x)},-1/0);return e-t},e.prototype.getHeight=function(){var t=this._points.reduce(function(t,e){return Math.min(t,e.y)},1/0),e=this._points.reduce(function(t,e){return Math.max(t,e.y)},-1/0);return t-e},e.prototype.contains=function(e){var i=new t.Ray(e,new t.Vector(1,0)),n=this.getSides().reduce(function(t,e){return i.intersect(e)>=0?t+1:t},0);return 0===n%2?!1:!0},e.prototype.collides=function(t){if(t instanceof e){var i=t,n=this.getAxes();n=i.getAxes().concat(n);for(var s=99999,o=null,r=0;n.length>r;r++){var h=this.project(n[r]),a=i.project(n[r]),c=h.getOverlap(a);if(0===c)return null;s>=c&&(s=c,o=n[r])}return o?o.normalize().scale(s):null}return null},e.prototype.debugDraw=function(e){e.beginPath(),e.lineWidth=2;var i=this._points[0];e.moveTo(i.x,i.y);var n=0,s=this._points.length;for(n;s>n;n++)e.lineTo(this._points[n].x,this._points[n].y);e.lineTo(i.x,i.y),e.closePath(),e.strokeStyle=""+t.Color.Blue,e.stroke()},e}();t.SATBoundingBox=i})(ex||(ex={}));var ex;(function(t){var e=function(){function e(){this.eventDispatcher=new t.EventDispatcher(this)}return e.prototype.addEventListener=function(t,e){this.eventDispatcher.subscribe(t,e)},e.prototype.removeEventListener=function(t,e){this.eventDispatcher.unsubscribe(t,e)},e.prototype.on=function(t,e){this.eventDispatcher.subscribe(t,e)},e.prototype.off=function(t,e){this.eventDispatcher.unsubscribe(t,e)},e.prototype.emit=function(t,e){this.eventDispatcher.emit(t,e)},e.extend=function(t){var i,n=this;i=t&&t.hasOwnProperty("constructor")?t.constructor:function(){return n.apply(this,arguments)};var s=function(){this.constructor=i};if(s.prototype=n.prototype,i.prototype=new s,t)for(var o in t)t.hasOwnProperty(o)&&(i.prototype[o]=t[o]);return i.extend=e.extend,i},e}();t.Class=e})(ex||(ex={})); +var ex;(function(t){var e=function(){function t(e,i,n){this.id=0,this.interval=10,this.fcn=function(){},this.repeats=!1,this._elapsedTime=0,this._totalTimeAlive=0,this.complete=!1,this.scene=null,this.id=t.id++,this.interval=i||this.interval,this.fcn=e||this.fcn,this.repeats=n||this.repeats}return t.prototype.update=function(t){this._totalTimeAlive+=t,this._elapsedTime+=t,this._elapsedTime>this.interval&&(this.fcn.call(this),this.repeats?this._elapsedTime=0:this.complete=!0)},t.prototype.getTimeRunning=function(){return this._totalTimeAlive},t.prototype.cancel=function(){this.scene&&this.scene.cancelTimer(this)},t.id=0,t}();t.Timer=e})(ex||(ex={}));var ex;(function(t){var e=function(){function e(){}return e.prototype.register=function(){},e.prototype.remove=function(){},e.prototype.evaluate=function(e){for(var i,n,s=e.filter(function(e){return!e.isKilled()&&e.collisionType!==t.CollisionType.PreventCollision}),o=[],r=0,h=s.length;h>r;r++){i=s[r];for(var a=r+1;h>a;a++){n=s[a];var c;if(c=i.collides(n)){var l=i.getSideFromIntersect(c),u=new t.CollisionPair(i,n,c,l);o.some(function(t){return t.equals(u)})||o.push(u)}}}var p=0,d=o.length;for(p;d>p;p++)o[p].evaluate();return o},e.prototype.update=function(){return 0},e.prototype.debugDraw=function(){},e}();t.NaiveCollisionResolver=e})(ex||(ex={}));var ex;(function(t){var e=function(){function e(e){this.parent=e,this.parent=e||null,this.actor=null,this.bounds=new t.BoundingBox,this.left=null,this.right=null,this.height=0}return e.prototype.isLeaf=function(){return!this.left&&!this.right},e}();t.TreeNode=e;var i=function(){function t(){this.root=null,this.nodes={}}return t.prototype.insert=function(t){if(null===this.root)return this.root=t,this.root.parent=null,void 0;for(var i=t.bounds,n=this.root;!n.isLeaf();){var s,o,r=n.left,h=n.right,a=n.bounds.getPerimeter(),c=n.bounds.combine(i),l=c.getPerimeter(),u=2*l,p=2*(l-a),d=0,f=i.combine(r.bounds);r.isLeaf()?d=f.getPerimeter()+p:(o=r.bounds.getPerimeter(),s=f.getPerimeter(),d=s-o+p);var g=0,_=i.combine(h.bounds);if(h.isLeaf()?g=_.getPerimeter()+p:(o=h.bounds.getPerimeter(),s=_.getPerimeter(),g=s-o+p),d>u&&g>u)break;n=g>d?r:h}var y=n.parent,A=new e(y);A.bounds=i.combine(n.bounds),A.height=n.height+1,null!==y?(y.left===n?y.left=A:y.right=A,A.left=n,A.right=t,n.parent=A,t.parent=A):(A.left=n,A.right=t,n.parent=A,t.parent=A,this.root=A);for(var v=t.parent;v;){if(v=this.balance(v),!v.left)throw Error("Parent of current leaf cannot have a null left child"+v);if(!v.right)throw Error("Parent of current leaf cannot have a null right child"+v);v.height=1+Math.max(v.left.height,v.right.height),v.bounds=v.left.bounds.combine(v.right.bounds),v=v.parent}},t.prototype.remove=function(t){if(t===this.root)return this.root=null,void 0;var e,i=t.parent,n=i.parent;if(e=i.left===t?i.right:i.left,n){n.left===i?n.left=e:n.right=e,e.parent=n;for(var s=n;s;)s=this.balance(s),s.bounds=s.left.bounds.combine(s.right.bounds),s.height=1+Math.max(s.left.height,s.right.height),s=s.parent}else this.root=e,e.parent=null},t.prototype.registerActor=function(t){var i=new e;i.actor=t,i.bounds=t.getBounds(),i.bounds.left-=2,i.bounds.top-=2,i.bounds.right+=2,i.bounds.bottom+=2,this.nodes[t.id]=i,this.insert(i)},t.prototype.updateActor=function(t){var e=this.nodes[t.id];if(e){var i=t.getBounds();if(e.bounds.contains(i))return!1;this.remove(e),i.left-=5,i.top-=5,i.right+=5,i.bottom+=5;var n=2*t.dx,s=2*t.dy;return 0>n?i.left+=n:i.right+=n,0>s?i.top+=s:i.bottom+=s,e.bounds=i,this.insert(e),!0}},t.prototype.removeActor=function(t){var e=this.nodes[t.id];e&&(this.remove(e),this.nodes[t.id]=null,delete this.nodes[t.id])},t.prototype.balance=function(t){if(null===t)throw Error("Cannot balance at null node");if(t.isLeaf()||2>t.height)return t;var e=t.left,i=t.right,n=t,s=e,o=i,r=e.left,h=e.right,a=i.left,c=i.right,l=o.height-s.height;if(l>1)return o.left=n,o.parent=n.parent,n.parent=o,o.parent?o.parent.left===n?o.parent.left=o:o.parent.right=o:this.root=o,a.height>c.height?(o.right=a,n.right=c,c.parent=n,n.bounds=s.bounds.combine(c.bounds),o.bounds=n.bounds.combine(a.bounds),n.height=1+Math.max(s.height,c.height),o.height=1+Math.max(n.height,a.height)):(o.right=c,n.right=a,a.parent=n,n.bounds=s.bounds.combine(a.bounds),o.bounds=n.bounds.combine(c.bounds),n.height=1+Math.max(s.height,a.height),o.height=1+Math.max(n.height,c.height)),o;if(-1>l){if(s.left=n,s.parent=n.parent,n.parent=s,s.parent)if(s.parent.left===n)s.parent.left=s;else{if(s.parent.right!==n)throw"Error rotating Dynamic Tree";s.parent.right=s}else this.root=s;return r.height>h.height?(s.right=r,n.left=h,h.parent=n,n.bounds=o.bounds.combine(h.bounds),s.bounds=n.bounds.combine(r.bounds),n.height=1+Math.max(o.height,h.height),s.height=1+Math.max(n.height,r.height)):(s.right=h,n.left=r,r.parent=n,n.bounds=o.bounds.combine(r.bounds),s.bounds=n.bounds.combine(h.bounds),n.height=1+Math.max(o.height,r.height),s.height=1+Math.max(n.height,h.height)),s}return t},t.prototype.getHeight=function(){return null===this.root?0:this.root.height},t.prototype.query=function(t,e){var i=t.getBounds(),n=function(s){return s&&s.bounds.collides(i)?s.isLeaf()&&s.actor!==t?e.call(t,s.actor)?!0:void 0:n(s.left)||n(s.right):null};return n(this.root)},t.prototype.rayCast=function(){return null},t.prototype.getNodes=function(){var t=function(e){return e?[e].concat(t(e.left),t(e.right)):[]};return t(this.root)},t.prototype.debugDraw=function(t){var e=function(i){i&&(t.strokeStyle=i.isLeaf()?"green":"white",i.bounds.debugDraw(t),i.left&&e(i.left),i.right&&e(i.right))};e(this.root)},t}();t.DynamicTree=i})(ex||(ex={}));var ex;(function(t){var e=function(){function e(){this._dynamicCollisionTree=new t.DynamicTree}return e.prototype.register=function(t){this._dynamicCollisionTree.registerActor(t)},e.prototype.remove=function(t){this._dynamicCollisionTree.removeActor(t)},e.prototype.evaluate=function(e){for(var i,n=e.filter(function(e){return!e.isKilled()&&e.collisionType!==t.CollisionType.PreventCollision}),s=[],o=0,r=n.length;r>o;o++)i=n[o],this._dynamicCollisionTree.query(i,function(e){if(e.collisionType===t.CollisionType.PreventCollision||e.isKilled())return!1;var n;if(n=i.collides(e)){var o=i.getSideFromIntersect(n),r=new t.CollisionPair(i,e,n,o);return s.some(function(t){return t.equals(r)})||s.push(r),!0}return!1});var h=0,a=s.length;for(h;a>h;h++)s[h].evaluate();return s},e.prototype.update=function(t){var e=0,i=0,n=t.length;for(i;n>i;i++)this._dynamicCollisionTree.updateActor(t[i])&&e++;return e},e.prototype.debugDraw=function(t,e){this._dynamicCollisionTree.debugDraw(t,e)},e}();t.DynamicTreeCollisionResolver=e})(ex||(ex={}));var ex;(function(t){var e=function(){function e(t,e,i,n){this.left=t,this.right=e,this.intersect=i,this.side=n}return e.prototype.equals=function(t){return t.left===this.left&&t.right===this.right||t.right===this.left&&t.left===this.right},e.prototype.evaluate=function(){this.left.eventDispatcher.emit("collision",new t.CollisionEvent(this.left,this.right,this.side,this.intersect)),this.right.eventDispatcher.emit("collision",new t.CollisionEvent(this.right,this.left,t.Util.getOppositeSide(this.side),this.intersect.scale(-1)));var e=this.side;this.left.collisionType!==t.CollisionType.Active&&this.left.collisionType!==t.CollisionType.Elastic||this.right.collisionType===t.CollisionType.Passive||(this.left.y+=this.intersect.y,this.left.x+=this.intersect.x,this.left.collisionType===t.CollisionType.Elastic?e===t.Side.Left?this.left.dx=Math.abs(this.left.dx):e===t.Side.Right?this.left.dx=-Math.abs(this.left.dx):e===t.Side.Top?this.left.dy=Math.abs(this.left.dy):e===t.Side.Bottom&&(this.left.dy=-Math.abs(this.left.dy)):(0!==this.intersect.x&&(this.left.dx=0>=this.left.dx&&0>=this.right.dx?Math.max(this.left.dx,this.right.dx):this.left.dx>=0&&this.right.dx>=0?Math.min(this.left.dx,this.right.dx):0),0!==this.intersect.y&&(this.left.dy=0>=this.left.dy&&0>=this.right.dy?Math.max(this.left.dy,this.right.dy):this.left.dy>=0&&this.right.dy>=0?Math.min(this.left.dy,this.right.dy):0)));var i=t.Util.getOppositeSide(this.side),n=this.intersect.scale(-1);this.right.collisionType!==t.CollisionType.Active&&this.right.collisionType!==t.CollisionType.Elastic||this.left.collisionType===t.CollisionType.Passive||(this.right.y+=n.y,this.right.x+=n.x,this.right.collisionType===t.CollisionType.Elastic?i===t.Side.Left?this.right.dx=Math.abs(this.right.dx):i===t.Side.Right?this.right.dx=-Math.abs(this.right.dx):i===t.Side.Top?this.right.dy=Math.abs(this.right.dy):i===t.Side.Bottom&&(this.right.dy=-Math.abs(this.right.dy)):(0!==n.x&&(this.right.dx=0>=this.right.dx&&0>=this.left.dx?Math.max(this.left.dx,this.right.dx):this.left.dx>=0&&this.right.dx>=0?Math.min(this.left.dx,this.right.dx):0),0!==n.y&&(this.right.dy=0>=this.right.dy&&0>=this.left.dy?Math.max(this.left.dy,this.right.dy):this.left.dy>=0&&this.right.dy>=0?Math.min(this.left.dy,this.right.dy):0)))},e}();t.CollisionPair=e})(ex||(ex={}));var ex;(function(t){var e=function(){function e(){this.focus=new t.Point(0,0),this.lerp=!1,this.x=0,this.y=0,this.z=1,this.dx=0,this.dy=0,this.dz=0,this.ax=0,this.ay=0,this.az=0,this.rotation=0,this.rx=0,this._cameraMoving=!1,this._currentLerpTime=0,this._lerpDuration=1e3,this._totalLerpTime=0,this._lerpStart=null,this._lerpEnd=null,this._isShaking=!1,this._shakeMagnitudeX=0,this._shakeMagnitudeY=0,this._shakeDuration=0,this._elapsedShakeTime=0,this._isZooming=!1,this._currentZoomScale=1,this._maxZoomScale=1,this._zoomDuration=0,this._elapsedZoomTime=0,this._zoomIncrement=.01}return e.prototype._easeInOutCubic=function(t,e,i,n){return i-=e,t/=n/2,1>t?i/2*t*t*t+e:(t-=2,i/2*(t*t*t+2)+e)},e.prototype.setActorToFollow=function(t){this._follow=t},e.prototype.getFocus=function(){return new t.Point(this.x,this.y)},e.prototype.setFocus=function(e,i){this._follow||this.lerp||(this.x=e,this.y=i),this.lerp&&(this._lerpStart=this.getFocus().clone(),this._lerpEnd=new t.Point(e,i),this._currentLerpTime=0,this._cameraMoving=!0)},e.prototype.shake=function(t,e,i){this._isShaking=!0,this._shakeMagnitudeX=t,this._shakeMagnitudeY=e,this._shakeDuration=i},e.prototype.zoom=function(t,e){void 0===e&&(e=0),this._isZooming=!0,this._maxZoomScale=t,this._zoomDuration=e,e&&(this._zoomIncrement=1e3*(Math.abs(this._maxZoomScale-this._currentZoomScale)/e)),1>this._maxZoomScale?e?this._zoomIncrement=-1*this._zoomIncrement:(this._isZooming=!1,this._setCurrentZoomScale(this._maxZoomScale)):e||(this._isZooming=!1,this._setCurrentZoomScale(this._maxZoomScale))},e.prototype.getZoom=function(){return this.z},e.prototype._setCurrentZoomScale=function(t){this.z=t},e.prototype.update=function(t,e){this.x+=this.dx*e/1e3,this.y+=this.dy*e/1e3,this.z+=this.dz*e/1e3,this.dx+=this.ax*e/1e3,this.dy+=this.ay*e/1e3,this.dz+=this.az*e/1e3,this.rotation+=this.rx*e/1e3;var i=this.getFocus(),n=0,s=0,o=t.canvas.width,r=t.canvas.height,h=o/this.getZoom(),a=r/this.getZoom();this.lerp&&(this._currentLerpTime=this._shakeDuration},e.prototype._isDoneZooming=function(){return 0!==this._zoomDuration?this._elapsedZoomTime>=this._zoomDuration:1>this._maxZoomScale?this._currentZoomScale<=this._maxZoomScale:this._currentZoomScale>=this._maxZoomScale},e}();t.BaseCamera=e;var i=function(e){function i(){e.apply(this,arguments)}return __extends(i,e),i.prototype.getFocus=function(){return this._follow?new t.Point(this._follow.x+this._follow.getWidth()/2,this.focus.y):this.focus},i}(e);t.SideCamera=i;var n=function(e){function i(){e.apply(this,arguments)}return __extends(i,e),i.prototype.getFocus=function(){return this._follow?new t.Point(this._follow.x+this._follow.getWidth()/2,this._follow.y+this._follow.getHeight()/2):this.focus},i}(e);t.LockedCamera=n})(ex||(ex={}));var ex;(function(t){(function(t){t[t.ShortestPath=0]="ShortestPath",t[t.LongestPath=1]="LongestPath",t[t.Clockwise=2]="Clockwise",t[t.CounterClockwise=3]="CounterClockwise"})(t.RotationType||(t.RotationType={})),t.RotationType})(ex||(ex={}));var ex;(function(t){var e;(function(e){var i;(function(e){var i=function(){function e(e,i,n,s,o){this.actor=e,this.easingFcn=o,this._currentLerpTime=0,this._lerpDuration=1e3,this._lerpStart=new t.Point(0,0),this._lerpEnd=new t.Point(0,0),this._initialized=!1,this._stopped=!1,this._distance=0,this._lerpDuration=s,this._lerpEnd=new t.Point(i,n)}return e.prototype._initialize=function(){this._lerpStart=new t.Point(this.actor.x,this.actor.y),this._currentLerpTime=0,this._distance=this._lerpStart.toVector().distance(this._lerpEnd.toVector())},e.prototype.update=function(t){this._initialized||(this._initialize(),this._initialized=!0);var e=this.actor.x,i=this.actor.y;this._currentLerpTime=this._distance},e.prototype.reset=function(){this._initialized=!1},e.prototype.stop=function(){this._stopped=!0},e}();e.EaseTo=i;var n=function(){function e(e,i,n,s){this._started=!1,this._stopped=!1,this._actor=e,this._end=new t.Vector(i,n),this._speed=s}return e.prototype.update=function(){this._started||(this._started=!0,this._start=new t.Vector(this._actor.x,this._actor.y),this._distance=this._start.distance(this._end),this._dir=this._end.minus(this._start).normalize());var e=this._dir.scale(this._speed);this._actor.dx=e.x,this._actor.dy=e.y,this.isComplete(this._actor)&&(this._actor.x=this._end.x,this._actor.y=this._end.y,this._actor.dy=0,this._actor.dx=0)},e.prototype.isComplete=function(e){return this._stopped||new t.Vector(e.x,e.y).distance(this._start)>=this._distance},e.prototype.stop=function(){this._actor.dy=0,this._actor.dx=0,this._stopped=!0},e.prototype.reset=function(){this._started=!1},e}();e.MoveTo=n;var s=function(){function e(e,i,n,s){if(this._started=!1,this._stopped=!1,this._actor=e,this._end=new t.Vector(i,n),0>=s)throw t.Logger.getInstance().error("Attempted to moveBy time less than or equal to zero : "+s),Error("Cannot move in time <= 0");this._time=s}return e.prototype.update=function(){this._started||(this._started=!0,this._start=new t.Vector(this._actor.x,this._actor.y),this._distance=this._start.distance(this._end),this._dir=this._end.minus(this._start).normalize(),this._speed=this._distance/(this._time/1e3));var e=this._dir.scale(this._speed);this._actor.dx=e.x,this._actor.dy=e.y,this.isComplete(this._actor)&&(this._actor.x=this._end.x,this._actor.y=this._end.y,this._actor.dy=0,this._actor.dx=0)},e.prototype.isComplete=function(e){return this._stopped||new t.Vector(e.x,e.y).distance(this._start)>=this._distance},e.prototype.stop=function(){this._actor.dy=0,this._actor.dx=0,this._stopped=!0},e.prototype.reset=function(){this._started=!1},e}();e.MoveBy=s;var o=function(){function e(e,i,n){this._started=!1,this._stopped=!1,this._actor=e,this._actorToFollow=i,this._current=new t.Vector(this._actor.x,this._actor.y),this._end=new t.Vector(i.x,i.y),this._maximumDistance=void 0!==n?n:this._current.distance(this._end),this._speed=0}return e.prototype.update=function(){this._started||(this._started=!0,this._distanceBetween=this._current.distance(this._end),this._dir=this._end.minus(this._current).normalize());var t=Math.sqrt(Math.pow(this._actorToFollow.dx,2)+Math.pow(this._actorToFollow.dy,2));if(0!==t&&(this._speed=t),this._current.x=this._actor.x,this._current.y=this._actor.y,this._end.x=this._actorToFollow.x,this._end.y=this._actorToFollow.y,this._distanceBetween=this._current.distance(this._end),this._dir=this._end.minus(this._current).normalize(),this._distanceBetween>=this._maximumDistance){var e=this._dir.scale(this._speed);this._actor.dx=e.x,this._actor.dy=e.y}else this._actor.dx=0,this._actor.dy=0;this.isComplete(this._actor)&&(this._actor.x=this._end.x,this._actor.y=this._end.y,this._actor.dy=0,this._actor.dx=0)},e.prototype.stop=function(){this._actor.dy=0,this._actor.dx=0,this._stopped=!0},e.prototype.isComplete=function(){return this._stopped},e.prototype.reset=function(){this._started=!1},e}();e.Follow=o;var r=function(){function e(e,i,n){this._started=!1,this._stopped=!1,this._speedWasSpecified=!1,this._actor=e,this._actorToMeet=i,this._current=new t.Vector(this._actor.x,this._actor.y),this._end=new t.Vector(i.x,i.y),this._speed=n||0,void 0!==n&&(this._speedWasSpecified=!0)}return e.prototype.update=function(){this._started||(this._started=!0,this._distanceBetween=this._current.distance(this._end),this._dir=this._end.minus(this._current).normalize());var t=Math.sqrt(Math.pow(this._actorToMeet.dx,2)+Math.pow(this._actorToMeet.dy,2));0===t||this._speedWasSpecified||(this._speed=t),this._current.x=this._actor.x,this._current.y=this._actor.y,this._end.x=this._actorToMeet.x,this._end.y=this._actorToMeet.y,this._distanceBetween=this._current.distance(this._end),this._dir=this._end.minus(this._current).normalize();var e=this._dir.scale(this._speed);this._actor.dx=e.x,this._actor.dy=e.y,this.isComplete(this._actor)&&(this._actor.x=this._end.x,this._actor.y=this._end.y,this._actor.dy=0,this._actor.dx=0)},e.prototype.isComplete=function(){return this._stopped||1>=this._distanceBetween},e.prototype.stop=function(){this._actor.dy=0,this._actor.dx=0,this._stopped=!0},e.prototype.reset=function(){this._started=!1},e}();e.Meet=r;var h=function(){function e(e,i,n,s){this._started=!1,this._stopped=!1,this._actor=e,this._end=i,this._speed=n,this._rotationType=s||t.RotationType.ShortestPath}return e.prototype.update=function(){if(!this._started){this._started=!0,this._start=this._actor.rotation;var e=Math.abs(this._end-this._start),i=t.Util.TwoPI-e;switch(e>i?(this._shortDistance=i,this._longDistance=e):(this._shortDistance=e,this._longDistance=i),this._shortestPathIsPositive=(this._start-this._end+t.Util.TwoPI)%t.Util.TwoPI>=Math.PI,this._rotationType){case t.RotationType.ShortestPath:this._distance=this._shortDistance,this._direction=this._shortestPathIsPositive?1:-1;break;case t.RotationType.LongestPath:this._distance=this._longDistance,this._direction=this._shortestPathIsPositive?-1:1;break;case t.RotationType.Clockwise:this._direction=1,this._distance=this._shortestPathIsPositive?this._shortDistance:this._longDistance;break;case t.RotationType.CounterClockwise:this._direction=-1,this._distance=this._shortestPathIsPositive?this._longDistance:this._shortDistance}}this._actor.rx=this._direction*this._speed,this.isComplete(this._actor)&&(this._actor.rotation=this._end,this._actor.rx=0,this._stopped=!0)},e.prototype.isComplete=function(){var t=Math.abs(this._actor.rotation-this._start);return this._stopped||t>=Math.abs(this._distance)},e.prototype.stop=function(){this._actor.rx=0,this._stopped=!0},e.prototype.reset=function(){this._started=!1},e}();e.RotateTo=h;var a=function(){function e(e,i,n,s){this._started=!1,this._stopped=!1,this._actor=e,this._end=i,this._time=n,this._rotationType=s||t.RotationType.ShortestPath}return e.prototype.update=function(){if(!this._started){this._started=!0,this._start=this._actor.rotation;var e=Math.abs(this._end-this._start),i=t.Util.TwoPI-e;switch(e>i?(this._shortDistance=i,this._longDistance=e):(this._shortDistance=e,this._longDistance=i),this._shortestPathIsPositive=(this._start-this._end+t.Util.TwoPI)%t.Util.TwoPI>=Math.PI,this._rotationType){case t.RotationType.ShortestPath:this._distance=this._shortDistance,this._direction=this._shortestPathIsPositive?1:-1;break;case t.RotationType.LongestPath:this._distance=this._longDistance,this._direction=this._shortestPathIsPositive?-1:1;break;case t.RotationType.Clockwise:this._direction=1,this._distance=this._shortDistance>=0?this._shortDistance:this._longDistance;break;case t.RotationType.CounterClockwise:this._direction=-1,this._distance=0>=this._shortDistance?this._shortDistance:this._longDistance}this._speed=Math.abs(1e3*(this._distance/this._time))}this._actor.rx=this._direction*this._speed,this.isComplete(this._actor)&&(this._actor.rotation=this._end,this._actor.rx=0,this._stopped=!0)},e.prototype.isComplete=function(){var t=Math.abs(this._actor.rotation-this._start);return this._stopped||t>=Math.abs(this._distance)},e.prototype.stop=function(){this._actor.rx=0,this._stopped=!0},e.prototype.reset=function(){this._started=!1},e}();e.RotateBy=a;var c=function(){function t(t,e,i,n,s){this._started=!1,this._stopped=!1,this._actor=t,this._endX=e,this._endY=i,this._speedX=n,this._speedY=s}return t.prototype.update=function(){if(this._started||(this._started=!0,this._startX=this._actor.scale.x,this._startY=this._actor.scale.y,this._distanceX=Math.abs(this._endX-this._startX),this._distanceY=Math.abs(this._endY-this._startY)),Math.abs(this._actor.scale.x-this._startX)>=this._distanceX)this._actor.sx=0;else{var t=this._endY=this._distanceY)this._actor.sy=0;else{var e=this._endY=this._distanceX&&Math.abs(this._actor.scale.y-this._startY)>=this._distanceY},t.prototype.stop=function(){this._actor.sx=0,this._actor.sy=0,this._stopped=!0},t.prototype.reset=function(){this._started=!1},t}();e.ScaleTo=c;var l=function(){function t(t,e,i,n){this._started=!1,this._stopped=!1,this._actor=t,this._endX=e,this._endY=i,this._time=n,this._speedX=1e3*((this._endX-this._actor.scale.x)/n),this._speedY=1e3*((this._endY-this._actor.scale.y)/n)}return t.prototype.update=function(){this._started||(this._started=!0,this._startX=this._actor.scale.x,this._startY=this._actor.scale.y,this._distanceX=Math.abs(this._endX-this._startX),this._distanceY=Math.abs(this._endY-this._startY));var t=this._endX=this._distanceX&&Math.abs(this._actor.scale.y-this._startY)>=this._distanceY},t.prototype.stop=function(){this._actor.sx=0,this._actor.sy=0,this._stopped=!0},t.prototype.reset=function(){this._started=!1},t}();e.ScaleBy=l;var u=function(){function t(t,e){this._elapsedTime=0,this._started=!1,this._stopped=!1,this._actor=t,this._delay=e}return t.prototype.update=function(t){this._started||(this._started=!0),this.x=this._actor.x,this.y=this._actor.y,this._elapsedTime+=t},t.prototype.isComplete=function(){return this._stopped||this._elapsedTime>=this._delay},t.prototype.stop=function(){this._stopped=!0},t.prototype.reset=function(){this._elapsedTime=0,this._started=!1},t}();e.Delay=u;var p=function(){function t(t,e,i,n){void 0===n&&(n=1),this._timeVisible=0,this._timeNotVisible=0,this._elapsedTime=0,this._totalTime=0,this._stopped=!1,this._started=!1,this._actor=t,this._timeVisible=e,this._timeNotVisible=i,this._duration=(e+i)*n}return t.prototype.update=function(t){this._started||(this._started=!0),this._elapsedTime+=t,this._totalTime+=t,this._actor.visible&&this._elapsedTime>=this._timeVisible&&(this._actor.visible=!1,this._elapsedTime=0),!this._actor.visible&&this._elapsedTime>=this._timeNotVisible&&(this._actor.visible=!0,this._elapsedTime=0),this.isComplete(this._actor)&&(this._actor.visible=!0)},t.prototype.isComplete=function(){return this._stopped||this._totalTime>=this._duration},t.prototype.stop=function(){this._actor.visible=!0,this._stopped=!0},t.prototype.reset=function(){this._started=!1,this._elapsedTime=0,this._totalTime=0},t}();e.Blink=p;var d=function(){function e(t,e,i){this._multiplyer=1,this._started=!1,this._stopped=!1,this._actor=t,this._endOpacity=e,this._speed=i,t.opacity>e&&(this._multiplyer=-1)}return e.prototype.update=function(e){this._started||(this._started=!0),this._speed>0&&(this._actor.opacity+=this._multiplyer*Math.abs(this._actor.opacity-this._endOpacity)*e/this._speed),this._speed-=e,t.Logger.getInstance().debug("actor opacity: "+this._actor.opacity),this.isComplete(this._actor)&&(this._actor.opacity=this._endOpacity)},e.prototype.isComplete=function(){return this._stopped||.05>Math.abs(this._actor.opacity-this._endOpacity)},e.prototype.stop=function(){this._stopped=!0},e.prototype.reset=function(){this._started=!1},e}();e.Fade=d;var f=function(){function t(t){this._started=!1,this._stopped=!1,this._actor=t}return t.prototype.update=function(){this._actor.actionQueue.clearActions(),this._actor.kill(),this._stopped=!0},t.prototype.isComplete=function(){return this._stopped},t.prototype.stop=function(){},t.prototype.reset=function(){},t}();e.Die=f;var g=function(){function t(t,e){this._method=null,this._actor=null,this._hasBeenCalled=!1,this._actor=t,this._method=e}return t.prototype.update=function(){this._method.call(this._actor),this._hasBeenCalled=!0},t.prototype.isComplete=function(){return this._hasBeenCalled},t.prototype.reset=function(){this._hasBeenCalled=!1},t.prototype.stop=function(){this._hasBeenCalled=!0},t}();e.CallMethod=g;var _=function(){function t(t,e,i){this._stopped=!1,this._actor=t,this._actionQueue=new A(t),this._repeat=e,this._originalRepeat=e;var n=0,s=i.length;for(n;s>n;n++)i[n].reset(),this._actionQueue.add(i[n])}return t.prototype.update=function(t){this.x=this._actor.x,this.y=this._actor.y,this._actionQueue.hasNext()||(this._actionQueue.reset(),this._repeat--),this._actionQueue.update(t)},t.prototype.isComplete=function(){return this._stopped||0>=this._repeat},t.prototype.stop=function(){this._stopped=!0},t.prototype.reset=function(){this._repeat=this._originalRepeat},t}();e.Repeat=_;var y=function(){function t(t,e){this._stopped=!1,this._actor=t,this._actionQueue=new A(t);var i=0,n=e.length;for(i;n>i;i++)e[i].reset(),this._actionQueue.add(e[i])}return t.prototype.update=function(t){this.x=this._actor.x,this.y=this._actor.y,this._stopped||(this._actionQueue.hasNext()||this._actionQueue.reset(),this._actionQueue.update(t))},t.prototype.isComplete=function(){return this._stopped},t.prototype.stop=function(){this._stopped=!0,this._actionQueue.clearActions()},t.prototype.reset=function(){},t}();e.RepeatForever=y;var A=function(){function t(t){this._actions=[],this._completedActions=[],this._actor=t}return t.prototype.add=function(t){this._actions.push(t)},t.prototype.remove=function(t){var e=this._actions.indexOf(t);this._actions.splice(e,1)},t.prototype.clearActions=function(){this._actions.length=0,this._completedActions.length=0,this._currentAction&&this._currentAction.stop()},t.prototype.getActions=function(){return this._actions.concat(this._completedActions)},t.prototype.hasNext=function(){return this._actions.length>0},t.prototype.reset=function(){this._actions=this.getActions();var t=0,e=this._actions.length;for(t;e>t;t++)this._actions[t].reset();this._completedActions=[]},t.prototype.update=function(t){this._actions.length>0&&(this._currentAction=this._actions[0],this._currentAction.update(t),this._currentAction.isComplete(this._actor)&&this._completedActions.push(this._actions.shift()))},t}();e.ActionQueue=A})(i=e.Actions||(e.Actions={}))})(e=t.Internal||(t.Internal={}))})(ex||(ex={}));var ex;(function(t){var e=function(){function e(){this._actors=[],this._queues=[],null!==arguments&&(this._actors=Array.prototype.slice.call(arguments,0),this._queues=this._actors.map(function(t){return t.actionQueue}))}return e.prototype.clearActions=function(){var t=0,e=this._queues.length;for(t;e>t;t++)this._queues[t].clearActions()},e.prototype.addActorToContext=function(t){this._actors.push(t),this._queues.push(t.actionQueue)},e.prototype.removeActorFromContext=function(t){var e=this._actors.indexOf(t);e>-1&&(this._actors.splice(e,1),this._queues.splice(e,1))},e.prototype.easeTo=function(e,i,n,s){void 0===s&&(s=t.EasingFunctions.Linear);var o=0,r=this._queues.length;for(o;r>o;o++)this._queues[o].add(new t.Internal.Actions.EaseTo(this._actors[o],e,i,n,s));return this},e.prototype.moveTo=function(e,i,n){var s=0,o=this._queues.length;for(s;o>s;s++)this._queues[s].add(new t.Internal.Actions.MoveTo(this._actors[s],e,i,n));return this},e.prototype.moveBy=function(e,i,n){var s=0,o=this._queues.length;for(s;o>s;s++)this._queues[s].add(new t.Internal.Actions.MoveBy(this._actors[s],e,i,n));return this},e.prototype.rotateTo=function(e,i){var n=0,s=this._queues.length;for(n;s>n;n++)this._queues[n].add(new t.Internal.Actions.RotateTo(this._actors[n],e,i));return this},e.prototype.rotateBy=function(e,i){var n=0,s=this._queues.length;for(n;s>n;n++)this._queues[n].add(new t.Internal.Actions.RotateBy(this._actors[n],e,i));return this},e.prototype.scaleTo=function(e,i,n,s){var o=0,r=this._queues.length;for(o;r>o;o++)this._queues[o].add(new t.Internal.Actions.ScaleTo(this._actors[o],e,i,n,s));return this},e.prototype.scaleBy=function(e,i,n){var s=0,o=this._queues.length;for(s;o>s;s++)this._queues[s].add(new t.Internal.Actions.ScaleBy(this._actors[s],e,i,n));return this},e.prototype.blink=function(e,i,n){void 0===n&&(n=1);var s=0,o=this._queues.length;for(s;o>s;s++)this._queues[s].add(new t.Internal.Actions.Blink(this._actors[s],e,i,n));return this},e.prototype.fade=function(e,i){var n=0,s=this._queues.length;for(n;s>n;n++)this._queues[n].add(new t.Internal.Actions.Fade(this._actors[n],e,i));return this},e.prototype.delay=function(e){var i=0,n=this._queues.length;for(i;n>i;i++)this._queues[i].add(new t.Internal.Actions.Delay(this._actors[i],e));return this},e.prototype.die=function(){var e=0,i=this._queues.length;for(e;i>e;e++)this._queues[e].add(new t.Internal.Actions.Die(this._actors[e]));return this},e.prototype.callMethod=function(e){var i=0,n=this._queues.length;for(i;n>i;i++)this._queues[i].add(new t.Internal.Actions.CallMethod(this._actors[i],e));return this},e.prototype.repeat=function(e){if(!e)return this.repeatForever(),this;var i=0,n=this._queues.length;for(i;n>i;i++)this._queues[i].add(new t.Internal.Actions.Repeat(this._actors[i],e,this._actors[i].actionQueue.getActions())); +return this},e.prototype.repeatForever=function(){var e=0,i=this._queues.length;for(e;i>e;e++)this._queues[e].add(new t.Internal.Actions.RepeatForever(this._actors[e],this._actors[e].actionQueue.getActions()));return this},e.prototype.follow=function(e,i){var n=0,s=this._queues.length;for(n;s>n;n++)void 0===i?this._queues[n].add(new t.Internal.Actions.Follow(this._actors[n],e)):this._queues[n].add(new t.Internal.Actions.Follow(this._actors[n],e,i));return this},e.prototype.meet=function(e,i){var n=0,s=this._queues.length;for(n;s>n;n++)void 0===i?this._queues[n].add(new t.Internal.Actions.Meet(this._actors[n],e)):this._queues[n].add(new t.Internal.Actions.Meet(this._actors[n],e,i));return this},e.prototype.asPromise=function(){var e=this,i=this._queues.map(function(i,n){var s=new t.Promise;return i.add(new t.Internal.Actions.CallMethod(e._actors[n],function(){s.resolve()})),s});return t.Promise.join.apply(this,i)},e}();t.ActionContext=e})(ex||(ex={}));var ex;(function(t){var e=function(e){function i(i,n){if(e.call(this),this.name=i,this.scene=n,this._logger=t.Logger.getInstance(),this._members=[],this.actions=new t.ActionContext,null==n)this._logger.error("Invalid constructor arguments passed to Group: ",i,", scene must not be null!");else{var s=n.groups[i];s&&this._logger.warn("Group with name",i,"already exists. This new group will replace it."),n.groups[i]=this}}return __extends(i,e),i.prototype.add=function(e){e instanceof t.Actor&&(e=[].concat(e));var i,n=0,s=e.length;for(n;s>n;n++)i=this.getMembers().indexOf(e[n]),-1===i&&(this._members.push(e[n]),this.scene.add(e[n]),this.actions.addActorToContext(e[n]),this.eventDispatcher.wire(e[n].eventDispatcher))},i.prototype.remove=function(t){var e=this._members.indexOf(t);e>-1&&(this._members.splice(e,1),this.actions.removeActorFromContext(t),this.eventDispatcher.unwire(t.eventDispatcher))},i.prototype.move=function(e){var i=0,n=this.getMembers(),s=n.length;if(1===arguments.length&&e instanceof t.Vector)for(i;s>i;i++)n[i].x+=e.x,n[i].y+=e.y;else if("number"==typeof arguments[0]&&"number"==typeof arguments[1]){var o=arguments[0],r=arguments[1];for(i;s>i;i++)n[i].x+=o,n[i].y+=r}else this._logger.error("Invalid arguments passed to group move",this.name,"args:",arguments)},i.prototype.rotate=function(){if("number"==typeof arguments[0]){var t=arguments[0],e=0,i=this.getMembers(),n=i.length;for(e;n>e;e++)i[e].rotation+=t}else this._logger.error("Invalid arguments passed to group rotate",this.name,"args:",arguments)},i.prototype.on=function(t,e){this.eventDispatcher.subscribe(t,e)},i.prototype.off=function(t,e){this.eventDispatcher.unsubscribe(t,e)},i.prototype.emit=function(t,e){this.eventDispatcher.emit(t,e)},i.prototype.contains=function(t){return this.getMembers().indexOf(t)>-1},i.prototype.getMembers=function(){return this._members},i.prototype.getRandomMember=function(){return this._members[Math.floor(Math.random()*this._members.length)]},i.prototype.getBounds=function(){return this.getMembers().map(function(t){return t.getBounds()}).reduce(function(t,e){return t.combine(e)})},i}(t.Class);t.Group=e})(ex||(ex={}));var ex;(function(t){var e=function(){function t(t){this._getComparable=t}return t.prototype.find=function(t){return this._find(this._root,t)},t.prototype._find=function(t,e){return null==t?!1:this._getComparable.call(e)===t.getKey()?t.getData().indexOf(e)>-1?!0:!1:this._getComparable.call(e)e?this._get(t.getLeft(),e):this._get(t.getRight(),e)},t.prototype.add=function(t){return null==this._root?(this._root=new i(this._getComparable.call(t),[t],null,null),!0):this._insert(this._root,t)},t.prototype._insert=function(t,e){return null!=t?this._getComparable.call(e)===t.getKey()?t.getData().indexOf(e)>-1?!1:(t.getData().push(e),!0):this._getComparable.call(e)-1){if(t.getData().splice(i,1),0===t.getData().length){if(null==t.getLeft()&&null==t.getRight())return null;if(null==t.getLeft())return t.getRight();if(null==t.getRight())return t.getLeft();var n=this._findMinNode(t.getRight());return t.setKey(n.getKey()),t.setData(n.getData()),t.setRight(this._cleanup(t.getRight(),n)),t}return t}},t.prototype._cleanup=function(t,e){var i=e.getKey();if(null==t)return null;if(i===t.getKey()){if(null==t.getLeft()&&null==t.getRight())return null;if(null==t.getLeft())return t.getRight();if(null==t.getRight())return t.getLeft();var n=this._findMinNode(t.getRight());return t.setKey(n.getKey()),t.setData(n.getData()),t.setRight(this._cleanup(t.getRight(),n)),t}return this._getComparable.call(e)n;n++)this.uiActors[n].update(e,i);for(n=0,s=this.tileMaps.length;s>n;n++)this.tileMaps[n].update(e,i);for(n=0,s=this.children.length;s>n;n++)this.children[n].update(e,i);this._collisionResolver&&(this._collisionResolver.update(this.children),this._collisionResolver.evaluate(this.children));var o;for(n=0,s=this._killQueue.length;s>n;n++)o=this.children.indexOf(this._killQueue[n]),o>-1&&(this._sortedDrawingTree.removeByComparable(this._killQueue[n]),this.children.splice(o,1));for(this._killQueue.length=0,n=0,s=this._cancelQueue.length;s>n;n++)this.removeTimer(this._cancelQueue[n]);this._cancelQueue.length=0,this._timers=this._timers.filter(function(t){return t.update(i),!t.complete}),this.emit("postupdate",new t.PostUpdateEvent(e,i,this))},i.prototype.draw=function(e,i){this.emit("predraw",new t.PreDrawEvent(e,i,this)),e.save(),this.camera&&this.camera.update(e,i);var n,s;for(n=0,s=this.tileMaps.length;s>n;n++)this.tileMaps[n].draw(e,i);var o=this._sortedDrawingTree.list();for(n=0,s=o.length;s>n;n++)o[n].visible&&!o[n].isOffScreen&&o[n].draw(e,i);for(this.engine&&this.engine.isDebug&&(e.strokeStyle="yellow",this.debugDraw(e)),e.restore(),n=0,s=this.uiActors.length;s>n;n++)this.uiActors[n].visible&&this.uiActors[n].draw(e,i);if(this.engine&&this.engine.isDebug)for(n=0,s=this.uiActors.length;s>n;n++)this.uiActors[n].debugDraw(e);this.emit("postdraw",new t.PreDrawEvent(e,i,this))},i.prototype.debugDraw=function(e){this.emit("predebugdraw",new t.PreDebugDrawEvent(e,this));var i,n;for(i=0,n=this.tileMaps.length;n>i;i++)this.tileMaps[i].debugDraw(e);for(i=0,n=this.children.length;n>i;i++)this.children[i].debugDraw(e);this.camera.debugDraw(e),this.emit("postdebugdraw",new t.PostDebugDrawEvent(e,this))},i.prototype.contains=function(t){return this.children.indexOf(t)>-1},i.prototype.add=function(e){return e instanceof t.UIActor?(t.Util.contains(this.uiActors,e)||this.addUIActor(e),void 0):e instanceof t.Actor?(t.Util.contains(this.children,e)||(this.addChild(e),this._sortedDrawingTree.add(e)),void 0):e instanceof t.Timer?(t.Util.contains(this._timers,e)||this.addTimer(e),void 0):(e instanceof t.TileMap&&(t.Util.contains(this.tileMaps,e)||this.addTileMap(e)),void 0)},i.prototype.remove=function(e){return e instanceof t.UIActor?(this.removeUIActor(e),void 0):(e instanceof t.Actor&&(this._collisionResolver.remove(e),this.removeChild(e)),e instanceof t.Timer&&this.removeTimer(e),e instanceof t.TileMap&&this.removeTileMap(e),void 0)},i.prototype.addUIActor=function(t){this.uiActors.push(t),t.scene=this},i.prototype.removeUIActor=function(t){var e=this.uiActors.indexOf(t);e>-1&&this.uiActors.splice(e,1)},i.prototype.addChild=function(t){this._collisionResolver.register(t),t.scene=this,this.children.push(t),this._sortedDrawingTree.add(t),t.parent=this.actor},i.prototype.addTileMap=function(t){this.tileMaps.push(t)},i.prototype.removeTileMap=function(t){var e=this.tileMaps.indexOf(t);e>-1&&this.tileMaps.splice(e,1)},i.prototype.removeChild=function(t){this._collisionResolver.remove(t),this._killQueue.push(t),t.parent=null},i.prototype.addTimer=function(t){return this._timers.push(t),t.scene=this,t},i.prototype.removeTimer=function(t){var e=this._timers.indexOf(t);return-1!==e&&this._timers.splice(e,1),t},i.prototype.cancelTimer=function(t){return this._cancelQueue.push(t),t},i.prototype.isTimerActive=function(t){return this._timers.indexOf(t)>-1},i.prototype.createGroup=function(e){return new t.Group(e,this)},i.prototype.getGroup=function(t){return this.groups[t]},i.prototype.removeGroup=function(e){"string"==typeof e?delete this.groups[e]:e instanceof t.Group?delete this.groups[e.name]:this._logger.error("Invalid arguments to removeGroup",e)},i.prototype.cleanupDrawTree=function(t){this._sortedDrawingTree.removeByComparable(t)},i.prototype.updateDrawTree=function(t){this._sortedDrawingTree.add(t)},i}(t.Class);t.Scene=e})(ex||(ex={}));var ex;(function(t){var e=function(){function t(){}return t.Linear=function(t,e,i,n){return i-=e,i*t/n+e},t.EaseInQuad=function(t,e,i,n){t/=n},t.EaseOutQuad=function(t,e,i,n){return t/=n,-i*t*(t-2)+e},t.EaseInOutQuad=function(t,e,i,n){return i-=e,t/=n/2,1>t?i/2*t*t+e:(t--,-i/2*(t*(t-2)-1)+e)},t.EaseInCubic=function(t,e,i,n){return i-=e,t/=n,i*t*t*t+e},t.EaseOutCubic=function(t,e,i,n){return i-=e,t/=n,i*(t*t*t+1)+e},t.EaseInOutCubic=function(t,e,i,n){return i-=e,t/=n/2,1>t?i/2*t*t*t+e:(t-=2,i/2*(t*t*t+2)+e)},t}();t.EasingFunctions=e})(ex||(ex={}));var ex;(function(t){var e=function(e){function n(s,o,r,h,a){e.call(this),this.id=n.maxId++,this.x=0,this.y=0,this._height=0,this._width=0,this.rotation=0,this.rx=0,this.scale=new t.Vector(1,1),this.sx=0,this.sy=0,this.dx=0,this.dy=0,this.ax=0,this.ay=0,this.isOffScreen=!1,this.visible=!0,this.opacity=1,this.previousOpacity=1,this.actions=new t.ActionContext(this),this.logger=t.Logger.getInstance(),this.scene=null,this.parent=null,this.children=[],this.collisionType=i.PreventCollision,this.collisionGroups=[],this._collisionHandlers={},this._isInitialized=!1,this.frames={},this.currentDrawing=null,this.centerDrawingX=!0,this.centerDrawingY=!0,this.traits=[],this.enableCapturePointer=!1,this.capturePointer={captureMoveEvents:!1},this._zIndex=0,this._isKilled=!1,this.x=s||0,this.y=o||0,this._width=r||0,this._height=h||0,a&&(this.color=a.clone(),this.opacity=a.a),this.traits.push(new t.Traits.Movement),this.traits.push(new t.Traits.CollisionDetection),this.traits.push(new t.Traits.OffscreenCulling),this.traits.push(new t.Traits.CapturePointer),this.actionQueue=new t.Internal.Actions.ActionQueue(this),this.anchor=new t.Point(.5,.5)}return __extends(n,e),n.prototype.onInitialize=function(){},n.prototype._checkForPointerOptIn=function(t){!t||"pointerdown"!==t.toLowerCase()&&"pointerdown"!==t.toLowerCase()&&"pointermove"!==t.toLowerCase()||(this.enableCapturePointer=!0,"pointermove"===t.toLowerCase()&&(this.capturePointer.captureMoveEvents=!0))},n.prototype.addEventListener=function(t,i){this._checkForPointerOptIn(t),e.prototype.addEventListener.call(this,t,i)},n.prototype.on=function(t,e){this._checkForPointerOptIn(t),this.eventDispatcher.subscribe(t,e)},n.prototype.kill=function(){this.scene?(this.scene.remove(this),this._isKilled=!0):this.logger.warn("Cannot kill actor, it was never added to the Scene")},n.prototype.isKilled=function(){return this._isKilled},n.prototype.add=function(e){e.collisionType=i.PreventCollision,t.Util.addItemToArray(e,this.children)&&(e.parent=this)},n.prototype.remove=function(e){t.Util.removeItemToArray(e,this.children)&&(e.parent=null)},n.prototype.setDrawing=function(e){e=""+e,this.currentDrawing!==this.frames[e]&&(null!=this.frames[e]?(this.frames[e].reset(),this.currentDrawing=this.frames[e]):t.Logger.getInstance().error("the specified drawing key '"+e+"' does not exist"))},n.prototype.addDrawing=function(){2===arguments.length?(this.frames[arguments[0]]=arguments[1],this.currentDrawing||(this.currentDrawing=arguments[1])):(arguments[0]instanceof t.Sprite&&this.addDrawing("default",arguments[0]),arguments[0]instanceof t.Texture&&this.addDrawing("default",arguments[0].asSprite()))},n.prototype.getZIndex=function(){return this._zIndex},n.prototype.setZIndex=function(t){this.scene.cleanupDrawTree(this),this._zIndex=t,this.scene.updateDrawTree(this)},n.prototype.addCollisionGroup=function(t){this.collisionGroups.push(t)},n.prototype.removeCollisionGroup=function(t){var e=this.collisionGroups.indexOf(t);-1!==e&&this.collisionGroups.splice(e,1)},n.prototype.getCenter=function(){return new t.Vector(this.x+this.getWidth()/2-this.anchor.x*this.getWidth(),this.y+this.getHeight()/2-this.anchor.y*this.getHeight())},n.prototype.getWidth=function(){return this._width*this.scale.x},n.prototype.setWidth=function(t){this._width=t/this.scale.x},n.prototype.getHeight=function(){return this._height*this.scale.y},n.prototype.setHeight=function(t){this._height=t/this.scale.y},n.prototype.setCenterDrawing=function(t){this.centerDrawingY=t,this.centerDrawingX=t},n.prototype.getLeft=function(){return this.x},n.prototype.getRight=function(){return this.x+this.getWidth()},n.prototype.getTop=function(){return this.y},n.prototype.getBottom=function(){return this.y+this.getHeight()},n.prototype.getWorldX=function(){return this.parent?this.x*this.parent.scale.x+this.parent.getWorldX():this.x},n.prototype.getWorldY=function(){return this.parent?this.y*this.parent.scale.y+this.parent.getWorldY():this.y},n.prototype.getGlobalScale=function(){if(!this.parent)return new t.Point(this.scale.x,this.scale.y);var e=this.parent.getGlobalScale();return new t.Point(this.scale.x*e.x,this.scale.y*e.y)},n.prototype.getBounds=function(){var e=this._getCalculatedAnchor();return new t.BoundingBox(this.getWorldX()-e.x,this.getWorldY()-e.y,this.getWorldX()+this.getWidth()-e.x,this.getWorldY()+this.getHeight()-e.y)},n.prototype.contains=function(e,i,n){void 0===n&&(n=!1);var s=this.getBounds().contains(new t.Point(e,i));return n?s||this.children.some(function(t){return t.contains(e,i,!0)}):s},n.prototype.getSideFromIntersect=function(e){return e?Math.abs(e.x)>Math.abs(e.y)?0>e.x?t.Side.Right:t.Side.Left:0>e.y?t.Side.Bottom:t.Side.Top:t.Side.None},n.prototype.collidesWithSide=function(e){var i=this.collides(e);return i?Math.abs(i.x)>Math.abs(i.y)?this.x=Math.sqrt(Math.pow(this.x-t.x,2)+Math.pow(this.y-t.y,2))},n.prototype.clearActions=function(){this.actionQueue.clearActions()},n.prototype.easeTo=function(e,i,n,s){return void 0===s&&(s=t.EasingFunctions.Linear),this.actionQueue.add(new t.Internal.Actions.EaseTo(this,e,i,n,s)),this},n.prototype.moveTo=function(e,i,n){return this.actionQueue.add(new t.Internal.Actions.MoveTo(this,e,i,n)),this},n.prototype.moveBy=function(e,i,n){return this.actionQueue.add(new t.Internal.Actions.MoveBy(this,e,i,n)),this},n.prototype.rotateTo=function(e,i,n){return this.actionQueue.add(new t.Internal.Actions.RotateTo(this,e,i,n)),this},n.prototype.rotateBy=function(e,i,n){return this.actionQueue.add(new t.Internal.Actions.RotateBy(this,e,i,n)),this},n.prototype.scaleTo=function(e,i,n,s){return this.actionQueue.add(new t.Internal.Actions.ScaleTo(this,e,i,n,s)),this},n.prototype.scaleBy=function(e,i,n){return this.actionQueue.add(new t.Internal.Actions.ScaleBy(this,e,i,n)),this},n.prototype.blink=function(e,i,n){return void 0===n&&(n=1),this.actionQueue.add(new t.Internal.Actions.Blink(this,e,i,n)),this},n.prototype.fade=function(e,i){return this.actionQueue.add(new t.Internal.Actions.Fade(this,e,i)),this},n.prototype.delay=function(e){return this.actionQueue.add(new t.Internal.Actions.Delay(this,e)),this},n.prototype.die=function(){return this.actionQueue.add(new t.Internal.Actions.Die(this)),this},n.prototype.callMethod=function(e){return this.actionQueue.add(new t.Internal.Actions.CallMethod(this,e)),this},n.prototype.repeat=function(e){return e?(this.actionQueue.add(new t.Internal.Actions.Repeat(this,e,this.actionQueue.getActions())),this):(this.repeatForever(),this)},n.prototype.repeatForever=function(){return this.actionQueue.add(new t.Internal.Actions.RepeatForever(this,this.actionQueue.getActions())),this},n.prototype.follow=function(e,i){return i===void 0?this.actionQueue.add(new t.Internal.Actions.Follow(this,e)):this.actionQueue.add(new t.Internal.Actions.Follow(this,e,i)),this},n.prototype.meet=function(e,i){return i===void 0?this.actionQueue.add(new t.Internal.Actions.Meet(this,e)):this.actionQueue.add(new t.Internal.Actions.Meet(this,e,i)),this},n.prototype.asPromise=function(){var e=new t.Promise;return this.callMethod(function(){e.resolve()}),e},n.prototype._getCalculatedAnchor=function(){return new t.Point(this.getWidth()*this.anchor.x,this.getHeight()*this.anchor.y)},n.prototype.update=function(e,i){this._isInitialized||(this.onInitialize(e),this.eventDispatcher.emit("initialize",new t.InitializeEvent(e)),this._isInitialized=!0),this.emit("preupdate",new t.PreUpdateEvent(e,i,this));var n=this.eventDispatcher;this.actionQueue.update(i),this.color&&(this.color.a=this.opacity);for(var s=0;this.traits.length>s;s++)this.traits[s].update(this,e,i);n.emit("update",new t.UpdateEvent(i)),this.emit("postupdate",new t.PostUpdateEvent(e,i,this))},n.prototype.draw=function(e,i){var n=this._getCalculatedAnchor();if(e.save(),e.translate(this.x,this.y),e.scale(this.scale.x,this.scale.y),e.rotate(this.rotation),this.emit("predraw",new t.PreDrawEvent(e,i,this)),this.previousOpacity!==this.opacity){for(var s in this.frames)this.frames[s].addEffect(new t.Effects.Opacity(this.opacity));this.previousOpacity=this.opacity}if(this.currentDrawing){var o=0,r=0;this.centerDrawingX&&(o=(this.currentDrawing.naturalWidth*this.currentDrawing.scale.x-this.getWidth())/2-this.currentDrawing.naturalWidth*this.currentDrawing.scale.x*this.currentDrawing.anchor.x),this.centerDrawingY&&(r=(this.currentDrawing.naturalHeight*this.currentDrawing.scale.y-this.getHeight())/2-this.currentDrawing.naturalHeight*this.currentDrawing.scale.y*this.currentDrawing.anchor.y),this.currentDrawing.draw(e,-n.x-o,-n.y-r)}else this.color&&(e.fillStyle=""+this.color,e.fillRect(-n.x,-n.y,this._width,this._height));for(var h=0;this.children.length>h;h++)this.children[h].visible&&this.children[h].draw(e,i);this.emit("postdraw",new t.PostDrawEvent(e,i,this)),e.restore()},n.prototype.debugDraw=function(e){this.emit("predebugdraw",new t.PreDebugDrawEvent(e,this));var i=this.getBounds();i.debugDraw(e),e.fillText("id: "+this.id,i.left+3,i.top+10),e.fillStyle=""+t.Color.Yellow,e.beginPath(),e.arc(this.getWorldX(),this.getWorldY(),3,0,2*Math.PI),e.closePath(),e.fill();for(var n=0;this.traits.length>n;n++)this.traits[n]instanceof t.Traits.OffscreenCulling&&this.traits[n].cullingBox.debugDraw(e);e.strokeStyle=""+t.Color.Yellow,e.beginPath();var s=Math.min(this.getWidth(),this.getHeight());e.arc(this.getWorldX(),this.getWorldY(),s,0,2*Math.PI),e.closePath(),e.stroke();var o={"0 Pi":0,"Pi/2":Math.PI/2,Pi:Math.PI,"3/2 Pi":3*Math.PI/2},r=e.font;for(var h in o)e.fillStyle=""+t.Color.Yellow,e.font="14px",e.textAlign="center",e.fillText(h,this.getWorldX()+Math.cos(o[h])*(s+10),this.getWorldY()+Math.sin(o[h])*(s+10));e.font=r,e.save(),e.translate(this.x,this.y),e.rotate(this.rotation);for(var a=0;this.children.length>a;a++)this.children[a].debugDraw(e);e.restore(),this.emit("postdebugdraw",new t.PostDebugDrawEvent(e,this))},n.maxId=0,n}(t.Class);t.Actor=e,function(t){t[t.PreventCollision=0]="PreventCollision",t[t.Passive=1]="Passive",t[t.Active=2]="Active",t[t.Elastic=3]="Elastic",t[t.Fixed=4]="Fixed"}(t.CollisionType||(t.CollisionType={}));var i=t.CollisionType})(ex||(ex={}));var ex;(function(t){(function(t){t[t.Debug=0]="Debug",t[t.Info=1]="Info",t[t.Warn=2]="Warn",t[t.Error=3]="Error",t[t.Fatal=4]="Fatal"})(t.LogLevel||(t.LogLevel={}));var e=t.LogLevel,i=function(){function t(){if(this._appenders=[],this.defaultLevel=e.Info,t._instance)throw Error("Logger is a singleton");return t._instance=this,t._instance.addAppender(new n),t._instance}return t.getInstance=function(){return null==t._instance&&(t._instance=new t),t._instance},t.prototype.addAppender=function(t){this._appenders.push(t)},t.prototype.clearAppenders=function(){this._appenders.length=0},t.prototype._log=function(t,e){null==t&&(t=this.defaultLevel);var i=0,n=this._appenders.length;for(i;n>i;i++)t>=this.defaultLevel&&this._appenders[i].log(t,e)},t.prototype.debug=function(){for(var t=[],i=0;arguments.length>i;i++)t[i-0]=arguments[i];this._log(e.Debug,t)},t.prototype.info=function(){for(var t=[],i=0;arguments.length>i;i++)t[i-0]=arguments[i];this._log(e.Info,t)},t.prototype.warn=function(){for(var t=[],i=0;arguments.length>i;i++)t[i-0]=arguments[i];this._log(e.Warn,t)},t.prototype.error=function(){for(var t=[],i=0;arguments.length>i;i++)t[i-0]=arguments[i];this._log(e.Error,t)},t.prototype.fatal=function(){for(var t=[],i=0;arguments.length>i;i++)t[i-0]=arguments[i];this._log(e.Fatal,t)},t._instance=null,t}();t.Logger=i;var n=function(){function t(){}return t.prototype.log=function(t,i){if(console||console.log||!console.warn||!console.error){var n=[];n.unshift.apply(n,i),n.unshift("["+e[t]+"] : "),e.Warn>t?console.log.apply?console.log.apply(console,n):console.log(n.join(" ")):e.Error>t?console.warn.apply?console.warn.apply(console,n):console.warn(n.join(" ")):console.error.apply?console.error.apply(console,n):console.error(n.join(" "))}},t}();t.ConsoleAppender=n;var s=function(){function t(t,e){this._messages=[],this._canvas=document.createElement("canvas"),this._canvas.width=t||window.innerWidth,this._canvas.height=e||window.innerHeight,this._canvas.style.position="absolute",this._ctx=this._canvas.getContext("2d"),document.body.appendChild(this._canvas)}return t.prototype.log=function(t,i){var n=i.join(",");this._ctx.clearRect(0,0,this._canvas.width,this._canvas.height),this._messages.unshift("["+e[t]+"] : "+n);for(var s=10,o=1,r=0;this._messages.length>r;r++)this._ctx.fillStyle="rgba(255,255,255,"+o.toFixed(2)+")",this._ctx.fillText(this._messages[r],200,s),s+=10,o=o>0?o-.05:0},t}();t.ScreenAppender=s})(ex||(ex={}));var ex;(function(t){var e=function(){function t(){}return t}();t.GameEvent=e;var i=function(t){function e(e,i,n){t.call(this),this.ctx=e,this.delta=i,this.target=n}return __extends(e,t),e}(e);t.PreDrawEvent=i;var n=function(t){function e(e,i,n){t.call(this),this.ctx=e,this.delta=i,this.target=n}return __extends(e,t),e}(e);t.PostDrawEvent=n;var s=function(t){function e(e,i){t.call(this),this.ctx=e,this.target=i}return __extends(e,t),e}(e);t.PreDebugDrawEvent=s;var o=function(t){function e(e,i){t.call(this),this.ctx=e,this.target=i}return __extends(e,t),e}(e);t.PostDebugDrawEvent=o;var r=function(t){function e(e,i,n){t.call(this),this.engine=e,this.delta=i,this.target=n}return __extends(e,t),e}(e);t.PreUpdateEvent=r;var h=function(t){function e(e,i,n){t.call(this),this.engine=e,this.delta=i,this.target=n}return __extends(e,t),e}(e);t.PostUpdateEvent=h;var a=function(t){function e(e,i){t.call(this),this.index=e,this.gamepad=i}return __extends(e,t),e}(e);t.GamepadConnectEvent=a;var c=function(t){function e(e){t.call(this),this.index=e}return __extends(e,t),e}(e);t.GamepadDisconnectEvent=c;var l=function(t){function e(e,i){t.call(this),this.button=e,this.value=i}return __extends(e,t),e}(t.GameEvent);t.GamepadButtonEvent=l;var u=function(t){function e(e,i){t.call(this),this.axis=e,this.value=i}return __extends(e,t),e}(t.GameEvent);t.GamepadAxisEvent=u;var p=function(t){function e(e,i){t.call(this),this.topic=e,this.handler=i}return __extends(e,t),e}(e);t.SubscribeEvent=p;var d=function(t){function e(e,i){t.call(this),this.topic=e,this.handler=i}return __extends(e,t),e}(e);t.UnsubscribeEvent=d;var f=function(t){function e(){t.call(this)}return __extends(e,t),e}(e);t.VisibleEvent=f;var g=function(t){function e(){t.call(this)}return __extends(e,t),e}(e);t.HiddenEvent=g;var _=function(t){function e(e,i,n,s){t.call(this),this.actor=e,this.other=i,this.side=n,this.intersection=s}return __extends(e,t),e}(e);t.CollisionEvent=_;var y=function(t){function e(e){t.call(this),this.delta=e}return __extends(e,t),e}(e);t.UpdateEvent=y;var A=function(t){function e(e){t.call(this),this.engine=e}return __extends(e,t),e}(e);t.InitializeEvent=A;var v=function(t){function e(e){t.call(this),this.oldScene=e}return __extends(e,t),e}(e);t.ActivateEvent=v;var m=function(t){function e(e){t.call(this),this.newScene=e}return __extends(e,t),e}(e);t.DeactivateEvent=m;var x=function(t){function e(){t.call(this)}return __extends(e,t),e}(e);t.ExitViewPortEvent=x;var w=function(t){function e(){t.call(this)}return __extends(e,t),e}(e);t.EnterViewPortEvent=w})(ex||(ex={}));var ex;(function(t){var e=function(){function e(e){this._handlers={},this._wiredEventDispatchers=[],this._log=t.Logger.getInstance(),this._target=e}return e.prototype.publish=function(e,i){if(e){e=e.toLowerCase();var n=this._target;i||(i=new t.GameEvent),i.target=n;var s,o;if(this._handlers[e])for(s=0,o=this._handlers[e].length,s;o>s;s++)this._handlers[e][s].call(n,i);for(s=0,o=this._wiredEventDispatchers.length,s;o>s;s++)this._wiredEventDispatchers[s].emit(e,i)}},e.prototype.emit=function(t,e){this.publish(t,e)},e.prototype.subscribe=function(e,i){e=e.toLowerCase(),this._handlers[e]||(this._handlers[e]=[]),this._handlers[e].push(i),"unsubscribe"!==e&&"subscribe"!==e&&this.emit("subscribe",new t.SubscribeEvent(e,i))},e.prototype.unsubscribe=function(e,i){e=e.toLowerCase();var n=this._handlers[e];if(n)if(i){var s=n.indexOf(i);this._handlers[e].splice(s,1)}else this._handlers[e].length=0;"unsubscribe"!==e&&"subscribe"!==e&&this.emit("unsubscribe",new t.UnsubscribeEvent(e,i))},e.prototype.wire=function(t){t._wiredEventDispatchers.push(this)},e.prototype.unwire=function(t){var e=t._wiredEventDispatchers.indexOf(this);e>-1&&t._wiredEventDispatchers.splice(e,1)},e}();t.EventDispatcher=e})(ex||(ex={}));var ex;(function(t){var e=function(){function t(t,e,i,n){this.r=t,this.g=e,this.b=i,this.a=null!=n?n:1}return t.fromRGB=function(e,i,n,s){return new t(e,i,n,s)},t.fromHex=function(e){var i=/^#?([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})?$/i,n=null;if(n=e.match(i)){var s=parseInt(n[1],16),o=parseInt(n[2],16),r=parseInt(n[3],16),h=1;return n[4]&&(h=parseInt(n[4],16)/255),new t(s,o,r,h)}throw Error("Invalid hex string: "+e)},t.fromHSL=function(t,e,n,s){void 0===s&&(s=1);var o=new i(t,e,n,s);return o.toRGBA()},t.prototype.lighten=function(t){void 0===t&&(t=.1);var e=i.fromRGBA(this.r,this.g,this.b,this.a);return e.l+=e.l*t,e.toRGBA()},t.prototype.darken=function(t){void 0===t&&(t=.1);var e=i.fromRGBA(this.r,this.g,this.b,this.a);return e.l-=e.l*t,e.toRGBA()},t.prototype.saturate=function(t){void 0===t&&(t=.1);var e=i.fromRGBA(this.r,this.g,this.b,this.a);return e.s+=e.s*t,e.toRGBA()},t.prototype.desaturate=function(t){void 0===t&&(t=.1);var e=i.fromRGBA(this.r,this.g,this.b,this.a);return e.s-=e.s*t,e.toRGBA()},t.prototype.mulitiply=function(e){var i=255*(e.r/255*this.r/255),n=255*(e.g/255*this.g/255),s=255*(e.b/255*this.b/255),o=e.a*this.a;return new t(i,n,s,o)},t.prototype.screen=function(t){var e=t.invert(),i=t.invert();return e.mulitiply(i).invert()},t.prototype.invert=function(){return new t(255-this.r,255-this.g,255-this.b,1-this.a)},t.prototype.average=function(e){var i=(e.r+this.r)/2,n=(e.g+this.g)/2,s=(e.b+this.b)/2,o=(e.a+this.a)/2;return new t(i,n,s,o)},t.prototype.toString=function(){var t=this.r.toFixed(0)+""+", "+(this.g.toFixed(0)+"")+", "+(this.b.toFixed(0)+"");return void 0!==this.a||null!==this.a?"rgba("+t+", "+(this.a+"")+")":"rgb("+t+")"},t.prototype.fillStyle=function(){return""+this},t.prototype.clone=function(){return new t(this.r,this.g,this.b,this.a)},t.Black=t.fromHex("#000000"),t.White=t.fromHex("#FFFFFF"),t.Gray=t.fromHex("#808080"),t.LightGray=t.fromHex("#D3D3D3"),t.DarkGray=t.fromHex("#A9A9A9"),t.Yellow=t.fromHex("#FFFF00"),t.Orange=t.fromHex("#FFA500"),t.Red=t.fromHex("#FF0000"),t.Vermillion=t.fromHex("#FF5B31"),t.Rose=t.fromHex("#FF007F"),t.Magenta=t.fromHex("#FF00FF"),t.Violet=t.fromHex("#7F00FF"),t.Blue=t.fromHex("#0000FF"),t.Azure=t.fromHex("#007FFF"),t.Cyan=t.fromHex("#00FFFF"),t.Viridian=t.fromHex("#59978F"),t.Green=t.fromHex("#00FF00"),t.Chartreuse=t.fromHex("#7FFF00"),t.Transparent=t.fromHex("#FFFFFF00"),t}();t.Color=e;var i=function(){function t(t,e,i,n){this.h=t,this.s=e,this.l=i,this.a=n}return t.fromRGBA=function(e,i,n,s){e/=255,i/=255,n/=255;var o,r,h=Math.max(e,i,n),a=Math.min(e,i,n),c=(h+a)/2;if(h===a)o=r=0;else{var l=h-a;switch(r=c>.5?l/(2-h-a):l/(h+a),h){case e:o=(i-n)/l+(n>i?6:0);break;case i:o=(n-e)/l+2;break;case n:o=(e-i)/l+4}o/=6}return new t(o,r,c,s)},t.prototype.toRGBA=function(){function t(t,e,i){return 0>i&&(i+=1),i>1&&(i-=1),1/6>i?t+6*(e-t)*i:.5>i?e:2/3>i?t+6*(e-t)*(2/3-i):t}var i,n,s;if(0===this.s)i=n=s=this.l;else{var o=.5>this.l?this.l*(1+this.s):this.l+this.s-this.l*this.s,r=2*this.l-o;i=t(r,o,this.h+1/3),n=t(r,o,this.h),s=t(r,o,this.h-1/3)}return new e(255*i,255*n,255*s,this.a)},t}()})(ex||(ex={}));var ex;(function(t){var e=function(e){function i(i,n,s,o){e.call(this,i,n,s,o),this.traits=[],this.traits.push(new t.Traits.Movement),this.traits.push(new t.Traits.CapturePointer),this.anchor.setTo(0,0),this.collisionType=t.CollisionType.PreventCollision,this.enableCapturePointer=!0 +}return __extends(i,e),i.prototype.onInitialize=function(t){this._engine=t},i.prototype.contains=function(i,n,s){if(void 0===s&&(s=!0),s)return e.prototype.contains.call(this,i,n);var o=this._engine.worldToScreenCoordinates(new t.Point(i,n));return e.prototype.contains.call(this,o.x,o.y)},i}(t.Actor);t.UIActor=e})(ex||(ex={}));var ex;(function(t){var e=function(e){function i(i,n,s,o,r,h){e.call(this,i,n,s,o),this._action=function(){},this.repeats=1,this.target=null,this.repeats=h||this.repeats,this._action=r||this._action,this.collisionType=t.CollisionType.PreventCollision,this.eventDispatcher=new t.EventDispatcher(this),this.actionQueue=new t.Internal.Actions.ActionQueue(this)}return __extends(i,e),i.prototype.update=function(e,i){if(this.actionQueue.update(i),this.x+=this.dx*i/1e3,this.y+=this.dy*i/1e3,this.rotation+=this.rx*i/1e3,this.scale.x+=this.sx*i/1e3,this.scale.y+=this.sy*i/1e3,this.target)this.collides(this.target)&&this._dispatchAction();else for(var n=0;e.currentScene.children.length>n;n++){var s=e.currentScene.children[n];s!==this&&s.collisionType!==t.CollisionType.PreventCollision&&this.collides(s)&&this._dispatchAction()}0===this.repeats&&this.kill()},i.prototype._dispatchAction=function(){this._action.call(this),this.repeats--},i.prototype.draw=function(){},i.prototype.debugDraw=function(i){e.prototype.debugDraw.call(this,i),i.save(),i.translate(this.x,this.y);var n=this.getBounds();n.left=n.left-this.getWorldX(),n.right=n.right-this.getWorldX(),n.top=n.top-this.getWorldY(),n.bottom=n.bottom-this.getWorldY(),i.fillStyle=""+t.Color.Violet,i.strokeStyle=""+t.Color.Violet,i.fillText("Trigger",10,10),n.debugDraw(i),i.restore()},i}(t.Actor);t.Trigger=e})(ex||(ex={}));var ex;(function(t){(function(t){t[t.Circle=0]="Circle",t[t.Rectangle=1]="Rectangle"})(t.EmitterType||(t.EmitterType={}));var e=t.EmitterType,i=function(){function e(e,i,n,s,o,r,h,a,c,l){this.position=new t.Vector(0,0),this.velocity=new t.Vector(0,0),this.acceleration=new t.Vector(0,0),this.particleRotationalVelocity=0,this.currentRotation=0,this.focus=null,this.focusAccel=0,this.opacity=1,this.beginColor=t.Color.White.clone(),this.endColor=t.Color.White.clone(),this.life=300,this.fadeFlag=!1,this._rRate=1,this._gRate=1,this._bRate=1,this._aRate=0,this._currentColor=t.Color.White.clone(),this.emitter=null,this.particleSize=5,this.particleSprite=null,this.sizeRate=0,this.elapsedMultiplier=0,this.emitter=e,this.life=i||this.life,this.opacity=n||this.opacity,this.endColor=o||this.endColor.clone(),this.beginColor=s||this.beginColor.clone(),this._currentColor=this.beginColor.clone(),this.position=r||this.position,this.velocity=h||this.velocity,this.acceleration=a||this.acceleration,this._rRate=(this.endColor.r-this.beginColor.r)/this.life,this._gRate=(this.endColor.g-this.beginColor.g)/this.life,this._bRate=(this.endColor.b-this.beginColor.b)/this.life,this._aRate=this.opacity/this.life,this.startSize=c||0,this.endSize=l||0,this.endSize>0&&this.startSize>0&&(this.sizeRate=(this.endSize-this.startSize)/this.life,this.particleSize=this.startSize)}return e.prototype.kill=function(){this.emitter.removeParticle(this)},e.prototype.update=function(e){if(this.life=this.life-e,this.elapsedMultiplier=this.elapsedMultiplier+e,0>this.life&&this.kill(),this.fadeFlag&&(this.opacity=t.Util.clamp(this._aRate*this.life,1e-4,1)),this.startSize>0&&this.endSize>0&&(this.particleSize=t.Util.clamp(this.sizeRate*e+this.particleSize,Math.min(this.startSize,this.endSize),Math.max(this.startSize,this.endSize))),this._currentColor.r=t.Util.clamp(this._currentColor.r+this._rRate*e,0,255),this._currentColor.g=t.Util.clamp(this._currentColor.g+this._gRate*e,0,255),this._currentColor.b=t.Util.clamp(this._currentColor.b+this._bRate*e,0,255),this._currentColor.a=t.Util.clamp(this.opacity,1e-4,1),this.focus){var i=this.focus.minus(this.position).normalize().scale(this.focusAccel).scale(e/1e3);this.velocity=this.velocity.add(i)}else this.velocity=this.velocity.add(this.acceleration.scale(e/1e3));this.position=this.position.add(this.velocity.scale(e/1e3)),this.particleRotationalVelocity&&(this.currentRotation=(this.currentRotation+this.particleRotationalVelocity*e/1e3)%(2*Math.PI))},e.prototype.draw=function(e){return this.particleSprite?(this.particleSprite.rotation=this.currentRotation,this.particleSprite.scale.setTo(this.particleSize,this.particleSize),this.particleSprite.draw(e,this.position.x,this.position.y),void 0):(this._currentColor.a=t.Util.clamp(this.opacity,1e-4,1),e.fillStyle=""+this._currentColor,e.beginPath(),e.arc(this.position.x,this.position.y,this.particleSize,0,2*Math.PI),e.fill(),e.closePath(),void 0)},e}();t.Particle=i;var n=function(n){function s(i,s,o,r){n.call(this,i,s,o,r,t.Color.White),this._particlesToEmit=0,this.numParticles=0,this.isEmitting=!0,this.particles=null,this.deadParticles=null,this.minVel=0,this.maxVel=0,this.acceleration=new t.Vector(0,0),this.minAngle=0,this.maxAngle=0,this.emitRate=1,this.particleLife=2e3,this.opacity=1,this.fadeFlag=!1,this.focus=null,this.focusAccel=1,this.startSize=null,this.endSize=null,this.minSize=5,this.maxSize=5,this.beginColor=t.Color.White,this.endColor=t.Color.White,this.particleSprite=null,this.emitterType=e.Rectangle,this.radius=0,this.particleRotationalVelocity=0,this.randomRotation=!1,this.collisionType=t.CollisionType.PreventCollision,this.particles=new t.Util.Collection,this.deadParticles=new t.Util.Collection;for(var h in this.traits)this.traits[h]instanceof t.Traits.OffscreenCulling&&this.traits.splice(h,1)}return __extends(s,n),s.prototype.removeParticle=function(t){this.deadParticles.push(t)},s.prototype.emitParticles=function(t){for(var e=0;t>e;e++)this.particles.push(this._createParticle())},s.prototype.clearParticles=function(){this.particles.clear()},s.prototype._createParticle=function(){var n=0,s=0,o=t.Util.randomInRange(this.minAngle,this.maxAngle),r=t.Util.randomInRange(this.minVel,this.maxVel),h=this.startSize||t.Util.randomInRange(this.minSize,this.maxSize),a=r*Math.cos(o),c=r*Math.sin(o);if(this.emitterType===e.Rectangle)n=t.Util.randomInRange(this.x,this.x+this.getWidth()),s=t.Util.randomInRange(this.y,this.y+this.getHeight());else if(this.emitterType===e.Circle){var l=t.Util.randomInRange(0,this.radius);n=l*Math.cos(o)+this.x,s=l*Math.sin(o)+this.y}var u=new i(this,this.particleLife,this.opacity,this.beginColor,this.endColor,new t.Vector(n,s),new t.Vector(a,c),this.acceleration,this.startSize,this.endSize);return u.fadeFlag=this.fadeFlag,u.particleSize=h,this.particleSprite&&(u.particleSprite=this.particleSprite),u.particleRotationalVelocity=this.particleRotationalVelocity,this.randomRotation&&(u.currentRotation=t.Util.randomInRange(0,2*Math.PI)),this.focus&&(u.focus=this.focus.add(new t.Vector(this.x,this.y)),u.focusAccel=this.focusAccel),u},s.prototype.update=function(t,e){var i=this;n.prototype.update.call(this,t,e),this.isEmitting&&(this._particlesToEmit+=this.emitRate*(e/1e3),this._particlesToEmit>1&&(this.emitParticles(Math.floor(this._particlesToEmit)),this._particlesToEmit=this._particlesToEmit-Math.floor(this._particlesToEmit))),this.particles.forEach(function(t){return t.update(e)}),this.deadParticles.forEach(function(t){return i.particles.removeElement(t)}),this.deadParticles.clear()},s.prototype.draw=function(t){this.particles.forEach(function(e){return e.draw(t)})},s.prototype.debugDraw=function(e){n.prototype.debugDraw.call(this,e),e.fillStyle=""+t.Color.Black,e.fillText("Particles: "+this.particles.count(),this.x,this.y+20),this.focus&&(e.fillRect(this.focus.x+this.x,this.focus.y+this.y,3,3),t.Util.drawLine(e,"yellow",this.focus.x+this.x,this.focus.y+this.y,n.prototype.getCenter.call(this).x,n.prototype.getCenter.call(this).y),e.fillText("Focus",this.focus.x+this.x,this.focus.y+this.y))},s}(t.Actor);t.ParticleEmitter=n})(ex||(ex={}));var ex;(function(t){var e=function(){function e(e,i,n,s){this.currentFrame=0,this._oldTime=Date.now(),this.anchor=new t.Point(0,0),this.rotation=0,this.scale=new t.Point(1,1),this.loop=!1,this.freezeFrame=-1,this.flipVertical=!1,this.flipHorizontal=!1,this.width=0,this.height=0,this.naturalWidth=0,this.naturalHeight=0,this.sprites=i,this.speed=n,this._engine=e,null!=s&&(this.loop=s),i&&i[0]&&(this.height=i[0]?i[0].height:0,this.width=i[0]?i[0].width:0,this.naturalWidth=i[0]?i[0].naturalWidth:0,this.naturalHeight=i[0]?i[0].naturalHeight:0,this.freezeFrame=i.length-1)}return e.prototype.opacity=function(e){this.addEffect(new t.Effects.Opacity(e))},e.prototype.grayscale=function(){this.addEffect(new t.Effects.Grayscale)},e.prototype.invert=function(){this.addEffect(new t.Effects.Invert)},e.prototype.fill=function(e){this.addEffect(new t.Effects.Fill(e))},e.prototype.colorize=function(e){this.addEffect(new t.Effects.Colorize(e))},e.prototype.lighten=function(e){void 0===e&&(e=.1),this.addEffect(new t.Effects.Lighten(e))},e.prototype.darken=function(e){void 0===e&&(e=.1),this.addEffect(new t.Effects.Darken(e))},e.prototype.saturate=function(e){void 0===e&&(e=.1),this.addEffect(new t.Effects.Saturate(e))},e.prototype.desaturate=function(e){void 0===e&&(e=.1),this.addEffect(new t.Effects.Desaturate(e))},e.prototype.addEffect=function(t){for(var e in this.sprites)this.sprites[e].addEffect(t)},e.prototype.removeEffect=function(t){for(var e in this.sprites)this.sprites[e].removeEffect(t)},e.prototype.clearEffects=function(){for(var t in this.sprites)this.sprites[t].clearEffects()},e.prototype._setAnchor=function(t){for(var e in this.sprites)this.sprites[e].anchor.setTo(t.x,t.y)},e.prototype._setRotation=function(t){for(var e in this.sprites)this.sprites[e].rotation=t},e.prototype._setScale=function(t){for(var e in this.sprites)this.sprites[e].scale=t},e.prototype.reset=function(){this.currentFrame=0},e.prototype.isDone=function(){return!this.loop&&this.currentFrame>=this.sprites.length},e.prototype.tick=function(){var t=Date.now();t-this._oldTime>this.speed&&(this.currentFrame=this.loop?(this.currentFrame+1)%this.sprites.length:this.currentFrame+1,this._oldTime=t)},e.prototype._updateValues=function(){this._setAnchor(this.anchor),this._setRotation(this.rotation),this._setScale(this.scale)},e.prototype.skip=function(t){this.currentFrame=(this.currentFrame+t)%this.sprites.length},e.prototype.draw=function(e,i,n){this.tick(),this._updateValues();var s;this.currentFrame=this.sprites.length&&(s=this.sprites[t.Util.clamp(this.freezeFrame,0,this.sprites.length-1)],s.draw(e,i,n)),s&&(this.width=s.width,this.height=s.height)},e.prototype.play=function(t,e){this.reset(),this._engine.playAnimation(this,t,e)},e}();t.Animation=e})(ex||(ex={}));var ex;(function(t){var e;(function(e){var i=function(){function e(e,i){this._log=t.Logger.getInstance(),this.onload=function(){},this.onprogress=function(){},this.onerror=function(){},window.AudioContext?(this._log.debug("Using new Web Audio Api for "+e),this._soundImpl=new o(e,i)):(this._log.debug("Falling back to Audio Element for "+e),this._soundImpl=new n(e,i))}return e.prototype.setVolume=function(t){this._soundImpl.setVolume(t)},e.prototype.setLoop=function(t){this._soundImpl.setLoop(t)},e.prototype.load=function(){this._soundImpl.onload=this.onload,this._soundImpl.onprogress=this.onprogress,this._soundImpl.onerror=this.onerror,this._soundImpl.load()},e.prototype.isPlaying=function(){return this._soundImpl.isPlaying()},e.prototype.play=function(){return this._soundImpl.play()},e.prototype.pause=function(){this._soundImpl.pause()},e.prototype.stop=function(){this._soundImpl.stop()},e}();e.FallbackAudio=i;var n=function(){function e(e,i){var n=this;this.path=e,this._audioElements=Array(5),this._loadedAudio=null,this._isLoaded=!1,this._index=0,this._log=t.Logger.getInstance(),this._isPlaying=!1,this._currentOffset=0,this.onload=function(){},this.onprogress=function(){},this.onerror=function(){};for(var s=0;this._audioElements.length>s;s++)(function(t){n._audioElements[t]=new Audio})(s);i?this.setVolume(t.Util.clamp(i,0,1)):this.setVolume(1)}return e.prototype.isPlaying=function(){return this._isPlaying},e.prototype._audioLoaded=function(){this._isLoaded=!0},e.prototype.setVolume=function(t){var e=0,i=this._audioElements.length;for(e;i>e;e++)this._audioElements[e].volume=t},e.prototype.setLoop=function(t){var e=0,i=this._audioElements.length;for(e;i>e;e++)this._audioElements[e].loop=t},e.prototype.getLoop=function(){this._audioElements.some(function(t){return t.loop})},e.prototype.load=function(){var t=this,e=new XMLHttpRequest;e.open("GET",this.path,!0),e.responseType="blob",e.onprogress=this.onprogress,e.onerror=this.onerror,e.onload=function(i){return 200!==e.status?(t._log.error("Failed to load audio resource ",t.path," server responded with error code",e.status),t.onerror(e.response),t._isLoaded=!1,void 0):(t._loadedAudio=URL.createObjectURL(e.response),t._audioElements.forEach(function(e){e.src=t._loadedAudio}),t.onload(i),void 0)},e.send()},e.prototype.play=function(){var e=this;this._audioElements[this._index].load(),this._audioElements[this._index].play(),this._currentOffset=0;var i=new t.Promise;return this._isPlaying=!0,this.getLoop()||this._audioElements[this._index].addEventListener("ended",function(){e._isPlaying=!1,i.resolve(!0)}),this._index=(this._index+1)%this._audioElements.length,i},e.prototype.pause=function(){this._index=(this._index-1+this._audioElements.length)%this._audioElements.length,this._currentOffset=this._audioElements[this._index].currentTime,this._audioElements.forEach(function(t){t.pause()}),this._isPlaying=!1},e.prototype.stop=function(){this._audioElements.forEach(function(t){t.pause()}),this._isPlaying=!1},e}();if(e.AudioTag=n,window.AudioContext)var s=new window.AudioContext;var o=function(){function e(e,i){this._context=s,this._volume=this._context.createGain(),this._buffer=null,this._sound=null,this._path="",this._isLoaded=!1,this._loop=!1,this._isPlaying=!1,this._isPaused=!1,this._currentOffset=0,this._logger=t.Logger.getInstance(),this.onload=function(){},this.onprogress=function(){},this.onerror=function(){},this._path=e,this._volume.gain.value=i?t.Util.clamp(i,0,1):1}return e.prototype.setVolume=function(t){this._volume.gain.value=t},e.prototype.load=function(){var t=this,e=new XMLHttpRequest;e.open("GET",this._path),e.responseType="arraybuffer",e.onprogress=this.onprogress,e.onerror=this.onerror,e.onload=function(){return 200!==e.status?(t._logger.error("Failed to load audio resource ",t._path," server responded with error code",e.status),t.onerror(e.response),t._isLoaded=!1,void 0):(t._context.decodeAudioData(e.response,function(e){t._buffer=e,t._isLoaded=!0,t.onload(t)},function(){t._logger.error("Unable to decode "+t._path+" this browser may not fully support this format, or the file may be corrupt, "+"if this is an mp3 try removing id3 tags and album art from the file."),t._isLoaded=!1,t.onload(t)}),void 0)};try{e.send()}catch(i){console.error("Error loading sound! If this is a cross origin error, you must host your sound with your html and javascript.")}},e.prototype.setLoop=function(t){this._loop=t},e.prototype.isPlaying=function(){return this._isPlaying},e.prototype.play=function(){var e=this;if(this._isLoaded){this._sound=this._context.createBufferSource(),this._sound.buffer=this._buffer,this._sound.loop=this._loop,this._sound.connect(this._volume),this._volume.connect(this._context.destination),this._sound.start(0,this._currentOffset%this._buffer.duration),this._currentOffset=0;var i;return i=this._isPaused&&this._playPromise?this._playPromise:new t.Promise,this._isPaused=!1,this._isPlaying=!0,this._loop||(this._sound.onended=function(){e._isPlaying=!1,e._isPaused||i.resolve(!0)}.bind(this)),this._playPromise=i,i}return t.Promise.wrap(!0)},e.prototype.pause=function(){if(this._isPlaying)try{window.clearTimeout(this._playingTimer),this._sound.stop(0),this._currentOffset=this._context.currentTime,this._isPlaying=!1,this._isPaused=!0}catch(t){this._logger.warn("The sound clip",this._path,"has already been paused!")}},e.prototype.stop=function(){if(this._sound)try{window.clearTimeout(this._playingTimer),this._currentOffset=0,this._sound.stop(0),this._isPlaying=!1,this._isPaused=!1}catch(t){this._logger.warn("The sound clip",this._path,"has already been stopped!")}},e}();e.WebAudio=o})(e=t.Internal||(t.Internal={}))})(ex||(ex={}));var ex;(function(t){(function(t){t[t.Resolved=0]="Resolved",t[t.Rejected=1]="Rejected",t[t.Pending=2]="Pending"})(t.PromiseState||(t.PromiseState={}));var e=t.PromiseState,i=function(){function i(){this._state=e.Pending,this._successCallbacks=[],this._rejectCallback=function(){},this._logger=t.Logger.getInstance()}return i.wrap=function(t){var e=(new i).resolve(t);return e},i.join=function(){for(var t=[],e=0;arguments.length>e;e++)t[e-0]=arguments[e];var n=new i;if(!t||!t.length)return n.resolve();var s=t.length,o=0,r=0,h=[];return t.forEach(function(t){t.then(function(){o+=1,o===s?n.resolve():o+r+h.length===s&&n.reject(h)},function(){r+=1,o+r+h.length===s&&n.reject(h)}).error(function(t){h.push(t),h.length+o+r===s&&n.reject(h)})}),n},i.prototype.then=function(t,i){if(t&&(this._successCallbacks.push(t),this.state()===e.Resolved))try{t.call(this,this._value)}catch(n){this._handleError(n)}if(i&&(this._rejectCallback=i,this.state()===e.Rejected))try{i.call(this,this._value)}catch(n){this._handleError(n)}return this},i.prototype.error=function(t){return t&&(this._errorCallback=t),this},i.prototype.resolve=function(t){var i=this;if(this._state!==e.Pending)throw Error("Cannot resolve a promise that is not in a pending state!");this._value=t;try{this._state=e.Resolved,this._successCallbacks.forEach(function(t){t.call(i,i._value)})}catch(n){this._handleError(n)}return this},i.prototype.reject=function(t){if(this._state!==e.Pending)throw Error("Cannot reject a promise that is not in a pending state!");this._value=t;try{this._state=e.Rejected,this._rejectCallback.call(this,this._value)}catch(i){this._handleError(i)}return this},i.prototype.state=function(){return this._state},i.prototype._handleError=function(t){if(!this._errorCallback)throw t;this._errorCallback.call(this,t)},i}();t.Promise=i})(ex||(ex={}));var ex;(function(t){var e=function(){function e(e,i,n){void 0===n&&(n=!0),this.path=e,this.responseType=i,this.bustCache=n,this.data=null,this.logger=t.Logger.getInstance(),this.onprogress=function(){},this.oncomplete=function(){},this.onerror=function(){}}return e.prototype.isLoaded=function(){return!!this.data},e.prototype.wireEngine=function(t){this._engine=t},e.prototype._cacheBust=function(t){var e=/\?\w*=\w*/;return t+=e.test(t)?"&__="+Date.now():"?__="+Date.now()},e.prototype._start=function(){this.logger.debug("Started loading resource "+this.path)},e.prototype.load=function(){var e=this,i=new t.Promise,n=new XMLHttpRequest;return n.open("GET",this.bustCache?this._cacheBust(this.path):this.path,!0),n.responseType=this.responseType,n.onloadstart=function(t){e._start(t)},n.onprogress=this.onprogress,n.onerror=this.onerror,n.onload=function(){return 200!==n.status?(e.logger.error("Failed to load resource ",e.path," server responded with error code",n.status),e.onerror(n.response),i.resolve(n.response),void 0):(e.data=e.processDownload(n.response),e.oncomplete(),e.logger.debug("Completed loading resource",e.path),i.resolve(e.data),void 0)},n.send(),i},e.prototype.getData=function(){return this.data},e.prototype.processDownload=function(t){return URL.createObjectURL(t)},e}();t.Resource=e})(ex||(ex={}));var ex;(function(t){var e=function(e){function i(i,n){void 0===n&&(n=!0),e.call(this,i,"blob",n),this.path=i,this.bustCache=n,this.loaded=new t.Promise,this._isLoaded=!1,this._sprite=null,this._sprite=new t.Sprite(this,0,0,0,0)}return __extends(i,e),i.prototype.isLoaded=function(){return this._isLoaded},i.prototype.load=function(){var i=this,n=new t.Promise,s=e.prototype.load.call(this);return s.then(function(){i.image=new Image,i.image.addEventListener("load",function(){i._isLoaded=!0,i.width=i._sprite.swidth=i._sprite.naturalWidth=i._sprite.width=i.image.naturalWidth,i.height=i._sprite.sheight=i._sprite.naturalHeight=i._sprite.height=i.image.naturalHeight,i.loaded.resolve(i.image),n.resolve(i.image)}),i.image.src=e.prototype.getData.call(i)},function(){n.reject("Error loading texture.")}),n},i.prototype.asSprite=function(){return this._sprite},i}(t.Resource);t.Texture=e;var i=function(){function e(){for(var i=[],n=0;arguments.length>n;n++)i[n-0]=arguments[n];this._logger=t.Logger.getInstance(),this.onprogress=function(){},this.oncomplete=function(){},this.onerror=function(){},this.onload=function(){},this._isLoaded=!1,this._selectedFile="",this._wasPlayingOnHidden=!1,this._selectedFile="";for(var s=0;i.length>s;s++)if(e.canPlayFile(i[s])){this._selectedFile=i[s];break}this._selectedFile||(this._logger.warn("This browser does not support any of the audio files specified:",i.join(", ")),this._logger.warn("Attempting to use",i[0]),this._selectedFile=i[0]),this.sound=new t.Internal.FallbackAudio(this._selectedFile,1)}return e.canPlayFile=function(e){try{var i=new Audio,n=/.*\.([A-Za-z0-9]+)$/,s=e.match(n)[1];return i.canPlayType("audio/"+s)?!0:!1}catch(o){return t.Logger.getInstance().warn("Cannot determine audio support, assuming no support for the Audio Tag",o),!1}},e.prototype.wireEngine=function(t){var e=this;t&&(this._engine=t,this._engine.on("hidden",function(){t.pauseAudioWhenHidden&&e.isPlaying()&&(e._wasPlayingOnHidden=!0,e.pause())}),this._engine.on("visible",function(){t.pauseAudioWhenHidden&&e._wasPlayingOnHidden&&(e.play(),e._wasPlayingOnHidden=!1)}))},e.prototype.setVolume=function(t){this.sound&&this.sound.setVolume(t)},e.prototype.setLoop=function(t){this.sound&&this.sound.setLoop(t)},e.prototype.isPlaying=function(){return this.sound?this.sound.isPlaying():void 0},e.prototype.play=function(){return this.sound?this.sound.play():void 0},e.prototype.pause=function(){this.sound&&this.sound.pause()},e.prototype.stop=function(){this.sound&&this.sound.stop()},e.prototype.isLoaded=function(){return this._isLoaded},e.prototype.load=function(){var e=this,i=new t.Promise;return this._logger.debug("Started loading sound",this._selectedFile),this.sound.onprogress=this.onprogress,this.sound.onload=function(){e.oncomplete(),e._isLoaded=!0,e._logger.debug("Completed loading sound",e._selectedFile),i.resolve(e.sound)},this.sound.onerror=function(t){e.onerror(t),i.resolve(t)},this.sound.load(),i},e}();t.Sound=i;var n=function(){function e(t){this._resourceList=[],this._index=0,this._resourceCount=0,this._numLoaded=0,this._progressCounts={},this._totalCounts={},this.onprogress=function(){},this.oncomplete=function(){},this.onerror=function(){},t&&this.addResources(t)}return e.prototype.wireEngine=function(t){this._engine=t},e.prototype.addResource=function(t){var e=this._index++;this._resourceList.push(t),this._progressCounts[e]=0,this._totalCounts[e]=1,this._resourceCount++},e.prototype.addResources=function(t){var e=0,i=t.length;for(e;i>e;e++)this.addResource(t[e])},e.prototype._sumCounts=function(t){var e=0;for(var i in t)e+=0|t[i];return e},e.prototype.isLoaded=function(){return this._numLoaded===this._resourceCount},e.prototype.load=function(){function e(t,i){t[i]&&t[i].load().then(function(){e(t,i+1)})}var i=this,n=new t.Promise,s=this;if(0===this._resourceList.length)return s.oncomplete.call(s),n;var o=Array(this._resourceList.length),r=this._resourceList.length;return this._resourceList.forEach(function(t,e){i._engine&&t.wireEngine(i._engine),t.onprogress=function(t){var i=t.total,n=t.loaded;o[e]={loaded:n/i*(100/r),total:100};var h=o.reduce(function(t,e){return{loaded:t.loaded+e.loaded,total:100}},{loaded:0,total:100});s.onprogress.call(s,h)},t.oncomplete=t.onerror=function(){s._numLoaded++,s._numLoaded===s._resourceCount&&(s.onprogress.call(s,{loaded:100,total:100}),s.oncomplete.call(s),n.resolve())}}),e(this._resourceList,0),n},e}();t.Loader=n})(ex||(ex={}));var ex;(function(t){var e=function(){function e(){this.failedTests=[],this._criticalTests={canvasSupport:function(){var t=document.createElement("canvas");return!(!t.getContext||!t.getContext("2d"))},arrayBufferSupport:function(){var t=new XMLHttpRequest;t.open("GET","/");try{t.responseType="arraybuffer"}catch(e){return!1}return"arraybuffer"===t.responseType},dataUrlSupport:function(){var t=document.createElement("canvas");return 0===t.toDataURL("image/png").indexOf("data:image/png")},objectUrlSupport:function(){return"URL"in window&&"revokeObjectURL"in URL&&"createObjectURL"in URL},rgbaSupport:function(){var t=document.createElement("a").style;return t.cssText="background-color:rgba(150,255,150,.5)",(""+t.backgroundColor).indexOf("rgba")>-1}},this._warningTest={webAudioSupport:function(){return!!(window.AudioContext||window.webkitAudioContext||window.mozAudioContext||window.msAudioContext||window.oAudioContext)},webglSupport:function(){var t=document.createElement("canvas");return!(!t.getContext||!t.getContext("webgl"))}}}return e.prototype.test=function(){var e=!1;for(var i in this._criticalTests)this._criticalTests[i]()||(this.failedTests.push(i),t.Logger.getInstance().error("Critical browser feature missing, Excalibur requires:",i),e=!0);if(e)return!1;for(var n in this._warningTest)this._warningTest[n]()||t.Logger.getInstance().warn("Warning browser feature missing, Excalibur will have reduced performance:",n);return!0},e}();t.Detector=e})(ex||(ex={}));var ex;(function(t){var e=function(){function e(e){this.path=e,this._isLoaded=!1,this.logger=t.Logger.getInstance(),this.onprogress=function(){},this.oncomplete=function(){},this.onerror=function(){},this._innerElement=document.createElement("div"),this._innerElement.className="excalibur-template"}return e.prototype.wireEngine=function(t){this._engine=t},e.prototype.getTemplateString=function(){return this._isLoaded?this._htmlString:""},e.prototype._compile=function(){this._innerElement.innerHTML=this._htmlString,this._styleElements=this._innerElement.querySelectorAll("[data-style]"),this._textElements=this._innerElement.querySelectorAll("[data-text]")},e.prototype._evaluateExpresion=function(t,e){var i=Function("return "+t+";"),n=i.call(e);return n},e.prototype.apply=function(t){for(var e=this,i=0;this._styleElements.length>i;i++)(function(){var n={};e._styleElements[i].dataset.style.split(";").forEach(function(t){if(t){var e=t.split(":");n[e[0].trim()]=e[1].trim()}});for(var s in n)(function(){var o=n[s];e._styleElements[i].style[s]=e._evaluateExpresion(o,t)})()})();for(var n=0;this._textElements.length>n;n++)(function(){var i=e._textElements[n].dataset.text;e._textElements[n].innerText=e._evaluateExpresion(i,t)})();return 1===this._innerElement.children.length&&(this._innerElement=this._innerElement.firstChild),this._innerElement},e.prototype.load=function(){var e=this,i=new t.Promise,n=new XMLHttpRequest;return n.open("GET",this.path,!0),n.responseType="text",n.onprogress=this.onprogress,n.onerror=this.onerror,n.onload=function(){return 200!==n.status?(e.logger.error("Failed to load html template resource ",e.path," server responded with error code",n.status),e.onerror(n.response),e._isLoaded=!1,i.resolve("error"),void 0):(e._htmlString=n.response,e.oncomplete(),e.logger.debug("Completed loading template",e.path),e._compile(),e._isLoaded=!0,i.resolve(e._htmlString),void 0)},n.overrideMimeType&&n.overrideMimeType("text/plain; charset=x-user-defined"),n.send(),i},e.prototype.isLoaded=function(){return this._isLoaded},e}();t.Template=e;var i=function(){function t(t,e,i){this.parent=document.getElementById(t),this.template=e,this._ctx=i,this.update()}return t.prototype.listen=function(t,e,i){var n=this;i||(i=function(){n.update()}),t.addEventListener&&e.forEach(function(e){t.addEventListener(e,i)})},t.prototype.update=function(){var t=this._applyTemplate(this.template,this._ctx);t instanceof String&&(this.parent.innerHTML=t),t instanceof Node&&this.parent.lastChild!==t&&this.parent.appendChild(t)},t.prototype._applyTemplate=function(t,e){return t.isLoaded()?t.apply(e):void 0},t}();t.Binding=i})(ex||(ex={}));var ex;(function(t){(function(t){t[t.Em=0]="Em",t[t.Rem=1]="Rem",t[t.Px=2]="Px",t[t.Pt=3]="Pt",t[t.Percent=4]="Percent"})(t.FontUnit||(t.FontUnit={}));var e=t.FontUnit;(function(t){t[t.Left=0]="Left",t[t.Right=1]="Right",t[t.Center=2]="Center",t[t.Start=3]="Start",t[t.End=4]="End"})(t.TextAlign||(t.TextAlign={}));var i=t.TextAlign;(function(t){t[t.Top=0]="Top",t[t.Hanging=1]="Hanging",t[t.Middle=2]="Middle",t[t.Alphabetic=3]="Alphabetic",t[t.Ideographic=4]="Ideographic",t[t.Bottom=5]="Bottom"})(t.BaseAlign||(t.BaseAlign={}));var n=t.BaseAlign,s=function(s){function o(o,r,h,a,c){s.call(this,r,h),this.fontSize=10,this.fontUnit=e.Px,this.textAlign=i.Left,this.baseAlign=n.Bottom,this.letterSpacing=0,this.caseInsensitive=!0,this._textShadowOn=!1,this._shadowOffsetX=0,this._shadowOffsetY=0,this._shadowColor=t.Color.Black.clone(),this._shadowColorDirty=!1,this._textSprites={},this._shadowSprites={},this._color=t.Color.Black.clone(),this.text=o||"",this.color=t.Color.Black.clone(),this.spriteFont=c,this.collisionType=t.CollisionType.PreventCollision,this.fontFamily=a||"10px sans-serif"}return __extends(o,s),o.prototype.getTextWidth=function(t){var e=t.font;t.font=this.fontFamily;var i=t.measureText(this.text).width;return t.font=e,i},o.prototype._lookupFontUnit=function(t){switch(t){case e.Em:return"em";case e.Rem:return"rem";case e.Pt:return"pt";case e.Px:return"px";case e.Percent:return"%";default:return"px"}},o.prototype._lookupTextAlign=function(t){switch(t){case i.Left:return"left";case i.Right:return"right";case i.Center:return"center";case i.End:return"end";case i.Start:return"start";default:return"start"}},o.prototype._lookupBaseAlign=function(t){switch(t){case n.Alphabetic:return"alphabetic";case n.Bottom:return"bottom";case n.Hanging:return"hangin";case n.Ideographic:return"ideographic";case n.Middle:return"middle";case n.Top:return"top";default:return"alphabetic"}},o.prototype.setTextShadow=function(t,e,i){this.spriteFont.setTextShadow(t,e,i)},o.prototype.useTextShadow=function(t){this.spriteFont.useTextShadow(t)},o.prototype.clearTextShadow=function(){this._textShadowOn=!1,this._shadowOffsetX=0,this._shadowOffsetY=0,this._shadowColor=t.Color.Black.clone()},o.prototype.update=function(t,e){s.prototype.update.call(this,t,e)},o.prototype.draw=function(t,e){t.save(),t.translate(this.x,this.y),t.scale(this.scale.x,this.scale.y),t.rotate(this.rotation),this._textShadowOn&&(t.save(),t.translate(this._shadowOffsetX,this._shadowOffsetY),this._fontDraw(t,e,this._shadowSprites),t.restore()),this._fontDraw(t,e,this._textSprites),s.prototype.draw.call(this,t,e),t.restore()},o.prototype._fontDraw=function(t){if(this.spriteFont)this.spriteFont.draw(t,this.text,0,0,{color:this.color.clone(),baseAlign:this.baseAlign,textAlign:this.textAlign,fontSize:this.fontSize,letterSpacing:this.letterSpacing,opacity:this.opacity});else{var e=t.textAlign,i=t.textBaseline;t.textAlign=this._lookupTextAlign(this.textAlign),t.textBaseline=this._lookupBaseAlign(this.baseAlign),this.color&&(this.color.a=this.opacity),t.fillStyle=""+this.color,t.font=""+this.fontSize+this._lookupFontUnit(this.fontUnit)+" "+this.fontFamily,this.maxWidth?t.fillText(this.text,0,0,this.maxWidth):t.fillText(this.text,0,0),t.textAlign=e,t.textBaseline=i}},o.prototype.debugDraw=function(t){s.prototype.debugDraw.call(this,t)},o}(t.Actor);t.Label=s})(ex||(ex={}));var ex;(function(t){var e;(function(e){(function(t){t[t.Touch=0]="Touch",t[t.Mouse=1]="Mouse",t[t.Pen=2]="Pen",t[t.Unknown=3]="Unknown"})(e.PointerType||(e.PointerType={}));var i=e.PointerType;(function(t){t[t.Left=0]="Left",t[t.Middle=1]="Middle",t[t.Right=2]="Right",t[t.Unknown=3]="Unknown"})(e.PointerButton||(e.PointerButton={}));var n=e.PointerButton;(function(t){t[t.Canvas=0]="Canvas",t[t.Document=1]="Document" +})(e.PointerScope||(e.PointerScope={}));var s=e.PointerScope,o=function(t){function e(e,i,n,s,o,r){t.call(this),this.x=e,this.y=i,this.index=n,this.pointerType=s,this.button=o,this.ev=r}return __extends(e,t),e}(t.GameEvent);e.PointerEvent=o;var r=function(e){function r(t){e.call(this),this._pointerDown=[],this._pointerUp=[],this._pointerMove=[],this._pointerCancel=[],this._pointers=[],this._activePointers=[],this._engine=t,this._pointers.push(new h),this._activePointers=[-1],this.primary=this._pointers[0]}return __extends(r,e),r.prototype.init=function(t){void 0===t&&(t=s.Document);var e=document;e=t===s.Document?document:this._engine.canvas,e.addEventListener("touchstart",this._handleTouchEvent("down",this._pointerDown)),e.addEventListener("touchend",this._handleTouchEvent("up",this._pointerUp)),e.addEventListener("touchmove",this._handleTouchEvent("move",this._pointerMove)),e.addEventListener("touchcancel",this._handleTouchEvent("cancel",this._pointerCancel)),window.PointerEvent?(this._engine.canvas.style.touchAction="none",e.addEventListener("pointerdown",this._handlePointerEvent("down",this._pointerDown)),e.addEventListener("pointerup",this._handlePointerEvent("up",this._pointerUp)),e.addEventListener("pointermove",this._handlePointerEvent("move",this._pointerMove)),e.addEventListener("pointercancel",this._handlePointerEvent("cancel",this._pointerMove))):window.MSPointerEvent?(this._engine.canvas.style.msTouchAction="none",e.addEventListener("MSPointerDown",this._handlePointerEvent("down",this._pointerDown)),e.addEventListener("MSPointerUp",this._handlePointerEvent("up",this._pointerUp)),e.addEventListener("MSPointerMove",this._handlePointerEvent("move",this._pointerMove)),e.addEventListener("MSPointerCancel",this._handlePointerEvent("cancel",this._pointerMove))):(e.addEventListener("mousedown",this._handleMouseEvent("down",this._pointerDown)),e.addEventListener("mouseup",this._handleMouseEvent("up",this._pointerUp)),e.addEventListener("mousemove",this._handleMouseEvent("move",this._pointerMove)))},r.prototype.update=function(){this._pointerUp.length=0,this._pointerDown.length=0,this._pointerMove.length=0,this._pointerCancel.length=0},r.prototype.at=function(t){if(t>=this._pointers.length)for(var e=this._pointers.length-1,i=t;i>e;e++)this._pointers.push(new h),this._activePointers.push(-1);return this._pointers[t]},r.prototype.count=function(){return this._pointers.length},r.prototype.propogate=function(e){var i=e instanceof t.UIActor,n=0,s=this._pointerUp.length;for(n;s>n;n++)e.contains(this._pointerUp[n].x,this._pointerUp[n].y,!i)&&e.eventDispatcher.emit("pointerup",this._pointerUp[n]);for(n=0,s=this._pointerDown.length,n;s>n;n++)e.contains(this._pointerDown[n].x,this._pointerDown[n].y,!i)&&e.eventDispatcher.emit("pointerdown",this._pointerDown[n]);if(e.capturePointer.captureMoveEvents)for(n=0,s=this._pointerMove.length,n;s>n;n++)e.contains(this._pointerMove[n].x,this._pointerMove[n].y,!i)&&e.eventDispatcher.emit("pointermove",this._pointerMove[n]);for(n=0,s=this._pointerCancel.length,n;s>n;n++)e.contains(this._pointerCancel[n].x,this._pointerCancel[n].y,!i)&&e.eventDispatcher.emit("pointercancel",this._pointerCancel[n])},r.prototype._handleMouseEvent=function(e,n){var s=this;return function(r){r.preventDefault();var h=r.pageX-t.Util.getPosition(s._engine.canvas).x,a=r.pageY-t.Util.getPosition(s._engine.canvas).y,c=s._engine.screenToWorldCoordinates(new t.Point(h,a)),l=new o(c.x,c.y,0,i.Mouse,r.button,r);n.push(l),s.at(0).eventDispatcher.emit(e,l)}},r.prototype._handleTouchEvent=function(e,s){var r=this;return function(h){h.preventDefault();for(var a=0,c=h.changedTouches.length;c>a;a++){var l=r._pointers.length>1?r._getPointerIndex(h.changedTouches[a].identifier):0;if(-1!==l){var u=h.changedTouches[a].pageX-t.Util.getPosition(r._engine.canvas).x,p=h.changedTouches[a].pageY-t.Util.getPosition(r._engine.canvas).y,d=r._engine.screenToWorldCoordinates(new t.Point(u,p)),f=new o(d.x,d.y,l,i.Touch,n.Unknown,h);s.push(f),r.at(l).eventDispatcher.emit(e,f),r._pointers.length>1&&("up"===e?r._activePointers[l]=-1:"down"===e&&(r._activePointers[l]=h.changedTouches[a].identifier))}}}},r.prototype._handlePointerEvent=function(e,i){var n=this;return function(s){s.preventDefault();var r=n._pointers.length>1?n._getPointerIndex(s.pointerId):0;if(-1!==r){var h=s.pageX-t.Util.getPosition(n._engine.canvas).x,a=s.pageY-t.Util.getPosition(n._engine.canvas).y,c=n._engine.screenToWorldCoordinates(new t.Point(h,a)),l=new o(c.x,c.y,r,n._stringToPointerType(s.pointerType),s.button,s);i.push(l),n.at(r).eventDispatcher.emit(e,l),n._pointers.length>1&&("up"===e?n._activePointers[r]=-1:"down"===e&&(n._activePointers[r]=s.pointerId))}}},r.prototype._getPointerIndex=function(t){var e;if((e=this._activePointers.indexOf(t))>-1)return e;for(var i=0;this._activePointers.length>i;i++)if(-1===this._activePointers[i])return i;return-1},r.prototype._stringToPointerType=function(t){switch(t){case"touch":return i.Touch;case"mouse":return i.Mouse;case"pen":return i.Pen;default:return i.Unknown}},r}(t.Class);e.Pointers=r;var h=function(t){function e(){t.apply(this,arguments)}return __extends(e,t),e}(t.Class);e.Pointer=h})(e=t.Input||(t.Input={}))})(ex||(ex={}));var ex;(function(t){var e;(function(e){(function(t){t[t.Num1=97]="Num1",t[t.Num2=98]="Num2",t[t.Num3=99]="Num3",t[t.Num4=100]="Num4",t[t.Num5=101]="Num5",t[t.Num6=102]="Num6",t[t.Num7=103]="Num7",t[t.Num8=104]="Num8",t[t.Num9=105]="Num9",t[t.Num0=96]="Num0",t[t.Numlock=144]="Numlock",t[t.Semicolon=186]="Semicolon",t[t.A=65]="A",t[t.B=66]="B",t[t.C=67]="C",t[t.D=68]="D",t[t.E=69]="E",t[t.F=70]="F",t[t.G=71]="G",t[t.H=72]="H",t[t.I=73]="I",t[t.J=74]="J",t[t.K=75]="K",t[t.L=76]="L",t[t.M=77]="M",t[t.N=78]="N",t[t.O=79]="O",t[t.P=80]="P",t[t.Q=81]="Q",t[t.R=82]="R",t[t.S=83]="S",t[t.T=84]="T",t[t.U=85]="U",t[t.V=86]="V",t[t.W=87]="W",t[t.X=88]="X",t[t.Y=89]="Y",t[t.Z=90]="Z",t[t.Shift=16]="Shift",t[t.Alt=18]="Alt",t[t.Up=38]="Up",t[t.Down=40]="Down",t[t.Left=37]="Left",t[t.Right=39]="Right",t[t.Space=32]="Space",t[t.Esc=27]="Esc"})(e.Keys||(e.Keys={})),e.Keys;var i=function(t){function e(e){t.call(this),this.key=e}return __extends(e,t),e}(t.GameEvent);e.KeyEvent=i;var n=function(t){function e(e){t.call(this),this._keys=[],this._keysUp=[],this._keysDown=[],this._engine=e}return __extends(e,t),e.prototype.init=function(){var t=this;window.addEventListener("blur",function(){t._keys.length=0}),window.addEventListener("keyup",function(e){var n=t._keys.indexOf(e.keyCode);t._keys.splice(n,1),t._keysUp.push(e.keyCode);var s=new i(e.keyCode);t.eventDispatcher.emit("up",s),t.eventDispatcher.emit("release",s)}),window.addEventListener("keydown",function(e){if(-1===t._keys.indexOf(e.keyCode)){t._keys.push(e.keyCode),t._keysDown.push(e.keyCode);var n=new i(e.keyCode);t.eventDispatcher.emit("down",n),t.eventDispatcher.emit("press",n)}})},e.prototype.update=function(){this._keysDown.length=0,this._keysUp.length=0;for(var t=0;this._keys.length>t;t++)this.eventDispatcher.emit("hold",new i(this._keys[t]))},e.prototype.getKeys=function(){return this._keys},e.prototype.wasPressed=function(t){return this._keysDown.indexOf(t)>-1},e.prototype.isHeld=function(t){return this._keys.indexOf(t)>-1},e.prototype.wasReleased=function(t){return this._keysUp.indexOf(t)>-1},e}(t.Class);e.Keyboard=n})(e=t.Input||(t.Input={}))})(ex||(ex={}));var ex;(function(t){var e;(function(e){var i=function(e){function i(t){e.call(this),this.enabled=!1,this.supported=!!navigator.getGamepads,this._gamePadTimeStamps=[0,0,0,0],this._oldPads=[],this._pads=[],this._initSuccess=!1,this._navigator=navigator,this._minimumConfiguration=null,this._engine=t}return __extends(i,e),i.prototype.init=function(){this.supported&&(this._initSuccess||(this._oldPads=this._clonePads(this._navigator.getGamepads()),this._oldPads.length&&this._oldPads[0]&&(this._initSuccess=!0)))},i.prototype.setMinimumGamepadConfiguration=function(t){this._enableAndUpdate(),this._minimumConfiguration=t},i.prototype._enableAndUpdate=function(){this.enabled||(this.enabled=!0,this.update(100))},i.prototype._isGamepadValid=function(t){if(!this._minimumConfiguration)return!0;if(!t)return!1;var e=t.axes.filter(function(t){return void 0!==typeof t}).length,i=t.buttons.filter(function(t){return void 0!==typeof t}).length;return e>=this._minimumConfiguration.axis&&i>=this._minimumConfiguration.buttons&&t.connected},i.prototype.on=function(t,i){this._enableAndUpdate(),e.prototype.on.call(this,t,i)},i.prototype.off=function(t,i){this._enableAndUpdate(),e.prototype.off.call(this,t,i)},i.prototype.update=function(){if(this.enabled&&this.supported){this.init();for(var e=this._navigator.getGamepads(),i=0;e.length>i;i++)if(e[i]){if(!this.at(i).connected&&this._isGamepadValid(e[i])&&this.eventDispatcher.emit("connect",new t.GamepadConnectEvent(i,this.at(i))),this.at(i).connected=!0,!e[i].timestamp||e[i].timestamp!==this._gamePadTimeStamps[i]){this._gamePadTimeStamps[i]=e[i].timestamp,this.at(i).navigatorGamepad=e[i];var n,r,h,a,c;for(n in s)"number"==typeof s[n]&&(a=s[n],e[i].buttons[a]&&(h=e[i].buttons[a].value,h!==this._oldPads[i].getButton(a)&&(e[i].buttons[a].pressed?(this.at(i).updateButton(a,h),this.at(i).eventDispatcher.publish("button",new t.GamepadButtonEvent(a,h))):this.at(i).updateButton(a,0))));for(r in o)"number"==typeof o[r]&&(c=o[r],h=e[i].axes[c],h!==this._oldPads[i].getAxes(c)&&(this.at(i).updateAxes(c,h),this.at(i).eventDispatcher.emit("axis",new t.GamepadAxisEvent(c,h))));this._oldPads[i]=this._clonePad(e[i])}}else this.at(i).connected&&this.eventDispatcher.emit("disconnect",new t.GamepadDisconnectEvent(i)),this.at(i).connected=!1}},i.prototype.at=function(t){if(this._enableAndUpdate(),t>=this._pads.length)for(var e=this._pads.length-1,i=t;i>e;e++)this._pads.push(new n),this._oldPads.push(new n);return this._pads[t]},i.prototype.getValidGamepads=function(){this._enableAndUpdate();for(var t=[],e=0;this._pads.length>e;e++)this._isGamepadValid(this.at(e).navigatorGamepad)&&this.at(e).connected&&t.push(this.at(e));return t},i.prototype.count=function(){return this._pads.filter(function(t){return t.connected}).length},i.prototype._clonePads=function(t){for(var e=[],i=0,n=t.length;n>i;i++)e.push(this._clonePad(t[i]));return e},i.prototype._clonePad=function(t){var e,i,s=new n;if(!t)return s;for(e=0,i=t.buttons.length;i>e;e++)t.buttons[e]&&s.updateButton(e,t.buttons[e].value);for(e=0,i=t.axes.length;i>e;e++)s.updateAxes(e,t.axes[e]);return s},i.MinAxisMoveThreshold=.05,i}(t.Class);e.Gamepads=i;var n=function(t){function e(){t.call(this),this.connected=!1,this._buttons=Array(16),this._axes=Array(4);var e;for(e=0;this._buttons.length>e;e++)this._buttons[e]=0;for(e=0;this._axes.length>e;e++)this._axes[e]=0}return __extends(e,t),e.prototype.isButtonPressed=function(t,e){return void 0===e&&(e=1),this._buttons[t]>=e},e.prototype.getButton=function(t){return this._buttons[t]},e.prototype.getAxes=function(t){var e=this._axes[t];return Math.abs(e)n;n++)this._animations[n].animation.draw(i,this._animations[n].x,this._animations[n].y);if(this.fps=1/(e/1e3),this.isDebug){this.ctx.font="Consolas",this.ctx.fillStyle=""+this.debugColor;for(var o=this.input.keyboard.getKeys(),r=0;o.length>r;r++)this.ctx.fillText(""+o[r]+" : "+(t.Input.Keys[o[r]]?t.Input.Keys[o[r]]:"Not Mapped"),100,10*r+10);this.ctx.fillText("FPS:"+(""+this.fps.toFixed(2)),10,10)}for(var h=0;this.postProcessors.length>h;h++)this.postProcessors[h].process(this.ctx.getImageData(0,0,this.width,this.height),this.ctx);this.emit("postdraw",new t.PreDrawEvent(i,e,this))},s.prototype.start=function(e){if(!this._compatible){var i=new t.Promise;return i.reject("Excalibur is incompatible with your browser")}var n;if(e?(e.wireEngine(this),n=this.load(e)):n=t.Promise.wrap(),!this._hasStarted){this._hasStarted=!0,this._logger.debug("Starting game...");var s=Date.now(),o=this;(function r(){if(o._hasStarted)try{o._requestId=window.requestAnimationFrame(r);var t=Date.now(),e=Math.floor(t-s)||1;e>200&&(e=1),o._update(e),o._draw(e),s=t}catch(i){window.cancelAnimationFrame(o._requestId),o.stop(),o.onFatalException(i)}})(),this._logger.debug("Game started")}return n},s.prototype.stop=function(){this._hasStarted&&(this._hasStarted=!1,this._logger.debug("Game stopped"))},s.prototype.screenshot=function(){var t=new Image,e=this.canvas.toDataURL("image/png");return t.src=e,t},s.prototype._drawLoadingBar=function(t,e,i){if(this._loadingDraw)return this._loadingDraw(t,e,i),void 0;var n=this.canvas.height/2,s=this.canvas.width/3,o=s,r=new Image;r.src="data:image/png;base64,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"; +var h=3*s/8,a=this.getAntialiasing();this.setAntialiasing(!0),t.drawImage(r,0,0,800,300,o,n-h-20,s,h),t.strokeStyle="white",t.lineWidth=2,t.strokeRect(o,n,s,20);var c=s*(e/i);t.fillStyle="white";var l=5,u=c-2*l,p=20-2*l;t.fillRect(o+l,n+l,u>0?u:0,p),this.setAntialiasing(a)},s.prototype.setLoadingDrawFunction=function(t){this._loadingDraw=t},s.prototype.load=function(e){var i=this,n=new t.Promise;return this._isLoading=!0,e.onprogress=function(t){i._progress=t.loaded,i._total=t.total,i._logger.debug("Loading "+(100*i._progress/i._total).toFixed(0))},e.oncomplete=function(){setTimeout(function(){i._isLoading=!1,n.resolve()},500)},e.load(),n},s}(t.Class);t.Engine=e,function(t){t[t.FullScreen=0]="FullScreen",t[t.Container=1]="Container",t[t.Fixed=2]="Fixed"}(t.DisplayMode||(t.DisplayMode={}));var i=t.DisplayMode,n=function(){function t(t,e,i){this.animation=t,this.x=e,this.y=i}return t}()})(ex||(ex={})); ; // Concatenated onto excalibur after build // Exports the excalibur module so it can be used with browserify diff --git a/dist/excalibur-0.5.1.min.js b/dist/excalibur-0.5.1.min.js deleted file mode 100644 index 3113751bd..000000000 --- a/dist/excalibur-0.5.1.min.js +++ /dev/null @@ -1,14 +0,0 @@ -/*! excalibur - v0.5.1 - 2015-09-14 -* https://github.com/excaliburjs/Excalibur -* Copyright (c) 2015 ; Licensed BSD-2-Clause*/ -"undefined"==typeof window&&(window={audioContext:function(){}}),"undefined"==typeof window||window.requestAnimationFrame||(window.requestAnimationFrame=window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||function(t){window.setInterval(t,1e3/60)}),"undefined"==typeof window||window.cancelAnimationFrame||(window.cancelAnimationFrame=window.webkitCancelAnimationFrame||window.mozCancelAnimationFrame||function(){}),"undefined"==typeof window||window.AudioContext||(window.AudioContext=window.AudioContext||window.webkitAudioContext||window.mozAudioContext||window.msAudioContext||window.oAudioContext),Array.prototype.forEach||(Array.prototype.forEach=function(t,e){var i,n;if(null==this)throw new TypeError(" this is null or not defined");var s=Object(this),o=s.length>>>0;if("function"!=typeof t)throw new TypeError(t+" is not a function");for(arguments.length>1&&(i=e),n=0;o>n;){var r;n in s&&(r=s[n],t.call(i,r,n,s)),n++}}),Array.prototype.some||(Array.prototype.some=function(t){"use strict";if(void 0===this||null===this)throw new TypeError;var e=Object(this),i=e.length>>>0;if("function"!=typeof t)throw new TypeError;for(var n=arguments.length>=2?arguments[1]:void 0,s=0;i>s;s++)if(s in e&&t.call(n,e[s],s,e))return!0;return!1}),Function.prototype.bind||(Function.prototype.bind=function(t){if("function"!=typeof this)throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");var e=Array.prototype.slice.call(arguments,1),i=this,n=function(){},s=function(){return i.apply(this instanceof n&&t?this:t,e.concat(Array.prototype.slice.call(arguments)))};return n.prototype=this.prototype,s.prototype=new n,s});var ex;(function(t){var e;(function(e){var i=function(){function t(){}return t.prototype.updatePixel=function(t,e,i){var n=4*(t+e*i.width),s=i.data,o=(s[n+0]+s[n+1]+s[n+2])/3;s[n+0]=o,s[n+1]=o,s[n+2]=o},t}();e.Grayscale=i;var n=function(){function t(){}return t.prototype.updatePixel=function(t,e,i){var n=4*(t+e*i.width),s=i.data;s[n+0]=255-s[n+0],s[n+1]=255-s[n+1],s[n+2]=255-s[n+2]},t}();e.Invert=n;var s=function(){function t(t){this.opacity=t}return t.prototype.updatePixel=function(t,e,i){var n=4*(t+e*i.width),s=i.data;0!==s[n+3]&&(s[n+3]=Math.round(255*this.opacity))},t}();e.Opacity=s;var o=function(){function t(t){this.color=t}return t.prototype.updatePixel=function(t,e,i){var n=4*(t+e*i.width),s=i.data;0!==s[n+3]&&(s[n+0]=(s[n+0]+this.color.r)/2,s[n+1]=(s[n+1]+this.color.g)/2,s[n+2]=(s[n+2]+this.color.b)/2)},t}();e.Colorize=o;var r=function(){function e(t){void 0===t&&(t=.1),this.factor=t}return e.prototype.updatePixel=function(e,i,n){var s=4*(e+i*n.width),o=n.data,r=t.Color.fromRGB(o[s+0],o[s+1],o[s+2],o[s+3]).lighten(this.factor);o[s+0]=r.r,o[s+1]=r.g,o[s+2]=r.b,o[s+3]=r.a},e}();e.Lighten=r;var h=function(){function e(t){void 0===t&&(t=.1),this.factor=t}return e.prototype.updatePixel=function(e,i,n){var s=4*(e+i*n.width),o=n.data,r=t.Color.fromRGB(o[s+0],o[s+1],o[s+2],o[s+3]).darken(this.factor);o[s+0]=r.r,o[s+1]=r.g,o[s+2]=r.b,o[s+3]=r.a},e}();e.Darken=h;var a=function(){function e(t){void 0===t&&(t=.1),this.factor=t}return e.prototype.updatePixel=function(e,i,n){var s=4*(e+i*n.width),o=n.data,r=t.Color.fromRGB(o[s+0],o[s+1],o[s+2],o[s+3]).saturate(this.factor);o[s+0]=r.r,o[s+1]=r.g,o[s+2]=r.b,o[s+3]=r.a},e}();e.Saturate=a;var c=function(){function e(t){void 0===t&&(t=.1),this.factor=t}return e.prototype.updatePixel=function(e,i,n){var s=4*(e+i*n.width),o=n.data,r=t.Color.fromRGB(o[s+0],o[s+1],o[s+2],o[s+3]).desaturate(this.factor);o[s+0]=r.r,o[s+1]=r.g,o[s+2]=r.b,o[s+3]=r.a},e}();e.Desaturate=c;var u=function(){function t(t){this.color=t}return t.prototype.updatePixel=function(t,e,i){var n=4*(t+e*i.width),s=i.data;0!==s[n+3]&&(s[n+0]=this.color.r,s[n+1]=this.color.g,s[n+2]=this.color.b)},t}();e.Fill=u})(e=t.Effects||(t.Effects={}))})(ex||(ex={}));var ex;(function(t){var e;(function(t){var e=function(){function t(){}return t.prototype.update=function(t,e,i){t.x+=t.dx*i/1e3,t.y+=t.dy*i/1e3,t.dx+=t.ax*i/1e3,t.dy+=t.ay*i/1e3,t.rotation+=t.rx*i/1e3,t.scale.x+=t.sx*i/1e3,t.scale.y+=t.sy*i/1e3},t}();t.Movement=e})(e=t.Traits||(t.Traits={}))})(ex||(ex={}));var ex;(function(t){var e=function(){function e(){this._topLeft=new t.Point(0,0),this._topRight=new t.Point(0,0),this._bottomLeft=new t.Point(0,0),this._bottomRight=new t.Point(0,0)}return e.prototype.isSpriteOffScreen=function(e,i){var n=e.currentDrawing.width*e.currentDrawing.scale.x,s=e.currentDrawing.height*e.currentDrawing.scale.y,o=e.rotation,r=e.getCenter().toPoint();this._topLeft.x=e.getWorldX()-n/2,this._topLeft.y=e.getWorldY()-s/2,this._topLeft=this._topLeft.rotate(o,r),this._topRight.x=e.getWorldX()+n/2,this._topRight.y=e.getWorldY()-s/2,this._topRight=this._topRight.rotate(o,r),this._bottomLeft.x=e.getWorldX()-n/2,this._bottomLeft.y=e.getWorldY()+s/2,this._bottomLeft=this._bottomLeft.rotate(o,r),this._bottomRight.x=e.getWorldX()+n/2,this._bottomRight.y=e.getWorldY()+s/2,this._bottomRight=this._bottomRight.rotate(o,r);var h=i.worldToScreenCoordinates(this._topLeft),a=i.worldToScreenCoordinates(this._topRight),c=i.worldToScreenCoordinates(this._bottomLeft),u=i.worldToScreenCoordinates(this._bottomRight);this._xCoords=[],this._yCoords=[],this._xCoords.push(h.x,a.x,c.x,u.x),this._yCoords.push(h.y,a.y,c.y,u.y),this._xMin=Math.min.apply(null,this._xCoords),this._yMin=Math.min.apply(null,this._yCoords),this._xMax=Math.max.apply(null,this._xCoords),this._yMax=Math.max.apply(null,this._yCoords);var l=i.screenToWorldCoordinates(new t.Point(this._xMin,this._yMin)),p=i.screenToWorldCoordinates(new t.Point(this._xMax,this._yMax));this._xMinWorld=l.x,this._yMinWorld=l.y,this._xMaxWorld=p.x,this._yMaxWorld=p.y;var d=[];d.push(new t.Point(this._xMin,this._yMin),new t.Point(this._xMax,this._yMin),new t.Point(this._xMin,this._yMax),new t.Point(this._xMax,this._yMax));for(var f=0;d.length>f;f++)if(d[f].x>0&&d[f].y>0&&d[f].x0&&a.y+h*c>0&&a.xa.x+r*c||0>a.y+h*c||a.x>i.width||a.y>i.height)&&u&&(n.publish("exitviewport",new t.ExitViewPortEvent),e.isOffScreen=!0)},e}();e.OffscreenCulling=i})(e=t.Traits||(t.Traits={}))})(ex||(ex={}));var ex;(function(t){var e;(function(t){var e=function(){function t(){}return t.prototype.update=function(t,e){t.enableCapturePointer&&(t.isKilled()||e.input.pointers.propogate(t))},t}();t.CapturePointer=e})(e=t.Traits||(t.Traits={}))})(ex||(ex={}));var ex;(function(t){var e;(function(e){var i=function(){function e(){}return e.prototype.update=function(e,i){var n=e.eventDispatcher;if(e.collisionType!==t.CollisionType.PreventCollision)for(var s=0;i.currentScene.tileMaps.length>s;s++)for(var o,r=i.currentScene.tileMaps[s],h=t.Side.None,a=2,c=!1;(o=r.collides(e))&&!(0>a--);)h=e.getSideFromIntersect(o),n.publish("collision",new t.CollisionEvent(e,null,h,o)),(e.collisionType===t.CollisionType.Active||e.collisionType===t.CollisionType.Elastic)&&(e.y+=o.y,e.x+=o.x,e.collisionType!==t.CollisionType.Elastic||c||(c=!0,h===t.Side.Left?e.dx=Math.abs(e.dx):h===t.Side.Right?e.dx=-Math.abs(e.dx):h===t.Side.Top?e.dy=Math.abs(e.dy):h===t.Side.Bottom&&(e.dy=-Math.abs(e.dy))))},e}();e.CollisionDetection=i})(e=t.Traits||(t.Traits={}))})(ex||(ex={}));var ex;(function(t){(function(t){t[t.None=0]="None",t[t.Top=1]="Top",t[t.Bottom=2]="Bottom",t[t.Left=3]="Left",t[t.Right=4]="Right"})(t.Side||(t.Side={})),t.Side})(ex||(ex={}));var __extends=this&&this.__extends||function(t,e){function i(){this.constructor=t}for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n]);i.prototype=e.prototype,t.prototype=new i},ex;(function(t){var e=function(){function e(t,e){this.x=t,this.y=e}return e.prototype.toVector=function(){return new i(this.x,this.y)},e.prototype.rotate=function(i,n){n||(n=new t.Point(0,0));var s=Math.sin(i),o=Math.cos(i),r=o*(this.x-n.x)-s*(this.y-n.y)+n.x,h=s*(this.x-n.x)+o*(this.y-n.y)+n.y;return new e(r,h)},e.prototype.add=function(t){return new e(this.x+t.x,this.y+t.y)},e.prototype.setTo=function(t,e){this.x=t,this.y=e},e.prototype.clone=function(){return new e(this.x,this.y)},e.prototype.equals=function(t){return this.x===t.x&&this.y===t.y},e}();t.Point=e;var i=function(t){function i(e,i){t.call(this,e,i),this.x=e,this.y=i}return __extends(i,t),i.fromAngle=function(t){return new i(Math.cos(t),Math.sin(t))},i.prototype.distance=function(t){return t||(t=new i(0,0)),Math.sqrt(Math.pow(this.x-t.x,2)+Math.pow(this.y-t.y,2))},i.prototype.normalize=function(){var t=this.distance();return t>0?new i(this.x/t,this.y/t):new i(0,1)},i.prototype.scale=function(t){return new i(this.x*t,this.y*t)},i.prototype.plus=function(t){return this.add(t)},i.prototype.add=function(t){return new i(this.x+t.x,this.y+t.y)},i.prototype.subtract=function(t){return this.minus(t)},i.prototype.minus=function(t){return new i(this.x-t.x,this.y-t.y)},i.prototype.dot=function(t){return this.x*t.x+this.y*t.y},i.prototype.cross=function(t){return this.x*t.y-this.y*t.x},i.prototype.perpendicular=function(){return new i(this.y,-this.x)},i.prototype.normal=function(){return this.perpendicular().normalize()},i.prototype.toAngle=function(){return Math.atan2(this.y,this.x)},i.prototype.toPoint=function(){return new e(this.x,this.y)},i.prototype.rotate=function(e,i){return t.prototype.rotate.call(this,e,i).toVector()},i.prototype.clone=function(){return new i(this.x,this.y)},i.Zero=new i(0,0),i}(e);t.Vector=i;var n=function(){function t(t,e){this.pos=t,this.dir=e.normalize()}return t.prototype.intersect=function(t){var e=t.begin.toVector().minus(this.pos.toVector());if(0===this.dir.cross(t.getSlope())&&0!==e.cross(this.dir))return-1;var i=this.dir.cross(t.getSlope());if(0===i)return-1;var n=e.cross(t.getSlope())/i;if(n>=0){var s=e.cross(this.dir)/i/t.getLength();if(s>=0&&1>=s)return n}return-1},t.prototype.getPoint=function(t){return this.pos.toVector().add(this.dir.scale(t)).toPoint()},t}();t.Ray=n;var s=function(){function t(t,e){this.begin=t,this.end=e}return t.prototype.getSlope=function(){var t=this.begin.toVector(),e=this.end.toVector(),i=t.distance(e);return e.minus(t).scale(1/i)},t.prototype.getLength=function(){var t=this.begin.toVector(),e=this.end.toVector(),i=t.distance(e);return i},t}();t.Line=s;var o=function(){function t(t,e){this.min=t,this.max=e}return t.prototype.overlaps=function(t){return this.max>t.min&&t.max>this.min},t.prototype.getOverlap=function(t){return this.overlaps(t)?this.max>t.max?t.max-this.min:this.max-t.min:0},t}();t.Projection=o})(ex||(ex={}));var ex;(function(t){var e;(function(e){function i(t){for(var e="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",i="",n=0;t.length>n;){var s,o,r=255&t.charCodeAt(n++),h=255&t.charCodeAt(n++),a=255&t.charCodeAt(n++),c=r>>2,u=(3&r)<<4|h>>4;isNaN(h)?s=o=64:(s=(15&h)<<2|a>>6,o=isNaN(a)?64:63&a),i+=e.charAt(c)+e.charAt(u)+e.charAt(s)+e.charAt(o)}return i}function n(t,e,i){return e>=t?e:t>=i?i:t}function s(t,e,i,n,s,o){t.beginPath(),t.strokeStyle=e,t.moveTo(i,n),t.lineTo(s,o),t.closePath(),t.stroke()}function o(t,e){return t+Math.random()*(e-t)}function r(t,e){return Math.round(o(t,e))}function h(t){var e=t;if(t>this.TwoPI)for(;e>this.TwoPI;)e-=this.TwoPI;if(0>t)for(;0>e;)e+=this.TwoPI;return e}function a(t){return 180/Math.PI*t}function c(t){return t/180*Math.PI}function u(e){var i=0,n=0,s=function(t){i+=t.offsetLeft,t.offsetParent&&s(t.offsetParent)},o=function(t){n+=t.offsetTop,t.offsetParent&&o(t.offsetParent)};return s(e),o(e),new t.Point(i,n)}function l(t,e){return-1===e.indexOf(t)?(e.push(t),!0):!1}function p(t,e){var i=-1;return(i=e.indexOf(t))>-1?(e.splice(i,1),!0):!1}function d(e){return e===t.Side.Top?t.Side.Bottom:e===t.Side.Bottom?t.Side.Top:e===t.Side.Left?t.Side.Right:e===t.Side.Right?t.Side.Left:t.Side.None}e.TwoPI=2*Math.PI,e.base64Encode=i,e.clamp=n,e.drawLine=s,e.randomInRange=o,e.randomIntInRange=r,e.canonicalizeAngle=h,e.toDegrees=a,e.toRadians=c,e.getPosition=u,e.addItemToArray=l,e.removeItemToArray=p,e.getOppositeSide=d;var f=function(){function t(e){void 0===e&&(e=t.DefaultSize),this._internalArray=null,this._endPointer=0,this._internalArray=Array(e)}return t.prototype._resize=function(){for(var t=2*this._internalArray.length,e=Array(t),i=this.count(),n=0;i>n;n++)e[n]=this._internalArray[n];delete this._internalArray,this._internalArray=e},t.prototype.push=function(t){return this._endPointer===this._internalArray.length&&this._resize(),this._internalArray[this._endPointer++]=t},t.prototype.pop=function(){return this._endPointer=0>this._endPointer-1?0:this._endPointer-1,this._internalArray[this._endPointer]},t.prototype.count=function(){return this._endPointer},t.prototype.clear=function(){this._endPointer=0},t.prototype.internalSize=function(){return this._internalArray.length},t.prototype.elementAt=function(t){return t>=this.count()?void 0:this._internalArray[t]},t.prototype.insert=function(t,e){return t>=this.count()&&this._resize(),this._internalArray[t]=e},t.prototype.remove=function(t){var e=this.count();if(0!==e){for(var i=this._internalArray[t],n=t;e>n;n++)this._internalArray[n]=this._internalArray[n+1];return this._endPointer--,i}},t.prototype.removeElement=function(t){var e=this._internalArray.indexOf(t);this.remove(e)},t.prototype.toArray=function(){return this._internalArray.slice(0,this._endPointer)},t.prototype.forEach=function(t){var e=0,i=this.count();for(e;i>e;e++)t.call(this,this._internalArray[e],e)},t.prototype.map=function(t){for(var e=this.count(),i=0;e>i;i++)this._internalArray[i]=t.call(this,this._internalArray[i],i)},t.DefaultSize=200,t}();e.Collection=f})(e=t.Util||(t.Util={}))})(ex||(ex={}));var ex;(function(t){var e=function(){function e(e,i,n,s,o){var r=this;this.sx=i,this.sy=n,this.swidth=s,this.sheight=o,this.rotation=0,this.anchor=new t.Point(0,0),this.scale=new t.Point(1,1),this.logger=t.Logger.getInstance(),this.flipVertical=!1,this.flipHorizontal=!1,this.width=0,this.height=0,this.effects=[],this.internalImage=new Image,this.naturalWidth=0,this.naturalHeight=0,this._spriteCanvas=null,this._spriteCtx=null,this._pixelData=null,this._pixelsLoaded=!1,this._dirtyEffect=!1,(0>i||0>n||0>s||0>o)&&this.logger.error("Sprite cannot have any negative dimensions x:",i,"y:",n,"width:",s,"height:",o),this._texture=e,this._spriteCanvas=document.createElement("canvas"),this._spriteCanvas.width=s,this._spriteCanvas.height=o,this._spriteCtx=this._spriteCanvas.getContext("2d"),this._texture.loaded.then(function(){r._spriteCanvas.width=r._spriteCanvas.width||r._texture.image.naturalWidth,r._spriteCanvas.height=r._spriteCanvas.height||r._texture.image.naturalHeight,r._loadPixels(),r._dirtyEffect=!0}).error(function(t){r.logger.error("Error loading texture ",r._texture.path,t)}),this.width=s,this.height=o,this.naturalWidth=s,this.naturalHeight=o}return e.prototype._loadPixels=function(){if(this._texture.isLoaded()&&!this._pixelsLoaded){var e=t.Util.clamp,i=this._texture.image.naturalWidth||0,n=this._texture.image.naturalHeight||0;this.swidth>i&&this.logger.warn("The sprite width",this.swidth,"exceeds the width",i,"of the backing texture",this._texture.path),this.sheight>n&&this.logger.warn("The sprite height",this.sheight,"exceeds the height",n,"of the backing texture",this._texture.path),this._spriteCtx.drawImage(this._texture.image,e(this.sx,0,i),e(this.sy,0,n),e(this.swidth,0,i),e(this.sheight,0,n),0,0,this.swidth,this.sheight),this.internalImage.src=this._spriteCanvas.toDataURL("image/png"),this._pixelsLoaded=!0}},e.prototype.opacity=function(e){this.addEffect(new t.Effects.Opacity(e))},e.prototype.grayscale=function(){this.addEffect(new t.Effects.Grayscale)},e.prototype.invert=function(){this.addEffect(new t.Effects.Invert)},e.prototype.fill=function(e){this.addEffect(new t.Effects.Fill(e))},e.prototype.colorize=function(e){this.addEffect(new t.Effects.Colorize(e))},e.prototype.lighten=function(e){void 0===e&&(e=.1),this.addEffect(new t.Effects.Lighten(e))},e.prototype.darken=function(e){void 0===e&&(e=.1),this.addEffect(new t.Effects.Darken(e))},e.prototype.saturate=function(e){void 0===e&&(e=.1),this.addEffect(new t.Effects.Saturate(e))},e.prototype.desaturate=function(e){void 0===e&&(e=.1),this.addEffect(new t.Effects.Desaturate(e))},e.prototype.addEffect=function(t){this.effects.push(t),this._texture.isLoaded()&&this._pixelsLoaded?this._applyEffects():this._dirtyEffect=!0},e.prototype.removeEffect=function(t){var e=null;e="number"==typeof t?t:this.effects.indexOf(t),this.effects.splice(e,1),this._texture.isLoaded()&&this._pixelsLoaded?this._applyEffects():this._dirtyEffect=!0},e.prototype._applyEffects=function(){var e=t.Util.clamp,i=this._texture.image.naturalWidth||0,n=this._texture.image.naturalHeight||0;this._spriteCtx.clearRect(0,0,this.swidth,this.sheight),this._spriteCtx.drawImage(this._texture.image,e(this.sx,0,i),e(this.sy,0,n),e(this.swidth,0,i),e(this.sheight,0,n),0,0,this.swidth,this.sheight),this._pixelData=this._spriteCtx.getImageData(0,0,this.swidth,this.sheight);var s=0,o=0,r=0,h=this.effects.length;for(s;h>s;s++)for(r=0;this.sheight>r;r++)for(o=0;this.swidth>o;o++)this.effects[s].updatePixel(o,r,this._pixelData);this._spriteCtx.clearRect(0,0,this.swidth,this.sheight),this._spriteCtx.putImageData(this._pixelData,0,0),this.internalImage.src=this._spriteCanvas.toDataURL("image/png")},e.prototype.clearEffects=function(){this.effects.length=0,this._applyEffects()},e.prototype.reset=function(){},e.prototype.debugDraw=function(e,i,n){e.save(),e.translate(i,n),e.rotate(this.rotation);var s=this.width*this.scale.x*this.anchor.x,o=this.height*this.scale.y*this.anchor.y;e.strokeStyle=t.Color.Black,e.strokeRect(-s,-o,this.width*this.scale.x,this.height*this.scale.y),e.restore()},e.prototype.draw=function(t,e,i){this._dirtyEffect&&(this._applyEffects(),this._dirtyEffect=!1),this.width=this.naturalWidth*this.scale.x,this.height=this.naturalHeight*this.scale.y,t.save();var n=this.width*this.anchor.x,s=this.height*this.anchor.y;t.translate(e,i),t.rotate(this.rotation),this.flipHorizontal&&(t.translate(this.swidth*this.scale.x,0),t.scale(-1,1)),this.flipVertical&&(t.translate(0,this.sheight*this.scale.y),t.scale(1,-1)),this.internalImage&&t.drawImage(this.internalImage,0,0,this.swidth,this.sheight,-n,-s,this.swidth*this.scale.x,this.sheight*this.scale.y),t.restore()},e.prototype.clone=function(){var t=new e(this._texture,this.sx,this.sy,this.swidth,this.sheight);t.scale=this.scale.clone(),t.rotation=this.rotation,t.flipHorizontal=this.flipHorizontal,t.flipVertical=this.flipVertical;var i=0,n=this.effects.length;for(i;n>i;i++)t.addEffect(this.effects[i]);return t},e}();t.Sprite=e})(ex||(ex={}));var ex;(function(t){var e=function(){function e(e,i,n,s,o){this.image=e,this.columns=i,this.rows=n,this.sprites=[],this._internalImage=e.image,this.sprites=Array(i*n);var r=0,h=0;for(r=0;n>r;r++)for(h=0;i>h;h++)this.sprites[h+r*i]=new t.Sprite(this.image,h*s,r*o,s,o)}return e.prototype.getAnimationByIndices=function(e,i,n){var s=this,o=i.map(function(t){return s.sprites[t]});return o=o.map(function(t){return t.clone()}),new t.Animation(e,o,n)},e.prototype.getAnimationBetween=function(e,i,n,s){var o=this.sprites.slice(i,n);return o=o.map(function(t){return t.clone()}),new t.Animation(e,o,s)},e.prototype.getAnimationForAll=function(e,i){var n=this.sprites.map(function(t){return t.clone()});return new t.Animation(e,n,i)},e.prototype.getSprite=function(t){return t>=0&&this.sprites.length>t?this.sprites[t]:void 0},e}();t.SpriteSheet=e;var i=function(e){function i(i,n,s,o,r,h,a){e.call(this,i,o,r,h,a),this.image=i,this.alphabet=n,this.caseInsensitive=s,this._spriteLookup={},this._colorLookup={},this._currentColor=t.Color.Black}return __extends(i,e),i.prototype.getTextSprites=function(){for(var t={},e=0;this.alphabet.length>e;e++){var i=this.alphabet[e];this.caseInsensitive&&(i=i.toLowerCase()),t[i]=this.sprites[e].clone()}return t},i}(e);t.SpriteFont=i})(ex||(ex={}));var ex;(function(t){var e=function(){function e(e,i,s,o,r,h){var a=this;this.x=e,this.y=i,this.cellWidth=s,this.cellHeight=o,this.rows=r,this.cols=h,this._collidingX=-1,this._collidingY=-1,this._onScreenXStart=0,this._onScreenXEnd=9999,this._onScreenYStart=0,this._onScreenYEnd=9999,this._spriteSheets={},this.logger=t.Logger.getInstance(),this.data=[],this.data=Array(r*h);for(var c=0;h>c;c++)for(var u=0;r>u;u++)(function(){var t=new n(c*s+e,u*o+i,s,o,c+u*h);a.data[c+u*h]=t})()}return e.prototype.registerSpriteSheet=function(t,e){this._spriteSheets[t]=e},e.prototype.collides=function(e){for(var i=e.x+e.getWidth(),n=e.y+e.getHeight(),s=e.getBounds(),o=[],r=s.left;i>=r;r+=Math.min(e.getWidth()/2,this.cellWidth/2))for(var h=s.top;n>=h;h+=Math.min(e.getHeight()/2,this.cellHeight/2)){var a=this.getCellByPoint(r,h);if(a&&a.solid){var c=s.collides(a.getBounds()),u=e.getCenter().minus(a.getCenter());c&&c.dot(u)>0&&o.push(c)}}if(0===o.length)return null;var l=o.reduce(function(e,i){var n=e.x,s=e.y;return Math.abs(e.x)t||0>e||t>=this.cols||e>=this.rows?null:this.data[t+e*this.cols]},e.prototype.getCellByPoint=function(t,e){t=Math.floor((t-this.x)/this.cellWidth),e=Math.floor((e-this.y)/this.cellHeight);var i=this.getCell(t,e);return t>=0&&e>=0&&this.cols>t&&this.rows>e&&i?i:null},e.prototype.update=function(e){var i=e.screenToWorldCoordinates(new t.Point(0,0)),n=e.screenToWorldCoordinates(new t.Point(e.canvas.clientWidth,e.canvas.clientHeight));this._onScreenXStart=Math.max(Math.floor(i.x/this.cellWidth)-2,0),this._onScreenYStart=Math.max(Math.floor((i.y-this.y)/this.cellHeight)-2,0),this._onScreenXEnd=Math.max(Math.floor(n.x/this.cellWidth)+2,0),this._onScreenYEnd=Math.max(Math.floor((n.y-this.y)/this.cellHeight)+2,0)},e.prototype.draw=function(t){t.save(),t.translate(this.x,this.y);var e,i,n,s=this._onScreenXStart,o=Math.min(this._onScreenXEnd,this.cols),r=this._onScreenYStart,h=Math.min(this._onScreenYEnd,this.rows);for(s;o>s;s++){for(r;h>r;r++)for(e=this.getCell(s,r).sprites.filter(function(t){return t.spriteId>-1}),i=0,n=e.length;n>i;i++){var a=this._spriteSheets[e[i].spriteSheetKey];if(a){var c=a.getSprite(e[i].spriteId);c?c.draw(t,s*this.cellWidth,r*this.cellHeight):this.logger.warn("Sprite does not exist for id",e[i].spriteId,"in sprite sheet",e[i].spriteSheetKey,c,a)}else this.logger.warn("Sprite sheet",e[i].spriteSheetKey,"does not exist",a)}r=this._onScreenYStart}t.restore()},e.prototype.debugDraw=function(e){var i=this.cols*this.cellWidth,n=this.rows*this.cellHeight;e.save(),e.strokeStyle=""+t.Color.Red;for(var s=0;this.cols+1>s;s++)e.beginPath(),e.moveTo(this.x+s*this.cellWidth,this.y),e.lineTo(this.x+s*this.cellWidth,this.y+n),e.stroke();for(var o=0;this.rows+1>o;o++)e.beginPath(),e.moveTo(this.x,this.y+o*this.cellHeight),e.lineTo(this.x+i,this.y+o*this.cellHeight),e.stroke();var r=t.Color.Red.clone();r.a=.3,this.data.filter(function(t){return t.solid}).forEach(function(t){e.fillStyle=""+r,e.fillRect(t.x,t.y,t.width,t.height)}),this._collidingY>-1&&this._collidingX>-1&&(e.fillStyle=""+t.Color.Cyan,e.fillRect(this.x+this._collidingX*this.cellWidth,this.y+this._collidingY*this.cellHeight,this.cellWidth,this.cellHeight)),e.restore()},e}();t.TileMap=e;var i=function(){function t(t,e){this.spriteSheetKey=t,this.spriteId=e}return t}();t.TileSprite=i;var n=function(){function e(e,i,n,s,o,r,h){void 0===r&&(r=!1),void 0===h&&(h=[]),this.x=e,this.y=i,this.width=n,this.height=s,this.index=o,this.solid=r,this.sprites=h,this._bounds=new t.BoundingBox(this.x,this.y,this.x+this.width,this.y+this.height)}return e.prototype.getBounds=function(){return this._bounds},e.prototype.getCenter=function(){return new t.Vector(this.x+this.width/2,this.y+this.height/2)},e.prototype.pushSprite=function(t){this.sprites.push(t)},e.prototype.removeSprite=function(t){var e=-1;(e=this.sprites.indexOf(t))>-1&&this.sprites.splice(e,1)},e.prototype.clearSprites=function(){this.sprites.length=0},e}();t.Cell=n})(ex||(ex={}));var ex;(function(t){(function(t){t[t.Naive=0]="Naive",t[t.DynamicAABBTree=1]="DynamicAABBTree",t[t.SeparatingAxis=2]="SeparatingAxis"})(t.CollisionStrategy||(t.CollisionStrategy={})),t.CollisionStrategy;var e=function(){function e(t,e,i,n){void 0===t&&(t=0),void 0===e&&(e=0),void 0===i&&(i=0),void 0===n&&(n=0),this.left=t,this.top=e,this.right=i,this.bottom=n}return e.prototype.getWidth=function(){return this.right-this.left},e.prototype.getHeight=function(){return this.bottom-this.top},e.prototype.getPerimeter=function(){var t=this.getWidth(),e=this.getHeight();return 2*(t+e)},e.prototype.contains=function(i){return i instanceof t.Point?this.left<=i.x&&this.top<=i.y&&this.bottom>=i.y&&this.right>=i.x:i instanceof e?this.left=n.left&&this.right<=n.right?n.left-this.right:n.right-this.left;var r=0;return r=this.top<=n.bottom&&this.top>=n.top?n.bottom-this.top:n.top-this.bottom,Math.abs(o)n;n++)e.push(new t.Line(this._points[n],this._points[(n+1)%i]));return e},e.prototype.getAxes=function(){for(var t=[],e=this._points.length,i=0;e>i;i++)t.push(this._points[i].minus(this._points[(i+1)%e]).normal());return t},e.prototype.project=function(e){for(var i=[],n=this._points.length,s=0;n>s;s++)i.push(this._points[s].dot(e));return new t.Projection(Math.min.apply(Math,i),Math.max.apply(Math,i))},e.prototype.getWidth=function(){var t=this._points.reduce(function(t,e){return Math.min(t,e.x)},1/0),e=this._points.reduce(function(t,e){return Math.max(t,e.x)},-1/0);return e-t},e.prototype.getHeight=function(){var t=this._points.reduce(function(t,e){return Math.min(t,e.y)},1/0),e=this._points.reduce(function(t,e){return Math.max(t,e.y)},-1/0);return t-e},e.prototype.contains=function(e){var i=new t.Ray(e,new t.Vector(1,0)),n=this.getSides().reduce(function(t,e){return i.intersect(e)>=0?t+1:t},0);return 0===n%2?!1:!0},e.prototype.collides=function(t){if(t instanceof e){var i=t,n=this.getAxes();n=i.getAxes().concat(n);for(var s=99999,o=null,r=0;n.length>r;r++){var h=this.project(n[r]),a=i.project(n[r]),c=h.getOverlap(a);if(0===c)return null;s>=c&&(s=c,o=n[r])}return o?o.normalize().scale(s):null}return null},e.prototype.debugDraw=function(e){e.beginPath(),e.lineWidth=2;var i=this._points[0];e.moveTo(i.x,i.y);var n=0,s=this._points.length;for(n;s>n;n++)e.lineTo(this._points[n].x,this._points[n].y);e.lineTo(i.x,i.y),e.closePath(),e.strokeStyle=""+t.Color.Blue,e.stroke()},e}();t.SATBoundingBox=i})(ex||(ex={}));var ex;(function(t){var e=function(){function e(){this.eventDispatcher=new t.EventDispatcher(this)}return e.prototype.addEventListener=function(t,e){this.eventDispatcher.subscribe(t,e)},e.prototype.removeEventListener=function(t,e){this.eventDispatcher.unsubscribe(t,e)},e.prototype.on=function(t,e){this.eventDispatcher.subscribe(t,e)},e.prototype.off=function(t,e){this.eventDispatcher.unsubscribe(t,e)},e.extend=function(t){var i,n=this;i=t&&t.hasOwnProperty("constructor")?t.constructor:function(){return n.apply(this,arguments)};var s=function(){this.constructor=i};if(s.prototype=n.prototype,i.prototype=new s,t)for(var o in t)t.hasOwnProperty(o)&&(i.prototype[o]=t[o]);return i.extend=e.extend,i},e}();t.Class=e})(ex||(ex={}));var ex;(function(t){var e=function(){function t(e,i,n){this.id=0,this.interval=10,this.fcn=function(){},this.repeats=!1,this._elapsedTime=0,this._totalTimeAlive=0,this.complete=!1,this.scene=null,this.id=t.id++,this.interval=i||this.interval,this.fcn=e||this.fcn,this.repeats=n||this.repeats}return t.prototype.update=function(t){this._totalTimeAlive+=t,this._elapsedTime+=t,this._elapsedTime>this.interval&&(this.fcn.call(this),this.repeats?this._elapsedTime=0:this.complete=!0)},t.prototype.getTimeRunning=function(){return this._totalTimeAlive},t.prototype.cancel=function(){this.scene&&this.scene.cancelTimer(this)},t.id=0,t}();t.Timer=e})(ex||(ex={}));var ex;(function(t){var e=function(){function e(){}return e.prototype.register=function(){},e.prototype.remove=function(){},e.prototype.evaluate=function(e){for(var i,n,s=e.filter(function(e){return!e.isKilled()&&e.collisionType!==t.CollisionType.PreventCollision}),o=[],r=0,h=s.length;h>r;r++){i=s[r];for(var a=r+1;h>a;a++){n=s[a];var c;if(c=i.collides(n)){var u=i.getSideFromIntersect(c),l=new t.CollisionPair(i,n,c,u);o.some(function(t){return t.equals(l)})||o.push(l)}}}var p=0,d=o.length;for(p;d>p;p++)o[p].evaluate();return o},e.prototype.update=function(){return 0},e.prototype.debugDraw=function(){},e}();t.NaiveCollisionResolver=e})(ex||(ex={}));var ex;(function(t){var e=function(){function e(e){this.parent=e,this.parent=e||null,this.actor=null,this.bounds=new t.BoundingBox,this.left=null,this.right=null,this.height=0}return e.prototype.isLeaf=function(){return!this.left&&!this.right},e}();t.TreeNode=e;var i=function(){function t(){this.root=null,this.nodes={}}return t.prototype.insert=function(t){if(null===this.root)return this.root=t,this.root.parent=null,void 0;for(var i=t.bounds,n=this.root;!n.isLeaf();){var s,o,r=n.left,h=n.right,a=n.bounds.getPerimeter(),c=n.bounds.combine(i),u=c.getPerimeter(),l=2*u,p=2*(u-a),d=0,f=i.combine(r.bounds);r.isLeaf()?d=f.getPerimeter()+p:(o=r.bounds.getPerimeter(),s=f.getPerimeter(),d=s-o+p);var g=0,_=i.combine(h.bounds);if(h.isLeaf()?g=_.getPerimeter()+p:(o=h.bounds.getPerimeter(),s=_.getPerimeter(),g=s-o+p),d>l&&g>l)break;n=g>d?r:h}var y=n.parent,A=new e(y);A.bounds=i.combine(n.bounds),A.height=n.height+1,null!==y?(y.left===n?y.left=A:y.right=A,A.left=n,A.right=t,n.parent=A,t.parent=A):(A.left=n,A.right=t,n.parent=A,t.parent=A,this.root=A);for(var v=t.parent;v;){if(v=this.balance(v),!v.left)throw Error("Parent of current leaf cannot have a null left child"+v);if(!v.right)throw Error("Parent of current leaf cannot have a null right child"+v);v.height=1+Math.max(v.left.height,v.right.height),v.bounds=v.left.bounds.combine(v.right.bounds),v=v.parent}},t.prototype.remove=function(t){if(t===this.root)return this.root=null,void 0; -var e,i=t.parent,n=i.parent;if(e=i.left===t?i.right:i.left,n){n.left===i?n.left=e:n.right=e,e.parent=n;for(var s=n;s;)s=this.balance(s),s.bounds=s.left.bounds.combine(s.right.bounds),s.height=1+Math.max(s.left.height,s.right.height),s=s.parent}else this.root=e,e.parent=null},t.prototype.registerActor=function(t){var i=new e;i.actor=t,i.bounds=t.getBounds(),i.bounds.left-=2,i.bounds.top-=2,i.bounds.right+=2,i.bounds.bottom+=2,this.nodes[t.id]=i,this.insert(i)},t.prototype.updateActor=function(t){var e=this.nodes[t.id];if(e){var i=t.getBounds();if(e.bounds.contains(i))return!1;this.remove(e),i.left-=5,i.top-=5,i.right+=5,i.bottom+=5;var n=2*t.dx,s=2*t.dy;return 0>n?i.left+=n:i.right+=n,0>s?i.top+=s:i.bottom+=s,e.bounds=i,this.insert(e),!0}},t.prototype.removeActor=function(t){var e=this.nodes[t.id];e&&(this.remove(e),this.nodes[t.id]=null,delete this.nodes[t.id])},t.prototype.balance=function(t){if(null===t)throw Error("Cannot balance at null node");if(t.isLeaf()||2>t.height)return t;var e=t.left,i=t.right,n=t,s=e,o=i,r=e.left,h=e.right,a=i.left,c=i.right,u=o.height-s.height;if(u>1)return o.left=n,o.parent=n.parent,n.parent=o,o.parent?o.parent.left===n?o.parent.left=o:o.parent.right=o:this.root=o,a.height>c.height?(o.right=a,n.right=c,c.parent=n,n.bounds=s.bounds.combine(c.bounds),o.bounds=n.bounds.combine(a.bounds),n.height=1+Math.max(s.height,c.height),o.height=1+Math.max(n.height,a.height)):(o.right=c,n.right=a,a.parent=n,n.bounds=s.bounds.combine(a.bounds),o.bounds=n.bounds.combine(c.bounds),n.height=1+Math.max(s.height,a.height),o.height=1+Math.max(n.height,c.height)),o;if(-1>u){if(s.left=n,s.parent=n.parent,n.parent=s,s.parent)if(s.parent.left===n)s.parent.left=s;else{if(s.parent.right!==n)throw"Error rotating Dynamic Tree";s.parent.right=s}else this.root=s;return r.height>h.height?(s.right=r,n.left=h,h.parent=n,n.bounds=o.bounds.combine(h.bounds),s.bounds=n.bounds.combine(r.bounds),n.height=1+Math.max(o.height,h.height),s.height=1+Math.max(n.height,r.height)):(s.right=h,n.left=r,r.parent=n,n.bounds=o.bounds.combine(r.bounds),s.bounds=n.bounds.combine(h.bounds),n.height=1+Math.max(o.height,r.height),s.height=1+Math.max(n.height,h.height)),s}return t},t.prototype.getHeight=function(){return null===this.root?0:this.root.height},t.prototype.query=function(t,e){var i=t.getBounds(),n=function(s){return s&&s.bounds.collides(i)?s.isLeaf()&&s.actor!==t?e.call(t,s.actor)?!0:void 0:n(s.left)||n(s.right):null};return n(this.root)},t.prototype.rayCast=function(){return null},t.prototype.getNodes=function(){var t=function(e){return e?[e].concat(t(e.left),t(e.right)):[]};return t(this.root)},t.prototype.debugDraw=function(t){var e=function(i){i&&(t.strokeStyle=i.isLeaf()?"green":"white",i.bounds.debugDraw(t),i.left&&e(i.left),i.right&&e(i.right))};e(this.root)},t}();t.DynamicTree=i})(ex||(ex={}));var ex;(function(t){var e=function(){function e(){this._dynamicCollisionTree=new t.DynamicTree}return e.prototype.register=function(t){this._dynamicCollisionTree.registerActor(t)},e.prototype.remove=function(t){this._dynamicCollisionTree.removeActor(t)},e.prototype.evaluate=function(e){for(var i,n=e.filter(function(e){return!e.isKilled()&&e.collisionType!==t.CollisionType.PreventCollision}),s=[],o=0,r=n.length;r>o;o++)i=n[o],this._dynamicCollisionTree.query(i,function(e){if(e.collisionType===t.CollisionType.PreventCollision||e.isKilled())return!1;var n;if(n=i.collides(e)){var o=i.getSideFromIntersect(n),r=new t.CollisionPair(i,e,n,o);return s.some(function(t){return t.equals(r)})||s.push(r),!0}return!1});var h=0,a=s.length;for(h;a>h;h++)s[h].evaluate();return s},e.prototype.update=function(t){var e=0,i=0,n=t.length;for(i;n>i;i++)this._dynamicCollisionTree.updateActor(t[i])&&e++;return e},e.prototype.debugDraw=function(t,e){this._dynamicCollisionTree.debugDraw(t,e)},e}();t.DynamicTreeCollisionResolver=e})(ex||(ex={}));var ex;(function(t){var e=function(){function e(t,e,i,n){this.left=t,this.right=e,this.intersect=i,this.side=n}return e.prototype.equals=function(t){return t.left===this.left&&t.right===this.right||t.right===this.left&&t.left===this.right},e.prototype.evaluate=function(){this.left.eventDispatcher.publish("collision",new t.CollisionEvent(this.left,this.right,this.side,this.intersect)),this.right.eventDispatcher.publish("collision",new t.CollisionEvent(this.right,this.left,t.Util.getOppositeSide(this.side),this.intersect.scale(-1)));var e=this.side;this.left.collisionType!==t.CollisionType.Active&&this.left.collisionType!==t.CollisionType.Elastic||this.right.collisionType===t.CollisionType.Passive||(this.left.y+=this.intersect.y,this.left.x+=this.intersect.x,this.left.collisionType===t.CollisionType.Elastic?e===t.Side.Left?this.left.dx=Math.abs(this.left.dx):e===t.Side.Right?this.left.dx=-Math.abs(this.left.dx):e===t.Side.Top?this.left.dy=Math.abs(this.left.dy):e===t.Side.Bottom&&(this.left.dy=-Math.abs(this.left.dy)):(0!==this.intersect.x&&(this.left.dx=0>=this.left.dx&&0>=this.right.dx?Math.max(this.left.dx,this.right.dx):this.left.dx>=0&&this.right.dx>=0?Math.min(this.left.dx,this.right.dx):0),0!==this.intersect.y&&(this.left.dy=0>=this.left.dy&&0>=this.right.dy?Math.max(this.left.dy,this.right.dy):this.left.dy>=0&&this.right.dy>=0?Math.min(this.left.dy,this.right.dy):0)));var i=t.Util.getOppositeSide(this.side),n=this.intersect.scale(-1);this.right.collisionType!==t.CollisionType.Active&&this.right.collisionType!==t.CollisionType.Elastic||this.left.collisionType===t.CollisionType.Passive||(this.right.y+=n.y,this.right.x+=n.x,this.right.collisionType===t.CollisionType.Elastic?i===t.Side.Left?this.right.dx=Math.abs(this.right.dx):i===t.Side.Right?this.right.dx=-Math.abs(this.right.dx):i===t.Side.Top?this.right.dy=Math.abs(this.right.dy):i===t.Side.Bottom&&(this.right.dy=-Math.abs(this.right.dy)):(0!==n.x&&(this.right.dx=0>=this.right.dx&&0>=this.left.dx?Math.max(this.left.dx,this.right.dx):this.left.dx>=0&&this.right.dx>=0?Math.min(this.left.dx,this.right.dx):0),0!==n.y&&(this.right.dy=0>=this.right.dy&&0>=this.left.dy?Math.max(this.left.dy,this.right.dy):this.left.dy>=0&&this.right.dy>=0?Math.min(this.left.dy,this.right.dy):0)))},e}();t.CollisionPair=e})(ex||(ex={}));var ex;(function(t){var e=function(){function e(){this._focus=new t.Point(0,0),this._lerp=!1,this._cameraMoving=!1,this._currentLerpTime=0,this._lerpDuration=1e3,this._totalLerpTime=0,this._lerpStart=null,this._lerpEnd=null,this._isShaking=!1,this._shakeMagnitudeX=0,this._shakeMagnitudeY=0,this._shakeDuration=0,this._elapsedShakeTime=0,this._isZooming=!1,this._currentZoomScale=1,this._maxZoomScale=1,this._zoomDuration=0,this._elapsedZoomTime=0,this._zoomIncrement=.01}return e.prototype._easeInOutCubic=function(t,e,i,n){return i-=e,t/=n/2,1>t?i/2*t*t*t+e:(t-=2,i/2*(t*t*t+2)+e)},e.prototype.setActorToFollow=function(t){this._follow=t},e.prototype.getFocus=function(){return this._focus},e.prototype.setFocus=function(e,i){this._follow||this._lerp||(this._focus.x=e,this._focus.y=i),this._lerp&&(this._lerpStart=this._focus.clone(),this._lerpEnd=new t.Point(e,i),this._currentLerpTime=0,this._cameraMoving=!0)},e.prototype.shake=function(t,e,i){this._isShaking=!0,this._shakeMagnitudeX=t,this._shakeMagnitudeY=e,this._shakeDuration=i},e.prototype.zoom=function(t,e){void 0===e&&(e=0),this._isZooming=!0,this._maxZoomScale=t,this._zoomDuration=e,e&&(this._zoomIncrement=1e3*(Math.abs(this._maxZoomScale-this._currentZoomScale)/e)),1>this._maxZoomScale?e?this._zoomIncrement=-1*this._zoomIncrement:(this._isZooming=!1,this._setCurrentZoomScale(this._maxZoomScale)):e||(this._isZooming=!1,this._setCurrentZoomScale(this._maxZoomScale))},e.prototype.getZoom=function(){return this._currentZoomScale},e.prototype._setCurrentZoomScale=function(t){this._currentZoomScale=t},e.prototype.update=function(t,e){var i=this.getFocus(),n=0,s=0,o=t.canvas.width,r=t.canvas.height,h=o/this.getZoom(),a=r/this.getZoom();this._lerp&&(this._currentLerpTime=this._shakeDuration},e.prototype._isDoneZooming=function(){return 0!==this._zoomDuration?this._elapsedZoomTime>=this._zoomDuration:1>this._maxZoomScale?this._currentZoomScale<=this._maxZoomScale:this._currentZoomScale>=this._maxZoomScale},e}();t.BaseCamera=e;var i=function(e){function i(){e.apply(this,arguments)}return __extends(i,e),i.prototype.getFocus=function(){return this._follow?new t.Point(this._follow.x+this._follow.getWidth()/2,this._focus.y):this._focus},i}(e);t.SideCamera=i;var n=function(e){function i(){e.apply(this,arguments)}return __extends(i,e),i.prototype.getFocus=function(){return this._follow?new t.Point(this._follow.x+this._follow.getWidth()/2,this._follow.y+this._follow.getHeight()/2):this._focus},i}(e);t.LockedCamera=n})(ex||(ex={}));var ex;(function(t){(function(t){t[t.ShortestPath=0]="ShortestPath",t[t.LongestPath=1]="LongestPath",t[t.Clockwise=2]="Clockwise",t[t.CounterClockwise=3]="CounterClockwise"})(t.RotationType||(t.RotationType={})),t.RotationType})(ex||(ex={}));var ex;(function(t){var e;(function(e){var i;(function(e){var i=function(){function e(e,i,n,s,o){this.actor=e,this.easingFcn=o,this._currentLerpTime=0,this._lerpDuration=1e3,this._lerpStart=new t.Point(0,0),this._lerpEnd=new t.Point(0,0),this._initialized=!1,this._stopped=!1,this._distance=0,this._lerpDuration=s,this._lerpEnd=new t.Point(i,n)}return e.prototype._initialize=function(){this._lerpStart=new t.Point(this.actor.x,this.actor.y),this._currentLerpTime=0,this._distance=this._lerpStart.toVector().distance(this._lerpEnd.toVector())},e.prototype.update=function(t){this._initialized||(this._initialize(),this._initialized=!0);var e=this.actor.x,i=this.actor.y;this._currentLerpTime=this._distance},e.prototype.reset=function(){this._initialized=!1},e.prototype.stop=function(){this._stopped=!0},e}();e.EaseTo=i;var n=function(){function e(e,i,n,s){this._started=!1,this._stopped=!1,this._actor=e,this._end=new t.Vector(i,n),this._speed=s}return e.prototype.update=function(){this._started||(this._started=!0,this._start=new t.Vector(this._actor.x,this._actor.y),this._distance=this._start.distance(this._end),this._dir=this._end.minus(this._start).normalize());var e=this._dir.scale(this._speed);this._actor.dx=e.x,this._actor.dy=e.y,this.isComplete(this._actor)&&(this._actor.x=this._end.x,this._actor.y=this._end.y,this._actor.dy=0,this._actor.dx=0)},e.prototype.isComplete=function(e){return this._stopped||new t.Vector(e.x,e.y).distance(this._start)>=this._distance},e.prototype.stop=function(){this._actor.dy=0,this._actor.dx=0,this._stopped=!0},e.prototype.reset=function(){this._started=!1},e}();e.MoveTo=n;var s=function(){function e(e,i,n,s){if(this._started=!1,this._stopped=!1,this._actor=e,this._end=new t.Vector(i,n),0>=s)throw t.Logger.getInstance().error("Attempted to moveBy time less than or equal to zero : "+s),Error("Cannot move in time <= 0");this._time=s}return e.prototype.update=function(){this._started||(this._started=!0,this._start=new t.Vector(this._actor.x,this._actor.y),this._distance=this._start.distance(this._end),this._dir=this._end.minus(this._start).normalize(),this._speed=this._distance/(this._time/1e3));var e=this._dir.scale(this._speed);this._actor.dx=e.x,this._actor.dy=e.y,this.isComplete(this._actor)&&(this._actor.x=this._end.x,this._actor.y=this._end.y,this._actor.dy=0,this._actor.dx=0)},e.prototype.isComplete=function(e){return this._stopped||new t.Vector(e.x,e.y).distance(this._start)>=this._distance},e.prototype.stop=function(){this._actor.dy=0,this._actor.dx=0,this._stopped=!0},e.prototype.reset=function(){this._started=!1},e}();e.MoveBy=s;var o=function(){function e(e,i,n){this._started=!1,this._stopped=!1,this._actor=e,this._actorToFollow=i,this._current=new t.Vector(this._actor.x,this._actor.y),this._end=new t.Vector(i.x,i.y),this._maximumDistance=void 0!==n?n:this._current.distance(this._end),this._speed=0}return e.prototype.update=function(){this._started||(this._started=!0,this._distanceBetween=this._current.distance(this._end),this._dir=this._end.minus(this._current).normalize());var t=Math.sqrt(Math.pow(this._actorToFollow.dx,2)+Math.pow(this._actorToFollow.dy,2));if(0!==t&&(this._speed=t),this._current.x=this._actor.x,this._current.y=this._actor.y,this._end.x=this._actorToFollow.x,this._end.y=this._actorToFollow.y,this._distanceBetween=this._current.distance(this._end),this._dir=this._end.minus(this._current).normalize(),this._distanceBetween>=this._maximumDistance){var e=this._dir.scale(this._speed);this._actor.dx=e.x,this._actor.dy=e.y}else this._actor.dx=0,this._actor.dy=0;this.isComplete(this._actor)&&(this._actor.x=this._end.x,this._actor.y=this._end.y,this._actor.dy=0,this._actor.dx=0)},e.prototype.stop=function(){this._actor.dy=0,this._actor.dx=0,this._stopped=!0},e.prototype.isComplete=function(){return this._stopped},e.prototype.reset=function(){this._started=!1},e}();e.Follow=o;var r=function(){function e(e,i,n){this._started=!1,this._stopped=!1,this._speedWasSpecified=!1,this._actor=e,this._actorToMeet=i,this._current=new t.Vector(this._actor.x,this._actor.y),this._end=new t.Vector(i.x,i.y),this._speed=n||0,void 0!==n&&(this._speedWasSpecified=!0)}return e.prototype.update=function(){this._started||(this._started=!0,this._distanceBetween=this._current.distance(this._end),this._dir=this._end.minus(this._current).normalize());var t=Math.sqrt(Math.pow(this._actorToMeet.dx,2)+Math.pow(this._actorToMeet.dy,2));0===t||this._speedWasSpecified||(this._speed=t),this._current.x=this._actor.x,this._current.y=this._actor.y,this._end.x=this._actorToMeet.x,this._end.y=this._actorToMeet.y,this._distanceBetween=this._current.distance(this._end),this._dir=this._end.minus(this._current).normalize();var e=this._dir.scale(this._speed);this._actor.dx=e.x,this._actor.dy=e.y,this.isComplete(this._actor)&&(this._actor.x=this._end.x,this._actor.y=this._end.y,this._actor.dy=0,this._actor.dx=0)},e.prototype.isComplete=function(){return this._stopped||1>=this._distanceBetween},e.prototype.stop=function(){this._actor.dy=0,this._actor.dx=0,this._stopped=!0},e.prototype.reset=function(){this._started=!1},e}();e.Meet=r;var h=function(){function e(e,i,n,s){this._started=!1,this._stopped=!1,this._actor=e,this._end=i,this._speed=n,this._rotationType=s||t.RotationType.ShortestPath}return e.prototype.update=function(){if(!this._started){this._started=!0,this._start=this._actor.rotation;var e=Math.abs(this._end-this._start),i=t.Util.TwoPI-e;switch(e>i?(this._shortDistance=i,this._longDistance=e):(this._shortDistance=e,this._longDistance=i),this._shortestPathIsPositive=(this._start-this._end+t.Util.TwoPI)%t.Util.TwoPI>=Math.PI,this._rotationType){case t.RotationType.ShortestPath:this._distance=this._shortDistance,this._direction=this._shortestPathIsPositive?1:-1;break;case t.RotationType.LongestPath:this._distance=this._longDistance,this._direction=this._shortestPathIsPositive?-1:1;break;case t.RotationType.Clockwise:this._direction=1,this._distance=this._shortestPathIsPositive?this._shortDistance:this._longDistance;break;case t.RotationType.CounterClockwise:this._direction=-1,this._distance=this._shortestPathIsPositive?this._longDistance:this._shortDistance}}this._actor.rx=this._direction*this._speed,this.isComplete(this._actor)&&(this._actor.rotation=this._end,this._actor.rx=0,this._stopped=!0)},e.prototype.isComplete=function(){var t=Math.abs(this._actor.rotation-this._start);return this._stopped||t>=Math.abs(this._distance)},e.prototype.stop=function(){this._actor.rx=0,this._stopped=!0},e.prototype.reset=function(){this._started=!1},e}();e.RotateTo=h;var a=function(){function e(e,i,n,s){this._started=!1,this._stopped=!1,this._actor=e,this._end=i,this._time=n,this._rotationType=s||t.RotationType.ShortestPath}return e.prototype.update=function(){if(!this._started){this._started=!0,this._start=this._actor.rotation;var e=Math.abs(this._end-this._start),i=t.Util.TwoPI-e;switch(e>i?(this._shortDistance=i,this._longDistance=e):(this._shortDistance=e,this._longDistance=i),this._shortestPathIsPositive=(this._start-this._end+t.Util.TwoPI)%t.Util.TwoPI>=Math.PI,this._rotationType){case t.RotationType.ShortestPath:this._distance=this._shortDistance,this._direction=this._shortestPathIsPositive?1:-1;break;case t.RotationType.LongestPath:this._distance=this._longDistance,this._direction=this._shortestPathIsPositive?-1:1;break;case t.RotationType.Clockwise:this._direction=1,this._distance=this._shortDistance>=0?this._shortDistance:this._longDistance;break;case t.RotationType.CounterClockwise:this._direction=-1,this._distance=0>=this._shortDistance?this._shortDistance:this._longDistance}this._speed=Math.abs(1e3*(this._distance/this._time))}this._actor.rx=this._direction*this._speed,this.isComplete(this._actor)&&(this._actor.rotation=this._end,this._actor.rx=0,this._stopped=!0)},e.prototype.isComplete=function(){var t=Math.abs(this._actor.rotation-this._start);return this._stopped||t>=Math.abs(this._distance)},e.prototype.stop=function(){this._actor.rx=0,this._stopped=!0},e.prototype.reset=function(){this._started=!1},e}();e.RotateBy=a;var c=function(){function t(t,e,i,n,s){this._started=!1,this._stopped=!1,this._actor=t,this._endX=e,this._endY=i,this._speedX=n,this._speedY=s}return t.prototype.update=function(){if(this._started||(this._started=!0,this._startX=this._actor.scale.x,this._startY=this._actor.scale.y,this._distanceX=Math.abs(this._endX-this._startX),this._distanceY=Math.abs(this._endY-this._startY)),Math.abs(this._actor.scale.x-this._startX)>=this._distanceX)this._actor.sx=0;else{var t=this._endY=this._distanceY)this._actor.sy=0;else{var e=this._endY=this._distanceX&&Math.abs(this._actor.scale.y-this._startY)>=this._distanceY},t.prototype.stop=function(){this._actor.sx=0,this._actor.sy=0,this._stopped=!0},t.prototype.reset=function(){this._started=!1},t}();e.ScaleTo=c;var u=function(){function t(t,e,i,n){this._started=!1,this._stopped=!1,this._actor=t,this._endX=e,this._endY=i,this._time=n,this._speedX=1e3*((this._endX-this._actor.scale.x)/n),this._speedY=1e3*((this._endY-this._actor.scale.y)/n)}return t.prototype.update=function(){this._started||(this._started=!0,this._startX=this._actor.scale.x,this._startY=this._actor.scale.y,this._distanceX=Math.abs(this._endX-this._startX),this._distanceY=Math.abs(this._endY-this._startY));var t=this._endX=this._distanceX&&Math.abs(this._actor.scale.y-this._startY)>=this._distanceY},t.prototype.stop=function(){this._actor.sx=0,this._actor.sy=0,this._stopped=!0},t.prototype.reset=function(){this._started=!1},t}();e.ScaleBy=u;var l=function(){function t(t,e){this._elapsedTime=0,this._started=!1,this._stopped=!1,this._actor=t,this._delay=e}return t.prototype.update=function(t){this._started||(this._started=!0),this.x=this._actor.x,this.y=this._actor.y,this._elapsedTime+=t},t.prototype.isComplete=function(){return this._stopped||this._elapsedTime>=this._delay},t.prototype.stop=function(){this._stopped=!0},t.prototype.reset=function(){this._elapsedTime=0,this._started=!1},t}();e.Delay=l;var p=function(){function t(t,e,i,n){void 0===n&&(n=1),this._timeVisible=0,this._timeNotVisible=0,this._elapsedTime=0,this._totalTime=0,this._stopped=!1,this._started=!1,this._actor=t,this._timeVisible=e,this._timeNotVisible=i,this._duration=(e+i)*n}return t.prototype.update=function(t){this._started||(this._started=!0),this._elapsedTime+=t,this._totalTime+=t,this._actor.visible&&this._elapsedTime>=this._timeVisible&&(this._actor.visible=!1,this._elapsedTime=0),!this._actor.visible&&this._elapsedTime>=this._timeNotVisible&&(this._actor.visible=!0,this._elapsedTime=0),this.isComplete(this._actor)&&(this._actor.visible=!0)},t.prototype.isComplete=function(){return this._stopped||this._totalTime>=this._duration},t.prototype.stop=function(){this._actor.visible=!0,this._stopped=!0},t.prototype.reset=function(){this._started=!1,this._elapsedTime=0,this._totalTime=0},t}();e.Blink=p;var d=function(){function e(t,e,i){this._multiplyer=1,this._started=!1,this._stopped=!1,this._actor=t,this._endOpacity=e,this._speed=i,t.opacity>e&&(this._multiplyer=-1)}return e.prototype.update=function(e){this._started||(this._started=!0),this._speed>0&&(this._actor.opacity+=this._multiplyer*Math.abs(this._actor.opacity-this._endOpacity)*e/this._speed),this._speed-=e,t.Logger.getInstance().debug("actor opacity: "+this._actor.opacity),this.isComplete(this._actor)&&(this._actor.opacity=this._endOpacity)},e.prototype.isComplete=function(){return this._stopped||.05>Math.abs(this._actor.opacity-this._endOpacity)},e.prototype.stop=function(){this._stopped=!0},e.prototype.reset=function(){this._started=!1},e}();e.Fade=d;var f=function(){function t(t){this._started=!1,this._stopped=!1,this._actor=t}return t.prototype.update=function(){this._actor.actionQueue.clearActions(),this._actor.kill(),this._stopped=!0},t.prototype.isComplete=function(){return this._stopped},t.prototype.stop=function(){},t.prototype.reset=function(){},t}();e.Die=f;var g=function(){function t(t,e){this._method=null,this._actor=null,this._hasBeenCalled=!1,this._actor=t,this._method=e}return t.prototype.update=function(){this._method.call(this._actor),this._hasBeenCalled=!0},t.prototype.isComplete=function(){return this._hasBeenCalled},t.prototype.reset=function(){this._hasBeenCalled=!1},t.prototype.stop=function(){this._hasBeenCalled=!0},t}();e.CallMethod=g;var _=function(){function t(t,e,i){this._stopped=!1,this._actor=t,this._actionQueue=new A(t),this._repeat=e,this._originalRepeat=e;var n=0,s=i.length;for(n;s>n;n++)i[n].reset(),this._actionQueue.add(i[n])}return t.prototype.update=function(t){this.x=this._actor.x,this.y=this._actor.y,this._actionQueue.hasNext()||(this._actionQueue.reset(),this._repeat--),this._actionQueue.update(t)},t.prototype.isComplete=function(){return this._stopped||0>=this._repeat},t.prototype.stop=function(){this._stopped=!0},t.prototype.reset=function(){this._repeat=this._originalRepeat},t}();e.Repeat=_;var y=function(){function t(t,e){this._stopped=!1,this._actor=t,this._actionQueue=new A(t);var i=0,n=e.length;for(i;n>i;i++)e[i].reset(),this._actionQueue.add(e[i])}return t.prototype.update=function(t){this.x=this._actor.x,this.y=this._actor.y,this._stopped||(this._actionQueue.hasNext()||this._actionQueue.reset(),this._actionQueue.update(t))},t.prototype.isComplete=function(){return this._stopped},t.prototype.stop=function(){this._stopped=!0,this._actionQueue.clearActions()},t.prototype.reset=function(){},t}();e.RepeatForever=y;var A=function(){function t(t){this._actions=[],this._completedActions=[],this._actor=t}return t.prototype.add=function(t){this._actions.push(t)},t.prototype.remove=function(t){var e=this._actions.indexOf(t);this._actions.splice(e,1)},t.prototype.clearActions=function(){this._actions.length=0,this._completedActions.length=0,this._currentAction&&this._currentAction.stop()},t.prototype.getActions=function(){return this._actions.concat(this._completedActions)},t.prototype.hasNext=function(){return this._actions.length>0},t.prototype.reset=function(){this._actions=this.getActions();var t=0,e=this._actions.length;for(t;e>t;t++)this._actions[t].reset();this._completedActions=[]},t.prototype.update=function(t){this._actions.length>0&&(this._currentAction=this._actions[0],this._currentAction.update(t),this._currentAction.isComplete(this._actor)&&this._completedActions.push(this._actions.shift()))},t}();e.ActionQueue=A})(i=e.Actions||(e.Actions={}))})(e=t.Internal||(t.Internal={}))})(ex||(ex={}));var ex;(function(t){var e=function(){function e(){this._actors=[],this._queues=[],null!==arguments&&(this._actors=Array.prototype.slice.call(arguments,0),this._queues=this._actors.map(function(t){return t.actionQueue}))}return e.prototype.clearActions=function(){var t=0,e=this._queues.length;for(t;e>t;t++)this._queues[t].clearActions()},e.prototype.addActorToContext=function(t){this._actors.push(t),this._queues.push(t.actionQueue)},e.prototype.removeActorFromContext=function(t){var e=this._actors.indexOf(t);e>-1&&(this._actors.splice(e,1),this._queues.splice(e,1))},e.prototype.moveTo=function(e,i,n){var s=0,o=this._queues.length;for(s;o>s;s++)this._queues[s].add(new t.Internal.Actions.MoveTo(this._actors[s],e,i,n));return this},e.prototype.moveBy=function(e,i,n){var s=0,o=this._queues.length;for(s;o>s;s++)this._queues[s].add(new t.Internal.Actions.MoveBy(this._actors[s],e,i,n));return this},e.prototype.rotateTo=function(e,i){var n=0,s=this._queues.length;for(n;s>n;n++)this._queues[n].add(new t.Internal.Actions.RotateTo(this._actors[n],e,i));return this},e.prototype.rotateBy=function(e,i){var n=0,s=this._queues.length;for(n;s>n;n++)this._queues[n].add(new t.Internal.Actions.RotateBy(this._actors[n],e,i));return this},e.prototype.scaleTo=function(e,i,n,s){var o=0,r=this._queues.length;for(o;r>o;o++)this._queues[o].add(new t.Internal.Actions.ScaleTo(this._actors[o],e,i,n,s));return this},e.prototype.scaleBy=function(e,i,n){var s=0,o=this._queues.length;for(s;o>s;s++)this._queues[s].add(new t.Internal.Actions.ScaleBy(this._actors[s],e,i,n));return this},e.prototype.blink=function(e,i,n){void 0===n&&(n=1);var s=0,o=this._queues.length;for(s;o>s;s++)this._queues[s].add(new t.Internal.Actions.Blink(this._actors[s],e,i,n));return this},e.prototype.fade=function(e,i){var n=0,s=this._queues.length;for(n;s>n;n++)this._queues[n].add(new t.Internal.Actions.Fade(this._actors[n],e,i));return this},e.prototype.delay=function(e){var i=0,n=this._queues.length;for(i;n>i;i++)this._queues[i].add(new t.Internal.Actions.Delay(this._actors[i],e));return this},e.prototype.die=function(){var e=0,i=this._queues.length;for(e;i>e;e++)this._queues[e].add(new t.Internal.Actions.Die(this._actors[e]));return this},e.prototype.callMethod=function(e){var i=0,n=this._queues.length;for(i;n>i;i++)this._queues[i].add(new t.Internal.Actions.CallMethod(this._actors[i],e));return this},e.prototype.repeat=function(e){if(!e)return this.repeatForever(),this;var i=0,n=this._queues.length;for(i;n>i;i++)this._queues[i].add(new t.Internal.Actions.Repeat(this._actors[i],e,this._actors[i].actionQueue.getActions()));return this},e.prototype.repeatForever=function(){var e=0,i=this._queues.length;for(e;i>e;e++)this._queues[e].add(new t.Internal.Actions.RepeatForever(this._actors[e],this._actors[e].actionQueue.getActions()));return this},e.prototype.follow=function(e,i){var n=0,s=this._queues.length;for(n;s>n;n++)void 0===i?this._queues[n].add(new t.Internal.Actions.Follow(this._actors[n],e)):this._queues[n].add(new t.Internal.Actions.Follow(this._actors[n],e,i));return this},e.prototype.meet=function(e,i){var n=0,s=this._queues.length;for(n;s>n;n++)void 0===i?this._queues[n].add(new t.Internal.Actions.Meet(this._actors[n],e)):this._queues[n].add(new t.Internal.Actions.Meet(this._actors[n],e,i));return this},e.prototype.asPromise=function(){var e=this,i=this._queues.map(function(i,n){var s=new t.Promise;return i.add(new t.Internal.Actions.CallMethod(e._actors[n],function(){s.resolve()})),s});return t.Promise.join.apply(this,i)},e}();t.ActionContext=e})(ex||(ex={}));var ex;(function(t){var e=function(e){function i(i,n){if(e.call(this),this.name=i,this.scene=n,this._logger=t.Logger.getInstance(),this._members=[],this.actions=new t.ActionContext,null==n)this._logger.error("Invalid constructor arguments passed to Group: ",i,", scene must not be null!");else{var s=n.groups[i];s&&this._logger.warn("Group with name",i,"already exists. This new group will replace it."),n.groups[i]=this}}return __extends(i,e),i.prototype.add=function(e){e instanceof t.Actor&&(e=[].concat(e));var i,n=0,s=e.length;for(n;s>n;n++)i=this.getMembers().indexOf(e[n]),-1===i&&(this._members.push(e[n]),this.scene.add(e[n]),this.actions.addActorToContext(e[n]),this.eventDispatcher.wire(e[n].eventDispatcher))},i.prototype.remove=function(t){var e=this._members.indexOf(t);e>-1&&(this._members.splice(e,1),this.actions.removeActorFromContext(t),this.eventDispatcher.unwire(t.eventDispatcher))},i.prototype.move=function(e){var i=0,n=this.getMembers(),s=n.length;if(1===arguments.length&&e instanceof t.Vector)for(i;s>i;i++)n[i].x+=e.x,n[i].y+=e.y;else if("number"==typeof arguments[0]&&"number"==typeof arguments[1]){var o=arguments[0],r=arguments[1];for(i;s>i;i++)n[i].x+=o,n[i].y+=r}else this._logger.error("Invalid arguments passed to group move",this.name,"args:",arguments)},i.prototype.rotate=function(){if("number"==typeof arguments[0]){var t=arguments[0],e=0,i=this.getMembers(),n=i.length;for(e;n>e;e++)i[e].rotation+=t}else this._logger.error("Invalid arguments passed to group rotate",this.name,"args:",arguments)},i.prototype.on=function(t,e){this.eventDispatcher.subscribe(t,e)},i.prototype.off=function(t,e){this.eventDispatcher.unsubscribe(t,e)},i.prototype.emit=function(t,e){this.eventDispatcher.emit(t,e)},i.prototype.contains=function(t){return this.getMembers().indexOf(t)>-1},i.prototype.getMembers=function(){return this._members},i.prototype.getRandomMember=function(){return this._members[Math.floor(Math.random()*this._members.length)] -},i.prototype.getBounds=function(){return this.getMembers().map(function(t){return t.getBounds()}).reduce(function(t,e){return t.combine(e)})},i}(t.Class);t.Group=e})(ex||(ex={}));var ex;(function(t){var e=function(){function t(t){this._getComparable=t}return t.prototype.find=function(t){return this._find(this._root,t)},t.prototype._find=function(t,e){return null==t?!1:this._getComparable.call(e)===t.getKey()?t.getData().indexOf(e)>-1?!0:!1:this._getComparable.call(e)e?this._get(t.getLeft(),e):this._get(t.getRight(),e)},t.prototype.add=function(t){return null==this._root?(this._root=new i(this._getComparable.call(t),[t],null,null),!0):this._insert(this._root,t)},t.prototype._insert=function(t,e){return null!=t?this._getComparable.call(e)===t.getKey()?t.getData().indexOf(e)>-1?!1:(t.getData().push(e),!0):this._getComparable.call(e)-1){if(t.getData().splice(i,1),0===t.getData().length){if(null==t.getLeft()&&null==t.getRight())return null;if(null==t.getLeft())return t.getRight();if(null==t.getRight())return t.getLeft();var n=this._findMinNode(t.getRight());return t.setKey(n.getKey()),t.setData(n.getData()),t.setRight(this._cleanup(t.getRight(),n)),t}return t}},t.prototype._cleanup=function(t,e){var i=e.getKey();if(null==t)return null;if(i===t.getKey()){if(null==t.getLeft()&&null==t.getRight())return null;if(null==t.getLeft())return t.getRight();if(null==t.getRight())return t.getLeft();var n=this._findMinNode(t.getRight());return t.setKey(n.getKey()),t.setData(n.getData()),t.setRight(this._cleanup(t.getRight(),n)),t}return this._getComparable.call(e)i;i++)this.children[i].triggerEvent(t,e)},i.prototype.update=function(t,e){var i,n;for(i=0,n=this.uiActors.length;n>i;i++)this.uiActors[i].update(t,e);for(i=0,n=this.tileMaps.length;n>i;i++)this.tileMaps[i].update(t,e);for(i=0,n=this.children.length;n>i;i++)this.children[i].update(t,e);this._collisionResolver&&(this._collisionResolver.update(this.children),this._collisionResolver.evaluate(this.children));var s;for(i=0,n=this._killQueue.length;n>i;i++)s=this.children.indexOf(this._killQueue[i]),s>-1&&(this._sortedDrawingTree.removeByComparable(this._killQueue[i]),this.children.splice(s,1));for(this._killQueue.length=0,i=0,n=this._cancelQueue.length;n>i;i++)this.removeTimer(this._cancelQueue[i]);this._cancelQueue.length=0,this._timers=this._timers.filter(function(t){return t.update(e),!t.complete})},i.prototype.draw=function(t,e){t.save(),this.camera&&this.camera.update(t,e);var i,n;for(i=0,n=this.tileMaps.length;n>i;i++)this.tileMaps[i].draw(t,e);var s=this._sortedDrawingTree.list();for(i=0,n=s.length;n>i;i++)s[i].visible&&!s[i].isOffScreen&&s[i].draw(t,e);for(this.engine&&this.engine.isDebug&&(t.strokeStyle="yellow",this.debugDraw(t)),t.restore(),i=0,n=this.uiActors.length;n>i;i++)this.uiActors[i].visible&&this.uiActors[i].draw(t,e);if(this.engine&&this.engine.isDebug)for(i=0,n=this.uiActors.length;n>i;i++)this.uiActors[i].debugDraw(t)},i.prototype.debugDraw=function(t){var e,i;for(e=0,i=this.tileMaps.length;i>e;e++)this.tileMaps[e].debugDraw(t);for(e=0,i=this.children.length;i>e;e++)this.children[e].debugDraw(t);this.camera.debugDraw(t)},i.prototype.contains=function(t){return this.children.indexOf(t)>-1},i.prototype.add=function(e){return e instanceof t.UIActor?(this.addUIActor(e),void 0):(e instanceof t.Actor&&(this.addChild(e),this._sortedDrawingTree.add(e)),e instanceof t.Timer&&this.addTimer(e),e instanceof t.TileMap&&this.addTileMap(e),void 0)},i.prototype.remove=function(e){return e instanceof t.UIActor?(this.removeUIActor(e),void 0):(e instanceof t.Actor&&(this._collisionResolver.remove(e),this.removeChild(e)),e instanceof t.Timer&&this.removeTimer(e),e instanceof t.TileMap&&this.removeTileMap(e),void 0)},i.prototype.addUIActor=function(t){this.uiActors.push(t),t.scene=this},i.prototype.removeUIActor=function(t){var e=this.uiActors.indexOf(t);e>-1&&this.uiActors.splice(e,1)},i.prototype.addChild=function(t){this._collisionResolver.register(t),t.scene=this,this.children.push(t),this._sortedDrawingTree.add(t),t.parent=this.actor},i.prototype.addTileMap=function(t){this.tileMaps.push(t)},i.prototype.removeTileMap=function(t){var e=this.tileMaps.indexOf(t);e>-1&&this.tileMaps.splice(e,1)},i.prototype.removeChild=function(t){this._collisionResolver.remove(t),this._killQueue.push(t),t.parent=null},i.prototype.addTimer=function(t){return this._timers.push(t),t.scene=this,t},i.prototype.removeTimer=function(t){var e=this._timers.indexOf(t);return-1!==e&&this._timers.splice(e,1),t},i.prototype.cancelTimer=function(t){return this._cancelQueue.push(t),t},i.prototype.isTimerActive=function(t){return this._timers.indexOf(t)>-1},i.prototype.createGroup=function(e){return new t.Group(e,this)},i.prototype.getGroup=function(t){return this.groups[t]},i.prototype.removeGroup=function(e){"string"==typeof e?delete this.groups[e]:e instanceof t.Group?delete this.groups[e.name]:this._logger.error("Invalid arguments to removeGroup",e)},i.prototype.cleanupDrawTree=function(t){this._sortedDrawingTree.removeByComparable(t)},i.prototype.updateDrawTree=function(t){this._sortedDrawingTree.add(t)},i}(t.Class);t.Scene=e})(ex||(ex={}));var ex;(function(t){var e=function(){function t(){}return t.Linear=function(t,e,i,n){return i-=e,i*t/n+e},t.EaseInQuad=function(t,e,i,n){t/=n},t.EaseOutQuad=function(t,e,i,n){return t/=n,-i*t*(t-2)+e},t.EaseInOutQuad=function(t,e,i,n){return i-=e,t/=n/2,1>t?i/2*t*t+e:(t--,-i/2*(t*(t-2)-1)+e)},t.EaseInCubic=function(t,e,i,n){return i-=e,t/=n,i*t*t*t+e},t.EaseOutCubic=function(t,e,i,n){return i-=e,t/=n,i*(t*t*t+1)+e},t.EaseInOutCubic=function(t,e,i,n){return i-=e,t/=n/2,1>t?i/2*t*t*t+e:(t-=2,i/2*(t*t*t+2)+e)},t}();t.EasingFunctions=e})(ex||(ex={}));var ex;(function(t){var e=function(e){function n(s,o,r,h,a){e.call(this),this.id=n.maxId++,this.x=0,this.y=0,this._height=0,this._width=0,this.rotation=0,this.rx=0,this.scale=new t.Vector(1,1),this.sx=0,this.sy=0,this.dx=0,this.dy=0,this.ax=0,this.ay=0,this.isOffScreen=!1,this.visible=!0,this.opacity=1,this.previousOpacity=1,this.actions=new t.ActionContext(this),this.logger=t.Logger.getInstance(),this.scene=null,this.parent=null,this.children=[],this.collisionType=i.PreventCollision,this.collisionGroups=[],this._collisionHandlers={},this._isInitialized=!1,this.frames={},this.currentDrawing=null,this.centerDrawingX=!0,this.centerDrawingY=!0,this.traits=[],this.enableCapturePointer=!1,this.capturePointer={captureMoveEvents:!1},this._zIndex=0,this._isKilled=!1,this.x=s||0,this.y=o||0,this._width=r||0,this._height=h||0,a&&(this.color=a.clone(),this.opacity=a.a),this.traits.push(new t.Traits.Movement),this.traits.push(new t.Traits.OffscreenCulling),this.traits.push(new t.Traits.CapturePointer),this.actionQueue=new t.Internal.Actions.ActionQueue(this),this.anchor=new t.Point(.5,.5)}return __extends(n,e),n.prototype.onInitialize=function(){},n.prototype._checkForPointerOptIn=function(t){!t||"pointerdown"!==t.toLowerCase()&&"pointerdown"!==t.toLowerCase()&&"pointermove"!==t.toLowerCase()||(this.enableCapturePointer=!0,"pointermove"===t.toLowerCase()&&(this.capturePointer.captureMoveEvents=!0))},n.prototype.addEventListener=function(t,i){this._checkForPointerOptIn(t),e.prototype.addEventListener.call(this,t,i)},n.prototype.on=function(t,e){this._checkForPointerOptIn(t),this.eventDispatcher.subscribe(t,e)},n.prototype.kill=function(){this.scene?(this.scene.remove(this),this._isKilled=!0):this.logger.warn("Cannot kill actor, it was never added to the Scene")},n.prototype.isKilled=function(){return this._isKilled},n.prototype.addChild=function(e){e.collisionType=i.PreventCollision,t.Util.addItemToArray(e,this.children)&&(e.parent=this)},n.prototype.removeChild=function(e){t.Util.removeItemToArray(e,this.children)&&(e.parent=null)},n.prototype.setDrawing=function(e){e=""+e,this.currentDrawing!==this.frames[e]&&(null!=this.frames[e]?(this.frames[e].reset(),this.currentDrawing=this.frames[e]):t.Logger.getInstance().error("the specified drawing key '"+e+"' does not exist"))},n.prototype.addDrawing=function(){2===arguments.length?(this.frames[arguments[0]]=arguments[1],this.currentDrawing||(this.currentDrawing=arguments[1])):(arguments[0]instanceof t.Sprite&&this.addDrawing("default",arguments[0]),arguments[0]instanceof t.Texture&&this.addDrawing("default",arguments[0].asSprite()))},n.prototype.getZIndex=function(){return this._zIndex},n.prototype.setZIndex=function(t){this.scene.cleanupDrawTree(this),this._zIndex=t,this.scene.updateDrawTree(this)},n.prototype.triggerEvent=function(t,e){this.eventDispatcher.publish(t,e)},n.prototype.addCollisionGroup=function(t){this.collisionGroups.push(t)},n.prototype.removeCollisionGroup=function(t){var e=this.collisionGroups.indexOf(t);-1!==e&&this.collisionGroups.splice(e,1)},n.prototype.getCenter=function(){return new t.Vector(this.x+this.getWidth()/2-this.anchor.x*this.getWidth(),this.y+this.getHeight()/2-this.anchor.y*this.getHeight())},n.prototype.getWidth=function(){return this._width*this.scale.x},n.prototype.setWidth=function(t){this._width=t/this.scale.x},n.prototype.getHeight=function(){return this._height*this.scale.y},n.prototype.setHeight=function(t){this._height=t/this.scale.y},n.prototype.setCenterDrawing=function(t){this.centerDrawingY=t,this.centerDrawingX=t},n.prototype.getLeft=function(){return this.x},n.prototype.getRight=function(){return this.x+this.getWidth()},n.prototype.getTop=function(){return this.y},n.prototype.getBottom=function(){return this.y+this.getHeight()},n.prototype.getWorldX=function(){return this.parent?this.x*this.parent.scale.x+this.parent.getWorldX():this.x},n.prototype.getWorldY=function(){return this.parent?this.y*this.parent.scale.y+this.parent.getWorldY():this.y},n.prototype.getGlobalScale=function(){if(!this.parent)return new t.Point(this.scale.x,this.scale.y);var e=this.parent.getGlobalScale();return new t.Point(this.scale.x*e.x,this.scale.y*e.y)},n.prototype.getBounds=function(){var e=this._getCalculatedAnchor();return new t.BoundingBox(this.getWorldX()-e.x,this.getWorldY()-e.y,this.getWorldX()+this.getWidth()-e.x,this.getWorldY()+this.getHeight()-e.y)},n.prototype.contains=function(e,i,n){void 0===n&&(n=!1);var s=this.getBounds().contains(new t.Point(e,i));return n?s||this.children.some(function(t){return t.contains(e,i,!0)}):s},n.prototype.getSideFromIntersect=function(e){return e?Math.abs(e.x)>Math.abs(e.y)?0>e.x?t.Side.Right:t.Side.Left:0>e.y?t.Side.Bottom:t.Side.Top:t.Side.None},n.prototype.collidesWithSide=function(e){var i=this.collides(e);return i?Math.abs(i.x)>Math.abs(i.y)?this.x=Math.sqrt(Math.pow(this.x-t.x,2)+Math.pow(this.y-t.y,2))},n.prototype.clearActions=function(){this.actionQueue.clearActions()},n.prototype.easeTo=function(e,i,n,s){return void 0===s&&(s=t.EasingFunctions.Linear),this.actionQueue.add(new t.Internal.Actions.EaseTo(this,e,i,n,s)),this},n.prototype.moveTo=function(e,i,n){return this.actionQueue.add(new t.Internal.Actions.MoveTo(this,e,i,n)),this},n.prototype.moveBy=function(e,i,n){return this.actionQueue.add(new t.Internal.Actions.MoveBy(this,e,i,n)),this},n.prototype.rotateTo=function(e,i,n){return this.actionQueue.add(new t.Internal.Actions.RotateTo(this,e,i,n)),this},n.prototype.rotateBy=function(e,i,n){return this.actionQueue.add(new t.Internal.Actions.RotateBy(this,e,i,n)),this},n.prototype.scaleTo=function(e,i,n,s){return this.actionQueue.add(new t.Internal.Actions.ScaleTo(this,e,i,n,s)),this},n.prototype.scaleBy=function(e,i,n){return this.actionQueue.add(new t.Internal.Actions.ScaleBy(this,e,i,n)),this},n.prototype.blink=function(e,i,n){return void 0===n&&(n=1),this.actionQueue.add(new t.Internal.Actions.Blink(this,e,i,n)),this},n.prototype.fade=function(e,i){return this.actionQueue.add(new t.Internal.Actions.Fade(this,e,i)),this},n.prototype.delay=function(e){return this.actionQueue.add(new t.Internal.Actions.Delay(this,e)),this},n.prototype.die=function(){return this.actionQueue.add(new t.Internal.Actions.Die(this)),this},n.prototype.callMethod=function(e){return this.actionQueue.add(new t.Internal.Actions.CallMethod(this,e)),this},n.prototype.repeat=function(e){return e?(this.actionQueue.add(new t.Internal.Actions.Repeat(this,e,this.actionQueue.getActions())),this):(this.repeatForever(),this)},n.prototype.repeatForever=function(){return this.actionQueue.add(new t.Internal.Actions.RepeatForever(this,this.actionQueue.getActions())),this},n.prototype.follow=function(e,i){return i===void 0?this.actionQueue.add(new t.Internal.Actions.Follow(this,e)):this.actionQueue.add(new t.Internal.Actions.Follow(this,e,i)),this},n.prototype.meet=function(e,i){return i===void 0?this.actionQueue.add(new t.Internal.Actions.Meet(this,e)):this.actionQueue.add(new t.Internal.Actions.Meet(this,e,i)),this},n.prototype.asPromise=function(){var e=new t.Promise;return this.callMethod(function(){e.resolve()}),e},n.prototype._getCalculatedAnchor=function(){return new t.Point(this.getWidth()*this.anchor.x,this.getHeight()*this.anchor.y)},n.prototype.update=function(e,i){this._isInitialized||(this.onInitialize(e),this.eventDispatcher.publish("initialize",new t.InitializeEvent(e)),this._isInitialized=!0);var n=this.eventDispatcher;this.actionQueue.update(i),this.color&&(this.color.a=this.opacity);for(var s=0;this.traits.length>s;s++)this.traits[s].update(this,e,i);n.publish(t.EventType[t.EventType.Update],new t.UpdateEvent(i))},n.prototype.draw=function(e,i){var n=this._getCalculatedAnchor();if(e.save(),e.scale(this.scale.x,this.scale.y),e.translate(this.x,this.y),e.rotate(this.rotation),this.previousOpacity!==this.opacity){for(var s in this.frames)this.frames[s].addEffect(new t.Effects.Opacity(this.opacity));this.previousOpacity=this.opacity}if(this.currentDrawing){var o=0,r=0;this.centerDrawingX&&(o=(this.currentDrawing.naturalWidth*this.currentDrawing.scale.x-this.getWidth())/2-this.currentDrawing.naturalWidth*this.currentDrawing.scale.x*this.currentDrawing.anchor.x),this.centerDrawingY&&(r=(this.currentDrawing.naturalHeight*this.currentDrawing.scale.y-this.getHeight())/2-this.currentDrawing.naturalHeight*this.currentDrawing.scale.y*this.currentDrawing.anchor.y),this.currentDrawing.draw(e,-n.x-o,-n.y-r)}else this.color&&(e.fillStyle=""+this.color,e.fillRect(-n.x,-n.y,this._width,this._height));for(var h=0;this.children.length>h;h++)this.children[h].draw(e,i);e.restore()},n.prototype.debugDraw=function(e){var i=this.getBounds();i.debugDraw(e),e.fillText("id: "+this.id,i.left+3,i.top+10),e.fillStyle=""+t.Color.Yellow,e.beginPath(),e.arc(this.getWorldX(),this.getWorldY(),3,0,2*Math.PI),e.closePath(),e.fill();for(var n=0;this.traits.length>n;n++)this.traits[n]instanceof t.Traits.OffscreenCulling&&this.traits[n].cullingBox.debugDraw(e);e.strokeStyle=""+t.Color.Yellow,e.beginPath();var s=Math.min(this.getWidth(),this.getHeight());e.arc(this.getWorldX(),this.getWorldY(),s,0,2*Math.PI),e.closePath(),e.stroke();var o={"0 Pi":0,"Pi/2":Math.PI/2,Pi:Math.PI,"3/2 Pi":3*Math.PI/2},r=e.font;for(var h in o)e.fillStyle=""+t.Color.Yellow,e.font="14px",e.textAlign="center",e.fillText(h,this.getWorldX()+Math.cos(o[h])*(s+10),this.getWorldY()+Math.sin(o[h])*(s+10));e.font=r,e.save(),e.translate(this.x,this.y),e.rotate(this.rotation);for(var a=0;this.children.length>a;a++)this.children[a].debugDraw(e);e.restore()},n.maxId=0,n}(t.Class);t.Actor=e,function(t){t[t.PreventCollision=0]="PreventCollision",t[t.Passive=1]="Passive",t[t.Active=2]="Active",t[t.Elastic=3]="Elastic",t[t.Fixed=4]="Fixed"}(t.CollisionType||(t.CollisionType={}));var i=t.CollisionType})(ex||(ex={}));var ex;(function(t){(function(t){t[t.Debug=0]="Debug",t[t.Info=1]="Info",t[t.Warn=2]="Warn",t[t.Error=3]="Error",t[t.Fatal=4]="Fatal"})(t.LogLevel||(t.LogLevel={}));var e=t.LogLevel,i=function(){function t(){if(this._appenders=[],this.defaultLevel=e.Info,t._instance)throw Error("Logger is a singleton");return t._instance=this,t._instance.addAppender(new n),t._instance}return t.getInstance=function(){return null==t._instance&&(t._instance=new t),t._instance},t.prototype.addAppender=function(t){this._appenders.push(t)},t.prototype.clearAppenders=function(){this._appenders.length=0},t.prototype._log=function(t,e){null==t&&(t=this.defaultLevel);var i=0,n=this._appenders.length;for(i;n>i;i++)t>=this.defaultLevel&&this._appenders[i].log(t,e)},t.prototype.debug=function(){for(var t=[],i=0;arguments.length>i;i++)t[i-0]=arguments[i];this._log(e.Debug,t)},t.prototype.info=function(){for(var t=[],i=0;arguments.length>i;i++)t[i-0]=arguments[i];this._log(e.Info,t)},t.prototype.warn=function(){for(var t=[],i=0;arguments.length>i;i++)t[i-0]=arguments[i];this._log(e.Warn,t)},t.prototype.error=function(){for(var t=[],i=0;arguments.length>i;i++)t[i-0]=arguments[i];this._log(e.Error,t)},t.prototype.fatal=function(){for(var t=[],i=0;arguments.length>i;i++)t[i-0]=arguments[i];this._log(e.Fatal,t)},t._instance=null,t}();t.Logger=i;var n=function(){function t(){}return t.prototype.log=function(t,i){if(console||console.log||!console.warn||!console.error){var n=[];n.unshift.apply(n,i),n.unshift("["+e[t]+"] : "),e.Warn>t?console.log.apply?console.log.apply(console,n):console.log(n.join(" ")):e.Error>t?console.warn.apply?console.warn.apply(console,n):console.warn(n.join(" ")):console.error.apply?console.error.apply(console,n):console.error(n.join(" "))}},t}();t.ConsoleAppender=n;var s=function(){function t(t,e){this._messages=[],this._canvas=document.createElement("canvas"),this._canvas.width=t||window.innerWidth,this._canvas.height=e||window.innerHeight,this._canvas.style.position="absolute",this._ctx=this._canvas.getContext("2d"),document.body.appendChild(this._canvas)}return t.prototype.log=function(t,i){var n=i.join(",");this._ctx.clearRect(0,0,this._canvas.width,this._canvas.height),this._messages.unshift("["+e[t]+"] : "+n);for(var s=10,o=1,r=0;this._messages.length>r;r++)this._ctx.fillStyle="rgba(255,255,255,"+o.toFixed(2)+")",this._ctx.fillText(this._messages[r],200,s),s+=10,o=o>0?o-.05:0},t}();t.ScreenAppender=s})(ex||(ex={}));var ex;(function(t){(function(t){t[t.Collision=0]="Collision",t[t.EnterViewPort=1]="EnterViewPort",t[t.ExitViewPort=2]="ExitViewPort",t[t.Blur=3]="Blur",t[t.Focus=4]="Focus",t[t.Update=5]="Update",t[t.Activate=6]="Activate",t[t.Deactivate=7]="Deactivate",t[t.Initialize=8]="Initialize"})(t.EventType||(t.EventType={})),t.EventType;var e=function(){function t(){}return t}();t.GameEvent=e;var i=function(t){function e(e,i){t.call(this),this.topic=e,this.handler=i}return __extends(e,t),e}(e);t.SubscribeEvent=i;var n=function(t){function e(e,i){t.call(this),this.topic=e,this.handler=i}return __extends(e,t),e}(e);t.UnsubscribeEvent=n;var s=function(t){function e(){t.call(this)}return __extends(e,t),e}(e);t.VisibleEvent=s;var o=function(t){function e(){t.call(this)}return __extends(e,t),e}(e);t.HiddenEvent=o;var r=function(t){function e(e,i,n,s){t.call(this),this.actor=e,this.other=i,this.side=n,this.intersection=s}return __extends(e,t),e}(e);t.CollisionEvent=r;var h=function(t){function e(e){t.call(this),this.delta=e}return __extends(e,t),e}(e);t.UpdateEvent=h;var a=function(t){function e(e){t.call(this),this.engine=e}return __extends(e,t),e}(e);t.InitializeEvent=a;var c=function(t){function e(e){t.call(this),this.oldScene=e}return __extends(e,t),e}(e);t.ActivateEvent=c;var u=function(t){function e(e){t.call(this),this.newScene=e}return __extends(e,t),e}(e);t.DeactivateEvent=u;var l=function(t){function e(){t.call(this)}return __extends(e,t),e}(e);t.ExitViewPortEvent=l;var p=function(t){function e(){t.call(this)}return __extends(e,t),e}(e);t.EnterViewPortEvent=p})(ex||(ex={}));var ex;(function(t){var e=function(){function e(e){this._handlers={},this._wiredEventDispatchers=[],this._log=t.Logger.getInstance(),this._target=e}return e.prototype.publish=function(e,i){if(e){e=e.toLowerCase();var n=this._target;i||(i=new t.GameEvent),i.target=n;var s,o;if(this._handlers[e])for(s=0,o=this._handlers[e].length,s;o>s;s++)this._handlers[e][s].call(n,i);for(s=0,o=this._wiredEventDispatchers.length,s;o>s;s++)this._wiredEventDispatchers[s].publish(e,i)}},e.prototype.emit=function(t,e){this.publish(t,e)},e.prototype.subscribe=function(e,i){e=e.toLowerCase(),this._handlers[e]||(this._handlers[e]=[]),this._handlers[e].push(i),"unsubscribe"!==e&&"subscribe"!==e&&this.emit("subscribe",new t.SubscribeEvent(e,i))},e.prototype.unsubscribe=function(e,i){e=e.toLowerCase();var n=this._handlers[e];if(n)if(i){var s=n.indexOf(i);this._handlers[e].splice(s,1)}else this._handlers[e].length=0;"unsubscribe"!==e&&"subscribe"!==e&&this.emit("unsubscribe",new t.UnsubscribeEvent(e,i))},e.prototype.wire=function(t){t._wiredEventDispatchers.push(this)},e.prototype.unwire=function(t){var e=t._wiredEventDispatchers.indexOf(this);e>-1&&t._wiredEventDispatchers.splice(e,1)},e}();t.EventDispatcher=e})(ex||(ex={}));var ex;(function(t){var e=function(){function t(t,e,i,n){this.r=t,this.g=e,this.b=i,this.a=null!=n?n:1}return t.fromRGB=function(e,i,n,s){return new t(e,i,n,s)},t.fromHex=function(e){var i=/^#?([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})?$/i,n=null;if(n=e.match(i)){var s=parseInt(n[1],16),o=parseInt(n[2],16),r=parseInt(n[3],16),h=1;return n[4]&&(h=parseInt(n[4],16)/255),new t(s,o,r,h)}throw Error("Invalid hex string: "+e)},t.fromHSL=function(t,e,n,s){void 0===s&&(s=1);var o=new i(t,e,n,s);return o.toRGBA()},t.prototype.lighten=function(t){void 0===t&&(t=.1);var e=i.fromRGBA(this.r,this.g,this.b,this.a);return e.l+=e.l*t,e.toRGBA()},t.prototype.darken=function(t){void 0===t&&(t=.1);var e=i.fromRGBA(this.r,this.g,this.b,this.a);return e.l-=e.l*t,e.toRGBA()},t.prototype.saturate=function(t){void 0===t&&(t=.1);var e=i.fromRGBA(this.r,this.g,this.b,this.a);return e.s+=e.s*t,e.toRGBA()},t.prototype.desaturate=function(t){void 0===t&&(t=.1);var e=i.fromRGBA(this.r,this.g,this.b,this.a);return e.s-=e.s*t,e.toRGBA()},t.prototype.mulitiply=function(e){var i=255*(e.r/255*this.r/255),n=255*(e.g/255*this.g/255),s=255*(e.b/255*this.b/255),o=e.a*this.a;return new t(i,n,s,o)},t.prototype.screen=function(t){var e=t.invert(),i=t.invert();return e.mulitiply(i).invert()},t.prototype.invert=function(){return new t(255-this.r,255-this.g,255-this.b,1-this.a)},t.prototype.average=function(e){var i=(e.r+this.r)/2,n=(e.g+this.g)/2,s=(e.b+this.b)/2,o=(e.a+this.a)/2;return new t(i,n,s,o)},t.prototype.toString=function(){var t=this.r.toFixed(0)+""+", "+(this.g.toFixed(0)+"")+", "+(this.b.toFixed(0)+"");return void 0!==this.a||null!==this.a?"rgba("+t+", "+(this.a+"")+")":"rgb("+t+")"},t.prototype.fillStyle=function(){return""+this},t.prototype.clone=function(){return new t(this.r,this.g,this.b,this.a)},t.Black=t.fromHex("#000000"),t.White=t.fromHex("#FFFFFF"),t.Gray=t.fromHex("#808080"),t.LightGray=t.fromHex("#D3D3D3"),t.DarkGray=t.fromHex("#A9A9A9"),t.Yellow=t.fromHex("#FFFF00"),t.Orange=t.fromHex("#FFA500"),t.Red=t.fromHex("#FF0000"),t.Vermillion=t.fromHex("#FF5B31"),t.Rose=t.fromHex("#FF007F"),t.Magenta=t.fromHex("#FF00FF"),t.Violet=t.fromHex("#7F00FF"),t.Blue=t.fromHex("#0000FF"),t.Azure=t.fromHex("#007FFF"),t.Cyan=t.fromHex("#00FFFF"),t.Viridian=t.fromHex("#59978F"),t.Green=t.fromHex("#00FF00"),t.Chartreuse=t.fromHex("#7FFF00"),t.Transparent=t.fromHex("#FFFFFF00"),t}();t.Color=e;var i=function(){function t(t,e,i,n){this.h=t,this.s=e,this.l=i,this.a=n}return t.fromRGBA=function(e,i,n,s){e/=255,i/=255,n/=255;var o,r,h=Math.max(e,i,n),a=Math.min(e,i,n),c=(h+a)/2;if(h===a)o=r=0;else{var u=h-a;switch(r=c>.5?u/(2-h-a):u/(h+a),h){case e:o=(i-n)/u+(n>i?6:0);break;case i:o=(n-e)/u+2;break;case n:o=(e-i)/u+4}o/=6}return new t(o,r,c,s)},t.prototype.toRGBA=function(){function t(t,e,i){return 0>i&&(i+=1),i>1&&(i-=1),1/6>i?t+6*(e-t)*i:.5>i?e:2/3>i?t+6*(e-t)*(2/3-i):t}var i,n,s;if(0===this.s)i=n=s=this.l;else{var o=.5>this.l?this.l*(1+this.s):this.l+this.s-this.l*this.s,r=2*this.l-o;i=t(r,o,this.h+1/3),n=t(r,o,this.h),s=t(r,o,this.h-1/3)}return new e(255*i,255*n,255*s,this.a)},t}()})(ex||(ex={}));var ex;(function(t){var e=function(e){function i(i,n,s,o){e.call(this,i,n,s,o),this.traits=[],this.traits.push(new t.Traits.Movement),this.traits.push(new t.Traits.CapturePointer),this.anchor.setTo(0,0),this.collisionType=t.CollisionType.PreventCollision,this.enableCapturePointer=!0}return __extends(i,e),i.prototype.onInitialize=function(t){this._engine=t},i.prototype.contains=function(i,n,s){if(void 0===s&&(s=!0),s)return e.prototype.contains.call(this,i,n);var o=this._engine.worldToScreenCoordinates(new t.Point(i,n));return e.prototype.contains.call(this,o.x,o.y)},i}(t.Actor);t.UIActor=e})(ex||(ex={}));var ex;(function(t){var e=function(e){function i(i,n,s,o,r,h){e.call(this,i,n,s,o),this._action=function(){},this.repeats=1,this.target=null,this.repeats=h||this.repeats,this._action=r||this._action,this.collisionType=t.CollisionType.PreventCollision,this.eventDispatcher=new t.EventDispatcher(this),this.actionQueue=new t.Internal.Actions.ActionQueue(this)}return __extends(i,e),i.prototype.update=function(e,i){if(this.actionQueue.update(i),this.x+=this.dx*i/1e3,this.y+=this.dy*i/1e3,this.rotation+=this.rx*i/1e3,this.scale.x+=this.sx*i/1e3,this.scale.y+=this.sy*i/1e3,this.target)this.collides(this.target)&&this._dispatchAction();else for(var n=0;e.currentScene.children.length>n;n++){var s=e.currentScene.children[n];s!==this&&s.collisionType!==t.CollisionType.PreventCollision&&this.collides(s)&&this._dispatchAction()}0===this.repeats&&this.kill()},i.prototype._dispatchAction=function(){this._action.call(this),this.repeats--},i.prototype.draw=function(){},i.prototype.debugDraw=function(i){e.prototype.debugDraw.call(this,i),i.save(),i.translate(this.x,this.y);var n=this.getBounds();n.left=n.left-this.getWorldX(),n.right=n.right-this.getWorldX(),n.top=n.top-this.getWorldY(),n.bottom=n.bottom-this.getWorldY(),i.fillStyle=""+t.Color.Violet,i.strokeStyle=""+t.Color.Violet,i.fillText("Trigger",10,10),n.debugDraw(i),i.restore()},i}(t.Actor);t.Trigger=e})(ex||(ex={}));var ex;(function(t){(function(t){t[t.Circle=0]="Circle",t[t.Rectangle=1]="Rectangle"})(t.EmitterType||(t.EmitterType={}));var e=t.EmitterType,i=function(){function e(e,i,n,s,o,r,h,a,c,u){this.position=new t.Vector(0,0),this.velocity=new t.Vector(0,0),this.acceleration=new t.Vector(0,0),this.particleRotationalVelocity=0,this.currentRotation=0,this.focus=null,this.focusAccel=0,this.opacity=1,this.beginColor=t.Color.White.clone(),this.endColor=t.Color.White.clone(),this.life=300,this.fadeFlag=!1,this._rRate=1,this._gRate=1,this._bRate=1,this._aRate=0,this._currentColor=t.Color.White.clone(),this.emitter=null,this.particleSize=5,this.particleSprite=null,this.sizeRate=0,this.elapsedMultiplier=0,this.emitter=e,this.life=i||this.life,this.opacity=n||this.opacity,this.endColor=o||this.endColor.clone(),this.beginColor=s||this.beginColor.clone(),this._currentColor=this.beginColor.clone(),this.position=r||this.position,this.velocity=h||this.velocity,this.acceleration=a||this.acceleration,this._rRate=(this.endColor.r-this.beginColor.r)/this.life,this._gRate=(this.endColor.g-this.beginColor.g)/this.life,this._bRate=(this.endColor.b-this.beginColor.b)/this.life,this._aRate=this.opacity/this.life,this.startSize=c||0,this.endSize=u||0,this.endSize>0&&this.startSize>0&&(this.sizeRate=(this.endSize-this.startSize)/this.life,this.particleSize=this.startSize)}return e.prototype.kill=function(){this.emitter.removeParticle(this)},e.prototype.update=function(e){if(this.life=this.life-e,this.elapsedMultiplier=this.elapsedMultiplier+e,0>this.life&&this.kill(),this.fadeFlag&&(this.opacity=t.Util.clamp(this._aRate*this.life,1e-4,1)),this.startSize>0&&this.endSize>0&&(this.particleSize=t.Util.clamp(this.sizeRate*e+this.particleSize,Math.min(this.startSize,this.endSize),Math.max(this.startSize,this.endSize))),this._currentColor.r=t.Util.clamp(this._currentColor.r+this._rRate*e,0,255),this._currentColor.g=t.Util.clamp(this._currentColor.g+this._gRate*e,0,255),this._currentColor.b=t.Util.clamp(this._currentColor.b+this._bRate*e,0,255),this._currentColor.a=t.Util.clamp(this.opacity,1e-4,1),this.focus){var i=this.focus.minus(this.position).normalize().scale(this.focusAccel).scale(e/1e3);this.velocity=this.velocity.add(i)}else this.velocity=this.velocity.add(this.acceleration.scale(e/1e3));this.position=this.position.add(this.velocity.scale(e/1e3)),this.particleRotationalVelocity&&(this.currentRotation=(this.currentRotation+this.particleRotationalVelocity*e/1e3)%(2*Math.PI))},e.prototype.draw=function(e){return this.particleSprite?(this.particleSprite.rotation=this.currentRotation,this.particleSprite.scale.setTo(this.particleSize,this.particleSize),this.particleSprite.draw(e,this.position.x,this.position.y),void 0):(this._currentColor.a=t.Util.clamp(this.opacity,1e-4,1),e.fillStyle=""+this._currentColor,e.beginPath(),e.arc(this.position.x,this.position.y,this.particleSize,0,2*Math.PI),e.fill(),e.closePath(),void 0) -},e}();t.Particle=i;var n=function(n){function s(i,s,o,r){n.call(this,i,s,o,r,t.Color.White),this._particlesToEmit=0,this.numParticles=0,this.isEmitting=!0,this.particles=null,this.deadParticles=null,this.minVel=0,this.maxVel=0,this.acceleration=new t.Vector(0,0),this.minAngle=0,this.maxAngle=0,this.emitRate=1,this.particleLife=2e3,this.opacity=1,this.fadeFlag=!1,this.focus=null,this.focusAccel=1,this.startSize=null,this.endSize=null,this.minSize=5,this.maxSize=5,this.beginColor=t.Color.White,this.endColor=t.Color.White,this.particleSprite=null,this.emitterType=e.Rectangle,this.radius=0,this.particleRotationalVelocity=0,this.randomRotation=!1,this.collisionType=t.CollisionType.PreventCollision,this.particles=new t.Util.Collection,this.deadParticles=new t.Util.Collection;for(var h in this.traits)this.traits[h]instanceof t.Traits.OffscreenCulling&&this.traits.splice(h,1)}return __extends(s,n),s.prototype.removeParticle=function(t){this.deadParticles.push(t)},s.prototype.emit=function(t){for(var e=0;t>e;e++)this.particles.push(this._createParticle())},s.prototype.clearParticles=function(){this.particles.clear()},s.prototype._createParticle=function(){var n=0,s=0,o=t.Util.randomInRange(this.minAngle,this.maxAngle),r=t.Util.randomInRange(this.minVel,this.maxVel),h=this.startSize||t.Util.randomInRange(this.minSize,this.maxSize),a=r*Math.cos(o),c=r*Math.sin(o);if(this.emitterType===e.Rectangle)n=t.Util.randomInRange(this.x,this.x+this.getWidth()),s=t.Util.randomInRange(this.y,this.y+this.getHeight());else if(this.emitterType===e.Circle){var u=t.Util.randomInRange(0,this.radius);n=u*Math.cos(o)+this.x,s=u*Math.sin(o)+this.y}var l=new i(this,this.particleLife,this.opacity,this.beginColor,this.endColor,new t.Vector(n,s),new t.Vector(a,c),this.acceleration,this.startSize,this.endSize);return l.fadeFlag=this.fadeFlag,l.particleSize=h,this.particleSprite&&(l.particleSprite=this.particleSprite),l.particleRotationalVelocity=this.particleRotationalVelocity,this.randomRotation&&(l.currentRotation=t.Util.randomInRange(0,2*Math.PI)),this.focus&&(l.focus=this.focus.add(new t.Vector(this.x,this.y)),l.focusAccel=this.focusAccel),l},s.prototype.update=function(t,e){var i=this;n.prototype.update.call(this,t,e),this.isEmitting&&(this._particlesToEmit+=this.emitRate*(e/1e3),this._particlesToEmit>1&&(this.emit(Math.floor(this._particlesToEmit)),this._particlesToEmit=this._particlesToEmit-Math.floor(this._particlesToEmit))),this.particles.forEach(function(t){return t.update(e)}),this.deadParticles.forEach(function(t){return i.particles.removeElement(t)}),this.deadParticles.clear()},s.prototype.draw=function(t){this.particles.forEach(function(e){return e.draw(t)})},s.prototype.debugDraw=function(e){n.prototype.debugDraw.call(this,e),e.fillStyle=""+t.Color.Black,e.fillText("Particles: "+this.particles.count(),this.x,this.y+20),this.focus&&(e.fillRect(this.focus.x+this.x,this.focus.y+this.y,3,3),t.Util.drawLine(e,"yellow",this.focus.x+this.x,this.focus.y+this.y,n.prototype.getCenter.call(this).x,n.prototype.getCenter.call(this).y),e.fillText("Focus",this.focus.x+this.x,this.focus.y+this.y))},s}(t.Actor);t.ParticleEmitter=n})(ex||(ex={}));var ex;(function(t){var e=function(){function e(e,i,n,s){this.currentFrame=0,this._oldTime=Date.now(),this.anchor=new t.Point(0,0),this.rotation=0,this.scale=new t.Point(1,1),this.loop=!1,this.freezeFrame=-1,this.flipVertical=!1,this.flipHorizontal=!1,this.width=0,this.height=0,this.naturalWidth=0,this.naturalHeight=0,this.sprites=i,this.speed=n,this._engine=e,null!=s&&(this.loop=s),i&&i[0]&&(this.height=i[0]?i[0].height:0,this.width=i[0]?i[0].width:0,this.naturalWidth=i[0]?i[0].naturalWidth:0,this.naturalHeight=i[0]?i[0].naturalHeight:0)}return e.prototype.opacity=function(e){this.addEffect(new t.Effects.Opacity(e))},e.prototype.grayscale=function(){this.addEffect(new t.Effects.Grayscale)},e.prototype.invert=function(){this.addEffect(new t.Effects.Invert)},e.prototype.fill=function(e){this.addEffect(new t.Effects.Fill(e))},e.prototype.colorize=function(e){this.addEffect(new t.Effects.Colorize(e))},e.prototype.lighten=function(e){void 0===e&&(e=.1),this.addEffect(new t.Effects.Lighten(e))},e.prototype.darken=function(e){void 0===e&&(e=.1),this.addEffect(new t.Effects.Darken(e))},e.prototype.saturate=function(e){void 0===e&&(e=.1),this.addEffect(new t.Effects.Saturate(e))},e.prototype.desaturate=function(e){void 0===e&&(e=.1),this.addEffect(new t.Effects.Desaturate(e))},e.prototype.addEffect=function(t){for(var e in this.sprites)this.sprites[e].addEffect(t)},e.prototype.removeEffect=function(t){for(var e in this.sprites)this.sprites[e].removeEffect(t)},e.prototype.clearEffects=function(){for(var t in this.sprites)this.sprites[t].clearEffects()},e.prototype._setAnchor=function(t){for(var e in this.sprites)this.sprites[e].anchor.setTo(t.x,t.y)},e.prototype._setRotation=function(t){for(var e in this.sprites)this.sprites[e].rotation=t},e.prototype._setScale=function(t){for(var e in this.sprites)this.sprites[e].scale=t},e.prototype.reset=function(){this.currentFrame=0},e.prototype.isDone=function(){return!this.loop&&this.currentFrame>=this.sprites.length},e.prototype.tick=function(){var t=Date.now();t-this._oldTime>this.speed&&(this.currentFrame=this.loop?(this.currentFrame+1)%this.sprites.length:this.currentFrame+1,this._oldTime=t)},e.prototype._updateValues=function(){this._setAnchor(this.anchor),this._setRotation(this.rotation),this._setScale(this.scale)},e.prototype.skip=function(t){this.currentFrame=(this.currentFrame+t)%this.sprites.length},e.prototype.draw=function(e,i,n){this.tick(),this._updateValues();var s;this.currentFrame=this.sprites.length&&(s=this.sprites[t.Util.clamp(this.freezeFrame,0,this.sprites.length-1)],s.draw(e,i,n)),s&&(this.width=s.width,this.height=s.height)},e.prototype.play=function(t,e){this.reset(),this._engine.playAnimation(this,t,e)},e}();t.Animation=e})(ex||(ex={}));var ex;(function(t){var e;(function(e){var i=function(){function e(e,i){this._log=t.Logger.getInstance(),this.onload=function(){},this.onprogress=function(){},this.onerror=function(){},window.AudioContext?(this._log.debug("Using new Web Audio Api for "+e),this._soundImpl=new o(e,i)):(this._log.debug("Falling back to Audio Element for "+e),this._soundImpl=new n(e,i))}return e.prototype.setVolume=function(t){this._soundImpl.setVolume(t)},e.prototype.setLoop=function(t){this._soundImpl.setLoop(t)},e.prototype.load=function(){this._soundImpl.onload=this.onload,this._soundImpl.onprogress=this.onprogress,this._soundImpl.onerror=this.onerror,this._soundImpl.load()},e.prototype.isPlaying=function(){return this._soundImpl.isPlaying()},e.prototype.play=function(){return this._soundImpl.play()},e.prototype.pause=function(){this._soundImpl.pause()},e.prototype.stop=function(){this._soundImpl.stop()},e}();e.FallbackAudio=i;var n=function(){function e(e,i){var n=this;this.path=e,this._audioElements=Array(5),this._loadedAudio=null,this._isLoaded=!1,this._index=0,this._log=t.Logger.getInstance(),this._isPlaying=!1,this._currentOffset=0,this.onload=function(){},this.onprogress=function(){},this.onerror=function(){};for(var s=0;this._audioElements.length>s;s++)(function(t){n._audioElements[t]=new Audio})(s);i?this.setVolume(t.Util.clamp(i,0,1)):this.setVolume(1)}return e.prototype.isPlaying=function(){return this._isPlaying},e.prototype._audioLoaded=function(){this._isLoaded=!0},e.prototype.setVolume=function(t){var e=0,i=this._audioElements.length;for(e;i>e;e++)this._audioElements[e].volume=t},e.prototype.setLoop=function(t){var e=0,i=this._audioElements.length;for(e;i>e;e++)this._audioElements[e].loop=t},e.prototype.getLoop=function(){this._audioElements.some(function(t){return t.loop})},e.prototype.load=function(){var t=this,e=new XMLHttpRequest;e.open("GET",this.path,!0),e.responseType="blob",e.onprogress=this.onprogress,e.onerror=this.onerror,e.onload=function(i){return 200!==e.status?(t._log.error("Failed to load audio resource ",t.path," server responded with error code",e.status),t.onerror(e.response),t._isLoaded=!1,void 0):(t._loadedAudio=URL.createObjectURL(e.response),t._audioElements.forEach(function(e){e.src=t._loadedAudio}),t.onload(i),void 0)},e.send()},e.prototype.play=function(){var e=this;this._audioElements[this._index].load(),this._audioElements[this._index].play(),this._currentOffset=0;var i=new t.Promise;return this._isPlaying=!0,this.getLoop()||this._audioElements[this._index].addEventListener("ended",function(){e._isPlaying=!1,i.resolve(!0)}),this._index=(this._index+1)%this._audioElements.length,i},e.prototype.pause=function(){this._index=(this._index-1+this._audioElements.length)%this._audioElements.length,this._currentOffset=this._audioElements[this._index].currentTime,this._audioElements.forEach(function(t){t.pause()}),this._isPlaying=!1},e.prototype.stop=function(){this._audioElements.forEach(function(t){t.pause()}),this._isPlaying=!1},e}();if(e.AudioTag=n,window.AudioContext)var s=new window.AudioContext;var o=function(){function e(e,i){this._context=s,this._volume=this._context.createGain(),this._buffer=null,this._sound=null,this._path="",this._isLoaded=!1,this._loop=!1,this._isPlaying=!1,this._isPaused=!1,this._currentOffset=0,this._logger=t.Logger.getInstance(),this.onload=function(){},this.onprogress=function(){},this.onerror=function(){},this._path=e,this._volume.gain.value=i?t.Util.clamp(i,0,1):1}return e.prototype.setVolume=function(t){this._volume.gain.value=t},e.prototype.load=function(){var t=this,e=new XMLHttpRequest;e.open("GET",this._path),e.responseType="arraybuffer",e.onprogress=this.onprogress,e.onerror=this.onerror,e.onload=function(){return 200!==e.status?(t._logger.error("Failed to load audio resource ",t._path," server responded with error code",e.status),t.onerror(e.response),t._isLoaded=!1,void 0):(t._context.decodeAudioData(e.response,function(e){t._buffer=e,t._isLoaded=!0,t.onload(t)},function(){t._logger.error("Unable to decode "+t._path+" this browser may not fully support this format, or the file may be corrupt, "+"if this is an mp3 try removing id3 tags and album art from the file."),t._isLoaded=!1,t.onload(t)}),void 0)};try{e.send()}catch(i){console.error("Error loading sound! If this is a cross origin error, you must host your sound with your html and javascript.")}},e.prototype.setLoop=function(t){this._loop=t},e.prototype.isPlaying=function(){return this._isPlaying},e.prototype.play=function(){var e=this;if(this._isLoaded){this._sound=this._context.createBufferSource(),this._sound.buffer=this._buffer,this._sound.loop=this._loop,this._sound.connect(this._volume),this._volume.connect(this._context.destination),this._sound.start(0,this._currentOffset%this._buffer.duration),this._currentOffset=0;var i;return i=this._isPaused&&this._playPromise?this._playPromise:new t.Promise,this._isPaused=!1,this._isPlaying=!0,this._loop||(this._sound.onended=function(){e._isPlaying=!1,e._isPaused||i.resolve(!0)}.bind(this)),this._playPromise=i,i}return t.Promise.wrap(!0)},e.prototype.pause=function(){if(this._isPlaying)try{window.clearTimeout(this._playingTimer),this._sound.stop(0),this._currentOffset=this._context.currentTime,this._isPlaying=!1,this._isPaused=!0}catch(t){this._logger.warn("The sound clip",this._path,"has already been paused!")}},e.prototype.stop=function(){if(this._sound)try{window.clearTimeout(this._playingTimer),this._currentOffset=0,this._sound.stop(0),this._isPlaying=!1,this._isPaused=!1}catch(t){this._logger.warn("The sound clip",this._path,"has already been stopped!")}},e}();e.WebAudio=o})(e=t.Internal||(t.Internal={}))})(ex||(ex={}));var ex;(function(t){(function(t){t[t.Resolved=0]="Resolved",t[t.Rejected=1]="Rejected",t[t.Pending=2]="Pending"})(t.PromiseState||(t.PromiseState={}));var e=t.PromiseState,i=function(){function i(){this._state=e.Pending,this._successCallbacks=[],this._rejectCallback=function(){},this._logger=t.Logger.getInstance()}return i.wrap=function(t){var e=(new i).resolve(t);return e},i.join=function(){for(var t=[],e=0;arguments.length>e;e++)t[e-0]=arguments[e];var n=new i;if(!t||!t.length)return n.resolve();var s=t.length,o=0,r=0,h=[];return t.forEach(function(t){t.then(function(){o+=1,o===s?n.resolve():o+r+h.length===s&&n.reject(h)},function(){r+=1,o+r+h.length===s&&n.reject(h)}).error(function(t){h.push(t),h.length+o+r===s&&n.reject(h)})}),n},i.prototype.then=function(t,i){if(t&&(this._successCallbacks.push(t),this.state()===e.Resolved))try{t.call(this,this._value)}catch(n){this._handleError(n)}if(i&&(this._rejectCallback=i,this.state()===e.Rejected))try{i.call(this,this._value)}catch(n){this._handleError(n)}return this},i.prototype.error=function(t){return t&&(this._errorCallback=t),this},i.prototype.resolve=function(t){var i=this;if(this._state!==e.Pending)throw Error("Cannot resolve a promise that is not in a pending state!");this._value=t;try{this._state=e.Resolved,this._successCallbacks.forEach(function(t){t.call(i,i._value)})}catch(n){this._handleError(n)}return this},i.prototype.reject=function(t){if(this._state!==e.Pending)throw Error("Cannot reject a promise that is not in a pending state!");this._value=t;try{this._state=e.Rejected,this._rejectCallback.call(this,this._value)}catch(i){this._handleError(i)}return this},i.prototype.state=function(){return this._state},i.prototype._handleError=function(t){if(!this._errorCallback)throw t;this._errorCallback.call(this,t)},i}();t.Promise=i})(ex||(ex={}));var ex;(function(t){var e=function(){function e(e,i,n){void 0===n&&(n=!0),this.path=e,this.responseType=i,this.bustCache=n,this.data=null,this.logger=t.Logger.getInstance(),this.onprogress=function(){},this.oncomplete=function(){},this.onerror=function(){}}return e.prototype.isLoaded=function(){return!!this.data},e.prototype.wireEngine=function(t){this._engine=t},e.prototype._cacheBust=function(t){var e=/\?\w*=\w*/;return t+=e.test(t)?"&__="+Date.now():"?__="+Date.now()},e.prototype._start=function(){this.logger.debug("Started loading resource "+this.path)},e.prototype.load=function(){var e=this,i=new t.Promise,n=new XMLHttpRequest;return n.open("GET",this.bustCache?this._cacheBust(this.path):this.path,!0),n.responseType=this.responseType,n.onloadstart=function(t){e._start(t)},n.onprogress=this.onprogress,n.onerror=this.onerror,n.onload=function(){return 200!==n.status?(e.logger.error("Failed to load resource ",e.path," server responded with error code",n.status),e.onerror(n.response),i.resolve(n.response),void 0):(e.data=e.processDownload(n.response),e.oncomplete(),e.logger.debug("Completed loading resource",e.path),i.resolve(e.data),void 0)},n.send(),i},e.prototype.getData=function(){return this.data},e.prototype.processDownload=function(t){return URL.createObjectURL(t)},e}();t.Resource=e})(ex||(ex={}));var ex;(function(t){var e=function(e){function i(i,n){void 0===n&&(n=!0),e.call(this,i,"blob",n),this.path=i,this.bustCache=n,this.loaded=new t.Promise,this._isLoaded=!1,this._sprite=null,this._sprite=new t.Sprite(this,0,0,0,0)}return __extends(i,e),i.prototype.isLoaded=function(){return this._isLoaded},i.prototype.load=function(){var i=this,n=new t.Promise,s=e.prototype.load.call(this);return s.then(function(){i.image=new Image,i.image.addEventListener("load",function(){i._isLoaded=!0,i.width=i._sprite.swidth=i._sprite.naturalWidth=i._sprite.width=i.image.naturalWidth,i.height=i._sprite.sheight=i._sprite.naturalHeight=i._sprite.height=i.image.naturalHeight,i.loaded.resolve(i.image),n.resolve(i.image)}),i.image.src=e.prototype.getData.call(i)},function(){n.reject("Error loading texture.")}),n},i.prototype.asSprite=function(){return this._sprite},i}(t.Resource);t.Texture=e;var i=function(){function e(){for(var i=[],n=0;arguments.length>n;n++)i[n-0]=arguments[n];this._logger=t.Logger.getInstance(),this.onprogress=function(){},this.oncomplete=function(){},this.onerror=function(){},this.onload=function(){},this._isLoaded=!1,this._selectedFile="",this._wasPlayingOnHidden=!1,this._selectedFile="";for(var s=0;i.length>s;s++)if(e.canPlayFile(i[s])){this._selectedFile=i[s];break}this._selectedFile||(this._logger.warn("This browser does not support any of the audio files specified:",i.join(", ")),this._logger.warn("Attempting to use",i[0]),this._selectedFile=i[0]),this.sound=new t.Internal.FallbackAudio(this._selectedFile,1)}return e.canPlayFile=function(e){try{var i=new Audio,n=/.*\.([A-Za-z0-9]+)$/,s=e.match(n)[1];return i.canPlayType("audio/"+s)?!0:!1}catch(o){return t.Logger.getInstance().warn("Cannot determine audio support, assuming no support for the Audio Tag",o),!1}},e.prototype.wireEngine=function(t){var e=this;t&&(this._engine=t,this._engine.on("hidden",function(){t.pauseAudioWhenHidden&&e.isPlaying()&&(e._wasPlayingOnHidden=!0,e.pause())}),this._engine.on("visible",function(){t.pauseAudioWhenHidden&&e._wasPlayingOnHidden&&(e.play(),e._wasPlayingOnHidden=!1)}))},e.prototype.setVolume=function(t){this.sound&&this.sound.setVolume(t)},e.prototype.setLoop=function(t){this.sound&&this.sound.setLoop(t)},e.prototype.isPlaying=function(){return this.sound?this.sound.isPlaying():void 0},e.prototype.play=function(){return this.sound?this.sound.play():void 0},e.prototype.pause=function(){this.sound&&this.sound.pause()},e.prototype.stop=function(){this.sound&&this.sound.stop()},e.prototype.isLoaded=function(){return this._isLoaded},e.prototype.load=function(){var e=this,i=new t.Promise;return this._logger.debug("Started loading sound",this._selectedFile),this.sound.onprogress=this.onprogress,this.sound.onload=function(){e.oncomplete(),e._isLoaded=!0,e._logger.debug("Completed loading sound",e._selectedFile),i.resolve(e.sound)},this.sound.onerror=function(t){e.onerror(t),i.resolve(t)},this.sound.load(),i},e}();t.Sound=i;var n=function(){function e(t){this._resourceList=[],this._index=0,this._resourceCount=0,this._numLoaded=0,this._progressCounts={},this._totalCounts={},this.onprogress=function(){},this.oncomplete=function(){},this.onerror=function(){},t&&this.addResources(t)}return e.prototype.wireEngine=function(t){this._engine=t},e.prototype.addResource=function(t){var e=this._index++;this._resourceList.push(t),this._progressCounts[e]=0,this._totalCounts[e]=1,this._resourceCount++},e.prototype.addResources=function(t){var e=0,i=t.length;for(e;i>e;e++)this.addResource(t[e])},e.prototype._sumCounts=function(t){var e=0;for(var i in t)e+=0|t[i];return e},e.prototype.isLoaded=function(){return this._numLoaded===this._resourceCount},e.prototype.load=function(){function e(t,i){t[i]&&t[i].load().then(function(){e(t,i+1)})}var i=this,n=new t.Promise,s=this;if(0===this._resourceList.length)return s.oncomplete.call(s),n;var o=Array(this._resourceList.length),r=this._resourceList.length;return this._resourceList.forEach(function(t,e){i._engine&&t.wireEngine(i._engine),t.onprogress=function(t){var i=t.total,n=t.loaded;o[e]={loaded:n/i*(100/r),total:100};var h=o.reduce(function(t,e){return{loaded:t.loaded+e.loaded,total:100}},{loaded:0,total:100});s.onprogress.call(s,h)},t.oncomplete=t.onerror=function(){s._numLoaded++,s._numLoaded===s._resourceCount&&(s.onprogress.call(s,{loaded:100,total:100}),s.oncomplete.call(s),n.resolve())}}),e(this._resourceList,0),n},e}();t.Loader=n})(ex||(ex={}));var ex;(function(t){var e=function(){function e(){this.failedTests=[],this._criticalTests={canvasSupport:function(){var t=document.createElement("canvas");return!(!t.getContext||!t.getContext("2d"))},arrayBufferSupport:function(){var t=new XMLHttpRequest;t.open("GET","/");try{t.responseType="arraybuffer"}catch(e){return!1}return"arraybuffer"===t.responseType},dataUrlSupport:function(){var t=document.createElement("canvas");return 0===t.toDataURL("image/png").indexOf("data:image/png")},objectUrlSupport:function(){return"URL"in window&&"revokeObjectURL"in URL&&"createObjectURL"in URL},rgbaSupport:function(){var t=document.createElement("a").style;return t.cssText="background-color:rgba(150,255,150,.5)",(""+t.backgroundColor).indexOf("rgba")>-1}},this._warningTest={webAudioSupport:function(){return!!(window.AudioContext||window.webkitAudioContext||window.mozAudioContext||window.msAudioContext||window.oAudioContext)},webglSupport:function(){var t=document.createElement("canvas");return!(!t.getContext||!t.getContext("webgl"))}}}return e.prototype.test=function(){var e=!1;for(var i in this._criticalTests)this._criticalTests[i]()||(this.failedTests.push(i),t.Logger.getInstance().error("Critical browser feature missing, Excalibur requires:",i),e=!0);if(e)return!1;for(var n in this._warningTest)this._warningTest[n]()||t.Logger.getInstance().warn("Warning browser feature missing, Excalibur will have reduced performance:",n);return!0},e}();t.Detector=e})(ex||(ex={}));var ex;(function(t){var e=function(){function e(e){this.path=e,this._isLoaded=!1,this.logger=t.Logger.getInstance(),this.onprogress=function(){},this.oncomplete=function(){},this.onerror=function(){},this._innerElement=document.createElement("div"),this._innerElement.className="excalibur-template"}return e.prototype.wireEngine=function(t){this._engine=t},e.prototype.getTemplateString=function(){return this._isLoaded?this._htmlString:""},e.prototype._compile=function(){this._innerElement.innerHTML=this._htmlString,this._styleElements=this._innerElement.querySelectorAll("[data-style]"),this._textElements=this._innerElement.querySelectorAll("[data-text]")},e.prototype._evaluateExpresion=function(t,e){var i=Function("return "+t+";"),n=i.call(e);return n},e.prototype.apply=function(t){for(var e=this,i=0;this._styleElements.length>i;i++)(function(){var n={};e._styleElements[i].dataset.style.split(";").forEach(function(t){if(t){var e=t.split(":");n[e[0].trim()]=e[1].trim()}});for(var s in n)(function(){var o=n[s];e._styleElements[i].style[s]=e._evaluateExpresion(o,t)})()})();for(var n=0;this._textElements.length>n;n++)(function(){var i=e._textElements[n].dataset.text;e._textElements[n].innerText=e._evaluateExpresion(i,t)})();return 1===this._innerElement.children.length&&(this._innerElement=this._innerElement.firstChild),this._innerElement},e.prototype.load=function(){var e=this,i=new t.Promise,n=new XMLHttpRequest;return n.open("GET",this.path,!0),n.responseType="text",n.onprogress=this.onprogress,n.onerror=this.onerror,n.onload=function(){return 200!==n.status?(e.logger.error("Failed to load html template resource ",e.path," server responded with error code",n.status),e.onerror(n.response),e._isLoaded=!1,i.resolve("error"),void 0):(e._htmlString=n.response,e.oncomplete(),e.logger.debug("Completed loading template",e.path),e._compile(),e._isLoaded=!0,i.resolve(e._htmlString),void 0)},n.overrideMimeType&&n.overrideMimeType("text/plain; charset=x-user-defined"),n.send(),i},e.prototype.isLoaded=function(){return this._isLoaded},e}();t.Template=e;var i=function(){function t(t,e,i){this.parent=document.getElementById(t),this.template=e,this._ctx=i,this.update()}return t.prototype.listen=function(t,e,i){var n=this;i||(i=function(){n.update()}),t.addEventListener&&e.forEach(function(e){t.addEventListener(e,i)})},t.prototype.update=function(){var t=this._applyTemplate(this.template,this._ctx);t instanceof String&&(this.parent.innerHTML=t),t instanceof Node&&this.parent.lastChild!==t&&this.parent.appendChild(t)},t.prototype._applyTemplate=function(t,e){return t.isLoaded()?t.apply(e):void 0},t}();t.Binding=i})(ex||(ex={}));var ex;(function(t){(function(t){t[t.Left=0]="Left",t[t.Right=1]="Right",t[t.Center=2]="Center",t[t.Start=3]="Start",t[t.End=4]="End"})(t.TextAlign||(t.TextAlign={}));var e=t.TextAlign;(function(t){t[t.Top=0]="Top",t[t.Hanging=1]="Hanging",t[t.Middle=2]="Middle",t[t.Alphabetic=3]="Alphabetic",t[t.Ideographic=4]="Ideographic",t[t.Bottom=5]="Bottom"})(t.BaseAlign||(t.BaseAlign={}));var i=t.BaseAlign,n=function(n){function s(e,i,s,o,r){n.call(this,i,s),this.letterSpacing=0,this.caseInsensitive=!0,this._textShadowOn=!1,this._shadowOffsetX=0,this._shadowOffsetY=0,this._shadowColor=t.Color.Black.clone(),this._shadowColorDirty=!1,this._textSprites={},this._shadowSprites={},this._color=t.Color.Black.clone(),this.text=e||"",this.color=t.Color.Black.clone(),this.spriteFont=r,this.collisionType=t.CollisionType.PreventCollision,this.font=o||"10px sans-serif",r&&(this._textSprites=r.getTextSprites())}return __extends(s,n),s.prototype.getTextWidth=function(t){var e=t.font;t.font=this.font;var i=t.measureText(this.text).width;return t.font=e,i},s.prototype._lookupTextAlign=function(t){switch(t){case e.Left:return"left";case e.Right:return"right";case e.Center:return"center";case e.End:return"end";case e.Start:return"start";default:return"start"}},s.prototype._lookupBaseAlign=function(t){switch(t){case i.Alphabetic:return"alphabetic";case i.Bottom:return"bottom";case i.Hanging:return"hangin";case i.Ideographic:return"ideographic";case i.Middle:return"middle";case i.Top:return"top";default:return"alphabetic"}},s.prototype.setTextShadow=function(t,e,i){this._textShadowOn=!0,this._shadowOffsetX=t,this._shadowOffsetY=e,this._shadowColor=i.clone(),this._shadowColorDirty=!0;for(var n in this._textSprites)this._shadowSprites[n]=this._textSprites[n].clone()},s.prototype.clearTextShadow=function(){this._textShadowOn=!1,this._shadowOffsetX=0,this._shadowOffsetY=0,this._shadowColor=t.Color.Black.clone()},s.prototype.update=function(e,i){if(n.prototype.update.call(this,e,i),this.spriteFont&&(this._color!==this.color||this.previousOpacity!==this.opacity)){for(var s in this._textSprites)this._textSprites[s].clearEffects(),this._textSprites[s].fill(this.color.clone()),this._textSprites[s].opacity(this.opacity);this._color=this.color,this.previousOpacity=this.opacity}if(this.spriteFont&&this._textShadowOn&&this._shadowColorDirty&&this._shadowColor){for(var o in this._shadowSprites)this._shadowSprites[o].clearEffects(),this._shadowSprites[o].addEffect(new t.Effects.Fill(this._shadowColor.clone()));this._shadowColorDirty=!1}},s.prototype.draw=function(t,e){t.save(),t.translate(this.x,this.y),t.scale(this.scale.x,this.scale.y),t.rotate(this.rotation),this._textShadowOn&&(t.save(),t.translate(this._shadowOffsetX,this._shadowOffsetY),this._fontDraw(t,e,this._shadowSprites),t.restore()),this._fontDraw(t,e,this._textSprites),n.prototype.draw.call(this,t,e),t.restore()},s.prototype._fontDraw=function(e,i,n){if(this.spriteFont)for(var s=0,o=0;this.text.length>o;o++){var r=this.text[o];this.caseInsensitive&&(r=r.toLowerCase());try{var h=n[r];h.draw(e,s,0),s+=h.swidth+this.letterSpacing}catch(a){t.Logger.getInstance().error("SpriteFont Error drawing char "+r)}}else{var c=e.textAlign,u=e.textBaseline;e.textAlign=this._lookupTextAlign(this.textAlign),e.textBaseline=this._lookupBaseAlign(this.baseAlign),this.color&&(this.color.a=this.opacity),e.fillStyle=""+this.color,e.font=this.font,this.maxWidth?e.fillText(this.text,0,0,this.maxWidth):e.fillText(this.text,0,0),e.textAlign=c,e.textBaseline=u}},s.prototype.debugDraw=function(t){n.prototype.debugDraw.call(this,t)},s}(t.Actor);t.Label=n})(ex||(ex={}));var ex;(function(t){var e;(function(e){(function(t){t[t.Touch=0]="Touch",t[t.Mouse=1]="Mouse",t[t.Pen=2]="Pen",t[t.Unknown=3]="Unknown"})(e.PointerType||(e.PointerType={}));var i=e.PointerType;(function(t){t[t.Left=0]="Left",t[t.Middle=1]="Middle",t[t.Right=2]="Right",t[t.Unknown=3]="Unknown"})(e.PointerButton||(e.PointerButton={}));var n=e.PointerButton;(function(t){t[t.Canvas=0]="Canvas",t[t.Document=1]="Document"})(e.PointerScope||(e.PointerScope={}));var s=e.PointerScope,o=function(t){function e(e,i,n,s,o,r){t.call(this),this.x=e,this.y=i,this.index=n,this.pointerType=s,this.button=o,this.ev=r}return __extends(e,t),e}(t.GameEvent);e.PointerEvent=o;var r=function(e){function r(t){e.call(this),this._pointerDown=[],this._pointerUp=[],this._pointerMove=[],this._pointerCancel=[],this._pointers=[],this._activePointers=[],this._engine=t,this._pointers.push(new h),this._activePointers=[-1],this.primary=this._pointers[0]}return __extends(r,e),r.prototype.init=function(t){void 0===t&&(t=s.Document);var e=document;e=t===s.Document?document:this._engine.canvas,e.addEventListener("touchstart",this._handleTouchEvent("down",this._pointerDown)),e.addEventListener("touchend",this._handleTouchEvent("up",this._pointerUp)),e.addEventListener("touchmove",this._handleTouchEvent("move",this._pointerMove)),e.addEventListener("touchcancel",this._handleTouchEvent("cancel",this._pointerCancel)),window.PointerEvent?(this._engine.canvas.style.touchAction="none",e.addEventListener("pointerdown",this._handlePointerEvent("down",this._pointerDown)),e.addEventListener("pointerup",this._handlePointerEvent("up",this._pointerUp)),e.addEventListener("pointermove",this._handlePointerEvent("move",this._pointerMove)),e.addEventListener("pointercancel",this._handlePointerEvent("cancel",this._pointerMove))):window.MSPointerEvent?(this._engine.canvas.style.msTouchAction="none",e.addEventListener("MSPointerDown",this._handlePointerEvent("down",this._pointerDown)),e.addEventListener("MSPointerUp",this._handlePointerEvent("up",this._pointerUp)),e.addEventListener("MSPointerMove",this._handlePointerEvent("move",this._pointerMove)),e.addEventListener("MSPointerCancel",this._handlePointerEvent("cancel",this._pointerMove))):(e.addEventListener("mousedown",this._handleMouseEvent("down",this._pointerDown)),e.addEventListener("mouseup",this._handleMouseEvent("up",this._pointerUp)),e.addEventListener("mousemove",this._handleMouseEvent("move",this._pointerMove)))},r.prototype.update=function(){this._pointerUp.length=0,this._pointerDown.length=0,this._pointerMove.length=0,this._pointerCancel.length=0},r.prototype.at=function(t){if(t>=this._pointers.length)for(var e=this._pointers.length-1,i=t;i>e;e++)this._pointers.push(new h),this._activePointers.push(-1);return this._pointers[t]},r.prototype.count=function(){return this._pointers.length},r.prototype.propogate=function(e){var i=e instanceof t.UIActor,n=0,s=this._pointerUp.length;for(n;s>n;n++)e.contains(this._pointerUp[n].x,this._pointerUp[n].y,!i)&&e.eventDispatcher.publish("pointerup",this._pointerUp[n]);for(n=0,s=this._pointerDown.length,n;s>n;n++)e.contains(this._pointerDown[n].x,this._pointerDown[n].y,!i)&&e.eventDispatcher.publish("pointerdown",this._pointerDown[n]);if(e.capturePointer.captureMoveEvents)for(n=0,s=this._pointerMove.length,n;s>n;n++)e.contains(this._pointerMove[n].x,this._pointerMove[n].y,!i)&&e.eventDispatcher.publish("pointermove",this._pointerMove[n]);for(n=0,s=this._pointerCancel.length,n;s>n;n++)e.contains(this._pointerCancel[n].x,this._pointerCancel[n].y,!i)&&e.eventDispatcher.publish("pointercancel",this._pointerCancel[n])},r.prototype._handleMouseEvent=function(e,n){var s=this;return function(r){r.preventDefault();var h=r.pageX-t.Util.getPosition(s._engine.canvas).x,a=r.pageY-t.Util.getPosition(s._engine.canvas).y,c=s._engine.screenToWorldCoordinates(new t.Point(h,a)),u=new o(c.x,c.y,0,i.Mouse,r.button,r);n.push(u),s.at(0).eventDispatcher.publish(e,u)}},r.prototype._handleTouchEvent=function(e,s){var r=this;return function(h){h.preventDefault();for(var a=0,c=h.changedTouches.length;c>a;a++){var u=r._pointers.length>1?r._getPointerIndex(h.changedTouches[a].identifier):0;if(-1!==u){var l=h.changedTouches[a].pageX-t.Util.getPosition(r._engine.canvas).x,p=h.changedTouches[a].pageY-t.Util.getPosition(r._engine.canvas).y,d=r._engine.screenToWorldCoordinates(new t.Point(l,p)),f=new o(d.x,d.y,u,i.Touch,n.Unknown,h);s.push(f),r.at(u).eventDispatcher.publish(e,f),r._pointers.length>1&&("up"===e?r._activePointers[u]=-1:"down"===e&&(r._activePointers[u]=h.changedTouches[a].identifier))}}}},r.prototype._handlePointerEvent=function(e,i){var n=this;return function(s){s.preventDefault();var r=n._pointers.length>1?n._getPointerIndex(s.pointerId):0;if(-1!==r){var h=s.pageX-t.Util.getPosition(n._engine.canvas).x,a=s.pageY-t.Util.getPosition(n._engine.canvas).y,c=n._engine.screenToWorldCoordinates(new t.Point(h,a)),u=new o(c.x,c.y,r,n._stringToPointerType(s.pointerType),s.button,s); -i.push(u),n.at(r).eventDispatcher.publish(e,u),n._pointers.length>1&&("up"===e?n._activePointers[r]=-1:"down"===e&&(n._activePointers[r]=s.pointerId))}}},r.prototype._getPointerIndex=function(t){var e;if((e=this._activePointers.indexOf(t))>-1)return e;for(var i=0;this._activePointers.length>i;i++)if(-1===this._activePointers[i])return i;return-1},r.prototype._stringToPointerType=function(t){switch(t){case"touch":return i.Touch;case"mouse":return i.Mouse;case"pen":return i.Pen;default:return i.Unknown}},r}(t.Class);e.Pointers=r;var h=function(t){function e(){t.apply(this,arguments)}return __extends(e,t),e}(t.Class);e.Pointer=h})(e=t.Input||(t.Input={}))})(ex||(ex={}));var ex;(function(t){var e;(function(e){(function(t){t[t.Num1=97]="Num1",t[t.Num2=98]="Num2",t[t.Num3=99]="Num3",t[t.Num4=100]="Num4",t[t.Num5=101]="Num5",t[t.Num6=102]="Num6",t[t.Num7=103]="Num7",t[t.Num8=104]="Num8",t[t.Num9=105]="Num9",t[t.Num0=96]="Num0",t[t.Numlock=144]="Numlock",t[t.Semicolon=186]="Semicolon",t[t.A=65]="A",t[t.B=66]="B",t[t.C=67]="C",t[t.D=68]="D",t[t.E=69]="E",t[t.F=70]="F",t[t.G=71]="G",t[t.H=72]="H",t[t.I=73]="I",t[t.J=74]="J",t[t.K=75]="K",t[t.L=76]="L",t[t.M=77]="M",t[t.N=78]="N",t[t.O=79]="O",t[t.P=80]="P",t[t.Q=81]="Q",t[t.R=82]="R",t[t.S=83]="S",t[t.T=84]="T",t[t.U=85]="U",t[t.V=86]="V",t[t.W=87]="W",t[t.X=88]="X",t[t.Y=89]="Y",t[t.Z=90]="Z",t[t.Shift=16]="Shift",t[t.Alt=18]="Alt",t[t.Up=38]="Up",t[t.Down=40]="Down",t[t.Left=37]="Left",t[t.Right=39]="Right",t[t.Space=32]="Space",t[t.Esc=27]="Esc"})(e.Keys||(e.Keys={})),e.Keys;var i=function(t){function e(e){t.call(this),this.key=e}return __extends(e,t),e}(t.GameEvent);e.KeyEvent=i;var n=function(t){function e(e){t.call(this),this._keys=[],this._keysUp=[],this._keysDown=[],this._engine=e}return __extends(e,t),e.prototype.init=function(){var t=this;window.addEventListener("blur",function(){t._keys.length=0}),window.addEventListener("keyup",function(e){var n=t._keys.indexOf(e.keyCode);t._keys.splice(n,1),t._keysUp.push(e.keyCode);var s=new i(e.keyCode);t.eventDispatcher.publish("up",s)}),window.addEventListener("keydown",function(e){if(-1===t._keys.indexOf(e.keyCode)){t._keys.push(e.keyCode),t._keysDown.push(e.keyCode);var n=new i(e.keyCode);t.eventDispatcher.publish("down",n)}})},e.prototype.update=function(){this._keysDown.length=0,this._keysUp.length=0},e.prototype.getKeys=function(){return this._keys},e.prototype.isKeyDown=function(t){return this._keysDown.indexOf(t)>-1},e.prototype.isKeyPressed=function(t){return this._keys.indexOf(t)>-1},e.prototype.isKeyUp=function(t){return this._keysUp.indexOf(t)>-1},e}(t.Class);e.Keyboard=n})(e=t.Input||(t.Input={}))})(ex||(ex={}));var ex;(function(t){var e;(function(e){var i=function(t){function e(e){t.call(this),this.enabled=!1,this.supported=!!navigator.getGamepads,this._gamePadTimeStamps=[0,0,0,0],this._oldPads=[],this._pads=[],this._initSuccess=!1,this._navigator=navigator,this._engine=e}return __extends(e,t),e.prototype.init=function(){this.supported&&(this._initSuccess||(this._oldPads=this._clonePads(this._navigator.getGamepads()),this._oldPads.length&&this._oldPads[0]&&(this._initSuccess=!0)))},e.prototype.update=function(){if(this.enabled&&this.supported){this.init();for(var t=this._navigator.getGamepads(),e=0;t.length>e;e++)if(t[e]){if(this.at(e).connected=!0,!t[e].timestamp||t[e].timestamp!==this._gamePadTimeStamps[e]){this._gamePadTimeStamps[e]=t[e].timestamp;var i,n,a,c,u;for(i in s)"number"==typeof s[i]&&(c=s[i],a=t[e].buttons[c].value,a!==this._oldPads[e].getButton(c)&&(t[e].buttons[c].pressed?(this.at(e).updateButton(c,a),this.at(e).eventDispatcher.publish("button",new r(c,a))):this.at(e).updateButton(c,0)));for(n in o)"number"==typeof o[n]&&(u=o[n],a=t[e].axes[u],a!==this._oldPads[e].getAxes(u)&&(this.at(e).updateAxes(u,a),this.at(e).eventDispatcher.publish("axis",new h(u,a))));this._oldPads[e]=this._clonePad(t[e])}}else this.at(e).connected=!1}},e.prototype.at=function(t){if(t>=this._pads.length)for(var e=this._pads.length-1,i=t;i>e;e++)this._pads.push(new n),this._oldPads.push(new n);return this._pads[t]},e.prototype.count=function(){return this._pads.filter(function(t){return t.connected}).length},e.prototype._clonePads=function(t){for(var e=[],i=0,n=t.length;n>i;i++)e.push(this._clonePad(t[i]));return e},e.prototype._clonePad=function(t){var e,i,s=new n;if(!t)return s;for(e=0,i=t.buttons.length;i>e;e++)s.updateButton(e,t.buttons[e].value);for(e=0,i=t.axes.length;i>e;e++)s.updateAxes(e,t.axes[e]);return s},e.MinAxisMoveThreshold=.05,e}(t.Class);e.Gamepads=i;var n=function(t){function e(){t.call(this),this.connected=!1,this._buttons=Array(16),this._axes=Array(4);var e;for(e=0;this._buttons.length>e;e++)this._buttons[e]=0;for(e=0;this._axes.length>e;e++)this._axes[e]=0}return __extends(e,t),e.prototype.isButtonPressed=function(t,e){return void 0===e&&(e=1),this._buttons[t]>=e},e.prototype.getButton=function(t){return this._buttons[t]},e.prototype.getAxes=function(t){var e=this._axes[t];return Math.abs(e)n;n++)this._animations[n].animation.draw(i,this._animations[n].x,this._animations[n].y);if(this.fps=1/(e/1e3),this.isDebug){this.ctx.font="Consolas",this.ctx.fillStyle=""+this.debugColor;for(var o=this.input.keyboard.getKeys(),r=0;o.length>r;r++)this.ctx.fillText(""+o[r]+" : "+(t.Input.Keys[o[r]]?t.Input.Keys[o[r]]:"Not Mapped"),100,10*r+10);this.ctx.fillText("FPS:"+(""+this.fps.toFixed(2)),10,10)}for(var h=0;this.postProcessors.length>h;h++)this.postProcessors[h].process(this.ctx.getImageData(0,0,this.width,this.height),this.ctx)},s.prototype.start=function(e){if(!this._compatible){var i=new t.Promise;return i.reject("Excalibur is incompatible with your browser")}var n;if(e?(e.wireEngine(this),n=this.load(e)):n=t.Promise.wrap(),!this._hasStarted){this._hasStarted=!0,this._logger.debug("Starting game...");var s=Date.now(),o=this;(function r(){if(o._hasStarted)try{o._requestId=window.requestAnimationFrame(r);var t=Date.now(),e=Math.floor(t-s)||1;e>200&&(e=1),o._update(e),o._draw(e),s=t}catch(i){window.cancelAnimationFrame(o._requestId),o.stop(),o.onFatalException(i)}})(),this._logger.debug("Game started")}return n},s.prototype.stop=function(){this._hasStarted&&(this._hasStarted=!1,this._logger.debug("Game stopped"))},s.prototype.screenshot=function(){var t=new Image,e=this.canvas.toDataURL("image/png");return t.src=e,t},s.prototype._drawLoadingBar=function(t,e,i){if(this._loadingDraw)return this._loadingDraw(t,e,i),void 0;var n=this.canvas.height/2,s=this.canvas.width/3,o=s,r=new Image;r.src="data:image/png;base64,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"; -var h=3*s/8,a=this.getAntialiasing();this.setAntialiasing(!0),t.drawImage(r,0,0,800,300,o,n-h-20,s,h),t.strokeStyle="white",t.lineWidth=2,t.strokeRect(o,n,s,20);var c=s*(e/i);t.fillStyle="white";var u=5,l=c-2*u,p=20-2*u;t.fillRect(o+u,n+u,l>0?l:0,p),this.setAntialiasing(a)},s.prototype.setLoadingDrawFunction=function(t){this._loadingDraw=t},s.prototype.load=function(e){var i=this,n=new t.Promise;return this._isLoading=!0,e.onprogress=function(t){i._progress=t.loaded,i._total=t.total,i._logger.debug("Loading "+(100*i._progress/i._total).toFixed(0))},e.oncomplete=function(){setTimeout(function(){i._isLoading=!1,n.resolve()},500)},e.load(),n},s}(t.Class);t.Engine=e,function(t){t[t.FullScreen=0]="FullScreen",t[t.Container=1]="Container",t[t.Fixed=2]="Fixed"}(t.DisplayMode||(t.DisplayMode={}));var i=t.DisplayMode,n=function(){function t(t,e,i){this.animation=t,this.x=e,this.y=i}return t}()})(ex||(ex={})); -; -// Concatenated onto excalibur after build -// Exports the excalibur module so it can be used with browserify -// https://github.com/excaliburjs/Excalibur/issues/312 -if (typeof module !== 'undefined') {module.exports = ex;} \ No newline at end of file diff --git a/dist/excalibur-0.5.1.d.ts b/dist/excalibur-0.6.0.d.ts similarity index 89% rename from dist/excalibur-0.5.1.d.ts rename to dist/excalibur-0.6.0.d.ts index 01802ca5d..2343a6795 100644 --- a/dist/excalibur-0.5.1.d.ts +++ b/dist/excalibur-0.6.0.d.ts @@ -265,6 +265,7 @@ declare module ex { declare module ex { /** * A simple 2D point on a plane + * @obsolete Use [[Vector|vector]]s instead of [[Point|points]] */ class Point { x: number; @@ -466,6 +467,7 @@ declare module ex.Util { function getPosition(el: HTMLElement): Point; function addItemToArray(item: T, array: T[]): boolean; function removeItemToArray(item: T, array: T[]): boolean; + function contains(array: Array, obj: any): boolean; function getOppositeSide(side: ex.Side): Side; /** * Excaliburs dynamically resizing collection @@ -579,10 +581,38 @@ declare module ex { * * Excalibur offers many sprite effects such as [[Effects.Colorize]] to let you manipulate * sprites. Keep in mind, more effects requires more power and can lead to memory or CPU - * constraints and hurt performance. + * constraints and hurt performance. Each effect must be reprocessed every frame for each sprite. * * It's still recommended to create an [[Animation]] or build in your effects to the sprites * for optimal performance. + * + * There are a number of convenience methods available to perform sprite effects. Sprite effects are + * side-effecting. + * + * ```typescript + * + * var playerSprite = new ex.Sprite(txPlayer, 0, 0, 80, 80); + * + * // darken a sprite by a percentage + * playerSprite.darken(.2); // 20% + * + * // lighten a sprite by a percentage + * playerSprite.lighten(.2); // 20% + * + * // saturate a sprite by a percentage + * playerSprite.saturate(.2); // 20% + * + * // implement a custom effect + * class CustomEffect implements ex.EffectsISpriteEffect { + * + * updatePixel(x: number, y: number, imageData: ImageData) { + * // modify ImageData + * } + * } + * + * playerSprite.addEffect(new CustomEffect()); + * + * ``` */ class Sprite implements IDrawable { sx: number; @@ -837,7 +867,8 @@ declare module ex { * Sprite Fonts * * Sprite fonts are a used in conjunction with a [[Label]] to specify - * a particular bitmap as a font. + * a particular bitmap as a font. Note that some font features are not + * supported by Sprite fonts. * * ## Generating the font sheet * @@ -917,9 +948,19 @@ declare module ex { image: Texture; private alphabet; private caseInsensitive; + spWidth: number; + spHeight: number; private _spriteLookup; private _colorLookup; private _currentColor; + private _currentOpacity; + private _sprites; + private _textShadowOn; + private _textShadowDirty; + private _textShadowColor; + private _textShadowSprites; + private _shadowOffsetX; + private _shadowOffsetY; /** * @param image The backing image texture to build the SpriteFont * @param alphabet A string representing all the characters in the image, in row major order. @@ -936,6 +977,34 @@ declare module ex { getTextSprites(): { [key: string]: Sprite; }; + /** + * Sets the text shadow for sprite fonts + * @param offsetX The x offset in pixels to place the shadow + * @param offsetY The y offset in pixles to place the shadow + * @param shadowColor The color of the text shadow + */ + setTextShadow(offsetX: number, offsetY: number, shadowColor: Color): void; + /** + * Toggles text shadows on or off + */ + useTextShadow(on: boolean): void; + /** + * Draws the current sprite font + */ + draw(ctx: CanvasRenderingContext2D, text: string, x: number, y: number, options: ISpriteFontOptions): void; + private _parseOptions(options); + } + /** + * Specify various font attributes for sprite fonts + */ + interface ISpriteFontOptions { + color?: Color; + opacity?: number; + fontSize?: number; + letterSpacing?: number; + textAlign?: TextAlign; + baseAlign?: BaseAlign; + maxWidth?: number; } } declare module ex { @@ -1342,6 +1411,12 @@ declare module ex { * @param handler Event handler for the thrown event */ off(eventName: string, handler?: (event?: GameEvent) => void): void; + /** + * Emits a new event + * @param eventName Name of the event to emit + * @param eventObject Data associated with this event + */ + emit(eventName: string, eventObject?: GameEvent): void; /** * You may wish to extend native Excalibur functionality in vanilla Javascript. * Any method on a class inheriting [[Class]] may be extended to support @@ -1549,8 +1624,19 @@ declare module ex { */ class BaseCamera { protected _follow: Actor; - protected _focus: Point; - protected _lerp: boolean; + focus: Point; + lerp: boolean; + x: number; + y: number; + z: number; + dx: number; + dy: number; + dz: number; + ax: number; + ay: number; + az: number; + rotation: number; + rx: number; private _cameraMoving; private _currentLerpTime; private _lerpDuration; @@ -1575,13 +1661,14 @@ declare module ex { */ setActorToFollow(actor: Actor): void; /** - * Returns the focal point of the camera + * Returns the focal point of the camera, a new point giving the x and y position of the camera */ getFocus(): Point; /** * Sets the focal point of the camera. This value can only be set if there is no actor to be followed. * @param x The x coordinate of the focal point * @param y The y coordinate of the focal point + * @deprecated */ setFocus(x: number, y: number): void; /** @@ -2076,11 +2163,6 @@ declare module ex { * in future versions to support multiple timelines/scripts, better eventing, * and a more robust API to allow for complex and customized actions. * - * ## Known Issues - * - * **Rotation actions do not use shortest angle** - * [Issue #282](https://github.com/excaliburjs/Excalibur/issues/282) - * */ class ActionContext { private _actors; @@ -2094,6 +2176,16 @@ declare module ex { clearActions(): void; addActorToContext(actor: Actor): void; removeActorFromContext(actor: Actor): void; + /** + * This method will move an actor to the specified `x` and `y` position over the + * specified duration using a given [[EasingFunctions]] and return back the actor. This + * method is part of the actor 'Action' fluent API allowing action chaining. + * @param x The x location to move the actor to + * @param y The y location to move the actor to + * @param duration The time it should take the actor to move to the new location in milliseconds + * @param easingFcn Use [[EasingFunctions]] or a custom function to use to calculate position + */ + easeTo(x: number, y: number, duration: number, easingFcn?: (currentTime: number, startValue: number, endValue: number, duration: number) => number): ActionContext; /** * This method will move an actor to the specified x and y position at the * speed specified (in pixels per second) and return back the actor. This @@ -2224,7 +2316,26 @@ declare module ex { * Groups are used for logically grouping Actors so they can be acted upon * in bulk. * - * @todo Document this + * ## Using Groups + * + * Groups can be used to detect collisions across a large nubmer of actors. For example + * perhaps a large group of "enemy" actors. + * + * ```typescript + * var enemyShips = engine.currentScene.createGroup("enemy"); + * var enemies = [...]; // Large array of enemies; + * enemyShips.add(enemies); + * + * var player = new Actor(); + * engine.currentScene.add(player); + * + * enemyShips.on('collision', function(ev: CollisionEvent){ + * if (e.other === player) { + * //console.log("collision with player!"); + * } + * }); + * + * ``` */ class Group extends Class implements IActionable { name: string; @@ -2343,6 +2454,13 @@ declare module ex { * * ``` * + * ## Scene Lifecycle + * + * A [[Scene|scene]] has a basic lifecycle that dictacts how it is initialized, updated, and drawn. Once a [[Scene|scene]] is added to + * the [[Engine|engine]] it will follow this lifecycle. + * + * ![Scene Lifecycle](/assets/images/docs/SceneLifeCycle.png) + * * ## Extending scenes * * For more complex games, you might want more control over a scene in which @@ -2457,12 +2575,6 @@ declare module ex { * this is where you should cleanup any DOM UI or event handlers needed for the scene. */ onDeactivate(): void; - /** - * Publish an event to all actors in the scene - * @param eventType The name of the event to publish - * @param event The event object to send - */ - publish(eventType: string, event: GameEvent): void; /** * Updates all the actors and timers in the scene. Called by the [[Engine]]. * @param engine Reference to the current Engine @@ -2535,6 +2647,8 @@ declare module ex { removeUIActor(actor: Actor): void; /** * Adds an actor to the scene, once this is done the actor will be drawn and updated. + * + * @obsolete Use [[add]] instead. */ addChild(actor: Actor): void; /** @@ -2597,32 +2711,44 @@ declare module ex { } declare module ex { /** - * Standard easing functions for motion in Excalibur + * Standard easing functions for motion in Excalibur, defined on a domain of [0, duration] and a range from [+startValue,+endValue] + * Given a time, the function will return a value from postive startValue to postive endValue. + * + * ```js + * function Linear (t) { + * return t * t; + * } * - * easeInQuad: function (t) { return t * t }, - * // decelerating to zero velocity - * easeOutQuad: function (t) { return t * (2 - t) }, - * // acceleration until halfway, then deceleration - * easeInOutQuad: function (t) { return t < .5 ? 2 * t * t : -1 + (4 - 2 * t) * t }, - * // accelerating from zero velocity - * easeInCubic: function (t) { return t * t * t }, - * // decelerating to zero velocity - * easeOutCubic: function (t) { return (--t) * t * t + 1 }, - * // acceleration until halfway, then deceleration - * easeInOutCubic: function (t) { return t < .5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1 }, * // accelerating from zero velocity - * easeInQuart: function (t) { return t * t * t * t }, + * function EaseInQuad (t) { + * return t * t; + * } + * * // decelerating to zero velocity - * easeOutQuart: function (t) { return 1 - (--t) * t * t * t }, + * function EaseOutQuad (t) { + * return t * (2 - t); + * } + * * // acceleration until halfway, then deceleration - * easeInOutQuart: function (t) { return t < .5 ? 8 * t * t * t * t : 1 - 8 * (--t) * t * t * t }, + * function EaseInOutQuad (t) { + * return t < .5 ? 2 * t * t : -1 + (4 - 2 * t) * t; + * } + * * // accelerating from zero velocity - * easeInQuint: function (t) { return t * t * t * t * t }, + * function EaseInCubic (t) { + * return t * t * t; + * } + * * // decelerating to zero velocity - * easeOutQuint: function (t) { return 1 + (--t) * t * t * t * t }, - * // acceleration until halfway, then deceleration - * easeInOutQuint: function (t) { return t < .5 ? 16 * t * t * t * t * t : 1 + 16 * (--t) * t * t * t * t } + * function EaseOutCubic (t) { + * return (--t) * t * t + 1; + * } * + * // acceleration until halfway, then deceleration + * function EaseInOutCubic (t) { + * return t < .5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1; + * } + * ``` */ class EasingFunctions { static Linear: (currentTime: number, startValue: number, endValue: number, duration: number) => number; @@ -2659,7 +2785,16 @@ declare module ex { * * // add player to the current scene * game.add(player); + * * ``` + * `game.add` is a convenience method for adding an `Actor` to the current scene. The equivalent verbose call is `game.currentScene.add`. + * + * ## Actor Lifecycle + * + * An [[Actor|actor]] has a basic lifecycle that dictacts how it is initialized, updated, and drawn. Once an actor is part of a + * [[Scene|scene]], it will follow this lifecycle. + * + * ![Actor Lifecycle](/assets/images/docs/ActorLifeCycle.png) * * ## Extending actors * @@ -2729,7 +2864,7 @@ declare module ex { * * The [[update]] method is passed an instance of the Excalibur engine, which * can be used to perform coordinate math or access global state. It is also - * passed `delta` which is the time since the last frame, which can be used + * passed `delta` which is the time in milliseconds since the last frame, which can be used * to perform time-based movement or time-based math (such as a timer). * * **TypeScript** @@ -2741,7 +2876,7 @@ declare module ex { * * // check if player died * if (this.health <= 0) { - * this.triggerEvent("death"); + * this.emit("death"); * this.onDeath(); * return; * } @@ -2758,7 +2893,7 @@ declare module ex { * * // check if player died * if (this.health <= 0) { - * this.triggerEvent("death"); + * this.emit("death"); * this.onDeath(); * return; * } @@ -2770,13 +2905,16 @@ declare module ex { * * Override the [[draw]] method to perform any custom drawing. For simple games, * you don't need to override `draw`, instead you can use [[addDrawing]] and [[setDrawing]] - * to manipulate the textures/animations that the actor is using. + * to manipulate the [[Sprite|sprites]]/[[Animation|animations]] that the actor is using. * * ### Working with Textures & Sprites * - * A common usage is to use a [[Texture]] or [[Sprite]] for an actor. If you are using the [[Loader]] to - * pre-load assets, you can simply assign an actor a [[Texture]] to draw. You can - * also create a [[Texture.asSprite|sprite from a Texture]] to quickly create a [[Sprite]] instance. + * Think of a [[Texture|texture]] as the raw image file that will be loaded into Excalibur. In order for it to be drawn + * it must be converted to a [[Sprite.sprite]]. + * + * A common usage is to load a [[Texture]] and convert it to a [[Sprite]] for an actor. If you are using the [[Loader]] to + * pre-load assets, you can simply assign an actor a [[Sprite]] to draw. You can also create a + * [[Texture.asSprite|sprite from a Texture]] to quickly create a [[Sprite]] instance. * * ```ts * // assume Resources.TxPlayer is a 80x80 png image @@ -2815,7 +2953,8 @@ declare module ex { * ### Custom drawing * * You can always override the default drawing logic for an actor in the [[draw]] method, - * for example, to draw complex shapes or to use the raw Canvas API. + * for example, to draw complex shapes or to use the raw + * [[https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D|Canvas API]]. * * Usually you should call `super.draw` to perform the base drawing logic, but other times * you may want to take over the drawing completely. @@ -2846,33 +2985,45 @@ declare module ex { * ## Collision Detection * * By default Actors do not participate in collisions. If you wish to make - * an actor participate, you need to enable the [[CollisionDetectionModule]] + * an actor participate, you need to switch from the default [[CollisionType.PreventCollision|prevent collision]] + * to [[CollisionType.Active|active]], [[CollisionType.Fixed|fixed]], or [[CollisionType.Passive|passive]] collision type. * * ```ts * public Player extends ex.Actor { * constructor() { * super(); - * - * // enable the pipeline - * this.pipelines.push(new ex.CollisionDetectionModule()); - * * // set preferred CollisionType * this.collisionType = ex.CollisionType.Active; * } * } - * ``` * - * ### Collision Groups + * // or set the collisionType + * + * var actor = new ex.Actor(); + * actor.collisionType = ex.CollisionType.Active; * + * ``` + * ### Collision Groups * TODO, needs more information. * + * ## Traits + * + * Traits describe actor behavior that occurs every update. If you wish to build a generic behavior + * without needing to extend every actor you can do it with a trait, a good example of this may be + * plugging in an external collision detection library like [[https://github.com/kripken/box2d.js/|Box2D]] or + * [[http://wellcaffeinated.net/PhysicsJS/|PhysicsJS]] by wrapping it in a trait. Removing traits can also make your + * actors more efficient. + * + * Default traits provided by Excalibur are [[Traits.CapturePointer|pointer capture]], + * [[Traits.CollisionDetection|tile map collision]], [[Traits.Movement|Euler style movement]], + * and [[Traits.OffscreenCulling|offscreen culling]]. + * + * * ## Known Issues * * **Actor bounding boxes do not rotate** * [Issue #68](https://github.com/excaliburjs/Excalibur/issues/68) * - * **Setting opacity when using a color doesn't do anything** - * [Issue #364](https://github.com/excaliburjs/Excalibur/issues/364) */ class Actor extends ex.Class implements IActionable { /** @@ -2884,11 +3035,11 @@ declare module ex { */ id: number; /** - * The x coordinate of the actor (left edge) + * The x coordinate of the actor (middle if anchor is (0.5, 0.5) left edge if anchor is (0, 0)) */ x: number; /** - * The y coordinate of the actor (top edge) + * The y coordinate of the actor (middle if anchor is (0.5, 0.5) and top edge if anchor is (0, 0)) */ y: number; /** @@ -3060,12 +3211,12 @@ declare module ex { * move with it. * @param actor The child actor to add */ - addChild(actor: Actor): void; + add(actor: Actor): void; /** * Removes a child actor from this actor. * @param actor The child actor to remove */ - removeChild(actor: Actor): void; + remove(actor: Actor): void; /** * Sets the current drawing of the actor to the drawing corresponding to * the key. @@ -3104,14 +3255,6 @@ declare module ex { * @param actor The child actor to remove */ setZIndex(newIndex: number): void; - /** - * Artificially trigger an event on an actor, useful when creating custom events. - * @param eventName The name of the event to trigger - * @param event The event object to pass to the callback - * - * @obsolete Will be replaced with `emit` - */ - triggerEvent(eventName: string, event?: GameEvent): void; /** * Adds an actor to a collision group. Actors with no named collision groups are * considered to be in every collision group. @@ -3231,6 +3374,7 @@ declare module ex { within(actor: Actor, distance: number): boolean; /** * Clears all queued actions from the Actor + * @obsolete Use [[ActionContext.clearActions|Actor.actions.clearActions]] */ clearActions(): void; /** @@ -3241,6 +3385,7 @@ declare module ex { * @param y The y location to move the actor to * @param duration The time it should take the actor to move to the new location in milliseconds * @param easingFcn Use [[EasingFunctions]] or a custom function to use to calculate position + * @obsolete Use [[ActionContext.easeTo|Actor.actions.easeTo]] */ easeTo(x: number, y: number, duration: number, easingFcn?: (currentTime: number, startValue: number, endValue: number, duration: number) => number): Actor; /** @@ -3250,6 +3395,7 @@ declare module ex { * @param x The x location to move the actor to * @param y The y location to move the actor to * @param speed The speed in pixels per second to move + * @obsolete Use [[ActionContext.moveTo|Actor.actions.moveTo]] */ moveTo(x: number, y: number, speed: number): Actor; /** @@ -3259,6 +3405,7 @@ declare module ex { * @param x The x location to move the actor to * @param y The y location to move the actor to * @param duration The time it should take the actor to move to the new location in milliseconds + * @obsolete Use [[ActionContext.moveBy|Actor.actions.moveBy]] */ moveBy(x: number, y: number, duration: number): Actor; /** @@ -3267,6 +3414,7 @@ declare module ex { * method is part of the actor 'Action' fluent API allowing action chaining. * @param angleRadians The angle to rotate to in radians * @param speed The angular velocity of the rotation specified in radians per second + * @obsolete Use [[ActionContext.rotateTo|Actor.actions.rotateTo]] */ rotateTo(angleRadians: number, speed: number, rotationType?: RotationType): Actor; /** @@ -3275,6 +3423,7 @@ declare module ex { * of the actor 'Action' fluent API allowing action chaining. * @param angleRadians The angle to rotate to in radians * @param duration The time it should take the actor to complete the rotation in milliseconds + * @obsolete Use [[ActionContext.rotateBy|ex.Actor.actions.rotateBy]] */ rotateBy(angleRadians: number, duration: number, rotationType?: RotationType): Actor; /** @@ -3286,6 +3435,7 @@ declare module ex { * @param sizeY The scaling factor in the y direction to apply * @param speedX The speed of scaling in the x direction specified in magnitude increase per second * @param speedY The speed of scaling in the y direction specified in magnitude increase per second + * @obsolete Use [[ActionContext.scaleTo|Actor.actions.scaleTo]] */ scaleTo(sizeX: number, sizeY: number, speedX: number, speedY: number): Actor; /** @@ -3295,6 +3445,7 @@ declare module ex { * @param sizeX The scaling factor in the x direction to apply * @param sizeY The scaling factor in the y direction to apply * @param duration The time it should take to complete the scaling in milliseconds + * @obsolete Use [[ActionContext.scaleBy|Actor.actions.scaleBy]] */ scaleBy(sizeX: number, sizeY: number, duration: number): Actor; /** @@ -3305,6 +3456,7 @@ declare module ex { * @param timeVisible The amount of time to stay visible per blink in milliseconds * @param timeNotVisible The amount of time to stay not visible per blink in milliseconds * @param numBlinks The number of times to blink + * @obsolete Use [[ActionContext.blink|Actor.actions.blink]] */ blink(timeVisible: number, timeNotVisible: number, numBlinks?: number): Actor; /** @@ -3313,6 +3465,7 @@ declare module ex { * part of the actor 'Action' fluent API allowing action chaining. * @param opacity The ending opacity * @param duration The time it should take to fade the actor (in milliseconds) + * @obsolete Use [[ActionContext.fade|Actor.actions.fade]] */ fade(opacity: number, duration: number): Actor; /** @@ -3320,18 +3473,21 @@ declare module ex { * `duration` (in milliseconds). This method is part of the actor * 'Action' fluent API allowing action chaining. * @param duration The amount of time to delay the next action in the queue from executing in milliseconds + * @obsolete Use [[ActionContext.delay|Actor.actions.delay]] */ delay(duration: number): Actor; /** * This method will add an action to the queue that will remove the actor from the * scene once it has completed its previous actions. Any actions on the * action queue after this action will not be executed. + * @obsolete Use [[ActionContext.die|Actor.actions.die]] */ die(): Actor; /** * This method allows you to call an arbitrary method as the next action in the * action queue. This is useful if you want to execute code in after a specific * action, i.e An actor arrives at a destination after traversing a path + * @obsolete Use [[ActionContext.callMethod|Actor.actions.callMethod]] */ callMethod(method: () => any): Actor; /** @@ -3341,18 +3497,21 @@ declare module ex { * the actor 'Action' fluent API allowing action chaining * @param times The number of times to repeat all the previous actions in the action queue. If nothing is specified the actions will * repeat forever + * @obsolete Use [[ActionContext.repeat|Actor.actions.repeat]] */ repeat(times?: number): Actor; /** * This method will cause the actor to repeat all of the previously * called actions forever. This method is part of the actor 'Action' * fluent API allowing action chaining. + * @obsolete Use [[ActionContext.repeatForever|Actor.actions.repeatForever]] */ repeatForever(): Actor; /** * This method will cause the actor to follow another at a specified distance * @param actor The actor to follow * @param followDistance The distance to maintain when following, if not specified the actor will follow at the current distance. + * @obsolete Use [[ActionContext.follow|Actor.actions.follow]] */ follow(actor: Actor, followDistance?: number): Actor; /** @@ -3360,11 +3519,13 @@ declare module ex { * collide ("meet") at a specified speed. * @param actor The actor to meet * @param speed The speed in pixels per second to move, if not specified it will match the speed of the other actor + * @obsolete Use [[ActionContext.meet|Actor.actions.meet]] */ meet(actor: Actor, speed?: number): Actor; /** * Returns a promise that resolves when the current action queue up to now * is finished. + * @obsolete Use [[ActionContext.asPromise|Actor.actions.asPromise]] */ asPromise(): Promise; private _getCalculatedAnchor(); @@ -3410,6 +3571,7 @@ declare module ex { * Actors with the `Elastic` setting will behave the same as `Active`, except that they will * "bounce" in the opposite direction given their velocity dx/dy. This is a naive implementation meant for * prototyping, for a more robust elastic collision listen to the "collision" event and perform your custom logic. + * @obsolete This behavior will be handled by a future physics system */ Elastic = 3, /** @@ -3552,22 +3714,23 @@ declare module ex { } declare module ex { /** - * An enum representing all of the built in event types for Excalibur - * @obsolete Phasing this out in favor of classes - */ - enum EventType { - Collision = 0, - EnterViewPort = 1, - ExitViewPort = 2, - Blur = 3, - Focus = 4, - Update = 5, - Activate = 6, - Deactivate = 7, - Initialize = 8, - } - /** - * Base event type in Excalibur that all other event types derive from. + * Base event type in Excalibur that all other event types derive from. Not all event types are thrown on all Excalibur game objects, + * some events are unique to a type, others are not. + * + * Excalibur events follow the convention that the name of the thrown event for listening will be the same as the Event object in all + * lower case with the 'Event' suffix removed. + * + * For example: + * - PreDrawEvent event object and "predraw" as the event name + * + * ```typescript + * + * actor.on('predraw', (evtObj: PreDrawEvent) => { + * // do some pre drawing + * }) + * + * ``` + * */ class GameEvent { /** @@ -3576,7 +3739,104 @@ declare module ex { target: any; } /** - * Subscribe event thrown when handlers for events other than subscribe are added + * The 'predraw' event is emitted on actors, scenes, and engine before drawing starts. Actors' predraw happens inside their graphics + * transform so that all drawing takes place with the actor as the origin. + * + */ + class PreDrawEvent extends GameEvent { + ctx: CanvasRenderingContext2D; + delta: any; + target: any; + constructor(ctx: CanvasRenderingContext2D, delta: any, target: any); + } + /** + * The 'postdraw' event is emitted on actors, scenes, and engine after drawing finishes. Actors' postdraw happens inside their graphics + * transform so that all drawing takes place with the actor as the origin. + * + */ + class PostDrawEvent extends GameEvent { + ctx: CanvasRenderingContext2D; + delta: any; + target: any; + constructor(ctx: CanvasRenderingContext2D, delta: any, target: any); + } + /** + * The 'predebugdraw' event is emitted on actors, scenes, and engine before debug drawing starts. + */ + class PreDebugDrawEvent extends GameEvent { + ctx: CanvasRenderingContext2D; + target: any; + constructor(ctx: CanvasRenderingContext2D, target: any); + } + /** + * The 'postdebugdraw' event is emitted on actors, scenes, and engine after debug drawing starts. + */ + class PostDebugDrawEvent extends GameEvent { + ctx: CanvasRenderingContext2D; + target: any; + constructor(ctx: CanvasRenderingContext2D, target: any); + } + /** + * The 'preupdate' event is emitted on actors, scenes, and engine before the update starts. + */ + class PreUpdateEvent extends GameEvent { + engine: Engine; + delta: any; + target: any; + constructor(engine: Engine, delta: any, target: any); + } + /** + * The 'postupdate' event is emitted on actors, scenes, and engine after the update ends. This is equivalent to the obsolete 'update' + * event. + */ + class PostUpdateEvent extends GameEvent { + engine: Engine; + delta: any; + target: any; + constructor(engine: Engine, delta: any, target: any); + } + /** + * Event received when a gamepad is connected to Excalibur. [[Input.Gamepads|engine.input.gamepads]] receives this event. + */ + class GamepadConnectEvent extends GameEvent { + index: number; + gamepad: ex.Input.Gamepad; + constructor(index: number, gamepad: ex.Input.Gamepad); + } + /** + * Event received when a gamepad is disconnected from Excalibur. [[Input.Gamepads|engine.input.gamepads]] receives this event. + */ + class GamepadDisconnectEvent extends GameEvent { + index: number; + constructor(index: number); + } + /** + * Gamepad button event. See [[Gamepads]] for information on responding to controller input. [[Gamepad]] instances receive this event; + */ + class GamepadButtonEvent extends ex.GameEvent { + button: ex.Input.Buttons; + value: number; + /** + * @param button The Gamepad button + * @param value A numeric value between 0 and 1 + */ + constructor(button: ex.Input.Buttons, value: number); + } + /** + * Gamepad axis event. See [[Gamepads]] for information on responding to controller input. [[Gamepad]] instances receive this event; + */ + class GamepadAxisEvent extends ex.GameEvent { + axis: ex.Input.Axes; + value: number; + /** + * @param axis The Gamepad axis + * @param value A numeric value between -1 and 1 + */ + constructor(axis: ex.Input.Axes, value: number); + } + /** + * Subscribe event thrown when handlers for events other than subscribe are added. Meta event that is received by + * [[EventDispatcher|event dispatchers]]. */ class SubscribeEvent extends GameEvent { topic: string; @@ -3584,7 +3844,8 @@ declare module ex { constructor(topic: string, handler: (event?: GameEvent) => void); } /** - * Unsubscribe event thrown when handlers for events other than unsubscribe are removed + * Unsubscribe event thrown when handlers for events other than unsubscribe are removed. Meta event that is received by + * [[EventDispatcher|event dispatchers]]. */ class UnsubscribeEvent extends GameEvent { topic: string; @@ -3592,19 +3853,19 @@ declare module ex { constructor(topic: string, handler: (event?: GameEvent) => void); } /** - * Event received by the Engine when the browser window is visible + * Event received by the [[Engine]] when the browser window is visible on a screen. */ class VisibleEvent extends GameEvent { constructor(); } /** - * Event received by the Engine when the browser window is hidden + * Event received by the [[Engine]] when the browser window is hidden from all screens. */ class HiddenEvent extends GameEvent { constructor(); } /** - * Event thrown on an actor when a collision has occured + * Event thrown on an [[Actor|actor]] when a collision has occured */ class CollisionEvent extends GameEvent { actor: Actor; @@ -3619,7 +3880,8 @@ declare module ex { constructor(actor: Actor, other: Actor, side: Side, intersection: Vector); } /** - * Event thrown on a game object on Excalibur update + * Event thrown on a game object on Excalibur update, this is equivalent to postupdate. + * @obsolete Please use [[PostUpdateEvent|postupdate]], or [[PreUpdateEvent|preupdate]]. */ class UpdateEvent extends GameEvent { delta: number; @@ -3629,7 +3891,7 @@ declare module ex { constructor(delta: number); } /** - * Event thrown on an Actor only once before the first update call + * Event thrown on an [[Actor]] only once before the first update call */ class InitializeEvent extends GameEvent { engine: Engine; @@ -3639,7 +3901,7 @@ declare module ex { constructor(engine: Engine); } /** - * Event thrown on a Scene on activation + * Event thrown on a [[Scene]] on activation */ class ActivateEvent extends GameEvent { oldScene: Scene; @@ -3649,7 +3911,7 @@ declare module ex { constructor(oldScene: Scene); } /** - * Event thrown on a Scene on deactivation + * Event thrown on a [[Scene]] on deactivation */ class DeactivateEvent extends GameEvent { newScene: Scene; @@ -3659,13 +3921,13 @@ declare module ex { constructor(newScene: Scene); } /** - * Event thrown on an Actor when it completely leaves the screen. + * Event thrown on an [[Actor]] when it completely leaves the screen. */ class ExitViewPortEvent extends GameEvent { constructor(); } /** - * Event thrown on an Actor when it completely leaves the screen. + * Event thrown on an [[Actor]] when it completely leaves the screen. */ class EnterViewPortEvent extends GameEvent { constructor(); @@ -3675,8 +3937,8 @@ declare module ex { /** * Excalibur's internal event dispatcher implementation. * Callbacks are fired immediately after an event is published. - * Typically you'd use [[Class.eventDispatcher]] since most classes in - * Excalibur inherit from [[Class]]. You'd rarely create an `EventDispatcher` + * Typically you will use [[Class.eventDispatcher]] since most classes in + * Excalibur inherit from [[Class]]. You will rarely create an `EventDispatcher` * yourself. * * When working with events, be sure to keep in mind the order of subscriptions @@ -3713,14 +3975,14 @@ declare module ex { * }); * * // trigger custom event - * player.triggerEvent("death", new DeathEvent()); + * player.emit("death", new DeathEvent()); * * ``` * * ## Example: Pub/Sub with Excalibur * * You can also create an EventDispatcher for any arbitrary object, for example - * a global game event aggregator (`vent`). Anything in your game can subscribe to + * a global game event aggregator (shown below as `vent`). Anything in your game can subscribe to * it, if the event aggregator is in the global scope. * * *Warning:* This can easily get out of hand. Avoid this usage, it just serves as @@ -3739,7 +4001,7 @@ declare module ex { * vent.subscribe("someevent", subscription); * * // publish an event somewhere in the game - * vent.publish("someevent", new ex.GameEvent()); + * vent.emit("someevent", new ex.GameEvent()); * ``` */ class EventDispatcher { @@ -3755,6 +4017,8 @@ declare module ex { * Publish an event for target * @param eventName The name of the event to publish * @param event Optionally pass an event data object to the handler + * + * @obsolete Use [[emit]] instead. */ publish(eventName: string, event?: GameEvent): void; /** @@ -4145,7 +4409,7 @@ declare module ex { * extend [[Actor]] allowing you to use all of the features that come with. * * The easiest way to create a `ParticleEmitter` is to use the - * [Particle Tester](http://excaliburjs.com/particle-tester/). + * [Particle Tester](http://excaliburjs.com/particle-tester/) to generate code for emitters. * * ## Example: Adding an emitter * @@ -4153,12 +4417,26 @@ declare module ex { * var actor = new ex.Actor(...); * var emitter = new ex.ParticleEmitter(...); * + * emitter.emitterType = ex.EmitterType.Circle; // Shape of emitter nozzle + * emitter.radius = 5; + * emitter.minVel = 100; + * emitter.maxVel = 200; + * emitter.minAngle = 0; + * emitter.maxAngle = Math.PI * 2; + * emitter.emitRate = 300; // 300 particles/second + * emitter.opacity = 0.5; + * emitter.fadeFlag = true; // fade particles overtime + * emitter.particleLife = 1000; // in milliseconds = 1 sec + * emitter.maxSize = 10; // in pixels + * emitter.minSize = 1; + * emitter.particleColor = ex.Color.Rose; + * * // set emitter settings - * emitter.isEmitting = true; + * emitter.isEmitting = true; // should the emitter be emitting * * // add the emitter as a child actor, it will draw on top of the parent actor * // and move with the parent - * actor.addChild(emitter); + * actor.add(emitter); * * // or, alternatively, add it to the current scene * engine.add(emitter); @@ -4274,7 +4552,7 @@ declare module ex { * Causes the emitter to emit particles * @param particleCount Number of particles to emit right now */ - emit(particleCount: number): void; + emitParticles(particleCount: number): void; clearParticles(): void; private _createParticle(); update(engine: Engine, delta: number): void; @@ -4850,7 +5128,8 @@ declare module ex { * is loaded, you can [[Sound.play|play]] it. * * ```js - * var sndPlayerDeath = new ex.Sound("/assets/snd/player-death.mp3", "/assets/snd/player-wav.mp3"); + * // define multiple sources (such as mp3/wav/ogg) as a browser fallback + * var sndPlayerDeath = new ex.Sound("/assets/snd/player-death.mp3", "/assets/snd/player-death.wav"); * * var loader = new ex.Loader(sndPlayerDeath); * @@ -5079,6 +5358,32 @@ declare module ex { } } declare module ex { + /** + * Enum representing the different font size units + * https://developer.mozilla.org/en-US/docs/Web/CSS/font-size + */ + enum FontUnit { + /** + * Em is a scalable unit, 1 em is equal to the current font size of the current element, parent elements can effect em values + */ + Em = 0, + /** + * Rem is similar to the Em, it is a scalable unit. 1 rem is eqaul to the font size of the root element + */ + Rem = 1, + /** + * Pixel is a unit of length in screen pixels + */ + Px = 2, + /** + * Point is a physical unit length (1/72 of an inch) + */ + Pt = 3, + /** + * Percent is a scalable unit similar to Em, the only difference is the Em units scale faster when Text-Size stuff + */ + Percent = 4, + } /** * Enum representing the different horizontal text alignments */ @@ -5234,10 +5539,18 @@ declare module ex { */ spriteFont: SpriteFont; /** - * The CSS font string (e.g. `10px sans-serif`, `10px Droid Sans Pro`). Web fonts + * The CSS font family string (e.g. `sans-serif`, `Droid Sans Pro`). Web fonts * are supported, same as in CSS. */ - font: string; + fontFamily: string; + /** + * The font size in the selected units, default is 10 (default units is pixel) + */ + fontSize: number; + /** + * The css units for a font size such as px, pt, em (SpriteFont only support px), by default is 'px'; + */ + fontUnit: FontUnit; /** * Gets or sets the horizontal text alignment property for the label. */ @@ -5274,12 +5587,13 @@ declare module ex { * @param spriteFont Use an Excalibur sprite font for the label's font, if a SpriteFont is provided it will take precendence * over a css font. */ - constructor(text?: string, x?: number, y?: number, font?: string, spriteFont?: SpriteFont); + constructor(text?: string, x?: number, y?: number, fontFamily?: string, spriteFont?: SpriteFont); /** * Returns the width of the text in the label (in pixels); * @param ctx Rending context to measure the string with */ getTextWidth(ctx: CanvasRenderingContext2D): number; + private _lookupFontUnit(fontUnit); private _lookupTextAlign(textAlign); private _lookupBaseAlign(baseAlign); /** @@ -5289,6 +5603,10 @@ declare module ex { * @param shadowColor The color of the text shadow */ setTextShadow(offsetX: number, offsetY: number, shadowColor: Color): void; + /** + * Toggles text shadows on or off, only applies when using sprite fonts + */ + useTextShadow(on: boolean): void; /** * Clears the current text shadow */ @@ -5300,6 +5618,73 @@ declare module ex { } } declare module ex { + /** + * Post Processors + * + * Sometimes it is necessary to apply an effect to the canvas after the engine has completed its drawing pass. A few reasons to do + * this might be creating a blur effect, adding a lighting effect, or changing how colors and pixels look. + * + * ## Basic post procesors + * + * To create and use a post processor you just need to implement a class that implements [[IPostProcessor]], which has one method + * [[IPostProcessor.process]]. Set the `out` canvas parameter to the final result, using the `image` pixel data. + * + * Click to read more about [[https://developer.mozilla.org/en-US/docs/Web/API/ImageData|ImageData]] on MDN. + * + * For example: + * ```typescript + * // simple way to grayscale, a faster way would be to implement using a webgl fragment shader + * class GrayscalePostProcessor implements IPostProcessor { + * process(image: ImageData, out: CanvasRenderingContext2D) { + * for(var i = 0; i < (image.height * image.width), i+=4){ + * // for pixel "i"" + * var r = image.data[i+0]; //0-255 + * var g = image.data[i+1]; //g + * var b = image.data[i+2]; //b + * image.data[i+3]; //a + * var result = Math.floor((r + g + b) / 3.0) | 0; // only valid on 0-255 integers `| 0` forces int + * image.data[i+0] = result; + * image.data[i+1] = result; + * image.data[i+2] = result; + * } + * // finish processing and write result + * out.putImageData(image, 0, 0); + * } + * } + * + * ``` + * + * ## Color Blind Corrector Post Processor + * + * Choosing colors that are friendly to players with color blindness is an important consideration when making a game. + * There is a significant portion of the population that has some form of color blindness, + * and choosing bad colors can make your game unplayable. We have built + * a post procesors that can shift your colors into as more visible range for the 3 most common types of + * [[https://en.wikipedia.org/wiki/Color_blindness|color blindness]]. + * + * - [[ColorBlindness.Protanope|Protanope]] + * - [[ColorBlindness.Deuteranope|Deuteranope]] + * - [[ColorBlindness.Tritanope|Tritanope]] + * + * This post processor can correct colors, and simulate color blindness. + * It is possible to use this on every game, but the game's performance + * will suffer measurably. It's better to use it as a helpful tool while developing your game. + * Remember, the best practice is to design with color blindness in mind. + * + * Example: + * ```typescript + * + * var game = new ex.Engine(); + * + * var colorBlindPostProcessor = new ex.ColorBlindCorrector(game, false, ColorBlindness.Protanope); + * + * // post processors evaluate left to right + * game.postProcessors.push(colorBlindPostProcessor); + * game.start(); + * + * ``` + * + */ interface IPostProcessor { process(image: ImageData, out: CanvasRenderingContext2D): void; } @@ -5388,7 +5773,7 @@ declare module ex.Input { * * ## Events * - * You can subscribe to pointer events through `engine.input.pointers`. A [[PointerEvent]] object is + * You can subscribe to pointer events through `engine.input.pointers.on`. A [[PointerEvent]] object is * passed to your handler which offers information about the pointer input being received. * * - `down` - When a pointer is pressed down (any mouse button or finger press) @@ -5411,7 +5796,7 @@ declare module ex.Input { * complex input and having control over every interaction. * * You can also use [[PointerScope.Canvas]] to only scope event handling to the game - * canvas. This is useful if you don't care about events that occur outside. + * canvas. This is useful if you don't care about events that occur outside the game. * * One real-world example is dragging and gestures. Sometimes a player will drag their * finger outside your game and then into it, expecting it to work. If [[PointerScope]] @@ -5420,8 +5805,8 @@ declare module ex.Input { * * ## Responding to input * - * The primary pointer can be a mouse, stylus, or 1 finger touch event. You - * can inspect what it is from the [[PointerEvent]] handled. + * The primary pointer can be a mouse, stylus, or single finger touch event. You + * can inspect what type of pointer it is from the [[PointerEvent]] handled. * * ```js * engine.input.pointers.primary.on("down", function (pe) { @@ -5473,9 +5858,10 @@ declare module ex.Input { * By default, [[Actor|Actors]] do not participate in pointer events. In other * words, when you "click" an Actor, it will not throw an event **for that Actor**, * only a generic pointer event for the game. This is to keep performance - * high and allow actors to "opt-in" to handling pointer events. + * high and allow actors to "opt-in" to handling pointer events. Actors will automatically + * opt-in if a pointer related event handler is set on them `actor.on("pointerdown", () => {})` for example. * - * To opt-in, set [[Actor.enableCapturePointer]] to `true` and the [[Actor]] will + * To opt-in manually, set [[Actor.enableCapturePointer]] to `true` and the [[Actor]] will * start publishing `pointerup` and `pointerdown` events. `pointermove` events * will not be published by default due to performance implications. If you want * an actor to receive move events, set [[ICapturePointerConfig.captureMoveEvents]] to @@ -5611,13 +5997,13 @@ declare module ex.Input { * Keyboard input * * Working with the keyboard is easy in Excalibur. You can inspect - * whether a button is [[Keyboard.isKeyDown|down]], [[Keyboard.isKeyUp|up]], or - * [[Keyboard.isKeyPressed|pressed]]. Common keys are held in the [[Input.Keys]] + * whether a button was just [[Keyboard.wasPressed|pressed]] or [[Keyboard.wasReleased|released]] this frame, or + * if the key is currently being [[Keyboard.isHeld|held]] down. Common keys are held in the [[Input.Keys]] * enumeration but you can pass any character code to the methods. * * Excalibur subscribes to the browser events and keeps track of - * what keys are currently down, up, or pressed. A key can be pressed - * for multiple frames, but a key cannot be down or up for more than one + * what keys are currently held, released, or pressed. A key can be held + * for multiple frames, but a key cannot be pressed or released for more than one subsequent * update frame. * * ## Inspecting the keyboard @@ -5625,19 +6011,36 @@ declare module ex.Input { * You can inspect [[Engine.input]] to see what the state of the keyboard * is during an update. * + * It is recommended that keyboard actions that directly effect actors be handled like so to improve code quality: * ```ts * class Player extends ex.Actor { * public update(engine, delta) { * - * if (engine.input.keyboard.isKeyPressed(ex.Input.Keys.W) || - * engine.input.keyboard.isKeyPressed(ex.Input.Keys.Up)) { + * if (engine.input.keyboard.isHeld(ex.Input.Keys.W) || + * engine.input.keyboard.isHeld(ex.Input.Keys.Up)) { * * player._moveForward(); * } * + * if (engine.input.keyboard.wasPressed(ex.Input.Keys.Right)) { + * player._fire(); + * } * } * } * ``` + * ## Events + * You can subscribe to keyboard events through `engine.input.keyboard.on`. A [[KeyEvent]] object is + * passed to your handler which offers information about the key that was part of the event. + * + * - `press` - When a key was just pressed this frame + * - `release` - When a key was just released this frame + * - `hold` - Whenever a key is in the down position + * + * ```ts + * engine.input.pointers.primary.on("press", (evt: KeyEvent) => {...}); + * engine.input.pointers.primary.on("release", (evt: KeyEvent) => {...}); + * engine.input.pointers.primary.on("hold", (evt: KeyEvent) => {...}); + * ``` */ class Keyboard extends ex.Class { private _keys; @@ -5655,20 +6058,20 @@ declare module ex.Input { */ getKeys(): Keys[]; /** - * Tests if a certain key is down. This is cleared at the end of the update frame. - * @param key Test wether a key is down + * Tests if a certain key was just pressed this frame. This is cleared at the end of the update frame. + * @param key Test wether a key was just pressed */ - isKeyDown(key: Keys): boolean; + wasPressed(key: Keys): boolean; /** - * Tests if a certain key is pressed. This is persisted between frames. - * @param key Test wether a key is pressed + * Tests if a certain key is held down. This is persisted between frames. + * @param key Test wether a key is held down */ - isKeyPressed(key: Keys): boolean; + isHeld(key: Keys): boolean; /** - * Tests if a certain key is up. This is cleared at the end of the update frame. - * @param key Test wether a key is up + * Tests if a certain key was just released this frame. This is cleared at the end of the update frame. + * @param key Test wether a key was just released */ - isKeyUp(key: Keys): boolean; + wasReleased(key: Keys): boolean; } } declare module ex.Input { @@ -5681,11 +6084,60 @@ declare module ex.Input { * You can query any [[Gamepad|Gamepads]] that are connected or listen to events ("button" and "axis"). * * You must opt-in to controller support ([[Gamepads.enabled]]) because it is a polling-based - * API, so we have to check it each update frame. + * API, so we have to check it each update frame. If an gamepad related event handler is set, you will + * automatically opt-in to controller polling. * - * Any number of gamepads are supported using the [[Gamepads.at]] method. If a [[Gamepad]] is + * HTML5 Gamepad API only supports a maximum of 4 gamepads. You can access them using the [[Gamepads.at]] method. If a [[Gamepad]] is * not connected, it will simply not throw events. * + * ## Gamepad Filtering + * + * Different browsers/devices are sometimes loose about the devices they consider Gamepads, you can set minimum device requirements with + * `engine.inpute.gamepads.setMinimumGamepadConfiguration` so that undesired devices are not reported to you (Touchpads, Mice, Web + * Cameras, etc.). + * ```js + * // ensures that only gamepads with at least 4 axis and 8 buttons are reported for events + * engine.input.gamepads.setMinimumGamepadConfiguration({ + * axis: 4, + * buttons: 8 + * }); + * ``` + * + * ## Events + * + * You can subscribe to gamepad connect and disconnect events through `engine.input.gamepads.on`. + * A [[GamepadConnectEvent]] or [[GamepadDisconnectEvent]] will be passed to you. + * + * - `connect` - When a gamepad connects it will fire this event and pass a [[GamepadConnectEvent]] with a reference to the gamepad. + * - `disconnect` - When a gamepad disconnects it will fire this event and pass a [[GamepadDisconnectEvent]] + * + * Once you have a reference to a gamepad you may listen to changes on that gamepad with `.on`. A [[GamepadButtonEvent]] or + * [[GamepadAxisEvent]] will be passed to you. + * - `button` - Whenever a button is pressed on the game + * - `axis` - Whenever an axis + * + * ```ts + * + * engine.input.gamepads.on('connect', (ce: ex.Input.GamepadConnectEvent) => { + * var newPlayer = CreateNewPlayer(); // pseudo-code for new player logic on gamepad connection + * console.log("Gamepad connected", ce); + * ce.gamepad.on('button', (be: ex.GamepadButtonEvent) => { + * if(be.button === ex.Input.Buttons.Face1) { + * newPlayer.jump(); + * } + * }); + * + * ce.gamepad.on('axis', (ae: ex.GamepadAxisEvent) => { + * if(ae.axis === ex.Input.Axis.LeftStickX && ae.value > .5){ + * newPlayer.moveRight(); + * } + * }) + * + * }); + * + * + * ``` + * * ## Responding to button input * * [[Buttons|Gamepad buttons]] typically have values between 0 and 1, however depending on @@ -5771,8 +6223,26 @@ declare module ex.Input { private _initSuccess; private _engine; private _navigator; + private _minimumConfiguration; constructor(engine: ex.Engine); init(): void; + /** + * Sets the minimum gamepad configuration, for example {axis: 4, buttons: 4} means + * this game requires at minimum 4 axis inputs and 4 buttons, this is not restrictive + * all other controllers with more axis or buttons are valid as well. If no minimum + * configuration is set all pads are valid. + */ + setMinimumGamepadConfiguration(config: IGamepadConfiguration): void; + /** + * When implicitely enabled, set the enabled flag and run an update so information is updated + */ + private _enableAndUpdate(); + /** + * Checks a navigator gamepad against the minimum configuration if present. + */ + private _isGamepadValid(pad); + on(eventName: string, handler: (event?: GameEvent) => void): void; + off(eventName: string, handler?: (event?: GameEvent) => void): void; /** * Updates Gamepad state and publishes Gamepad events */ @@ -5781,6 +6251,10 @@ declare module ex.Input { * Safely retrieves a Gamepad at a specific index and creates one if it doesn't yet exist */ at(index: number): Gamepad; + /** + * Returns a list of all valid gamepads that meet the minimum configuration requirment. + */ + getValidGamepads(): Gamepad[]; /** * Gets the number of connected gamepads */ @@ -5797,6 +6271,7 @@ declare module ex.Input { */ class Gamepad extends ex.Class { connected: boolean; + navigatorGamepad: INavigatorGamepad; private _buttons; private _axes; constructor(); @@ -5908,30 +6383,6 @@ declare module ex.Input { */ RightStickY = 3, } - /** - * Gamepad button event. See [[Gamepads]] for information on responding to controller input. - */ - class GamepadButtonEvent extends ex.GameEvent { - button: Buttons; - value: number; - /** - * @param button The Gamepad button - * @param value A numeric value between 0 and 1 - */ - constructor(button: Buttons, value: number); - } - /** - * Gamepad axis event. See [[Gamepads]] for information on responding to controller input. - */ - class GamepadAxisEvent extends ex.GameEvent { - axis: Axes; - value: number; - /** - * @param axis The Gamepad axis - * @param value A numeric value between -1 and 1 - */ - constructor(axis: Axes, value: number); - } /** * @internal */ @@ -5957,6 +6408,13 @@ declare module ex.Input { interface INavigatorGamepadEvent { gamepad: INavigatorGamepad; } + /** + * @internal + */ + interface IGamepadConfiguration { + axis: number; + buttons: number; + } } /** * # Welcome to the Excalibur API @@ -5973,7 +6431,7 @@ declare module ex.Input { * * ## Where to Start * - * These are the core concepts of Excalibur that you should be + * These are the core concepts of Excalibur that you should become * familiar with. * * - [[Engine|Intro to the Engine]] @@ -6012,6 +6470,7 @@ declare module ex.Input { * - [[Sound|Working with Sounds]] * - [[SpriteSheet|Working with SpriteSheets]] * - [[Animation|Working with Animations]] + * - [[TileMap|Working with TileMaps]] * * ## Effects and Particles * @@ -6020,6 +6479,7 @@ declare module ex.Input { * * - [[Effects|Sprite Effects]] * - [[ParticleEmitter|Particle Emitters]] + * - [[IPostProcessor|Post Processors]] * * ## Math * @@ -6100,9 +6560,11 @@ declare module ex { * * The Excalibur engine uses a simple main loop. The engine updates and renders * the "scene graph" which is the [[Scene|scenes]] and the tree of [[Actor|actors]] within that - * scene. Only one [[Scene]] can be active at once, the engine does not update/draw any other + * scene. Only one [[Scene]] can be active at a time. The engine does not update/draw any other * scene, which means any actors will not be updated/drawn if they are part of a deactivated scene. * + * ![Engine Lifecycle](/assets/images/docs/EngineLifeCycle.png) + * * **Scene Graph** * * ``` @@ -6121,13 +6583,13 @@ declare module ex { * * ### Update Loop * - * The first operation run is the [[Engine.update|update]] loop. [[Actor]] and [[Scene]] both implement + * The first operation run is the [[Engine._update|update]] loop. [[Actor]] and [[Scene]] both implement * an overridable/extendable `update` method. Use it to perform any logic-based operations * in your game for a particular class. * * ### Draw Loop * - * The next step is the [[Engine.draw|draw]] loop. A [[Scene]] loops through its child [[Actor|actors]] and + * The next step is the [[Engine._draw|draw]] loop. A [[Scene]] loops through its child [[Actor|actors]] and * draws each one. You can override the `draw` method on an actor to customize its drawing. * You should **not** perform any logic in a draw call, it should only relate to drawing. * @@ -6350,6 +6812,8 @@ declare module ex { * the [[currentScene]] may be drawn or updated. * * @param actor The actor to add to the [[currentScene]] + * + * @obsolete Use [[add]] instead. */ addChild(actor: Actor): void; /** @@ -6416,7 +6880,7 @@ declare module ex { add(tileMap: TileMap): void; /** * Adds an actor to the [[currentScene]] of the game. This is synonymous - * to calling `engine.currentScene.addChild(actor)`. + * to calling `engine.currentScene.add(actor)`. * * Actors can only be drawn if they are a member of a scene, and only * the [[currentScene]] may be drawn or updated. diff --git a/dist/excalibur-0.5.1.js b/dist/excalibur-0.6.0.js similarity index 91% rename from dist/excalibur-0.5.1.js rename to dist/excalibur-0.6.0.js index 73d8b67c5..1442266d5 100644 --- a/dist/excalibur-0.5.1.js +++ b/dist/excalibur-0.6.0.js @@ -1,6 +1,6 @@ -/*! excalibur - v0.5.1 - 2015-09-14 +/*! excalibur - v0.6.0 - 2016-01-19 * https://github.com/excaliburjs/Excalibur -* Copyright (c) 2015 ; Licensed BSD-2-Clause*/ +* Copyright (c) 2016 ; Licensed BSD-2-Clause*/ if (typeof window === 'undefined') { window = { audioContext: function () { return; } }; } @@ -460,7 +460,7 @@ var ex; actorScreenCoords.x > engine.width || actorScreenCoords.y > engine.height) && isSpriteOffScreen) { - eventDispatcher.publish('exitviewport', new ex.ExitViewPortEvent()); + eventDispatcher.emit('exitviewport', new ex.ExitViewPortEvent()); actor.isOffScreen = true; } } @@ -470,7 +470,7 @@ var ex; actorScreenCoords.x < engine.width && actorScreenCoords.y < engine.height) || !isSpriteOffScreen) { - eventDispatcher.publish('enterviewport', new ex.EnterViewPortEvent()); + eventDispatcher.emit('enterviewport', new ex.EnterViewPortEvent()); actor.isOffScreen = false; } } @@ -515,7 +515,7 @@ var ex; } CollisionDetection.prototype.update = function (actor, engine, delta) { var eventDispatcher = actor.eventDispatcher; - if (actor.collisionType !== ex.CollisionType.PreventCollision) { + if (actor.collisionType !== ex.CollisionType.PreventCollision && engine.currentScene && engine.currentScene.tileMaps) { for (var j = 0; j < engine.currentScene.tileMaps.length; j++) { var map = engine.currentScene.tileMaps[j]; var intersectMap; @@ -527,7 +527,7 @@ var ex; break; } side = actor.getSideFromIntersect(intersectMap); - eventDispatcher.publish('collision', new ex.CollisionEvent(actor, null, side, intersectMap)); + eventDispatcher.emit('collision', new ex.CollisionEvent(actor, null, side, intersectMap)); if ((actor.collisionType === ex.CollisionType.Active || actor.collisionType === ex.CollisionType.Elastic)) { actor.y += intersectMap.y; actor.x += intersectMap.x; @@ -574,13 +574,13 @@ var ex; var __extends = (this && this.__extends) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } - __.prototype = b.prototype; - d.prototype = new __(); + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; var ex; (function (ex) { /** * A simple 2D point on a plane + * @obsolete Use [[Vector|vector]]s instead of [[Point|points]] */ var Point = (function () { /** @@ -1007,6 +1007,15 @@ var ex; return false; } Util.removeItemToArray = removeItemToArray; + function contains(array, obj) { + for (var i = 0; i < array.length; i++) { + if (array[i] === obj) { + return true; + } + } + return false; + } + Util.contains = contains; function getOppositeSide(side) { if (side === ex.Side.Top) { return ex.Side.Bottom; @@ -1202,10 +1211,38 @@ var ex; * * Excalibur offers many sprite effects such as [[Effects.Colorize]] to let you manipulate * sprites. Keep in mind, more effects requires more power and can lead to memory or CPU - * constraints and hurt performance. + * constraints and hurt performance. Each effect must be reprocessed every frame for each sprite. * * It's still recommended to create an [[Animation]] or build in your effects to the sprites * for optimal performance. + * + * There are a number of convenience methods available to perform sprite effects. Sprite effects are + * side-effecting. + * + * ```typescript + * + * var playerSprite = new ex.Sprite(txPlayer, 0, 0, 80, 80); + * + * // darken a sprite by a percentage + * playerSprite.darken(.2); // 20% + * + * // lighten a sprite by a percentage + * playerSprite.lighten(.2); // 20% + * + * // saturate a sprite by a percentage + * playerSprite.saturate(.2); // 20% + * + * // implement a custom effect + * class CustomEffect implements ex.EffectsISpriteEffect { + * + * updatePixel(x: number, y: number, imageData: ImageData) { + * // modify ImageData + * } + * } + * + * playerSprite.addEffect(new CustomEffect()); + * + * ``` */ var Sprite = (function () { /** @@ -1655,7 +1692,8 @@ var ex; * Sprite Fonts * * Sprite fonts are a used in conjunction with a [[Label]] to specify - * a particular bitmap as a font. + * a particular bitmap as a font. Note that some font features are not + * supported by Sprite fonts. * * ## Generating the font sheet * @@ -1747,9 +1785,21 @@ var ex; this.image = image; this.alphabet = alphabet; this.caseInsensitive = caseInsensitive; + this.spWidth = spWidth; + this.spHeight = spHeight; this._spriteLookup = {}; this._colorLookup = {}; - this._currentColor = ex.Color.Black; + this._currentColor = ex.Color.Black.clone(); + this._currentOpacity = 1.0; + this._sprites = {}; + // text shadow + this._textShadowOn = false; + this._textShadowDirty = true; + this._textShadowColor = ex.Color.Black.clone(); + this._textShadowSprites = {}; + this._shadowOffsetX = 5; + this._shadowOffsetY = 5; + this._sprites = this.getTextSprites(); } /** * Returns a dictionary that maps each character in the alphabet to the appropriate [[Sprite]]. @@ -1765,6 +1815,115 @@ var ex; } return lookup; }; + /** + * Sets the text shadow for sprite fonts + * @param offsetX The x offset in pixels to place the shadow + * @param offsetY The y offset in pixles to place the shadow + * @param shadowColor The color of the text shadow + */ + SpriteFont.prototype.setTextShadow = function (offsetX, offsetY, shadowColor) { + this._textShadowOn = true; + this._shadowOffsetX = offsetX; + this._shadowOffsetY = offsetY; + this._textShadowColor = shadowColor.clone(); + this._textShadowDirty = true; + for (var character in this._sprites) { + this._textShadowSprites[character] = this._sprites[character].clone(); + } + }; + /** + * Toggles text shadows on or off + */ + SpriteFont.prototype.useTextShadow = function (on) { + this._textShadowOn = on; + if (on) { + this.setTextShadow(5, 5, this._textShadowColor); + } + }; + /** + * Draws the current sprite font + */ + SpriteFont.prototype.draw = function (ctx, text, x, y, options) { + options = this._parseOptions(options); + if (this._currentColor.toString() !== options.color.toString() || this._currentOpacity !== options.opacity) { + this._currentOpacity = options.opacity; + this._currentColor = options.color; + for (var char in this._sprites) { + this._sprites[char].clearEffects(); + this._sprites[char].fill(options.color); + this._sprites[char].opacity(options.opacity); + } + } + if (this._textShadowOn && this._textShadowDirty && this._textShadowColor) { + for (var characterShadow in this._textShadowSprites) { + this._textShadowSprites[characterShadow].clearEffects(); + this._textShadowSprites[characterShadow].addEffect(new ex.Effects.Fill(this._textShadowColor.clone())); + } + this._textShadowDirty = false; + } + // find the current length of text in pixels + var sprite = this.sprites[0]; + // find the current height fo the text in pixels + var height = sprite.sheight; + // calculate appropriate scale for font size + var scale = options.fontSize / height; + var length = (text.length * sprite.swidth * scale) + (text.length * options.letterSpacing); + var currX = x; + if (options.textAlign === ex.TextAlign.Left || options.textAlign === ex.TextAlign.Start) { + currX = x; + } + else if (options.textAlign === ex.TextAlign.Right || options.textAlign === ex.TextAlign.End) { + currX = x - length; + } + else if (options.textAlign === ex.TextAlign.Center) { + currX = x - length / 2; + } + var currY = y - height * scale; + if (options.baseAlign === ex.BaseAlign.Top || options.baseAlign === ex.BaseAlign.Hanging) { + currY = y; + } + else if (options.baseAlign === ex.BaseAlign.Ideographic || + options.baseAlign === ex.BaseAlign.Bottom || + options.baseAlign === ex.BaseAlign.Alphabetic) { + currY = y - height * scale; + } + else if (options.baseAlign === ex.BaseAlign.Middle) { + currY = y - (height * scale) / 2; + } + for (var i = 0; i < text.length; i++) { + var character = text[i]; + if (this.caseInsensitive) { + character = character.toLowerCase(); + } + try { + // if text shadow + if (this._textShadowOn) { + this._textShadowSprites[character].scale.x = scale; + this._textShadowSprites[character].scale.y = scale; + this._textShadowSprites[character].draw(ctx, currX + this._shadowOffsetX, currY + this._shadowOffsetY); + } + var charSprite = this._sprites[character]; + charSprite.scale.x = scale; + charSprite.scale.y = scale; + charSprite.draw(ctx, currX, currY); + currX += (charSprite.width + options.letterSpacing); + } + catch (e) { + ex.Logger.getInstance().error("SpriteFont Error drawing char " + character); + } + } + }; + SpriteFont.prototype._parseOptions = function (options) { + return { + fontSize: options.fontSize || 10, + letterSpacing: options.letterSpacing || 0, + color: options.color || ex.Color.Black.clone(), + textAlign: typeof options.textAlign === undefined ? ex.TextAlign.Left : options.textAlign, + baseAlign: typeof options.baseAlign === undefined ? ex.BaseAlign.Bottom : options.baseAlign, + maxWidth: options.maxWidth || -1, + opacity: options.opacity || 0 + }; + }; return SpriteFont; })(SpriteSheet); ex.SpriteFont = SpriteFont; @@ -2481,6 +2640,14 @@ var ex; Class.prototype.off = function (eventName, handler) { this.eventDispatcher.unsubscribe(eventName, handler); }; + /** + * Emits a new event + * @param eventName Name of the event to emit + * @param eventObject Data associated with this event + */ + Class.prototype.emit = function (eventName, eventObject) { + this.eventDispatcher.emit(eventName, eventObject); + }; /** * You may wish to extend native Excalibur functionality in vanilla Javascript. * Any method on a class inheriting [[Class]] may be extended to support @@ -3121,8 +3288,8 @@ var ex; // todo fire collision events on left and right actor // todo resolve collisions // Publish collision events on both participants - this.left.eventDispatcher.publish('collision', new ex.CollisionEvent(this.left, this.right, this.side, this.intersect)); - this.right.eventDispatcher.publish('collision', new ex.CollisionEvent(this.right, this.left, ex.Util.getOppositeSide(this.side), this.intersect.scale(-1.0))); + this.left.eventDispatcher.emit('collision', new ex.CollisionEvent(this.left, this.right, this.side, this.intersect)); + this.right.eventDispatcher.emit('collision', new ex.CollisionEvent(this.right, this.left, ex.Util.getOppositeSide(this.side), this.intersect.scale(-1.0))); // If the actor is active push the actor out if its not passive var leftSide = this.side; if ((this.left.collisionType === ex.CollisionType.Active || @@ -3283,8 +3450,20 @@ var ex; */ var BaseCamera = (function () { function BaseCamera() { - this._focus = new ex.Point(0, 0); - this._lerp = false; + this.focus = new ex.Point(0, 0); + this.lerp = false; + // camera physical quantities + this.x = 0; + this.y = 0; + this.z = 1; + this.dx = 0; + this.dy = 0; + this.dz = 0; + this.ax = 0; + this.ay = 0; + this.az = 0; + this.rotation = 0; + this.rx = 0; this._cameraMoving = false; this._currentLerpTime = 0; this._lerpDuration = 1 * 1000; // 5 seconds @@ -3321,23 +3500,24 @@ var ex; this._follow = actor; }; /** - * Returns the focal point of the camera + * Returns the focal point of the camera, a new point giving the x and y position of the camera */ BaseCamera.prototype.getFocus = function () { - return this._focus; + return new ex.Point(this.x, this.y); }; /** * Sets the focal point of the camera. This value can only be set if there is no actor to be followed. * @param x The x coordinate of the focal point * @param y The y coordinate of the focal point + * @deprecated */ BaseCamera.prototype.setFocus = function (x, y) { - if (!this._follow && !this._lerp) { - this._focus.x = x; - this._focus.y = y; + if (!this._follow && !this.lerp) { + this.x = x; + this.y = y; } - if (this._lerp) { - this._lerpStart = this._focus.clone(); + if (this.lerp) { + this._lerpStart = this.getFocus().clone(); this._lerpEnd = new ex.Point(x, y); this._currentLerpTime = 0; this._cameraMoving = true; @@ -3389,16 +3569,24 @@ var ex; * Gets the current zoom scale */ BaseCamera.prototype.getZoom = function () { - return this._currentZoomScale; + return this.z; }; BaseCamera.prototype._setCurrentZoomScale = function (zoomScale) { - this._currentZoomScale = zoomScale; + this.z = zoomScale; }; /** * Applies the relevant transformations to the game canvas to "move" or apply effects to the Camera * @param delta The number of milliseconds since the last update */ BaseCamera.prototype.update = function (ctx, delta) { + // Update placements based on linear algebra + this.x += this.dx * delta / 1000; + this.y += this.dy * delta / 1000; + this.z += this.dz * delta / 1000; + this.dx += this.ax * delta / 1000; + this.dy += this.ay * delta / 1000; + this.dz += this.az * delta / 1000; + this.rotation += this.rx * delta / 1000; var focus = this.getFocus(); var xShake = 0; var yShake = 0; @@ -3408,19 +3596,19 @@ var ex; // if zoom is .5x then canvas is 2x as high var newCanvasWidth = canvasWidth / this.getZoom(); var newCanvasHeight = canvasHeight / this.getZoom(); - if (this._lerp) { + if (this.lerp) { if (this._currentLerpTime < this._lerpDuration && this._cameraMoving) { if (this._lerpEnd.x < this._lerpStart.x) { - this._focus.x = this._lerpStart.x - (this._easeInOutCubic(this._currentLerpTime, this._lerpEnd.x, this._lerpStart.x, this._lerpDuration) - this._lerpEnd.x); + this.x = this._lerpStart.x - (this._easeInOutCubic(this._currentLerpTime, this._lerpEnd.x, this._lerpStart.x, this._lerpDuration) - this._lerpEnd.x); } else { - this._focus.x = this._easeInOutCubic(this._currentLerpTime, this._lerpStart.x, this._lerpEnd.x, this._lerpDuration); + this.x = this._easeInOutCubic(this._currentLerpTime, this._lerpStart.x, this._lerpEnd.x, this._lerpDuration); } if (this._lerpEnd.y < this._lerpStart.y) { - this._focus.y = this._lerpStart.y - (this._easeInOutCubic(this._currentLerpTime, this._lerpEnd.y, this._lerpStart.y, this._lerpDuration) - this._lerpEnd.y); + this.y = this._lerpStart.y - (this._easeInOutCubic(this._currentLerpTime, this._lerpEnd.y, this._lerpStart.y, this._lerpDuration) - this._lerpEnd.y); } else { - this._focus.y = this._easeInOutCubic(this._currentLerpTime, this._lerpStart.y, this._lerpEnd.y, this._lerpDuration); + this.y = this._easeInOutCubic(this._currentLerpTime, this._lerpStart.y, this._lerpEnd.y, this._lerpDuration); } this._currentLerpTime += delta; } @@ -3443,16 +3631,17 @@ var ex; xShake = (Math.random() * this._shakeMagnitudeX | 0) + 1; yShake = (Math.random() * this._shakeMagnitudeY | 0) + 1; } - if (this._isDoneZooming()) { - this._isZooming = false; - this._elapsedZoomTime = 0; - this._zoomDuration = 0; - this._setCurrentZoomScale(this._maxZoomScale); - } - else { - this._elapsedZoomTime += delta; - this._setCurrentZoomScale(this.getZoom() + this._zoomIncrement * delta / 1000); - } + /*if (this._isDoneZooming()) { + this._isZooming = false; + this._elapsedZoomTime = 0; + this._zoomDuration = 0; + this._setCurrentZoomScale(this._maxZoomScale); + + } else { + this._elapsedZoomTime += delta; + + this._setCurrentZoomScale(this.getZoom() + this._zoomIncrement * delta / 1000); + }*/ ctx.scale(this.getZoom(), this.getZoom()); ctx.translate(-focus.x + newCanvasWidth / 2 + xShake, -focus.y + newCanvasHeight / 2 + yShake); }; @@ -3501,10 +3690,10 @@ var ex; } SideCamera.prototype.getFocus = function () { if (this._follow) { - return new ex.Point(this._follow.x + this._follow.getWidth() / 2, this._focus.y); + return new ex.Point(this._follow.x + this._follow.getWidth() / 2, this.focus.y); } else { - return this._focus; + return this.focus; } }; return SideCamera; @@ -3527,7 +3716,7 @@ var ex; return new ex.Point(this._follow.x + this._follow.getWidth() / 2, this._follow.y + this._follow.getHeight() / 2); } else { - return this._focus; + return this.focus; } }; return LockedCamera; @@ -4493,11 +4682,6 @@ var ex; * in future versions to support multiple timelines/scripts, better eventing, * and a more robust API to allow for complex and customized actions. * - * ## Known Issues - * - * **Rotation actions do not use shortest angle** - * [Issue #282](https://github.com/excaliburjs/Excalibur/issues/282) - * */ var ActionContext = (function () { function ActionContext() { @@ -4531,6 +4715,23 @@ var ex; this._queues.splice(index, 1); } }; + /** + * This method will move an actor to the specified `x` and `y` position over the + * specified duration using a given [[EasingFunctions]] and return back the actor. This + * method is part of the actor 'Action' fluent API allowing action chaining. + * @param x The x location to move the actor to + * @param y The y location to move the actor to + * @param duration The time it should take the actor to move to the new location in milliseconds + * @param easingFcn Use [[EasingFunctions]] or a custom function to use to calculate position + */ + ActionContext.prototype.easeTo = function (x, y, duration, easingFcn) { + if (easingFcn === void 0) { easingFcn = ex.EasingFunctions.Linear; } + var i = 0, len = this._queues.length; + for (i; i < len; i++) { + this._queues[i].add(new ex.Internal.Actions.EaseTo(this._actors[i], x, y, duration, easingFcn)); + } + return this; + }; /** * This method will move an actor to the specified x and y position at the * speed specified (in pixels per second) and return back the actor. This @@ -4782,7 +4983,26 @@ var ex; * Groups are used for logically grouping Actors so they can be acted upon * in bulk. * - * @todo Document this + * ## Using Groups + * + * Groups can be used to detect collisions across a large nubmer of actors. For example + * perhaps a large group of "enemy" actors. + * + * ```typescript + * var enemyShips = engine.currentScene.createGroup("enemy"); + * var enemies = [...]; // Large array of enemies; + * enemyShips.add(enemies); + * + * var player = new Actor(); + * engine.currentScene.add(player); + * + * enemyShips.on('collision', function(ev: CollisionEvent){ + * if (e.other === player) { + * //console.log("collision with player!"); + * } + * }); + * + * ``` */ var Group = (function (_super) { __extends(Group, _super); @@ -5190,6 +5410,13 @@ var ex; * * ``` * + * ## Scene Lifecycle + * + * A [[Scene|scene]] has a basic lifecycle that dictacts how it is initialized, updated, and drawn. Once a [[Scene|scene]] is added to + * the [[Engine|engine]] it will follow this lifecycle. + * + * ![Scene Lifecycle](/assets/images/docs/SceneLifeCycle.png) + * * ## Extending scenes * * For more complex games, you might want more control over a scene in which @@ -5309,23 +5536,13 @@ var ex; // will be overridden this._logger.debug('Scene.onDeactivate', this); }; - /** - * Publish an event to all actors in the scene - * @param eventType The name of the event to publish - * @param event The event object to send - */ - Scene.prototype.publish = function (eventType, event) { - var i = 0, len = this.children.length; - for (i; i < len; i++) { - this.children[i].triggerEvent(eventType, event); - } - }; /** * Updates all the actors and timers in the scene. Called by the [[Engine]]. * @param engine Reference to the current Engine * @param delta The number of milliseconds since the last update */ Scene.prototype.update = function (engine, delta) { + this.emit('preupdate', new ex.PreUpdateEvent(engine, delta, this)); var i, len; // Cycle through actors updating UI actors for (i = 0, len = this.uiActors.length; i < len; i++) { @@ -5364,6 +5581,7 @@ var ex; timer.update(delta); return !timer.complete; }); + this.emit('postupdate', new ex.PostUpdateEvent(engine, delta, this)); }; /** * Draws all the actors in the Scene. Called by the [[Engine]]. @@ -5371,6 +5589,7 @@ var ex; * @param delta The number of milliseconds since the last draw */ Scene.prototype.draw = function (ctx, delta) { + this.emit('predraw', new ex.PreDrawEvent(ctx, delta, this)); ctx.save(); if (this.camera) { this.camera.update(ctx, delta); @@ -5402,12 +5621,14 @@ var ex; this.uiActors[i].debugDraw(ctx); } } + this.emit('postdraw', new ex.PreDrawEvent(ctx, delta, this)); }; /** * Draws all the actors' debug information in the Scene. Called by the [[Engine]]. * @param ctx The current rendering context */ Scene.prototype.debugDraw = function (ctx) { + this.emit('predebugdraw', new ex.PreDebugDrawEvent(ctx, this)); var i, len; for (i = 0, len = this.tileMaps.length; i < len; i++) { this.tileMaps[i].debugDraw(ctx); @@ -5418,6 +5639,7 @@ var ex; // todo possibly enable this with excalibur flags features? //this._collisionResolver.debugDraw(ctx, 20); this.camera.debugDraw(ctx); + this.emit('postdebugdraw', new ex.PostDebugDrawEvent(ctx, this)); }; /** * Checks whether an actor is contained in this scene or not @@ -5427,18 +5649,28 @@ var ex; }; Scene.prototype.add = function (entity) { if (entity instanceof ex.UIActor) { - this.addUIActor(entity); + if (!ex.Util.contains(this.uiActors, entity)) { + this.addUIActor(entity); + } return; } if (entity instanceof ex.Actor) { - this.addChild(entity); - this._sortedDrawingTree.add(entity); + if (!ex.Util.contains(this.children, entity)) { + this.addChild(entity); + this._sortedDrawingTree.add(entity); + } + return; } if (entity instanceof ex.Timer) { - this.addTimer(entity); + if (!ex.Util.contains(this._timers, entity)) { + this.addTimer(entity); + } + return; } if (entity instanceof ex.TileMap) { - this.addTileMap(entity); + if (!ex.Util.contains(this.tileMaps, entity)) { + this.addTileMap(entity); + } } }; Scene.prototype.remove = function (entity) { @@ -5477,6 +5709,8 @@ var ex; }; /** * Adds an actor to the scene, once this is done the actor will be drawn and updated. + * + * @obsolete Use [[add]] instead. */ Scene.prototype.addChild = function (actor) { this._collisionResolver.register(actor); @@ -5585,32 +5819,44 @@ var ex; var ex; (function (ex) { /** - * Standard easing functions for motion in Excalibur + * Standard easing functions for motion in Excalibur, defined on a domain of [0, duration] and a range from [+startValue,+endValue] + * Given a time, the function will return a value from postive startValue to postive endValue. + * + * ```js + * function Linear (t) { + * return t * t; + * } * - * easeInQuad: function (t) { return t * t }, - * // decelerating to zero velocity - * easeOutQuad: function (t) { return t * (2 - t) }, - * // acceleration until halfway, then deceleration - * easeInOutQuad: function (t) { return t < .5 ? 2 * t * t : -1 + (4 - 2 * t) * t }, - * // accelerating from zero velocity - * easeInCubic: function (t) { return t * t * t }, - * // decelerating to zero velocity - * easeOutCubic: function (t) { return (--t) * t * t + 1 }, - * // acceleration until halfway, then deceleration - * easeInOutCubic: function (t) { return t < .5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1 }, * // accelerating from zero velocity - * easeInQuart: function (t) { return t * t * t * t }, + * function EaseInQuad (t) { + * return t * t; + * } + * * // decelerating to zero velocity - * easeOutQuart: function (t) { return 1 - (--t) * t * t * t }, + * function EaseOutQuad (t) { + * return t * (2 - t); + * } + * * // acceleration until halfway, then deceleration - * easeInOutQuart: function (t) { return t < .5 ? 8 * t * t * t * t : 1 - 8 * (--t) * t * t * t }, + * function EaseInOutQuad (t) { + * return t < .5 ? 2 * t * t : -1 + (4 - 2 * t) * t; + * } + * * // accelerating from zero velocity - * easeInQuint: function (t) { return t * t * t * t * t }, + * function EaseInCubic (t) { + * return t * t * t; + * } + * * // decelerating to zero velocity - * easeOutQuint: function (t) { return 1 + (--t) * t * t * t * t }, - * // acceleration until halfway, then deceleration - * easeInOutQuint: function (t) { return t < .5 ? 16 * t * t * t * t * t : 1 + 16 * (--t) * t * t * t * t } + * function EaseOutCubic (t) { + * return (--t) * t * t + 1; + * } * + * // acceleration until halfway, then deceleration + * function EaseInOutCubic (t) { + * return t < .5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1; + * } + * ``` */ var EasingFunctions = (function () { function EasingFunctions() { @@ -5701,7 +5947,16 @@ var ex; * * // add player to the current scene * game.add(player); + * * ``` + * `game.add` is a convenience method for adding an `Actor` to the current scene. The equivalent verbose call is `game.currentScene.add`. + * + * ## Actor Lifecycle + * + * An [[Actor|actor]] has a basic lifecycle that dictacts how it is initialized, updated, and drawn. Once an actor is part of a + * [[Scene|scene]], it will follow this lifecycle. + * + * ![Actor Lifecycle](/assets/images/docs/ActorLifeCycle.png) * * ## Extending actors * @@ -5771,7 +6026,7 @@ var ex; * * The [[update]] method is passed an instance of the Excalibur engine, which * can be used to perform coordinate math or access global state. It is also - * passed `delta` which is the time since the last frame, which can be used + * passed `delta` which is the time in milliseconds since the last frame, which can be used * to perform time-based movement or time-based math (such as a timer). * * **TypeScript** @@ -5783,7 +6038,7 @@ var ex; * * // check if player died * if (this.health <= 0) { - * this.triggerEvent("death"); + * this.emit("death"); * this.onDeath(); * return; * } @@ -5800,7 +6055,7 @@ var ex; * * // check if player died * if (this.health <= 0) { - * this.triggerEvent("death"); + * this.emit("death"); * this.onDeath(); * return; * } @@ -5812,13 +6067,16 @@ var ex; * * Override the [[draw]] method to perform any custom drawing. For simple games, * you don't need to override `draw`, instead you can use [[addDrawing]] and [[setDrawing]] - * to manipulate the textures/animations that the actor is using. + * to manipulate the [[Sprite|sprites]]/[[Animation|animations]] that the actor is using. * * ### Working with Textures & Sprites * - * A common usage is to use a [[Texture]] or [[Sprite]] for an actor. If you are using the [[Loader]] to - * pre-load assets, you can simply assign an actor a [[Texture]] to draw. You can - * also create a [[Texture.asSprite|sprite from a Texture]] to quickly create a [[Sprite]] instance. + * Think of a [[Texture|texture]] as the raw image file that will be loaded into Excalibur. In order for it to be drawn + * it must be converted to a [[Sprite.sprite]]. + * + * A common usage is to load a [[Texture]] and convert it to a [[Sprite]] for an actor. If you are using the [[Loader]] to + * pre-load assets, you can simply assign an actor a [[Sprite]] to draw. You can also create a + * [[Texture.asSprite|sprite from a Texture]] to quickly create a [[Sprite]] instance. * * ```ts * // assume Resources.TxPlayer is a 80x80 png image @@ -5857,7 +6115,8 @@ var ex; * ### Custom drawing * * You can always override the default drawing logic for an actor in the [[draw]] method, - * for example, to draw complex shapes or to use the raw Canvas API. + * for example, to draw complex shapes or to use the raw + * [[https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D|Canvas API]]. * * Usually you should call `super.draw` to perform the base drawing logic, but other times * you may want to take over the drawing completely. @@ -5888,33 +6147,45 @@ var ex; * ## Collision Detection * * By default Actors do not participate in collisions. If you wish to make - * an actor participate, you need to enable the [[CollisionDetectionModule]] + * an actor participate, you need to switch from the default [[CollisionType.PreventCollision|prevent collision]] + * to [[CollisionType.Active|active]], [[CollisionType.Fixed|fixed]], or [[CollisionType.Passive|passive]] collision type. * * ```ts * public Player extends ex.Actor { * constructor() { * super(); - * - * // enable the pipeline - * this.pipelines.push(new ex.CollisionDetectionModule()); - * * // set preferred CollisionType * this.collisionType = ex.CollisionType.Active; * } * } - * ``` * - * ### Collision Groups + * // or set the collisionType * + * var actor = new ex.Actor(); + * actor.collisionType = ex.CollisionType.Active; + * + * ``` + * ### Collision Groups * TODO, needs more information. * + * ## Traits + * + * Traits describe actor behavior that occurs every update. If you wish to build a generic behavior + * without needing to extend every actor you can do it with a trait, a good example of this may be + * plugging in an external collision detection library like [[https://github.com/kripken/box2d.js/|Box2D]] or + * [[http://wellcaffeinated.net/PhysicsJS/|PhysicsJS]] by wrapping it in a trait. Removing traits can also make your + * actors more efficient. + * + * Default traits provided by Excalibur are [[Traits.CapturePointer|pointer capture]], + * [[Traits.CollisionDetection|tile map collision]], [[Traits.Movement|Euler style movement]], + * and [[Traits.OffscreenCulling|offscreen culling]]. + * + * * ## Known Issues * * **Actor bounding boxes do not rotate** * [Issue #68](https://github.com/excaliburjs/Excalibur/issues/68) * - * **Setting opacity when using a color doesn't do anything** - * [Issue #364](https://github.com/excaliburjs/Excalibur/issues/364) */ var Actor = (function (_super) { __extends(Actor, _super); @@ -5933,11 +6204,11 @@ var ex; */ this.id = Actor.maxId++; /** - * The x coordinate of the actor (left edge) + * The x coordinate of the actor (middle if anchor is (0.5, 0.5) left edge if anchor is (0, 0)) */ this.x = 0; /** - * The y coordinate of the actor (top edge) + * The y coordinate of the actor (middle if anchor is (0.5, 0.5) and top edge if anchor is (0, 0)) */ this.y = 0; this._height = 0; @@ -6055,7 +6326,7 @@ var ex; } // Build default pipeline this.traits.push(new ex.Traits.Movement()); - //this.pipeline.push(new ex.CollisionDetectionModule()); + this.traits.push(new ex.Traits.CollisionDetection()); this.traits.push(new ex.Traits.OffscreenCulling()); this.traits.push(new ex.Traits.CapturePointer()); this.actionQueue = new ex.Internal.Actions.ActionQueue(this); @@ -6124,7 +6395,7 @@ var ex; * move with it. * @param actor The child actor to add */ - Actor.prototype.addChild = function (actor) { + Actor.prototype.add = function (actor) { actor.collisionType = CollisionType.PreventCollision; if (ex.Util.addItemToArray(actor, this.children)) { actor.parent = this; @@ -6134,7 +6405,7 @@ var ex; * Removes a child actor from this actor. * @param actor The child actor to remove */ - Actor.prototype.removeChild = function (actor) { + Actor.prototype.remove = function (actor) { if (ex.Util.removeItemToArray(actor, this.children)) { actor.parent = null; } @@ -6185,16 +6456,6 @@ var ex; this._zIndex = newIndex; this.scene.updateDrawTree(this); }; - /** - * Artificially trigger an event on an actor, useful when creating custom events. - * @param eventName The name of the event to trigger - * @param event The event object to pass to the callback - * - * @obsolete Will be replaced with `emit` - */ - Actor.prototype.triggerEvent = function (eventName, event) { - this.eventDispatcher.publish(eventName, event); - }; /** * Adds an actor to a collision group. Actors with no named collision groups are * considered to be in every collision group. @@ -6420,6 +6681,7 @@ var ex; }; /** * Clears all queued actions from the Actor + * @obsolete Use [[ActionContext.clearActions|Actor.actions.clearActions]] */ Actor.prototype.clearActions = function () { this.actionQueue.clearActions(); @@ -6432,6 +6694,7 @@ var ex; * @param y The y location to move the actor to * @param duration The time it should take the actor to move to the new location in milliseconds * @param easingFcn Use [[EasingFunctions]] or a custom function to use to calculate position + * @obsolete Use [[ActionContext.easeTo|Actor.actions.easeTo]] */ Actor.prototype.easeTo = function (x, y, duration, easingFcn) { if (easingFcn === void 0) { easingFcn = ex.EasingFunctions.Linear; } @@ -6445,6 +6708,7 @@ var ex; * @param x The x location to move the actor to * @param y The y location to move the actor to * @param speed The speed in pixels per second to move + * @obsolete Use [[ActionContext.moveTo|Actor.actions.moveTo]] */ Actor.prototype.moveTo = function (x, y, speed) { this.actionQueue.add(new ex.Internal.Actions.MoveTo(this, x, y, speed)); @@ -6457,6 +6721,7 @@ var ex; * @param x The x location to move the actor to * @param y The y location to move the actor to * @param duration The time it should take the actor to move to the new location in milliseconds + * @obsolete Use [[ActionContext.moveBy|Actor.actions.moveBy]] */ Actor.prototype.moveBy = function (x, y, duration) { this.actionQueue.add(new ex.Internal.Actions.MoveBy(this, x, y, duration)); @@ -6468,6 +6733,7 @@ var ex; * method is part of the actor 'Action' fluent API allowing action chaining. * @param angleRadians The angle to rotate to in radians * @param speed The angular velocity of the rotation specified in radians per second + * @obsolete Use [[ActionContext.rotateTo|Actor.actions.rotateTo]] */ Actor.prototype.rotateTo = function (angleRadians, speed, rotationType) { this.actionQueue.add(new ex.Internal.Actions.RotateTo(this, angleRadians, speed, rotationType)); @@ -6479,6 +6745,7 @@ var ex; * of the actor 'Action' fluent API allowing action chaining. * @param angleRadians The angle to rotate to in radians * @param duration The time it should take the actor to complete the rotation in milliseconds + * @obsolete Use [[ActionContext.rotateBy|ex.Actor.actions.rotateBy]] */ Actor.prototype.rotateBy = function (angleRadians, duration, rotationType) { this.actionQueue.add(new ex.Internal.Actions.RotateBy(this, angleRadians, duration, rotationType)); @@ -6493,6 +6760,7 @@ var ex; * @param sizeY The scaling factor in the y direction to apply * @param speedX The speed of scaling in the x direction specified in magnitude increase per second * @param speedY The speed of scaling in the y direction specified in magnitude increase per second + * @obsolete Use [[ActionContext.scaleTo|Actor.actions.scaleTo]] */ Actor.prototype.scaleTo = function (sizeX, sizeY, speedX, speedY) { this.actionQueue.add(new ex.Internal.Actions.ScaleTo(this, sizeX, sizeY, speedX, speedY)); @@ -6505,6 +6773,7 @@ var ex; * @param sizeX The scaling factor in the x direction to apply * @param sizeY The scaling factor in the y direction to apply * @param duration The time it should take to complete the scaling in milliseconds + * @obsolete Use [[ActionContext.scaleBy|Actor.actions.scaleBy]] */ Actor.prototype.scaleBy = function (sizeX, sizeY, duration) { this.actionQueue.add(new ex.Internal.Actions.ScaleBy(this, sizeX, sizeY, duration)); @@ -6518,6 +6787,7 @@ var ex; * @param timeVisible The amount of time to stay visible per blink in milliseconds * @param timeNotVisible The amount of time to stay not visible per blink in milliseconds * @param numBlinks The number of times to blink + * @obsolete Use [[ActionContext.blink|Actor.actions.blink]] */ Actor.prototype.blink = function (timeVisible, timeNotVisible, numBlinks) { if (numBlinks === void 0) { numBlinks = 1; } @@ -6530,6 +6800,7 @@ var ex; * part of the actor 'Action' fluent API allowing action chaining. * @param opacity The ending opacity * @param duration The time it should take to fade the actor (in milliseconds) + * @obsolete Use [[ActionContext.fade|Actor.actions.fade]] */ Actor.prototype.fade = function (opacity, duration) { this.actionQueue.add(new ex.Internal.Actions.Fade(this, opacity, duration)); @@ -6540,6 +6811,7 @@ var ex; * `duration` (in milliseconds). This method is part of the actor * 'Action' fluent API allowing action chaining. * @param duration The amount of time to delay the next action in the queue from executing in milliseconds + * @obsolete Use [[ActionContext.delay|Actor.actions.delay]] */ Actor.prototype.delay = function (duration) { this.actionQueue.add(new ex.Internal.Actions.Delay(this, duration)); @@ -6549,6 +6821,7 @@ var ex; * This method will add an action to the queue that will remove the actor from the * scene once it has completed its previous actions. Any actions on the * action queue after this action will not be executed. + * @obsolete Use [[ActionContext.die|Actor.actions.die]] */ Actor.prototype.die = function () { this.actionQueue.add(new ex.Internal.Actions.Die(this)); @@ -6558,6 +6831,7 @@ var ex; * This method allows you to call an arbitrary method as the next action in the * action queue. This is useful if you want to execute code in after a specific * action, i.e An actor arrives at a destination after traversing a path + * @obsolete Use [[ActionContext.callMethod|Actor.actions.callMethod]] */ Actor.prototype.callMethod = function (method) { this.actionQueue.add(new ex.Internal.Actions.CallMethod(this, method)); @@ -6570,6 +6844,7 @@ var ex; * the actor 'Action' fluent API allowing action chaining * @param times The number of times to repeat all the previous actions in the action queue. If nothing is specified the actions will * repeat forever + * @obsolete Use [[ActionContext.repeat|Actor.actions.repeat]] */ Actor.prototype.repeat = function (times) { if (!times) { @@ -6583,6 +6858,7 @@ var ex; * This method will cause the actor to repeat all of the previously * called actions forever. This method is part of the actor 'Action' * fluent API allowing action chaining. + * @obsolete Use [[ActionContext.repeatForever|Actor.actions.repeatForever]] */ Actor.prototype.repeatForever = function () { this.actionQueue.add(new ex.Internal.Actions.RepeatForever(this, this.actionQueue.getActions())); @@ -6592,6 +6868,7 @@ var ex; * This method will cause the actor to follow another at a specified distance * @param actor The actor to follow * @param followDistance The distance to maintain when following, if not specified the actor will follow at the current distance. + * @obsolete Use [[ActionContext.follow|Actor.actions.follow]] */ Actor.prototype.follow = function (actor, followDistance) { if (typeof followDistance === 'undefined') { @@ -6607,6 +6884,7 @@ var ex; * collide ("meet") at a specified speed. * @param actor The actor to meet * @param speed The speed in pixels per second to move, if not specified it will match the speed of the other actor + * @obsolete Use [[ActionContext.meet|Actor.actions.meet]] */ Actor.prototype.meet = function (actor, speed) { if (typeof speed === 'undefined') { @@ -6620,6 +6898,7 @@ var ex; /** * Returns a promise that resolves when the current action queue up to now * is finished. + * @obsolete Use [[ActionContext.asPromise|Actor.actions.asPromise]] */ Actor.prototype.asPromise = function () { var complete = new ex.Promise(); @@ -6639,9 +6918,10 @@ var ex; Actor.prototype.update = function (engine, delta) { if (!this._isInitialized) { this.onInitialize(engine); - this.eventDispatcher.publish('initialize', new ex.InitializeEvent(engine)); + this.eventDispatcher.emit('initialize', new ex.InitializeEvent(engine)); this._isInitialized = true; } + this.emit('preupdate', new ex.PreUpdateEvent(engine, delta, this)); var eventDispatcher = this.eventDispatcher; // Update action queue this.actionQueue.update(delta); @@ -6653,7 +6933,8 @@ var ex; for (var i = 0; i < this.traits.length; i++) { this.traits[i].update(this, engine, delta); } - eventDispatcher.publish(ex.EventType[ex.EventType.Update], new ex.UpdateEvent(delta)); + eventDispatcher.emit('update', new ex.UpdateEvent(delta)); + this.emit('postupdate', new ex.PostUpdateEvent(engine, delta, this)); }; /** * Called by the Engine, draws the actor to the screen @@ -6663,9 +6944,10 @@ var ex; Actor.prototype.draw = function (ctx, delta) { var anchorPoint = this._getCalculatedAnchor(); ctx.save(); - ctx.scale(this.scale.x, this.scale.y); ctx.translate(this.x, this.y); + ctx.scale(this.scale.x, this.scale.y); ctx.rotate(this.rotation); + this.emit('predraw', new ex.PreDrawEvent(ctx, delta, this)); // calculate changing opacity if (this.previousOpacity !== this.opacity) { for (var drawing in this.frames) { @@ -6694,8 +6976,11 @@ var ex; } // Draw child actors for (var i = 0; i < this.children.length; i++) { - this.children[i].draw(ctx, delta); + if (this.children[i].visible) { + this.children[i].draw(ctx, delta); + } } + this.emit('postdraw', new ex.PostDrawEvent(ctx, delta, this)); ctx.restore(); }; /** @@ -6703,6 +6988,7 @@ var ex; * @param ctx The rendering context */ Actor.prototype.debugDraw = function (ctx) { + this.emit('predebugdraw', new ex.PreDebugDrawEvent(ctx, this)); // Draw actor bounding box var bb = this.getBounds(); bb.debugDraw(ctx); @@ -6748,6 +7034,7 @@ var ex; this.children[i].debugDraw(ctx); } ctx.restore(); + this.emit('postdebugdraw', new ex.PostDebugDrawEvent(ctx, this)); }; /** * Indicates the next id to be set @@ -6780,6 +7067,7 @@ var ex; * Actors with the `Elastic` setting will behave the same as `Active`, except that they will * "bounce" in the opposite direction given their velocity dx/dy. This is a naive implementation meant for * prototyping, for a more robust elastic collision listen to the "collision" event and perform your custom logic. + * @obsolete This behavior will be handled by a future physics system */ CollisionType[CollisionType["Elastic"] = 3] = "Elastic"; /** @@ -7039,23 +7327,23 @@ var ex; var ex; (function (ex) { /** - * An enum representing all of the built in event types for Excalibur - * @obsolete Phasing this out in favor of classes - */ - (function (EventType) { - EventType[EventType["Collision"] = 0] = "Collision"; - EventType[EventType["EnterViewPort"] = 1] = "EnterViewPort"; - EventType[EventType["ExitViewPort"] = 2] = "ExitViewPort"; - EventType[EventType["Blur"] = 3] = "Blur"; - EventType[EventType["Focus"] = 4] = "Focus"; - EventType[EventType["Update"] = 5] = "Update"; - EventType[EventType["Activate"] = 6] = "Activate"; - EventType[EventType["Deactivate"] = 7] = "Deactivate"; - EventType[EventType["Initialize"] = 8] = "Initialize"; - })(ex.EventType || (ex.EventType = {})); - var EventType = ex.EventType; - /** - * Base event type in Excalibur that all other event types derive from. + * Base event type in Excalibur that all other event types derive from. Not all event types are thrown on all Excalibur game objects, + * some events are unique to a type, others are not. + * + * Excalibur events follow the convention that the name of the thrown event for listening will be the same as the Event object in all + * lower case with the 'Event' suffix removed. + * + * For example: + * - PreDrawEvent event object and "predraw" as the event name + * + * ```typescript + * + * actor.on('predraw', (evtObj: PreDrawEvent) => { + * // do some pre drawing + * }) + * + * ``` + * */ var GameEvent = (function () { function GameEvent() { @@ -7064,7 +7352,154 @@ var ex; })(); ex.GameEvent = GameEvent; /** - * Subscribe event thrown when handlers for events other than subscribe are added + * The 'predraw' event is emitted on actors, scenes, and engine before drawing starts. Actors' predraw happens inside their graphics + * transform so that all drawing takes place with the actor as the origin. + * + */ + var PreDrawEvent = (function (_super) { + __extends(PreDrawEvent, _super); + function PreDrawEvent(ctx, delta, target) { + _super.call(this); + this.ctx = ctx; + this.delta = delta; + this.target = target; + } + return PreDrawEvent; + })(GameEvent); + ex.PreDrawEvent = PreDrawEvent; + /** + * The 'postdraw' event is emitted on actors, scenes, and engine after drawing finishes. Actors' postdraw happens inside their graphics + * transform so that all drawing takes place with the actor as the origin. + * + */ + var PostDrawEvent = (function (_super) { + __extends(PostDrawEvent, _super); + function PostDrawEvent(ctx, delta, target) { + _super.call(this); + this.ctx = ctx; + this.delta = delta; + this.target = target; + } + return PostDrawEvent; + })(GameEvent); + ex.PostDrawEvent = PostDrawEvent; + /** + * The 'predebugdraw' event is emitted on actors, scenes, and engine before debug drawing starts. + */ + var PreDebugDrawEvent = (function (_super) { + __extends(PreDebugDrawEvent, _super); + function PreDebugDrawEvent(ctx, target) { + _super.call(this); + this.ctx = ctx; + this.target = target; + } + return PreDebugDrawEvent; + })(GameEvent); + ex.PreDebugDrawEvent = PreDebugDrawEvent; + /** + * The 'postdebugdraw' event is emitted on actors, scenes, and engine after debug drawing starts. + */ + var PostDebugDrawEvent = (function (_super) { + __extends(PostDebugDrawEvent, _super); + function PostDebugDrawEvent(ctx, target) { + _super.call(this); + this.ctx = ctx; + this.target = target; + } + return PostDebugDrawEvent; + })(GameEvent); + ex.PostDebugDrawEvent = PostDebugDrawEvent; + /** + * The 'preupdate' event is emitted on actors, scenes, and engine before the update starts. + */ + var PreUpdateEvent = (function (_super) { + __extends(PreUpdateEvent, _super); + function PreUpdateEvent(engine, delta, target) { + _super.call(this); + this.engine = engine; + this.delta = delta; + this.target = target; + } + return PreUpdateEvent; + })(GameEvent); + ex.PreUpdateEvent = PreUpdateEvent; + /** + * The 'postupdate' event is emitted on actors, scenes, and engine after the update ends. This is equivalent to the obsolete 'update' + * event. + */ + var PostUpdateEvent = (function (_super) { + __extends(PostUpdateEvent, _super); + function PostUpdateEvent(engine, delta, target) { + _super.call(this); + this.engine = engine; + this.delta = delta; + this.target = target; + } + return PostUpdateEvent; + })(GameEvent); + ex.PostUpdateEvent = PostUpdateEvent; + /** + * Event received when a gamepad is connected to Excalibur. [[Input.Gamepads|engine.input.gamepads]] receives this event. + */ + var GamepadConnectEvent = (function (_super) { + __extends(GamepadConnectEvent, _super); + function GamepadConnectEvent(index, gamepad) { + _super.call(this); + this.index = index; + this.gamepad = gamepad; + } + return GamepadConnectEvent; + })(GameEvent); + ex.GamepadConnectEvent = GamepadConnectEvent; + /** + * Event received when a gamepad is disconnected from Excalibur. [[Input.Gamepads|engine.input.gamepads]] receives this event. + */ + var GamepadDisconnectEvent = (function (_super) { + __extends(GamepadDisconnectEvent, _super); + function GamepadDisconnectEvent(index) { + _super.call(this); + this.index = index; + } + return GamepadDisconnectEvent; + })(GameEvent); + ex.GamepadDisconnectEvent = GamepadDisconnectEvent; + /** + * Gamepad button event. See [[Gamepads]] for information on responding to controller input. [[Gamepad]] instances receive this event; + */ + var GamepadButtonEvent = (function (_super) { + __extends(GamepadButtonEvent, _super); + /** + * @param button The Gamepad button + * @param value A numeric value between 0 and 1 + */ + function GamepadButtonEvent(button, value) { + _super.call(this); + this.button = button; + this.value = value; + } + return GamepadButtonEvent; + })(ex.GameEvent); + ex.GamepadButtonEvent = GamepadButtonEvent; + /** + * Gamepad axis event. See [[Gamepads]] for information on responding to controller input. [[Gamepad]] instances receive this event; + */ + var GamepadAxisEvent = (function (_super) { + __extends(GamepadAxisEvent, _super); + /** + * @param axis The Gamepad axis + * @param value A numeric value between -1 and 1 + */ + function GamepadAxisEvent(axis, value) { + _super.call(this); + this.axis = axis; + this.value = value; + } + return GamepadAxisEvent; + })(ex.GameEvent); + ex.GamepadAxisEvent = GamepadAxisEvent; + /** + * Subscribe event thrown when handlers for events other than subscribe are added. Meta event that is received by + * [[EventDispatcher|event dispatchers]]. */ var SubscribeEvent = (function (_super) { __extends(SubscribeEvent, _super); @@ -7077,7 +7512,8 @@ var ex; })(GameEvent); ex.SubscribeEvent = SubscribeEvent; /** - * Unsubscribe event thrown when handlers for events other than unsubscribe are removed + * Unsubscribe event thrown when handlers for events other than unsubscribe are removed. Meta event that is received by + * [[EventDispatcher|event dispatchers]]. */ var UnsubscribeEvent = (function (_super) { __extends(UnsubscribeEvent, _super); @@ -7090,7 +7526,7 @@ var ex; })(GameEvent); ex.UnsubscribeEvent = UnsubscribeEvent; /** - * Event received by the Engine when the browser window is visible + * Event received by the [[Engine]] when the browser window is visible on a screen. */ var VisibleEvent = (function (_super) { __extends(VisibleEvent, _super); @@ -7101,7 +7537,7 @@ var ex; })(GameEvent); ex.VisibleEvent = VisibleEvent; /** - * Event received by the Engine when the browser window is hidden + * Event received by the [[Engine]] when the browser window is hidden from all screens. */ var HiddenEvent = (function (_super) { __extends(HiddenEvent, _super); @@ -7112,7 +7548,7 @@ var ex; })(GameEvent); ex.HiddenEvent = HiddenEvent; /** - * Event thrown on an actor when a collision has occured + * Event thrown on an [[Actor|actor]] when a collision has occured */ var CollisionEvent = (function (_super) { __extends(CollisionEvent, _super); @@ -7132,7 +7568,8 @@ var ex; })(GameEvent); ex.CollisionEvent = CollisionEvent; /** - * Event thrown on a game object on Excalibur update + * Event thrown on a game object on Excalibur update, this is equivalent to postupdate. + * @obsolete Please use [[PostUpdateEvent|postupdate]], or [[PreUpdateEvent|preupdate]]. */ var UpdateEvent = (function (_super) { __extends(UpdateEvent, _super); @@ -7147,7 +7584,7 @@ var ex; })(GameEvent); ex.UpdateEvent = UpdateEvent; /** - * Event thrown on an Actor only once before the first update call + * Event thrown on an [[Actor]] only once before the first update call */ var InitializeEvent = (function (_super) { __extends(InitializeEvent, _super); @@ -7162,7 +7599,7 @@ var ex; })(GameEvent); ex.InitializeEvent = InitializeEvent; /** - * Event thrown on a Scene on activation + * Event thrown on a [[Scene]] on activation */ var ActivateEvent = (function (_super) { __extends(ActivateEvent, _super); @@ -7177,7 +7614,7 @@ var ex; })(GameEvent); ex.ActivateEvent = ActivateEvent; /** - * Event thrown on a Scene on deactivation + * Event thrown on a [[Scene]] on deactivation */ var DeactivateEvent = (function (_super) { __extends(DeactivateEvent, _super); @@ -7192,7 +7629,7 @@ var ex; })(GameEvent); ex.DeactivateEvent = DeactivateEvent; /** - * Event thrown on an Actor when it completely leaves the screen. + * Event thrown on an [[Actor]] when it completely leaves the screen. */ var ExitViewPortEvent = (function (_super) { __extends(ExitViewPortEvent, _super); @@ -7203,7 +7640,7 @@ var ex; })(GameEvent); ex.ExitViewPortEvent = ExitViewPortEvent; /** - * Event thrown on an Actor when it completely leaves the screen. + * Event thrown on an [[Actor]] when it completely leaves the screen. */ var EnterViewPortEvent = (function (_super) { __extends(EnterViewPortEvent, _super); @@ -7220,8 +7657,8 @@ var ex; /** * Excalibur's internal event dispatcher implementation. * Callbacks are fired immediately after an event is published. - * Typically you'd use [[Class.eventDispatcher]] since most classes in - * Excalibur inherit from [[Class]]. You'd rarely create an `EventDispatcher` + * Typically you will use [[Class.eventDispatcher]] since most classes in + * Excalibur inherit from [[Class]]. You will rarely create an `EventDispatcher` * yourself. * * When working with events, be sure to keep in mind the order of subscriptions @@ -7258,14 +7695,14 @@ var ex; * }); * * // trigger custom event - * player.triggerEvent("death", new DeathEvent()); + * player.emit("death", new DeathEvent()); * * ``` * * ## Example: Pub/Sub with Excalibur * * You can also create an EventDispatcher for any arbitrary object, for example - * a global game event aggregator (`vent`). Anything in your game can subscribe to + * a global game event aggregator (shown below as `vent`). Anything in your game can subscribe to * it, if the event aggregator is in the global scope. * * *Warning:* This can easily get out of hand. Avoid this usage, it just serves as @@ -7284,7 +7721,7 @@ var ex; * vent.subscribe("someevent", subscription); * * // publish an event somewhere in the game - * vent.publish("someevent", new ex.GameEvent()); + * vent.emit("someevent", new ex.GameEvent()); * ``` */ var EventDispatcher = (function () { @@ -7301,6 +7738,8 @@ var ex; * Publish an event for target * @param eventName The name of the event to publish * @param event Optionally pass an event data object to the handler + * + * @obsolete Use [[emit]] instead. */ EventDispatcher.prototype.publish = function (eventName, event) { if (!eventName) { @@ -7324,7 +7763,7 @@ var ex; i = 0; len = this._wiredEventDispatchers.length; for (i; i < len; i++) { - this._wiredEventDispatchers[i].publish(eventName, event); + this._wiredEventDispatchers[i].emit(eventName, event); } }; /** @@ -8033,7 +8472,7 @@ var ex; * extend [[Actor]] allowing you to use all of the features that come with. * * The easiest way to create a `ParticleEmitter` is to use the - * [Particle Tester](http://excaliburjs.com/particle-tester/). + * [Particle Tester](http://excaliburjs.com/particle-tester/) to generate code for emitters. * * ## Example: Adding an emitter * @@ -8041,12 +8480,26 @@ var ex; * var actor = new ex.Actor(...); * var emitter = new ex.ParticleEmitter(...); * + * emitter.emitterType = ex.EmitterType.Circle; // Shape of emitter nozzle + * emitter.radius = 5; + * emitter.minVel = 100; + * emitter.maxVel = 200; + * emitter.minAngle = 0; + * emitter.maxAngle = Math.PI * 2; + * emitter.emitRate = 300; // 300 particles/second + * emitter.opacity = 0.5; + * emitter.fadeFlag = true; // fade particles overtime + * emitter.particleLife = 1000; // in milliseconds = 1 sec + * emitter.maxSize = 10; // in pixels + * emitter.minSize = 1; + * emitter.particleColor = ex.Color.Rose; + * * // set emitter settings - * emitter.isEmitting = true; + * emitter.isEmitting = true; // should the emitter be emitting * * // add the emitter as a child actor, it will draw on top of the parent actor * // and move with the parent - * actor.addChild(emitter); + * actor.add(emitter); * * // or, alternatively, add it to the current scene * engine.add(emitter); @@ -8182,7 +8635,7 @@ var ex; * Causes the emitter to emit particles * @param particleCount Number of particles to emit right now */ - ParticleEmitter.prototype.emit = function (particleCount) { + ParticleEmitter.prototype.emitParticles = function (particleCount) { for (var i = 0; i < particleCount; i++) { this.particles.push(this._createParticle()); } @@ -8232,7 +8685,7 @@ var ex; this._particlesToEmit += this.emitRate * (delta / 1000); //var numParticles = Math.ceil(this.emitRate * delta / 1000); if (this._particlesToEmit > 1.0) { - this.emit(Math.floor(this._particlesToEmit)); + this.emitParticles(Math.floor(this._particlesToEmit)); this._particlesToEmit = this._particlesToEmit - Math.floor(this._particlesToEmit); } } @@ -8354,6 +8807,7 @@ var ex; this.width = images[0] ? images[0].width : 0; this.naturalWidth = images[0] ? images[0].naturalWidth : 0; this.naturalHeight = images[0] ? images[0].naturalHeight : 0; + this.freezeFrame = images.length - 1; } } /** @@ -9264,7 +9718,8 @@ var ex; * is loaded, you can [[Sound.play|play]] it. * * ```js - * var sndPlayerDeath = new ex.Sound("/assets/snd/player-death.mp3", "/assets/snd/player-wav.mp3"); + * // define multiple sources (such as mp3/wav/ogg) as a browser fallback + * var sndPlayerDeath = new ex.Sound("/assets/snd/player-death.mp3", "/assets/snd/player-death.wav"); * * var loader = new ex.Loader(sndPlayerDeath); * @@ -9846,6 +10301,33 @@ var ex; /// var ex; (function (ex) { + /** + * Enum representing the different font size units + * https://developer.mozilla.org/en-US/docs/Web/CSS/font-size + */ + (function (FontUnit) { + /** + * Em is a scalable unit, 1 em is equal to the current font size of the current element, parent elements can effect em values + */ + FontUnit[FontUnit["Em"] = 0] = "Em"; + /** + * Rem is similar to the Em, it is a scalable unit. 1 rem is eqaul to the font size of the root element + */ + FontUnit[FontUnit["Rem"] = 1] = "Rem"; + /** + * Pixel is a unit of length in screen pixels + */ + FontUnit[FontUnit["Px"] = 2] = "Px"; + /** + * Point is a physical unit length (1/72 of an inch) + */ + FontUnit[FontUnit["Pt"] = 3] = "Pt"; + /** + * Percent is a scalable unit similar to Em, the only difference is the Em units scale faster when Text-Size stuff + */ + FontUnit[FontUnit["Percent"] = 4] = "Percent"; + })(ex.FontUnit || (ex.FontUnit = {})); + var FontUnit = ex.FontUnit; /** * Enum representing the different horizontal text alignments */ @@ -10003,8 +10485,24 @@ var ex; * @param spriteFont Use an Excalibur sprite font for the label's font, if a SpriteFont is provided it will take precendence * over a css font. */ - function Label(text, x, y, font, spriteFont) { + function Label(text, x, y, fontFamily, spriteFont) { _super.call(this, x, y); + /** + * The font size in the selected units, default is 10 (default units is pixel) + */ + this.fontSize = 10; + /** + * The css units for a font size such as px, pt, em (SpriteFont only support px), by default is 'px'; + */ + this.fontUnit = FontUnit.Px; + /** + * Gets or sets the horizontal text alignment property for the label. + */ + this.textAlign = TextAlign.Left; + /** + * Gets or sets the baseline alignment property for the label. + */ + this.baseAlign = BaseAlign.Bottom; /** * Gets or sets the letter spacing on a Label. Only supported with Sprite Fonts. */ @@ -10025,9 +10523,8 @@ var ex; this.color = ex.Color.Black.clone(); this.spriteFont = spriteFont; this.collisionType = ex.CollisionType.PreventCollision; - this.font = font || '10px sans-serif'; // coallesce to default canvas font + this.fontFamily = fontFamily || '10px sans-serif'; // coallesce to default canvas font if (spriteFont) { - this._textSprites = spriteFont.getTextSprites(); } } /** @@ -10036,12 +10533,28 @@ var ex; */ Label.prototype.getTextWidth = function (ctx) { var oldFont = ctx.font; - ctx.font = this.font; + ctx.font = this.fontFamily; var width = ctx.measureText(this.text).width; ctx.font = oldFont; return width; }; // TypeScript doesn't support string enums :( + Label.prototype._lookupFontUnit = function (fontUnit) { + switch (fontUnit) { + case FontUnit.Em: + return 'em'; + case FontUnit.Rem: + return 'rem'; + case FontUnit.Pt: + return 'pt'; + case FontUnit.Px: + return 'px'; + case FontUnit.Percent: + return '%'; + default: + return 'px'; + } + }; Label.prototype._lookupTextAlign = function (textAlign) { switch (textAlign) { case TextAlign.Left: @@ -10083,14 +10596,13 @@ var ex; * @param shadowColor The color of the text shadow */ Label.prototype.setTextShadow = function (offsetX, offsetY, shadowColor) { - this._textShadowOn = true; - this._shadowOffsetX = offsetX; - this._shadowOffsetY = offsetY; - this._shadowColor = shadowColor.clone(); - this._shadowColorDirty = true; - for (var character in this._textSprites) { - this._shadowSprites[character] = this._textSprites[character].clone(); - } + this.spriteFont.setTextShadow(offsetX, offsetY, shadowColor); + }; + /** + * Toggles text shadows on or off, only applies when using sprite fonts + */ + Label.prototype.useTextShadow = function (on) { + this.spriteFont.useTextShadow(on); }; /** * Clears the current text shadow @@ -10103,22 +10615,25 @@ var ex; }; Label.prototype.update = function (engine, delta) { _super.prototype.update.call(this, engine, delta); - if (this.spriteFont && (this._color !== this.color || this.previousOpacity !== this.opacity)) { - for (var character in this._textSprites) { - this._textSprites[character].clearEffects(); - this._textSprites[character].fill(this.color.clone()); - this._textSprites[character].opacity(this.opacity); - } - this._color = this.color; - this.previousOpacity = this.opacity; - } - if (this.spriteFont && this._textShadowOn && this._shadowColorDirty && this._shadowColor) { - for (var characterShadow in this._shadowSprites) { - this._shadowSprites[characterShadow].clearEffects(); - this._shadowSprites[characterShadow].addEffect(new ex.Effects.Fill(this._shadowColor.clone())); - } - this._shadowColorDirty = false; - } + /* + if (this.spriteFont && (this._color !== this.color || this.previousOpacity !== this.opacity)) { + for (var character in this._textSprites) { + this._textSprites[character].clearEffects(); + this._textSprites[character].fill(this.color.clone()); + this._textSprites[character].opacity(this.opacity); + + } + this._color = this.color; + this.previousOpacity = this.opacity; + } + + if (this.spriteFont && this._textShadowOn && this._shadowColorDirty && this._shadowColor) { + for (var characterShadow in this._shadowSprites) { + this._shadowSprites[characterShadow].clearEffects(); + this._shadowSprites[characterShadow].addEffect(new Effects.Fill(this._shadowColor.clone())); + } + this._shadowColorDirty = false; + }*/ }; Label.prototype.draw = function (ctx, delta) { ctx.save(); @@ -10137,21 +10652,14 @@ var ex; }; Label.prototype._fontDraw = function (ctx, delta, sprites) { if (this.spriteFont) { - var currX = 0; - for (var i = 0; i < this.text.length; i++) { - var character = this.text[i]; - if (this.caseInsensitive) { - character = character.toLowerCase(); - } - try { - var charSprite = sprites[character]; - charSprite.draw(ctx, currX, 0); - currX += (charSprite.swidth + this.letterSpacing); - } - catch (e) { - ex.Logger.getInstance().error('SpriteFont Error drawing char ' + character); - } - } + this.spriteFont.draw(ctx, this.text, 0, 0, { + color: this.color.clone(), + baseAlign: this.baseAlign, + textAlign: this.textAlign, + fontSize: this.fontSize, + letterSpacing: this.letterSpacing, + opacity: this.opacity + }); } else { var oldAlign = ctx.textAlign; @@ -10162,7 +10670,7 @@ var ex; this.color.a = this.opacity; } ctx.fillStyle = this.color.toString(); - ctx.font = this.font; + ctx.font = "" + this.fontSize + this._lookupFontUnit(this.fontUnit) + " " + this.fontFamily; if (this.maxWidth) { ctx.fillText(this.text, 0, 0, this.maxWidth); } @@ -10270,7 +10778,7 @@ var ex; * * ## Events * - * You can subscribe to pointer events through `engine.input.pointers`. A [[PointerEvent]] object is + * You can subscribe to pointer events through `engine.input.pointers.on`. A [[PointerEvent]] object is * passed to your handler which offers information about the pointer input being received. * * - `down` - When a pointer is pressed down (any mouse button or finger press) @@ -10293,7 +10801,7 @@ var ex; * complex input and having control over every interaction. * * You can also use [[PointerScope.Canvas]] to only scope event handling to the game - * canvas. This is useful if you don't care about events that occur outside. + * canvas. This is useful if you don't care about events that occur outside the game. * * One real-world example is dragging and gestures. Sometimes a player will drag their * finger outside your game and then into it, expecting it to work. If [[PointerScope]] @@ -10302,8 +10810,8 @@ var ex; * * ## Responding to input * - * The primary pointer can be a mouse, stylus, or 1 finger touch event. You - * can inspect what it is from the [[PointerEvent]] handled. + * The primary pointer can be a mouse, stylus, or single finger touch event. You + * can inspect what type of pointer it is from the [[PointerEvent]] handled. * * ```js * engine.input.pointers.primary.on("down", function (pe) { @@ -10355,9 +10863,10 @@ var ex; * By default, [[Actor|Actors]] do not participate in pointer events. In other * words, when you "click" an Actor, it will not throw an event **for that Actor**, * only a generic pointer event for the game. This is to keep performance - * high and allow actors to "opt-in" to handling pointer events. + * high and allow actors to "opt-in" to handling pointer events. Actors will automatically + * opt-in if a pointer related event handler is set on them `actor.on("pointerdown", () => {})` for example. * - * To opt-in, set [[Actor.enableCapturePointer]] to `true` and the [[Actor]] will + * To opt-in manually, set [[Actor.enableCapturePointer]] to `true` and the [[Actor]] will * start publishing `pointerup` and `pointerdown` events. `pointermove` events * will not be published by default due to performance implications. If you want * an actor to receive move events, set [[ICapturePointerConfig.captureMoveEvents]] to @@ -10471,14 +10980,14 @@ var ex; var i = 0, len = this._pointerUp.length; for (i; i < len; i++) { if (actor.contains(this._pointerUp[i].x, this._pointerUp[i].y, !isUIActor)) { - actor.eventDispatcher.publish('pointerup', this._pointerUp[i]); + actor.eventDispatcher.emit('pointerup', this._pointerUp[i]); } } i = 0; len = this._pointerDown.length; for (i; i < len; i++) { if (actor.contains(this._pointerDown[i].x, this._pointerDown[i].y, !isUIActor)) { - actor.eventDispatcher.publish('pointerdown', this._pointerDown[i]); + actor.eventDispatcher.emit('pointerdown', this._pointerDown[i]); } } if (actor.capturePointer.captureMoveEvents) { @@ -10486,7 +10995,7 @@ var ex; len = this._pointerMove.length; for (i; i < len; i++) { if (actor.contains(this._pointerMove[i].x, this._pointerMove[i].y, !isUIActor)) { - actor.eventDispatcher.publish('pointermove', this._pointerMove[i]); + actor.eventDispatcher.emit('pointermove', this._pointerMove[i]); } } } @@ -10494,7 +11003,7 @@ var ex; len = this._pointerCancel.length; for (i; i < len; i++) { if (actor.contains(this._pointerCancel[i].x, this._pointerCancel[i].y, !isUIActor)) { - actor.eventDispatcher.publish('pointercancel', this._pointerCancel[i]); + actor.eventDispatcher.emit('pointercancel', this._pointerCancel[i]); } } }; @@ -10507,7 +11016,7 @@ var ex; var transformedPoint = _this._engine.screenToWorldCoordinates(new ex.Point(x, y)); var pe = new PointerEvent(transformedPoint.x, transformedPoint.y, 0, PointerType.Mouse, e.button, e); eventArr.push(pe); - _this.at(0).eventDispatcher.publish(eventName, pe); + _this.at(0).eventDispatcher.emit(eventName, pe); }; }; Pointers.prototype._handleTouchEvent = function (eventName, eventArr) { @@ -10524,7 +11033,7 @@ var ex; var transformedPoint = _this._engine.screenToWorldCoordinates(new ex.Point(x, y)); var pe = new PointerEvent(transformedPoint.x, transformedPoint.y, index, PointerType.Touch, PointerButton.Unknown, e); eventArr.push(pe); - _this.at(index).eventDispatcher.publish(eventName, pe); + _this.at(index).eventDispatcher.emit(eventName, pe); // only with multi-pointer if (_this._pointers.length > 1) { if (eventName === 'up') { @@ -10553,7 +11062,7 @@ var ex; var transformedPoint = _this._engine.screenToWorldCoordinates(new ex.Point(x, y)); var pe = new PointerEvent(transformedPoint.x, transformedPoint.y, index, _this._stringToPointerType(e.pointerType), e.button, e); eventArr.push(pe); - _this.at(index).eventDispatcher.publish(eventName, pe); + _this.at(index).eventDispatcher.emit(eventName, pe); // only with multi-pointer if (_this._pointers.length > 1) { if (eventName === 'up') { @@ -10688,13 +11197,13 @@ var ex; * Keyboard input * * Working with the keyboard is easy in Excalibur. You can inspect - * whether a button is [[Keyboard.isKeyDown|down]], [[Keyboard.isKeyUp|up]], or - * [[Keyboard.isKeyPressed|pressed]]. Common keys are held in the [[Input.Keys]] + * whether a button was just [[Keyboard.wasPressed|pressed]] or [[Keyboard.wasReleased|released]] this frame, or + * if the key is currently being [[Keyboard.isHeld|held]] down. Common keys are held in the [[Input.Keys]] * enumeration but you can pass any character code to the methods. * * Excalibur subscribes to the browser events and keeps track of - * what keys are currently down, up, or pressed. A key can be pressed - * for multiple frames, but a key cannot be down or up for more than one + * what keys are currently held, released, or pressed. A key can be held + * for multiple frames, but a key cannot be pressed or released for more than one subsequent * update frame. * * ## Inspecting the keyboard @@ -10702,19 +11211,36 @@ var ex; * You can inspect [[Engine.input]] to see what the state of the keyboard * is during an update. * + * It is recommended that keyboard actions that directly effect actors be handled like so to improve code quality: * ```ts * class Player extends ex.Actor { * public update(engine, delta) { * - * if (engine.input.keyboard.isKeyPressed(ex.Input.Keys.W) || - * engine.input.keyboard.isKeyPressed(ex.Input.Keys.Up)) { + * if (engine.input.keyboard.isHeld(ex.Input.Keys.W) || + * engine.input.keyboard.isHeld(ex.Input.Keys.Up)) { * * player._moveForward(); * } * + * if (engine.input.keyboard.wasPressed(ex.Input.Keys.Right)) { + * player._fire(); + * } * } * } * ``` + * ## Events + * You can subscribe to keyboard events through `engine.input.keyboard.on`. A [[KeyEvent]] object is + * passed to your handler which offers information about the key that was part of the event. + * + * - `press` - When a key was just pressed this frame + * - `release` - When a key was just released this frame + * - `hold` - Whenever a key is in the down position + * + * ```ts + * engine.input.pointers.primary.on("press", (evt: KeyEvent) => {...}); + * engine.input.pointers.primary.on("release", (evt: KeyEvent) => {...}); + * engine.input.pointers.primary.on("hold", (evt: KeyEvent) => {...}); + * ``` */ var Keyboard = (function (_super) { __extends(Keyboard, _super); @@ -10739,7 +11265,9 @@ var ex; _this._keys.splice(key, 1); _this._keysUp.push(ev.keyCode); var keyEvent = new KeyEvent(ev.keyCode); - _this.eventDispatcher.publish('up', keyEvent); + // alias the old api, we may want to deprecate this in the future + _this.eventDispatcher.emit('up', keyEvent); + _this.eventDispatcher.emit('release', keyEvent); }); // key down is on window because canvas cannot have focus window.addEventListener('keydown', function (ev) { @@ -10747,7 +11275,8 @@ var ex; _this._keys.push(ev.keyCode); _this._keysDown.push(ev.keyCode); var keyEvent = new KeyEvent(ev.keyCode); - _this.eventDispatcher.publish('down', keyEvent); + _this.eventDispatcher.emit('down', keyEvent); + _this.eventDispatcher.emit('press', keyEvent); } }); }; @@ -10755,6 +11284,10 @@ var ex; // Reset keysDown and keysUp after update is complete this._keysDown.length = 0; this._keysUp.length = 0; + // Emit synthetic "hold" event + for (var i = 0; i < this._keys.length; i++) { + this.eventDispatcher.emit('hold', new KeyEvent(this._keys[i])); + } }; /** * Gets list of keys being pressed down @@ -10763,24 +11296,24 @@ var ex; return this._keys; }; /** - * Tests if a certain key is down. This is cleared at the end of the update frame. - * @param key Test wether a key is down + * Tests if a certain key was just pressed this frame. This is cleared at the end of the update frame. + * @param key Test wether a key was just pressed */ - Keyboard.prototype.isKeyDown = function (key) { + Keyboard.prototype.wasPressed = function (key) { return this._keysDown.indexOf(key) > -1; }; /** - * Tests if a certain key is pressed. This is persisted between frames. - * @param key Test wether a key is pressed + * Tests if a certain key is held down. This is persisted between frames. + * @param key Test wether a key is held down */ - Keyboard.prototype.isKeyPressed = function (key) { + Keyboard.prototype.isHeld = function (key) { return this._keys.indexOf(key) > -1; }; /** - * Tests if a certain key is up. This is cleared at the end of the update frame. - * @param key Test wether a key is up + * Tests if a certain key was just released this frame. This is cleared at the end of the update frame. + * @param key Test wether a key was just released */ - Keyboard.prototype.isKeyUp = function (key) { + Keyboard.prototype.wasReleased = function (key) { return this._keysUp.indexOf(key) > -1; }; return Keyboard; @@ -10801,11 +11334,60 @@ var ex; * You can query any [[Gamepad|Gamepads]] that are connected or listen to events ("button" and "axis"). * * You must opt-in to controller support ([[Gamepads.enabled]]) because it is a polling-based - * API, so we have to check it each update frame. + * API, so we have to check it each update frame. If an gamepad related event handler is set, you will + * automatically opt-in to controller polling. * - * Any number of gamepads are supported using the [[Gamepads.at]] method. If a [[Gamepad]] is + * HTML5 Gamepad API only supports a maximum of 4 gamepads. You can access them using the [[Gamepads.at]] method. If a [[Gamepad]] is * not connected, it will simply not throw events. * + * ## Gamepad Filtering + * + * Different browsers/devices are sometimes loose about the devices they consider Gamepads, you can set minimum device requirements with + * `engine.inpute.gamepads.setMinimumGamepadConfiguration` so that undesired devices are not reported to you (Touchpads, Mice, Web + * Cameras, etc.). + * ```js + * // ensures that only gamepads with at least 4 axis and 8 buttons are reported for events + * engine.input.gamepads.setMinimumGamepadConfiguration({ + * axis: 4, + * buttons: 8 + * }); + * ``` + * + * ## Events + * + * You can subscribe to gamepad connect and disconnect events through `engine.input.gamepads.on`. + * A [[GamepadConnectEvent]] or [[GamepadDisconnectEvent]] will be passed to you. + * + * - `connect` - When a gamepad connects it will fire this event and pass a [[GamepadConnectEvent]] with a reference to the gamepad. + * - `disconnect` - When a gamepad disconnects it will fire this event and pass a [[GamepadDisconnectEvent]] + * + * Once you have a reference to a gamepad you may listen to changes on that gamepad with `.on`. A [[GamepadButtonEvent]] or + * [[GamepadAxisEvent]] will be passed to you. + * - `button` - Whenever a button is pressed on the game + * - `axis` - Whenever an axis + * + * ```ts + * + * engine.input.gamepads.on('connect', (ce: ex.Input.GamepadConnectEvent) => { + * var newPlayer = CreateNewPlayer(); // pseudo-code for new player logic on gamepad connection + * console.log("Gamepad connected", ce); + * ce.gamepad.on('button', (be: ex.GamepadButtonEvent) => { + * if(be.button === ex.Input.Buttons.Face1) { + * newPlayer.jump(); + * } + * }); + * + * ce.gamepad.on('axis', (ae: ex.GamepadAxisEvent) => { + * if(ae.axis === ex.Input.Axis.LeftStickX && ae.value > .5){ + * newPlayer.moveRight(); + * } + * }) + * + * }); + * + * + * ``` + * * ## Responding to button input * * [[Buttons|Gamepad buttons]] typically have values between 0 and 1, however depending on @@ -10889,6 +11471,7 @@ var ex; this._pads = []; this._initSuccess = false; this._navigator = navigator; + this._minimumConfiguration = null; this._engine = engine; } Gamepads.prototype.init = function () { @@ -10905,6 +11488,55 @@ var ex; this._initSuccess = true; } }; + /** + * Sets the minimum gamepad configuration, for example {axis: 4, buttons: 4} means + * this game requires at minimum 4 axis inputs and 4 buttons, this is not restrictive + * all other controllers with more axis or buttons are valid as well. If no minimum + * configuration is set all pads are valid. + */ + Gamepads.prototype.setMinimumGamepadConfiguration = function (config) { + this._enableAndUpdate(); // if config is used, implicitely enable + this._minimumConfiguration = config; + }; + /** + * When implicitely enabled, set the enabled flag and run an update so information is updated + */ + Gamepads.prototype._enableAndUpdate = function () { + if (!this.enabled) { + this.enabled = true; + this.update(100); + } + }; + /** + * Checks a navigator gamepad against the minimum configuration if present. + */ + Gamepads.prototype._isGamepadValid = function (pad) { + if (!this._minimumConfiguration) { + return true; + } + ; + if (!pad) { + return false; + } + ; + var axesLength = pad.axes.filter(function (value, index, array) { + return (typeof value !== undefined); + }).length; + var buttonLength = pad.buttons.filter(function (value, index, array) { + return (typeof value !== undefined); + }).length; + return axesLength >= this._minimumConfiguration.axis && + buttonLength >= this._minimumConfiguration.buttons && + pad.connected; + }; + Gamepads.prototype.on = function (eventName, handler) { + this._enableAndUpdate(); // implicitly enable + _super.prototype.on.call(this, eventName, handler); + }; + Gamepads.prototype.off = function (eventName, handler) { + this._enableAndUpdate(); // implicitly enable + _super.prototype.off.call(this, eventName, handler); + }; /** * Updates Gamepad state and publishes Gamepad events */ @@ -10916,11 +11548,18 @@ var ex; var gamepads = this._navigator.getGamepads(); for (var i = 0; i < gamepads.length; i++) { if (!gamepads[i]) { + // If was connected, but now isn't emit the disconnect event + if (this.at(i).connected) { + this.eventDispatcher.emit('disconnect', new ex.GamepadDisconnectEvent(i)); + } // Reset connection status this.at(i).connected = false; continue; } else { + if (!this.at(i).connected && this._isGamepadValid(gamepads[i])) { + this.eventDispatcher.emit('connect', new ex.GamepadConnectEvent(i, this.at(i))); + } // Set connection status this.at(i).connected = true; } @@ -10930,6 +11569,8 @@ var ex; continue; } this._gamePadTimeStamps[i] = gamepads[i].timestamp; + // Add reference to navigator gamepad + this.at(i).navigatorGamepad = gamepads[i]; // Buttons var b, a, value, buttonIndex, axesIndex; for (b in Buttons) { @@ -10937,14 +11578,16 @@ var ex; continue; } buttonIndex = Buttons[b]; - value = gamepads[i].buttons[buttonIndex].value; - if (value !== this._oldPads[i].getButton(buttonIndex)) { - if (gamepads[i].buttons[buttonIndex].pressed) { - this.at(i).updateButton(buttonIndex, value); - this.at(i).eventDispatcher.publish('button', new GamepadButtonEvent(buttonIndex, value)); - } - else { - this.at(i).updateButton(buttonIndex, 0); + if (gamepads[i].buttons[buttonIndex]) { + value = gamepads[i].buttons[buttonIndex].value; + if (value !== this._oldPads[i].getButton(buttonIndex)) { + if (gamepads[i].buttons[buttonIndex].pressed) { + this.at(i).updateButton(buttonIndex, value); + this.at(i).eventDispatcher.publish('button', new ex.GamepadButtonEvent(buttonIndex, value)); + } + else { + this.at(i).updateButton(buttonIndex, 0); + } } } } @@ -10957,7 +11600,7 @@ var ex; value = gamepads[i].axes[axesIndex]; if (value !== this._oldPads[i].getAxes(axesIndex)) { this.at(i).updateAxes(axesIndex, value); - this.at(i).eventDispatcher.publish('axis', new GamepadAxisEvent(axesIndex, value)); + this.at(i).eventDispatcher.emit('axis', new ex.GamepadAxisEvent(axesIndex, value)); } } this._oldPads[i] = this._clonePad(gamepads[i]); @@ -10967,6 +11610,7 @@ var ex; * Safely retrieves a Gamepad at a specific index and creates one if it doesn't yet exist */ Gamepads.prototype.at = function (index) { + this._enableAndUpdate(); // implicitly enable gamepads when at() is called if (index >= this._pads.length) { // Ensure there is a pad to retrieve for (var i = this._pads.length - 1, max = index; i < max; i++) { @@ -10976,6 +11620,19 @@ var ex; } return this._pads[index]; }; + /** + * Returns a list of all valid gamepads that meet the minimum configuration requirment. + */ + Gamepads.prototype.getValidGamepads = function () { + this._enableAndUpdate(); + var result = []; + for (var i = 0; i < this._pads.length; i++) { + if (this._isGamepadValid(this.at(i).navigatorGamepad) && this.at(i).connected) { + result.push(this.at(i)); + } + } + return result; + }; /** * Gets the number of connected gamepads */ @@ -10999,7 +11656,9 @@ var ex; return clonedPad; } for (i = 0, len = pad.buttons.length; i < len; i++) { - clonedPad.updateButton(i, pad.buttons[i].value); + if (pad.buttons[i]) { + clonedPad.updateButton(i, pad.buttons[i].value); + } } for (i = 0, len = pad.axes.length; i < len; i++) { clonedPad.updateAxes(i, pad.axes[i]); @@ -11161,40 +11820,6 @@ var ex; Axes[Axes["RightStickY"] = 3] = "RightStickY"; })(Input.Axes || (Input.Axes = {})); var Axes = Input.Axes; - /** - * Gamepad button event. See [[Gamepads]] for information on responding to controller input. - */ - var GamepadButtonEvent = (function (_super) { - __extends(GamepadButtonEvent, _super); - /** - * @param button The Gamepad button - * @param value A numeric value between 0 and 1 - */ - function GamepadButtonEvent(button, value) { - _super.call(this); - this.button = button; - this.value = value; - } - return GamepadButtonEvent; - })(ex.GameEvent); - Input.GamepadButtonEvent = GamepadButtonEvent; - /** - * Gamepad axis event. See [[Gamepads]] for information on responding to controller input. - */ - var GamepadAxisEvent = (function (_super) { - __extends(GamepadAxisEvent, _super); - /** - * @param axis The Gamepad axis - * @param value A numeric value between -1 and 1 - */ - function GamepadAxisEvent(axis, value) { - _super.call(this); - this.axis = axis; - this.value = value; - } - return GamepadAxisEvent; - })(ex.GameEvent); - Input.GamepadAxisEvent = GamepadAxisEvent; })(Input = ex.Input || (ex.Input = {})); })(ex || (ex = {})); /// @@ -11239,7 +11864,7 @@ var ex; * * ## Where to Start * - * These are the core concepts of Excalibur that you should be + * These are the core concepts of Excalibur that you should become * familiar with. * * - [[Engine|Intro to the Engine]] @@ -11278,6 +11903,7 @@ var ex; * - [[Sound|Working with Sounds]] * - [[SpriteSheet|Working with SpriteSheets]] * - [[Animation|Working with Animations]] + * - [[TileMap|Working with TileMaps]] * * ## Effects and Particles * @@ -11286,6 +11912,7 @@ var ex; * * - [[Effects|Sprite Effects]] * - [[ParticleEmitter|Particle Emitters]] + * - [[IPostProcessor|Post Processors]] * * ## Math * @@ -11341,9 +11968,11 @@ var ex; * * The Excalibur engine uses a simple main loop. The engine updates and renders * the "scene graph" which is the [[Scene|scenes]] and the tree of [[Actor|actors]] within that - * scene. Only one [[Scene]] can be active at once, the engine does not update/draw any other + * scene. Only one [[Scene]] can be active at a time. The engine does not update/draw any other * scene, which means any actors will not be updated/drawn if they are part of a deactivated scene. * + * ![Engine Lifecycle](/assets/images/docs/EngineLifeCycle.png) + * * **Scene Graph** * * ``` @@ -11362,13 +11991,13 @@ var ex; * * ### Update Loop * - * The first operation run is the [[Engine.update|update]] loop. [[Actor]] and [[Scene]] both implement + * The first operation run is the [[Engine._update|update]] loop. [[Actor]] and [[Scene]] both implement * an overridable/extendable `update` method. Use it to perform any logic-based operations * in your game for a particular class. * * ### Draw Loop * - * The next step is the [[Engine.draw|draw]] loop. A [[Scene]] loops through its child [[Actor|actors]] and + * The next step is the [[Engine._draw|draw]] loop. A [[Scene]] loops through its child [[Actor|actors]] and * draws each one. You can override the `draw` method on an actor to customize its drawing. * You should **not** perform any logic in a draw call, it should only relate to drawing. * @@ -11615,6 +12244,8 @@ var ex; * the [[currentScene]] may be drawn or updated. * * @param actor The actor to add to the [[currentScene]] + * + * @obsolete Use [[add]] instead. */ Engine.prototype.addChild = function (actor) { this.currentScene.addChild(actor); @@ -11741,17 +12372,17 @@ var ex; // only deactivate when initialized if (this.currentScene.isInitialized) { this.currentScene.onDeactivate.call(this.currentScene); - this.currentScene.eventDispatcher.publish('deactivate', new ex.DeactivateEvent(newScene)); + this.currentScene.eventDispatcher.emit('deactivate', new ex.DeactivateEvent(newScene)); } // set current scene to new one this.currentScene = newScene; if (!this.currentScene.isInitialized) { this.currentScene.onInitialize.call(this.currentScene, this); - this.currentScene.eventDispatcher.publish('initialize', new ex.InitializeEvent(this)); + this.currentScene.eventDispatcher.emit('initialize', new ex.InitializeEvent(this)); this.currentScene.isInitialized = true; } this.currentScene.onActivate.call(this.currentScene); - this.currentScene.eventDispatcher.publish('activate', new ex.ActivateEvent(oldScene)); + this.currentScene.eventDispatcher.emit('activate', new ex.ActivateEvent(oldScene)); } else { this._logger.error('Scene', key, 'does not exist!'); @@ -11861,11 +12492,11 @@ var ex; // https://developer.mozilla.org/en-US/docs/Web/Guide/User_experience/Using_the_Page_Visibility_API document.addEventListener('visibilitychange', function () { if (document.hidden || document.msHidden) { - _this.eventDispatcher.publish('hidden', new ex.HiddenEvent()); + _this.eventDispatcher.emit('hidden', new ex.HiddenEvent()); _this._logger.debug('Window hidden'); } else { - _this.eventDispatcher.publish('visible', new ex.VisibleEvent()); + _this.eventDispatcher.emit('visible', new ex.VisibleEvent()); _this._logger.debug('Window visible'); } }); @@ -11914,6 +12545,7 @@ var ex; // suspend updates untill loading is finished return; } + this.emit('preupdate', new ex.PreUpdateEvent(this, delta, this)); // process engine level events this.currentScene.update(this, delta); // update animations @@ -11925,7 +12557,8 @@ var ex; this.input.pointers.update(delta); this.input.gamepads.update(delta); // Publish update event - this.eventDispatcher.publish(ex.EventType[ex.EventType.Update], new ex.UpdateEvent(delta)); + this.eventDispatcher.emit('update', new ex.UpdateEvent(delta)); + this.emit('postupdate', new ex.PreUpdateEvent(this, delta, this)); }; /** * Draws the entire game @@ -11933,6 +12566,7 @@ var ex; */ Engine.prototype._draw = function (delta) { var ctx = this.ctx; + this.emit('predraw', new ex.PreDrawEvent(ctx, delta, this)); if (this._isLoading) { ctx.fillStyle = 'black'; ctx.fillRect(0, 0, this.width, this.height); @@ -11964,7 +12598,7 @@ var ex; for (var i = 0; i < this.postProcessors.length; i++) { this.postProcessors[i].process(this.ctx.getImageData(0, 0, this.width, this.height), this.ctx); } - //ctx.drawImage(currentImage, 0, 0, this.width, this.height); + this.emit('postdraw', new ex.PreDrawEvent(ctx, delta, this)); }; /** * Starts the internal game loop for Excalibur after loading @@ -12143,7 +12777,7 @@ var ex; return AnimationNode; })(); })(ex || (ex = {})); -//# sourceMappingURL=excalibur-0.5.1.js.map +//# sourceMappingURL=excalibur-0.6.0.js.map ; // Concatenated onto excalibur after build // Exports the excalibur module so it can be used with browserify diff --git a/dist/excalibur-0.6.0.min.js b/dist/excalibur-0.6.0.min.js new file mode 100644 index 000000000..dba61a9b9 --- /dev/null +++ b/dist/excalibur-0.6.0.min.js @@ -0,0 +1,14 @@ +/*! excalibur - v0.6.0 - 2016-01-19 +* https://github.com/excaliburjs/Excalibur +* Copyright (c) 2016 ; Licensed BSD-2-Clause*/ +"undefined"==typeof window&&(window={audioContext:function(){}}),"undefined"==typeof window||window.requestAnimationFrame||(window.requestAnimationFrame=window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||function(t){window.setInterval(t,1e3/60)}),"undefined"==typeof window||window.cancelAnimationFrame||(window.cancelAnimationFrame=window.webkitCancelAnimationFrame||window.mozCancelAnimationFrame||function(){}),"undefined"==typeof window||window.AudioContext||(window.AudioContext=window.AudioContext||window.webkitAudioContext||window.mozAudioContext||window.msAudioContext||window.oAudioContext),Array.prototype.forEach||(Array.prototype.forEach=function(t,e){var i,n;if(null==this)throw new TypeError(" this is null or not defined");var s=Object(this),o=s.length>>>0;if("function"!=typeof t)throw new TypeError(t+" is not a function");for(arguments.length>1&&(i=e),n=0;o>n;){var r;n in s&&(r=s[n],t.call(i,r,n,s)),n++}}),Array.prototype.some||(Array.prototype.some=function(t){"use strict";if(void 0===this||null===this)throw new TypeError;var e=Object(this),i=e.length>>>0;if("function"!=typeof t)throw new TypeError;for(var n=arguments.length>=2?arguments[1]:void 0,s=0;i>s;s++)if(s in e&&t.call(n,e[s],s,e))return!0;return!1}),Function.prototype.bind||(Function.prototype.bind=function(t){if("function"!=typeof this)throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");var e=Array.prototype.slice.call(arguments,1),i=this,n=function(){},s=function(){return i.apply(this instanceof n&&t?this:t,e.concat(Array.prototype.slice.call(arguments)))};return n.prototype=this.prototype,s.prototype=new n,s});var ex;(function(t){var e;(function(e){var i=function(){function t(){}return t.prototype.updatePixel=function(t,e,i){var n=4*(t+e*i.width),s=i.data,o=(s[n+0]+s[n+1]+s[n+2])/3;s[n+0]=o,s[n+1]=o,s[n+2]=o},t}();e.Grayscale=i;var n=function(){function t(){}return t.prototype.updatePixel=function(t,e,i){var n=4*(t+e*i.width),s=i.data;s[n+0]=255-s[n+0],s[n+1]=255-s[n+1],s[n+2]=255-s[n+2]},t}();e.Invert=n;var s=function(){function t(t){this.opacity=t}return t.prototype.updatePixel=function(t,e,i){var n=4*(t+e*i.width),s=i.data;0!==s[n+3]&&(s[n+3]=Math.round(255*this.opacity))},t}();e.Opacity=s;var o=function(){function t(t){this.color=t}return t.prototype.updatePixel=function(t,e,i){var n=4*(t+e*i.width),s=i.data;0!==s[n+3]&&(s[n+0]=(s[n+0]+this.color.r)/2,s[n+1]=(s[n+1]+this.color.g)/2,s[n+2]=(s[n+2]+this.color.b)/2)},t}();e.Colorize=o;var r=function(){function e(t){void 0===t&&(t=.1),this.factor=t}return e.prototype.updatePixel=function(e,i,n){var s=4*(e+i*n.width),o=n.data,r=t.Color.fromRGB(o[s+0],o[s+1],o[s+2],o[s+3]).lighten(this.factor);o[s+0]=r.r,o[s+1]=r.g,o[s+2]=r.b,o[s+3]=r.a},e}();e.Lighten=r;var h=function(){function e(t){void 0===t&&(t=.1),this.factor=t}return e.prototype.updatePixel=function(e,i,n){var s=4*(e+i*n.width),o=n.data,r=t.Color.fromRGB(o[s+0],o[s+1],o[s+2],o[s+3]).darken(this.factor);o[s+0]=r.r,o[s+1]=r.g,o[s+2]=r.b,o[s+3]=r.a},e}();e.Darken=h;var a=function(){function e(t){void 0===t&&(t=.1),this.factor=t}return e.prototype.updatePixel=function(e,i,n){var s=4*(e+i*n.width),o=n.data,r=t.Color.fromRGB(o[s+0],o[s+1],o[s+2],o[s+3]).saturate(this.factor);o[s+0]=r.r,o[s+1]=r.g,o[s+2]=r.b,o[s+3]=r.a},e}();e.Saturate=a;var c=function(){function e(t){void 0===t&&(t=.1),this.factor=t}return e.prototype.updatePixel=function(e,i,n){var s=4*(e+i*n.width),o=n.data,r=t.Color.fromRGB(o[s+0],o[s+1],o[s+2],o[s+3]).desaturate(this.factor);o[s+0]=r.r,o[s+1]=r.g,o[s+2]=r.b,o[s+3]=r.a},e}();e.Desaturate=c;var l=function(){function t(t){this.color=t}return t.prototype.updatePixel=function(t,e,i){var n=4*(t+e*i.width),s=i.data;0!==s[n+3]&&(s[n+0]=this.color.r,s[n+1]=this.color.g,s[n+2]=this.color.b)},t}();e.Fill=l})(e=t.Effects||(t.Effects={}))})(ex||(ex={}));var ex;(function(t){var e;(function(t){var e=function(){function t(){}return t.prototype.update=function(t,e,i){t.x+=t.dx*i/1e3,t.y+=t.dy*i/1e3,t.dx+=t.ax*i/1e3,t.dy+=t.ay*i/1e3,t.rotation+=t.rx*i/1e3,t.scale.x+=t.sx*i/1e3,t.scale.y+=t.sy*i/1e3},t}();t.Movement=e})(e=t.Traits||(t.Traits={}))})(ex||(ex={}));var ex;(function(t){var e=function(){function e(){this._topLeft=new t.Point(0,0),this._topRight=new t.Point(0,0),this._bottomLeft=new t.Point(0,0),this._bottomRight=new t.Point(0,0)}return e.prototype.isSpriteOffScreen=function(e,i){var n=e.currentDrawing.width*e.currentDrawing.scale.x,s=e.currentDrawing.height*e.currentDrawing.scale.y,o=e.rotation,r=e.getCenter().toPoint();this._topLeft.x=e.getWorldX()-n/2,this._topLeft.y=e.getWorldY()-s/2,this._topLeft=this._topLeft.rotate(o,r),this._topRight.x=e.getWorldX()+n/2,this._topRight.y=e.getWorldY()-s/2,this._topRight=this._topRight.rotate(o,r),this._bottomLeft.x=e.getWorldX()-n/2,this._bottomLeft.y=e.getWorldY()+s/2,this._bottomLeft=this._bottomLeft.rotate(o,r),this._bottomRight.x=e.getWorldX()+n/2,this._bottomRight.y=e.getWorldY()+s/2,this._bottomRight=this._bottomRight.rotate(o,r);var h=i.worldToScreenCoordinates(this._topLeft),a=i.worldToScreenCoordinates(this._topRight),c=i.worldToScreenCoordinates(this._bottomLeft),l=i.worldToScreenCoordinates(this._bottomRight);this._xCoords=[],this._yCoords=[],this._xCoords.push(h.x,a.x,c.x,l.x),this._yCoords.push(h.y,a.y,c.y,l.y),this._xMin=Math.min.apply(null,this._xCoords),this._yMin=Math.min.apply(null,this._yCoords),this._xMax=Math.max.apply(null,this._xCoords),this._yMax=Math.max.apply(null,this._yCoords);var u=i.screenToWorldCoordinates(new t.Point(this._xMin,this._yMin)),p=i.screenToWorldCoordinates(new t.Point(this._xMax,this._yMax));this._xMinWorld=u.x,this._yMinWorld=u.y,this._xMaxWorld=p.x,this._yMaxWorld=p.y;var d=[];d.push(new t.Point(this._xMin,this._yMin),new t.Point(this._xMax,this._yMin),new t.Point(this._xMin,this._yMax),new t.Point(this._xMax,this._yMax));for(var f=0;d.length>f;f++)if(d[f].x>0&&d[f].y>0&&d[f].x0&&a.y+h*c>0&&a.xa.x+r*c||0>a.y+h*c||a.x>i.width||a.y>i.height)&&l&&(n.emit("exitviewport",new t.ExitViewPortEvent),e.isOffScreen=!0)},e}();e.OffscreenCulling=i})(e=t.Traits||(t.Traits={}))})(ex||(ex={}));var ex;(function(t){var e;(function(t){var e=function(){function t(){}return t.prototype.update=function(t,e){t.enableCapturePointer&&(t.isKilled()||e.input.pointers.propogate(t))},t}();t.CapturePointer=e})(e=t.Traits||(t.Traits={}))})(ex||(ex={}));var ex;(function(t){var e;(function(e){var i=function(){function e(){}return e.prototype.update=function(e,i){var n=e.eventDispatcher;if(e.collisionType!==t.CollisionType.PreventCollision&&i.currentScene&&i.currentScene.tileMaps)for(var s=0;i.currentScene.tileMaps.length>s;s++)for(var o,r=i.currentScene.tileMaps[s],h=t.Side.None,a=2,c=!1;(o=r.collides(e))&&!(0>a--);)h=e.getSideFromIntersect(o),n.emit("collision",new t.CollisionEvent(e,null,h,o)),(e.collisionType===t.CollisionType.Active||e.collisionType===t.CollisionType.Elastic)&&(e.y+=o.y,e.x+=o.x,e.collisionType!==t.CollisionType.Elastic||c||(c=!0,h===t.Side.Left?e.dx=Math.abs(e.dx):h===t.Side.Right?e.dx=-Math.abs(e.dx):h===t.Side.Top?e.dy=Math.abs(e.dy):h===t.Side.Bottom&&(e.dy=-Math.abs(e.dy))))},e}();e.CollisionDetection=i})(e=t.Traits||(t.Traits={}))})(ex||(ex={}));var ex;(function(t){(function(t){t[t.None=0]="None",t[t.Top=1]="Top",t[t.Bottom=2]="Bottom",t[t.Left=3]="Left",t[t.Right=4]="Right"})(t.Side||(t.Side={})),t.Side})(ex||(ex={}));var __extends=this&&this.__extends||function(t,e){function i(){this.constructor=t}for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n]);t.prototype=null===e?Object.create(e):(i.prototype=e.prototype,new i)},ex;(function(t){var e=function(){function e(t,e){this.x=t,this.y=e}return e.prototype.toVector=function(){return new i(this.x,this.y)},e.prototype.rotate=function(i,n){n||(n=new t.Point(0,0));var s=Math.sin(i),o=Math.cos(i),r=o*(this.x-n.x)-s*(this.y-n.y)+n.x,h=s*(this.x-n.x)+o*(this.y-n.y)+n.y;return new e(r,h)},e.prototype.add=function(t){return new e(this.x+t.x,this.y+t.y)},e.prototype.setTo=function(t,e){this.x=t,this.y=e},e.prototype.clone=function(){return new e(this.x,this.y)},e.prototype.equals=function(t){return this.x===t.x&&this.y===t.y},e}();t.Point=e;var i=function(t){function i(e,i){t.call(this,e,i),this.x=e,this.y=i}return __extends(i,t),i.fromAngle=function(t){return new i(Math.cos(t),Math.sin(t))},i.prototype.distance=function(t){return t||(t=new i(0,0)),Math.sqrt(Math.pow(this.x-t.x,2)+Math.pow(this.y-t.y,2))},i.prototype.normalize=function(){var t=this.distance();return t>0?new i(this.x/t,this.y/t):new i(0,1)},i.prototype.scale=function(t){return new i(this.x*t,this.y*t)},i.prototype.plus=function(t){return this.add(t)},i.prototype.add=function(t){return new i(this.x+t.x,this.y+t.y)},i.prototype.subtract=function(t){return this.minus(t)},i.prototype.minus=function(t){return new i(this.x-t.x,this.y-t.y)},i.prototype.dot=function(t){return this.x*t.x+this.y*t.y},i.prototype.cross=function(t){return this.x*t.y-this.y*t.x},i.prototype.perpendicular=function(){return new i(this.y,-this.x)},i.prototype.normal=function(){return this.perpendicular().normalize()},i.prototype.toAngle=function(){return Math.atan2(this.y,this.x)},i.prototype.toPoint=function(){return new e(this.x,this.y)},i.prototype.rotate=function(e,i){return t.prototype.rotate.call(this,e,i).toVector()},i.prototype.clone=function(){return new i(this.x,this.y)},i.Zero=new i(0,0),i}(e);t.Vector=i;var n=function(){function t(t,e){this.pos=t,this.dir=e.normalize()}return t.prototype.intersect=function(t){var e=t.begin.toVector().minus(this.pos.toVector());if(0===this.dir.cross(t.getSlope())&&0!==e.cross(this.dir))return-1;var i=this.dir.cross(t.getSlope());if(0===i)return-1;var n=e.cross(t.getSlope())/i;if(n>=0){var s=e.cross(this.dir)/i/t.getLength();if(s>=0&&1>=s)return n}return-1},t.prototype.getPoint=function(t){return this.pos.toVector().add(this.dir.scale(t)).toPoint()},t}();t.Ray=n;var s=function(){function t(t,e){this.begin=t,this.end=e}return t.prototype.getSlope=function(){var t=this.begin.toVector(),e=this.end.toVector(),i=t.distance(e);return e.minus(t).scale(1/i)},t.prototype.getLength=function(){var t=this.begin.toVector(),e=this.end.toVector(),i=t.distance(e);return i},t}();t.Line=s;var o=function(){function t(t,e){this.min=t,this.max=e}return t.prototype.overlaps=function(t){return this.max>t.min&&t.max>this.min},t.prototype.getOverlap=function(t){return this.overlaps(t)?this.max>t.max?t.max-this.min:this.max-t.min:0},t}();t.Projection=o})(ex||(ex={}));var ex;(function(t){var e;(function(e){function i(t){for(var e="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",i="",n=0;t.length>n;){var s,o,r=255&t.charCodeAt(n++),h=255&t.charCodeAt(n++),a=255&t.charCodeAt(n++),c=r>>2,l=(3&r)<<4|h>>4;isNaN(h)?s=o=64:(s=(15&h)<<2|a>>6,o=isNaN(a)?64:63&a),i+=e.charAt(c)+e.charAt(l)+e.charAt(s)+e.charAt(o)}return i}function n(t,e,i){return e>=t?e:t>=i?i:t}function s(t,e,i,n,s,o){t.beginPath(),t.strokeStyle=e,t.moveTo(i,n),t.lineTo(s,o),t.closePath(),t.stroke()}function o(t,e){return t+Math.random()*(e-t)}function r(t,e){return Math.round(o(t,e))}function h(t){var e=t;if(t>this.TwoPI)for(;e>this.TwoPI;)e-=this.TwoPI;if(0>t)for(;0>e;)e+=this.TwoPI;return e}function a(t){return 180/Math.PI*t}function c(t){return t/180*Math.PI}function l(e){var i=0,n=0,s=function(t){i+=t.offsetLeft,t.offsetParent&&s(t.offsetParent)},o=function(t){n+=t.offsetTop,t.offsetParent&&o(t.offsetParent)};return s(e),o(e),new t.Point(i,n)}function u(t,e){return-1===e.indexOf(t)?(e.push(t),!0):!1}function p(t,e){var i=-1;return(i=e.indexOf(t))>-1?(e.splice(i,1),!0):!1}function d(t,e){for(var i=0;t.length>i;i++)if(t[i]===e)return!0;return!1}function f(e){return e===t.Side.Top?t.Side.Bottom:e===t.Side.Bottom?t.Side.Top:e===t.Side.Left?t.Side.Right:e===t.Side.Right?t.Side.Left:t.Side.None}e.TwoPI=2*Math.PI,e.base64Encode=i,e.clamp=n,e.drawLine=s,e.randomInRange=o,e.randomIntInRange=r,e.canonicalizeAngle=h,e.toDegrees=a,e.toRadians=c,e.getPosition=l,e.addItemToArray=u,e.removeItemToArray=p,e.contains=d,e.getOppositeSide=f;var g=function(){function t(e){void 0===e&&(e=t.DefaultSize),this._internalArray=null,this._endPointer=0,this._internalArray=Array(e)}return t.prototype._resize=function(){for(var t=2*this._internalArray.length,e=Array(t),i=this.count(),n=0;i>n;n++)e[n]=this._internalArray[n];delete this._internalArray,this._internalArray=e},t.prototype.push=function(t){return this._endPointer===this._internalArray.length&&this._resize(),this._internalArray[this._endPointer++]=t},t.prototype.pop=function(){return this._endPointer=0>this._endPointer-1?0:this._endPointer-1,this._internalArray[this._endPointer]},t.prototype.count=function(){return this._endPointer},t.prototype.clear=function(){this._endPointer=0},t.prototype.internalSize=function(){return this._internalArray.length},t.prototype.elementAt=function(t){return t>=this.count()?void 0:this._internalArray[t]},t.prototype.insert=function(t,e){return t>=this.count()&&this._resize(),this._internalArray[t]=e},t.prototype.remove=function(t){var e=this.count();if(0!==e){for(var i=this._internalArray[t],n=t;e>n;n++)this._internalArray[n]=this._internalArray[n+1];return this._endPointer--,i}},t.prototype.removeElement=function(t){var e=this._internalArray.indexOf(t);this.remove(e)},t.prototype.toArray=function(){return this._internalArray.slice(0,this._endPointer)},t.prototype.forEach=function(t){var e=0,i=this.count();for(e;i>e;e++)t.call(this,this._internalArray[e],e)},t.prototype.map=function(t){for(var e=this.count(),i=0;e>i;i++)this._internalArray[i]=t.call(this,this._internalArray[i],i)},t.DefaultSize=200,t}();e.Collection=g})(e=t.Util||(t.Util={}))})(ex||(ex={}));var ex;(function(t){var e=function(){function e(e,i,n,s,o){var r=this;this.sx=i,this.sy=n,this.swidth=s,this.sheight=o,this.rotation=0,this.anchor=new t.Point(0,0),this.scale=new t.Point(1,1),this.logger=t.Logger.getInstance(),this.flipVertical=!1,this.flipHorizontal=!1,this.width=0,this.height=0,this.effects=[],this.internalImage=new Image,this.naturalWidth=0,this.naturalHeight=0,this._spriteCanvas=null,this._spriteCtx=null,this._pixelData=null,this._pixelsLoaded=!1,this._dirtyEffect=!1,(0>i||0>n||0>s||0>o)&&this.logger.error("Sprite cannot have any negative dimensions x:",i,"y:",n,"width:",s,"height:",o),this._texture=e,this._spriteCanvas=document.createElement("canvas"),this._spriteCanvas.width=s,this._spriteCanvas.height=o,this._spriteCtx=this._spriteCanvas.getContext("2d"),this._texture.loaded.then(function(){r._spriteCanvas.width=r._spriteCanvas.width||r._texture.image.naturalWidth,r._spriteCanvas.height=r._spriteCanvas.height||r._texture.image.naturalHeight,r._loadPixels(),r._dirtyEffect=!0}).error(function(t){r.logger.error("Error loading texture ",r._texture.path,t)}),this.width=s,this.height=o,this.naturalWidth=s,this.naturalHeight=o}return e.prototype._loadPixels=function(){if(this._texture.isLoaded()&&!this._pixelsLoaded){var e=t.Util.clamp,i=this._texture.image.naturalWidth||0,n=this._texture.image.naturalHeight||0;this.swidth>i&&this.logger.warn("The sprite width",this.swidth,"exceeds the width",i,"of the backing texture",this._texture.path),this.sheight>n&&this.logger.warn("The sprite height",this.sheight,"exceeds the height",n,"of the backing texture",this._texture.path),this._spriteCtx.drawImage(this._texture.image,e(this.sx,0,i),e(this.sy,0,n),e(this.swidth,0,i),e(this.sheight,0,n),0,0,this.swidth,this.sheight),this.internalImage.src=this._spriteCanvas.toDataURL("image/png"),this._pixelsLoaded=!0}},e.prototype.opacity=function(e){this.addEffect(new t.Effects.Opacity(e))},e.prototype.grayscale=function(){this.addEffect(new t.Effects.Grayscale)},e.prototype.invert=function(){this.addEffect(new t.Effects.Invert)},e.prototype.fill=function(e){this.addEffect(new t.Effects.Fill(e))},e.prototype.colorize=function(e){this.addEffect(new t.Effects.Colorize(e))},e.prototype.lighten=function(e){void 0===e&&(e=.1),this.addEffect(new t.Effects.Lighten(e))},e.prototype.darken=function(e){void 0===e&&(e=.1),this.addEffect(new t.Effects.Darken(e))},e.prototype.saturate=function(e){void 0===e&&(e=.1),this.addEffect(new t.Effects.Saturate(e))},e.prototype.desaturate=function(e){void 0===e&&(e=.1),this.addEffect(new t.Effects.Desaturate(e))},e.prototype.addEffect=function(t){this.effects.push(t),this._texture.isLoaded()&&this._pixelsLoaded?this._applyEffects():this._dirtyEffect=!0},e.prototype.removeEffect=function(t){var e=null;e="number"==typeof t?t:this.effects.indexOf(t),this.effects.splice(e,1),this._texture.isLoaded()&&this._pixelsLoaded?this._applyEffects():this._dirtyEffect=!0},e.prototype._applyEffects=function(){var e=t.Util.clamp,i=this._texture.image.naturalWidth||0,n=this._texture.image.naturalHeight||0;this._spriteCtx.clearRect(0,0,this.swidth,this.sheight),this._spriteCtx.drawImage(this._texture.image,e(this.sx,0,i),e(this.sy,0,n),e(this.swidth,0,i),e(this.sheight,0,n),0,0,this.swidth,this.sheight),this._pixelData=this._spriteCtx.getImageData(0,0,this.swidth,this.sheight);var s=0,o=0,r=0,h=this.effects.length;for(s;h>s;s++)for(r=0;this.sheight>r;r++)for(o=0;this.swidth>o;o++)this.effects[s].updatePixel(o,r,this._pixelData);this._spriteCtx.clearRect(0,0,this.swidth,this.sheight),this._spriteCtx.putImageData(this._pixelData,0,0),this.internalImage.src=this._spriteCanvas.toDataURL("image/png")},e.prototype.clearEffects=function(){this.effects.length=0,this._applyEffects()},e.prototype.reset=function(){},e.prototype.debugDraw=function(e,i,n){e.save(),e.translate(i,n),e.rotate(this.rotation);var s=this.width*this.scale.x*this.anchor.x,o=this.height*this.scale.y*this.anchor.y;e.strokeStyle=t.Color.Black,e.strokeRect(-s,-o,this.width*this.scale.x,this.height*this.scale.y),e.restore()},e.prototype.draw=function(t,e,i){this._dirtyEffect&&(this._applyEffects(),this._dirtyEffect=!1),this.width=this.naturalWidth*this.scale.x,this.height=this.naturalHeight*this.scale.y,t.save();var n=this.width*this.anchor.x,s=this.height*this.anchor.y;t.translate(e,i),t.rotate(this.rotation),this.flipHorizontal&&(t.translate(this.swidth*this.scale.x,0),t.scale(-1,1)),this.flipVertical&&(t.translate(0,this.sheight*this.scale.y),t.scale(1,-1)),this.internalImage&&t.drawImage(this.internalImage,0,0,this.swidth,this.sheight,-n,-s,this.swidth*this.scale.x,this.sheight*this.scale.y),t.restore()},e.prototype.clone=function(){var t=new e(this._texture,this.sx,this.sy,this.swidth,this.sheight);t.scale=this.scale.clone(),t.rotation=this.rotation,t.flipHorizontal=this.flipHorizontal,t.flipVertical=this.flipVertical;var i=0,n=this.effects.length;for(i;n>i;i++)t.addEffect(this.effects[i]);return t},e}();t.Sprite=e})(ex||(ex={}));var ex;(function(t){var e=function(){function e(e,i,n,s,o){this.image=e,this.columns=i,this.rows=n,this.sprites=[],this._internalImage=e.image,this.sprites=Array(i*n);var r=0,h=0;for(r=0;n>r;r++)for(h=0;i>h;h++)this.sprites[h+r*i]=new t.Sprite(this.image,h*s,r*o,s,o)}return e.prototype.getAnimationByIndices=function(e,i,n){var s=this,o=i.map(function(t){return s.sprites[t]});return o=o.map(function(t){return t.clone()}),new t.Animation(e,o,n)},e.prototype.getAnimationBetween=function(e,i,n,s){var o=this.sprites.slice(i,n);return o=o.map(function(t){return t.clone()}),new t.Animation(e,o,s)},e.prototype.getAnimationForAll=function(e,i){var n=this.sprites.map(function(t){return t.clone()});return new t.Animation(e,n,i)},e.prototype.getSprite=function(t){return t>=0&&this.sprites.length>t?this.sprites[t]:void 0},e}();t.SpriteSheet=e;var i=function(e){function i(i,n,s,o,r,h,a){e.call(this,i,o,r,h,a),this.image=i,this.alphabet=n,this.caseInsensitive=s,this.spWidth=h,this.spHeight=a,this._spriteLookup={},this._colorLookup={},this._currentColor=t.Color.Black.clone(),this._currentOpacity=1,this._sprites={},this._textShadowOn=!1,this._textShadowDirty=!0,this._textShadowColor=t.Color.Black.clone(),this._textShadowSprites={},this._shadowOffsetX=5,this._shadowOffsetY=5,this._sprites=this.getTextSprites()}return __extends(i,e),i.prototype.getTextSprites=function(){for(var t={},e=0;this.alphabet.length>e;e++){var i=this.alphabet[e];this.caseInsensitive&&(i=i.toLowerCase()),t[i]=this.sprites[e].clone()}return t},i.prototype.setTextShadow=function(t,e,i){this._textShadowOn=!0,this._shadowOffsetX=t,this._shadowOffsetY=e,this._textShadowColor=i.clone(),this._textShadowDirty=!0;for(var n in this._sprites)this._textShadowSprites[n]=this._sprites[n].clone()},i.prototype.useTextShadow=function(t){this._textShadowOn=t,t&&this.setTextShadow(5,5,this._textShadowColor)},i.prototype.draw=function(e,i,n,s,o){if(o=this._parseOptions(o),""+this._currentColor!=""+o.color||this._currentOpacity!==o.opacity){this._currentOpacity=o.opacity,this._currentColor=o.color;for(var r in this._sprites)this._sprites[r].clearEffects(),this._sprites[r].fill(o.color),this._sprites[r].opacity(o.opacity)}if(this._textShadowOn&&this._textShadowDirty&&this._textShadowColor){for(var h in this._textShadowSprites)this._textShadowSprites[h].clearEffects(),this._textShadowSprites[h].addEffect(new t.Effects.Fill(this._textShadowColor.clone()));this._textShadowDirty=!1}var a=this.sprites[0],c=a.sheight,l=o.fontSize/c,u=i.length*a.swidth*l+i.length*o.letterSpacing,p=n;o.textAlign===t.TextAlign.Left||o.textAlign===t.TextAlign.Start?p=n:o.textAlign===t.TextAlign.Right||o.textAlign===t.TextAlign.End?p=n-u:o.textAlign===t.TextAlign.Center&&(p=n-u/2);var d=s-c*l;o.baseAlign===t.BaseAlign.Top||o.baseAlign===t.BaseAlign.Hanging?d=s:o.baseAlign===t.BaseAlign.Ideographic||o.baseAlign===t.BaseAlign.Bottom||o.baseAlign===t.BaseAlign.Alphabetic?d=s-c*l:o.baseAlign===t.BaseAlign.Middle&&(d=s-c*l/2);for(var f=0;i.length>f;f++){var g=i[f];this.caseInsensitive&&(g=g.toLowerCase());try{this._textShadowOn&&(this._textShadowSprites[g].scale.x=l,this._textShadowSprites[g].scale.y=l,this._textShadowSprites[g].draw(e,p+this._shadowOffsetX,d+this._shadowOffsetY));var _=this._sprites[g];_.scale.x=l,_.scale.y=l,_.draw(e,p,d),p+=_.width+o.letterSpacing}catch(y){t.Logger.getInstance().error("SpriteFont Error drawing char "+g)}}},i.prototype._parseOptions=function(e){return{fontSize:e.fontSize||10,letterSpacing:e.letterSpacing||0,color:e.color||t.Color.Black.clone(),textAlign:void 0===typeof e.textAlign?t.TextAlign.Left:e.textAlign,baseAlign:void 0===typeof e.baseAlign?t.BaseAlign.Bottom:e.baseAlign,maxWidth:e.maxWidth||-1,opacity:e.opacity||0}},i}(e);t.SpriteFont=i})(ex||(ex={}));var ex;(function(t){var e=function(){function e(e,i,s,o,r,h){var a=this;this.x=e,this.y=i,this.cellWidth=s,this.cellHeight=o,this.rows=r,this.cols=h,this._collidingX=-1,this._collidingY=-1,this._onScreenXStart=0,this._onScreenXEnd=9999,this._onScreenYStart=0,this._onScreenYEnd=9999,this._spriteSheets={},this.logger=t.Logger.getInstance(),this.data=[],this.data=Array(r*h);for(var c=0;h>c;c++)for(var l=0;r>l;l++)(function(){var t=new n(c*s+e,l*o+i,s,o,c+l*h);a.data[c+l*h]=t})()}return e.prototype.registerSpriteSheet=function(t,e){this._spriteSheets[t]=e},e.prototype.collides=function(e){for(var i=e.x+e.getWidth(),n=e.y+e.getHeight(),s=e.getBounds(),o=[],r=s.left;i>=r;r+=Math.min(e.getWidth()/2,this.cellWidth/2))for(var h=s.top;n>=h;h+=Math.min(e.getHeight()/2,this.cellHeight/2)){var a=this.getCellByPoint(r,h);if(a&&a.solid){var c=s.collides(a.getBounds()),l=e.getCenter().minus(a.getCenter());c&&c.dot(l)>0&&o.push(c)}}if(0===o.length)return null;var u=o.reduce(function(e,i){var n=e.x,s=e.y;return Math.abs(e.x)t||0>e||t>=this.cols||e>=this.rows?null:this.data[t+e*this.cols]},e.prototype.getCellByPoint=function(t,e){t=Math.floor((t-this.x)/this.cellWidth),e=Math.floor((e-this.y)/this.cellHeight);var i=this.getCell(t,e);return t>=0&&e>=0&&this.cols>t&&this.rows>e&&i?i:null},e.prototype.update=function(e){var i=e.screenToWorldCoordinates(new t.Point(0,0)),n=e.screenToWorldCoordinates(new t.Point(e.canvas.clientWidth,e.canvas.clientHeight));this._onScreenXStart=Math.max(Math.floor(i.x/this.cellWidth)-2,0),this._onScreenYStart=Math.max(Math.floor((i.y-this.y)/this.cellHeight)-2,0),this._onScreenXEnd=Math.max(Math.floor(n.x/this.cellWidth)+2,0),this._onScreenYEnd=Math.max(Math.floor((n.y-this.y)/this.cellHeight)+2,0)},e.prototype.draw=function(t){t.save(),t.translate(this.x,this.y);var e,i,n,s=this._onScreenXStart,o=Math.min(this._onScreenXEnd,this.cols),r=this._onScreenYStart,h=Math.min(this._onScreenYEnd,this.rows);for(s;o>s;s++){for(r;h>r;r++)for(e=this.getCell(s,r).sprites.filter(function(t){return t.spriteId>-1}),i=0,n=e.length;n>i;i++){var a=this._spriteSheets[e[i].spriteSheetKey];if(a){var c=a.getSprite(e[i].spriteId);c?c.draw(t,s*this.cellWidth,r*this.cellHeight):this.logger.warn("Sprite does not exist for id",e[i].spriteId,"in sprite sheet",e[i].spriteSheetKey,c,a)}else this.logger.warn("Sprite sheet",e[i].spriteSheetKey,"does not exist",a)}r=this._onScreenYStart}t.restore()},e.prototype.debugDraw=function(e){var i=this.cols*this.cellWidth,n=this.rows*this.cellHeight;e.save(),e.strokeStyle=""+t.Color.Red;for(var s=0;this.cols+1>s;s++)e.beginPath(),e.moveTo(this.x+s*this.cellWidth,this.y),e.lineTo(this.x+s*this.cellWidth,this.y+n),e.stroke();for(var o=0;this.rows+1>o;o++)e.beginPath(),e.moveTo(this.x,this.y+o*this.cellHeight),e.lineTo(this.x+i,this.y+o*this.cellHeight),e.stroke();var r=t.Color.Red.clone();r.a=.3,this.data.filter(function(t){return t.solid}).forEach(function(t){e.fillStyle=""+r,e.fillRect(t.x,t.y,t.width,t.height)}),this._collidingY>-1&&this._collidingX>-1&&(e.fillStyle=""+t.Color.Cyan,e.fillRect(this.x+this._collidingX*this.cellWidth,this.y+this._collidingY*this.cellHeight,this.cellWidth,this.cellHeight)),e.restore()},e}();t.TileMap=e;var i=function(){function t(t,e){this.spriteSheetKey=t,this.spriteId=e}return t}();t.TileSprite=i;var n=function(){function e(e,i,n,s,o,r,h){void 0===r&&(r=!1),void 0===h&&(h=[]),this.x=e,this.y=i,this.width=n,this.height=s,this.index=o,this.solid=r,this.sprites=h,this._bounds=new t.BoundingBox(this.x,this.y,this.x+this.width,this.y+this.height)}return e.prototype.getBounds=function(){return this._bounds},e.prototype.getCenter=function(){return new t.Vector(this.x+this.width/2,this.y+this.height/2)},e.prototype.pushSprite=function(t){this.sprites.push(t)},e.prototype.removeSprite=function(t){var e=-1;(e=this.sprites.indexOf(t))>-1&&this.sprites.splice(e,1)},e.prototype.clearSprites=function(){this.sprites.length=0},e}();t.Cell=n})(ex||(ex={}));var ex;(function(t){(function(t){t[t.Naive=0]="Naive",t[t.DynamicAABBTree=1]="DynamicAABBTree",t[t.SeparatingAxis=2]="SeparatingAxis"})(t.CollisionStrategy||(t.CollisionStrategy={})),t.CollisionStrategy;var e=function(){function e(t,e,i,n){void 0===t&&(t=0),void 0===e&&(e=0),void 0===i&&(i=0),void 0===n&&(n=0),this.left=t,this.top=e,this.right=i,this.bottom=n}return e.prototype.getWidth=function(){return this.right-this.left},e.prototype.getHeight=function(){return this.bottom-this.top},e.prototype.getPerimeter=function(){var t=this.getWidth(),e=this.getHeight();return 2*(t+e)},e.prototype.contains=function(i){return i instanceof t.Point?this.left<=i.x&&this.top<=i.y&&this.bottom>=i.y&&this.right>=i.x:i instanceof e?this.left=n.left&&this.right<=n.right?n.left-this.right:n.right-this.left;var r=0;return r=this.top<=n.bottom&&this.top>=n.top?n.bottom-this.top:n.top-this.bottom,Math.abs(o)n;n++)e.push(new t.Line(this._points[n],this._points[(n+1)%i]));return e},e.prototype.getAxes=function(){for(var t=[],e=this._points.length,i=0;e>i;i++)t.push(this._points[i].minus(this._points[(i+1)%e]).normal());return t},e.prototype.project=function(e){for(var i=[],n=this._points.length,s=0;n>s;s++)i.push(this._points[s].dot(e));return new t.Projection(Math.min.apply(Math,i),Math.max.apply(Math,i))},e.prototype.getWidth=function(){var t=this._points.reduce(function(t,e){return Math.min(t,e.x)},1/0),e=this._points.reduce(function(t,e){return Math.max(t,e.x)},-1/0);return e-t},e.prototype.getHeight=function(){var t=this._points.reduce(function(t,e){return Math.min(t,e.y)},1/0),e=this._points.reduce(function(t,e){return Math.max(t,e.y)},-1/0);return t-e},e.prototype.contains=function(e){var i=new t.Ray(e,new t.Vector(1,0)),n=this.getSides().reduce(function(t,e){return i.intersect(e)>=0?t+1:t},0);return 0===n%2?!1:!0},e.prototype.collides=function(t){if(t instanceof e){var i=t,n=this.getAxes();n=i.getAxes().concat(n);for(var s=99999,o=null,r=0;n.length>r;r++){var h=this.project(n[r]),a=i.project(n[r]),c=h.getOverlap(a);if(0===c)return null;s>=c&&(s=c,o=n[r])}return o?o.normalize().scale(s):null}return null},e.prototype.debugDraw=function(e){e.beginPath(),e.lineWidth=2;var i=this._points[0];e.moveTo(i.x,i.y);var n=0,s=this._points.length;for(n;s>n;n++)e.lineTo(this._points[n].x,this._points[n].y);e.lineTo(i.x,i.y),e.closePath(),e.strokeStyle=""+t.Color.Blue,e.stroke()},e}();t.SATBoundingBox=i})(ex||(ex={}));var ex;(function(t){var e=function(){function e(){this.eventDispatcher=new t.EventDispatcher(this)}return e.prototype.addEventListener=function(t,e){this.eventDispatcher.subscribe(t,e)},e.prototype.removeEventListener=function(t,e){this.eventDispatcher.unsubscribe(t,e)},e.prototype.on=function(t,e){this.eventDispatcher.subscribe(t,e)},e.prototype.off=function(t,e){this.eventDispatcher.unsubscribe(t,e)},e.prototype.emit=function(t,e){this.eventDispatcher.emit(t,e)},e.extend=function(t){var i,n=this;i=t&&t.hasOwnProperty("constructor")?t.constructor:function(){return n.apply(this,arguments)};var s=function(){this.constructor=i};if(s.prototype=n.prototype,i.prototype=new s,t)for(var o in t)t.hasOwnProperty(o)&&(i.prototype[o]=t[o]);return i.extend=e.extend,i},e}();t.Class=e})(ex||(ex={})); +var ex;(function(t){var e=function(){function t(e,i,n){this.id=0,this.interval=10,this.fcn=function(){},this.repeats=!1,this._elapsedTime=0,this._totalTimeAlive=0,this.complete=!1,this.scene=null,this.id=t.id++,this.interval=i||this.interval,this.fcn=e||this.fcn,this.repeats=n||this.repeats}return t.prototype.update=function(t){this._totalTimeAlive+=t,this._elapsedTime+=t,this._elapsedTime>this.interval&&(this.fcn.call(this),this.repeats?this._elapsedTime=0:this.complete=!0)},t.prototype.getTimeRunning=function(){return this._totalTimeAlive},t.prototype.cancel=function(){this.scene&&this.scene.cancelTimer(this)},t.id=0,t}();t.Timer=e})(ex||(ex={}));var ex;(function(t){var e=function(){function e(){}return e.prototype.register=function(){},e.prototype.remove=function(){},e.prototype.evaluate=function(e){for(var i,n,s=e.filter(function(e){return!e.isKilled()&&e.collisionType!==t.CollisionType.PreventCollision}),o=[],r=0,h=s.length;h>r;r++){i=s[r];for(var a=r+1;h>a;a++){n=s[a];var c;if(c=i.collides(n)){var l=i.getSideFromIntersect(c),u=new t.CollisionPair(i,n,c,l);o.some(function(t){return t.equals(u)})||o.push(u)}}}var p=0,d=o.length;for(p;d>p;p++)o[p].evaluate();return o},e.prototype.update=function(){return 0},e.prototype.debugDraw=function(){},e}();t.NaiveCollisionResolver=e})(ex||(ex={}));var ex;(function(t){var e=function(){function e(e){this.parent=e,this.parent=e||null,this.actor=null,this.bounds=new t.BoundingBox,this.left=null,this.right=null,this.height=0}return e.prototype.isLeaf=function(){return!this.left&&!this.right},e}();t.TreeNode=e;var i=function(){function t(){this.root=null,this.nodes={}}return t.prototype.insert=function(t){if(null===this.root)return this.root=t,this.root.parent=null,void 0;for(var i=t.bounds,n=this.root;!n.isLeaf();){var s,o,r=n.left,h=n.right,a=n.bounds.getPerimeter(),c=n.bounds.combine(i),l=c.getPerimeter(),u=2*l,p=2*(l-a),d=0,f=i.combine(r.bounds);r.isLeaf()?d=f.getPerimeter()+p:(o=r.bounds.getPerimeter(),s=f.getPerimeter(),d=s-o+p);var g=0,_=i.combine(h.bounds);if(h.isLeaf()?g=_.getPerimeter()+p:(o=h.bounds.getPerimeter(),s=_.getPerimeter(),g=s-o+p),d>u&&g>u)break;n=g>d?r:h}var y=n.parent,A=new e(y);A.bounds=i.combine(n.bounds),A.height=n.height+1,null!==y?(y.left===n?y.left=A:y.right=A,A.left=n,A.right=t,n.parent=A,t.parent=A):(A.left=n,A.right=t,n.parent=A,t.parent=A,this.root=A);for(var v=t.parent;v;){if(v=this.balance(v),!v.left)throw Error("Parent of current leaf cannot have a null left child"+v);if(!v.right)throw Error("Parent of current leaf cannot have a null right child"+v);v.height=1+Math.max(v.left.height,v.right.height),v.bounds=v.left.bounds.combine(v.right.bounds),v=v.parent}},t.prototype.remove=function(t){if(t===this.root)return this.root=null,void 0;var e,i=t.parent,n=i.parent;if(e=i.left===t?i.right:i.left,n){n.left===i?n.left=e:n.right=e,e.parent=n;for(var s=n;s;)s=this.balance(s),s.bounds=s.left.bounds.combine(s.right.bounds),s.height=1+Math.max(s.left.height,s.right.height),s=s.parent}else this.root=e,e.parent=null},t.prototype.registerActor=function(t){var i=new e;i.actor=t,i.bounds=t.getBounds(),i.bounds.left-=2,i.bounds.top-=2,i.bounds.right+=2,i.bounds.bottom+=2,this.nodes[t.id]=i,this.insert(i)},t.prototype.updateActor=function(t){var e=this.nodes[t.id];if(e){var i=t.getBounds();if(e.bounds.contains(i))return!1;this.remove(e),i.left-=5,i.top-=5,i.right+=5,i.bottom+=5;var n=2*t.dx,s=2*t.dy;return 0>n?i.left+=n:i.right+=n,0>s?i.top+=s:i.bottom+=s,e.bounds=i,this.insert(e),!0}},t.prototype.removeActor=function(t){var e=this.nodes[t.id];e&&(this.remove(e),this.nodes[t.id]=null,delete this.nodes[t.id])},t.prototype.balance=function(t){if(null===t)throw Error("Cannot balance at null node");if(t.isLeaf()||2>t.height)return t;var e=t.left,i=t.right,n=t,s=e,o=i,r=e.left,h=e.right,a=i.left,c=i.right,l=o.height-s.height;if(l>1)return o.left=n,o.parent=n.parent,n.parent=o,o.parent?o.parent.left===n?o.parent.left=o:o.parent.right=o:this.root=o,a.height>c.height?(o.right=a,n.right=c,c.parent=n,n.bounds=s.bounds.combine(c.bounds),o.bounds=n.bounds.combine(a.bounds),n.height=1+Math.max(s.height,c.height),o.height=1+Math.max(n.height,a.height)):(o.right=c,n.right=a,a.parent=n,n.bounds=s.bounds.combine(a.bounds),o.bounds=n.bounds.combine(c.bounds),n.height=1+Math.max(s.height,a.height),o.height=1+Math.max(n.height,c.height)),o;if(-1>l){if(s.left=n,s.parent=n.parent,n.parent=s,s.parent)if(s.parent.left===n)s.parent.left=s;else{if(s.parent.right!==n)throw"Error rotating Dynamic Tree";s.parent.right=s}else this.root=s;return r.height>h.height?(s.right=r,n.left=h,h.parent=n,n.bounds=o.bounds.combine(h.bounds),s.bounds=n.bounds.combine(r.bounds),n.height=1+Math.max(o.height,h.height),s.height=1+Math.max(n.height,r.height)):(s.right=h,n.left=r,r.parent=n,n.bounds=o.bounds.combine(r.bounds),s.bounds=n.bounds.combine(h.bounds),n.height=1+Math.max(o.height,r.height),s.height=1+Math.max(n.height,h.height)),s}return t},t.prototype.getHeight=function(){return null===this.root?0:this.root.height},t.prototype.query=function(t,e){var i=t.getBounds(),n=function(s){return s&&s.bounds.collides(i)?s.isLeaf()&&s.actor!==t?e.call(t,s.actor)?!0:void 0:n(s.left)||n(s.right):null};return n(this.root)},t.prototype.rayCast=function(){return null},t.prototype.getNodes=function(){var t=function(e){return e?[e].concat(t(e.left),t(e.right)):[]};return t(this.root)},t.prototype.debugDraw=function(t){var e=function(i){i&&(t.strokeStyle=i.isLeaf()?"green":"white",i.bounds.debugDraw(t),i.left&&e(i.left),i.right&&e(i.right))};e(this.root)},t}();t.DynamicTree=i})(ex||(ex={}));var ex;(function(t){var e=function(){function e(){this._dynamicCollisionTree=new t.DynamicTree}return e.prototype.register=function(t){this._dynamicCollisionTree.registerActor(t)},e.prototype.remove=function(t){this._dynamicCollisionTree.removeActor(t)},e.prototype.evaluate=function(e){for(var i,n=e.filter(function(e){return!e.isKilled()&&e.collisionType!==t.CollisionType.PreventCollision}),s=[],o=0,r=n.length;r>o;o++)i=n[o],this._dynamicCollisionTree.query(i,function(e){if(e.collisionType===t.CollisionType.PreventCollision||e.isKilled())return!1;var n;if(n=i.collides(e)){var o=i.getSideFromIntersect(n),r=new t.CollisionPair(i,e,n,o);return s.some(function(t){return t.equals(r)})||s.push(r),!0}return!1});var h=0,a=s.length;for(h;a>h;h++)s[h].evaluate();return s},e.prototype.update=function(t){var e=0,i=0,n=t.length;for(i;n>i;i++)this._dynamicCollisionTree.updateActor(t[i])&&e++;return e},e.prototype.debugDraw=function(t,e){this._dynamicCollisionTree.debugDraw(t,e)},e}();t.DynamicTreeCollisionResolver=e})(ex||(ex={}));var ex;(function(t){var e=function(){function e(t,e,i,n){this.left=t,this.right=e,this.intersect=i,this.side=n}return e.prototype.equals=function(t){return t.left===this.left&&t.right===this.right||t.right===this.left&&t.left===this.right},e.prototype.evaluate=function(){this.left.eventDispatcher.emit("collision",new t.CollisionEvent(this.left,this.right,this.side,this.intersect)),this.right.eventDispatcher.emit("collision",new t.CollisionEvent(this.right,this.left,t.Util.getOppositeSide(this.side),this.intersect.scale(-1)));var e=this.side;this.left.collisionType!==t.CollisionType.Active&&this.left.collisionType!==t.CollisionType.Elastic||this.right.collisionType===t.CollisionType.Passive||(this.left.y+=this.intersect.y,this.left.x+=this.intersect.x,this.left.collisionType===t.CollisionType.Elastic?e===t.Side.Left?this.left.dx=Math.abs(this.left.dx):e===t.Side.Right?this.left.dx=-Math.abs(this.left.dx):e===t.Side.Top?this.left.dy=Math.abs(this.left.dy):e===t.Side.Bottom&&(this.left.dy=-Math.abs(this.left.dy)):(0!==this.intersect.x&&(this.left.dx=0>=this.left.dx&&0>=this.right.dx?Math.max(this.left.dx,this.right.dx):this.left.dx>=0&&this.right.dx>=0?Math.min(this.left.dx,this.right.dx):0),0!==this.intersect.y&&(this.left.dy=0>=this.left.dy&&0>=this.right.dy?Math.max(this.left.dy,this.right.dy):this.left.dy>=0&&this.right.dy>=0?Math.min(this.left.dy,this.right.dy):0)));var i=t.Util.getOppositeSide(this.side),n=this.intersect.scale(-1);this.right.collisionType!==t.CollisionType.Active&&this.right.collisionType!==t.CollisionType.Elastic||this.left.collisionType===t.CollisionType.Passive||(this.right.y+=n.y,this.right.x+=n.x,this.right.collisionType===t.CollisionType.Elastic?i===t.Side.Left?this.right.dx=Math.abs(this.right.dx):i===t.Side.Right?this.right.dx=-Math.abs(this.right.dx):i===t.Side.Top?this.right.dy=Math.abs(this.right.dy):i===t.Side.Bottom&&(this.right.dy=-Math.abs(this.right.dy)):(0!==n.x&&(this.right.dx=0>=this.right.dx&&0>=this.left.dx?Math.max(this.left.dx,this.right.dx):this.left.dx>=0&&this.right.dx>=0?Math.min(this.left.dx,this.right.dx):0),0!==n.y&&(this.right.dy=0>=this.right.dy&&0>=this.left.dy?Math.max(this.left.dy,this.right.dy):this.left.dy>=0&&this.right.dy>=0?Math.min(this.left.dy,this.right.dy):0)))},e}();t.CollisionPair=e})(ex||(ex={}));var ex;(function(t){var e=function(){function e(){this.focus=new t.Point(0,0),this.lerp=!1,this.x=0,this.y=0,this.z=1,this.dx=0,this.dy=0,this.dz=0,this.ax=0,this.ay=0,this.az=0,this.rotation=0,this.rx=0,this._cameraMoving=!1,this._currentLerpTime=0,this._lerpDuration=1e3,this._totalLerpTime=0,this._lerpStart=null,this._lerpEnd=null,this._isShaking=!1,this._shakeMagnitudeX=0,this._shakeMagnitudeY=0,this._shakeDuration=0,this._elapsedShakeTime=0,this._isZooming=!1,this._currentZoomScale=1,this._maxZoomScale=1,this._zoomDuration=0,this._elapsedZoomTime=0,this._zoomIncrement=.01}return e.prototype._easeInOutCubic=function(t,e,i,n){return i-=e,t/=n/2,1>t?i/2*t*t*t+e:(t-=2,i/2*(t*t*t+2)+e)},e.prototype.setActorToFollow=function(t){this._follow=t},e.prototype.getFocus=function(){return new t.Point(this.x,this.y)},e.prototype.setFocus=function(e,i){this._follow||this.lerp||(this.x=e,this.y=i),this.lerp&&(this._lerpStart=this.getFocus().clone(),this._lerpEnd=new t.Point(e,i),this._currentLerpTime=0,this._cameraMoving=!0)},e.prototype.shake=function(t,e,i){this._isShaking=!0,this._shakeMagnitudeX=t,this._shakeMagnitudeY=e,this._shakeDuration=i},e.prototype.zoom=function(t,e){void 0===e&&(e=0),this._isZooming=!0,this._maxZoomScale=t,this._zoomDuration=e,e&&(this._zoomIncrement=1e3*(Math.abs(this._maxZoomScale-this._currentZoomScale)/e)),1>this._maxZoomScale?e?this._zoomIncrement=-1*this._zoomIncrement:(this._isZooming=!1,this._setCurrentZoomScale(this._maxZoomScale)):e||(this._isZooming=!1,this._setCurrentZoomScale(this._maxZoomScale))},e.prototype.getZoom=function(){return this.z},e.prototype._setCurrentZoomScale=function(t){this.z=t},e.prototype.update=function(t,e){this.x+=this.dx*e/1e3,this.y+=this.dy*e/1e3,this.z+=this.dz*e/1e3,this.dx+=this.ax*e/1e3,this.dy+=this.ay*e/1e3,this.dz+=this.az*e/1e3,this.rotation+=this.rx*e/1e3;var i=this.getFocus(),n=0,s=0,o=t.canvas.width,r=t.canvas.height,h=o/this.getZoom(),a=r/this.getZoom();this.lerp&&(this._currentLerpTime=this._shakeDuration},e.prototype._isDoneZooming=function(){return 0!==this._zoomDuration?this._elapsedZoomTime>=this._zoomDuration:1>this._maxZoomScale?this._currentZoomScale<=this._maxZoomScale:this._currentZoomScale>=this._maxZoomScale},e}();t.BaseCamera=e;var i=function(e){function i(){e.apply(this,arguments)}return __extends(i,e),i.prototype.getFocus=function(){return this._follow?new t.Point(this._follow.x+this._follow.getWidth()/2,this.focus.y):this.focus},i}(e);t.SideCamera=i;var n=function(e){function i(){e.apply(this,arguments)}return __extends(i,e),i.prototype.getFocus=function(){return this._follow?new t.Point(this._follow.x+this._follow.getWidth()/2,this._follow.y+this._follow.getHeight()/2):this.focus},i}(e);t.LockedCamera=n})(ex||(ex={}));var ex;(function(t){(function(t){t[t.ShortestPath=0]="ShortestPath",t[t.LongestPath=1]="LongestPath",t[t.Clockwise=2]="Clockwise",t[t.CounterClockwise=3]="CounterClockwise"})(t.RotationType||(t.RotationType={})),t.RotationType})(ex||(ex={}));var ex;(function(t){var e;(function(e){var i;(function(e){var i=function(){function e(e,i,n,s,o){this.actor=e,this.easingFcn=o,this._currentLerpTime=0,this._lerpDuration=1e3,this._lerpStart=new t.Point(0,0),this._lerpEnd=new t.Point(0,0),this._initialized=!1,this._stopped=!1,this._distance=0,this._lerpDuration=s,this._lerpEnd=new t.Point(i,n)}return e.prototype._initialize=function(){this._lerpStart=new t.Point(this.actor.x,this.actor.y),this._currentLerpTime=0,this._distance=this._lerpStart.toVector().distance(this._lerpEnd.toVector())},e.prototype.update=function(t){this._initialized||(this._initialize(),this._initialized=!0);var e=this.actor.x,i=this.actor.y;this._currentLerpTime=this._distance},e.prototype.reset=function(){this._initialized=!1},e.prototype.stop=function(){this._stopped=!0},e}();e.EaseTo=i;var n=function(){function e(e,i,n,s){this._started=!1,this._stopped=!1,this._actor=e,this._end=new t.Vector(i,n),this._speed=s}return e.prototype.update=function(){this._started||(this._started=!0,this._start=new t.Vector(this._actor.x,this._actor.y),this._distance=this._start.distance(this._end),this._dir=this._end.minus(this._start).normalize());var e=this._dir.scale(this._speed);this._actor.dx=e.x,this._actor.dy=e.y,this.isComplete(this._actor)&&(this._actor.x=this._end.x,this._actor.y=this._end.y,this._actor.dy=0,this._actor.dx=0)},e.prototype.isComplete=function(e){return this._stopped||new t.Vector(e.x,e.y).distance(this._start)>=this._distance},e.prototype.stop=function(){this._actor.dy=0,this._actor.dx=0,this._stopped=!0},e.prototype.reset=function(){this._started=!1},e}();e.MoveTo=n;var s=function(){function e(e,i,n,s){if(this._started=!1,this._stopped=!1,this._actor=e,this._end=new t.Vector(i,n),0>=s)throw t.Logger.getInstance().error("Attempted to moveBy time less than or equal to zero : "+s),Error("Cannot move in time <= 0");this._time=s}return e.prototype.update=function(){this._started||(this._started=!0,this._start=new t.Vector(this._actor.x,this._actor.y),this._distance=this._start.distance(this._end),this._dir=this._end.minus(this._start).normalize(),this._speed=this._distance/(this._time/1e3));var e=this._dir.scale(this._speed);this._actor.dx=e.x,this._actor.dy=e.y,this.isComplete(this._actor)&&(this._actor.x=this._end.x,this._actor.y=this._end.y,this._actor.dy=0,this._actor.dx=0)},e.prototype.isComplete=function(e){return this._stopped||new t.Vector(e.x,e.y).distance(this._start)>=this._distance},e.prototype.stop=function(){this._actor.dy=0,this._actor.dx=0,this._stopped=!0},e.prototype.reset=function(){this._started=!1},e}();e.MoveBy=s;var o=function(){function e(e,i,n){this._started=!1,this._stopped=!1,this._actor=e,this._actorToFollow=i,this._current=new t.Vector(this._actor.x,this._actor.y),this._end=new t.Vector(i.x,i.y),this._maximumDistance=void 0!==n?n:this._current.distance(this._end),this._speed=0}return e.prototype.update=function(){this._started||(this._started=!0,this._distanceBetween=this._current.distance(this._end),this._dir=this._end.minus(this._current).normalize());var t=Math.sqrt(Math.pow(this._actorToFollow.dx,2)+Math.pow(this._actorToFollow.dy,2));if(0!==t&&(this._speed=t),this._current.x=this._actor.x,this._current.y=this._actor.y,this._end.x=this._actorToFollow.x,this._end.y=this._actorToFollow.y,this._distanceBetween=this._current.distance(this._end),this._dir=this._end.minus(this._current).normalize(),this._distanceBetween>=this._maximumDistance){var e=this._dir.scale(this._speed);this._actor.dx=e.x,this._actor.dy=e.y}else this._actor.dx=0,this._actor.dy=0;this.isComplete(this._actor)&&(this._actor.x=this._end.x,this._actor.y=this._end.y,this._actor.dy=0,this._actor.dx=0)},e.prototype.stop=function(){this._actor.dy=0,this._actor.dx=0,this._stopped=!0},e.prototype.isComplete=function(){return this._stopped},e.prototype.reset=function(){this._started=!1},e}();e.Follow=o;var r=function(){function e(e,i,n){this._started=!1,this._stopped=!1,this._speedWasSpecified=!1,this._actor=e,this._actorToMeet=i,this._current=new t.Vector(this._actor.x,this._actor.y),this._end=new t.Vector(i.x,i.y),this._speed=n||0,void 0!==n&&(this._speedWasSpecified=!0)}return e.prototype.update=function(){this._started||(this._started=!0,this._distanceBetween=this._current.distance(this._end),this._dir=this._end.minus(this._current).normalize());var t=Math.sqrt(Math.pow(this._actorToMeet.dx,2)+Math.pow(this._actorToMeet.dy,2));0===t||this._speedWasSpecified||(this._speed=t),this._current.x=this._actor.x,this._current.y=this._actor.y,this._end.x=this._actorToMeet.x,this._end.y=this._actorToMeet.y,this._distanceBetween=this._current.distance(this._end),this._dir=this._end.minus(this._current).normalize();var e=this._dir.scale(this._speed);this._actor.dx=e.x,this._actor.dy=e.y,this.isComplete(this._actor)&&(this._actor.x=this._end.x,this._actor.y=this._end.y,this._actor.dy=0,this._actor.dx=0)},e.prototype.isComplete=function(){return this._stopped||1>=this._distanceBetween},e.prototype.stop=function(){this._actor.dy=0,this._actor.dx=0,this._stopped=!0},e.prototype.reset=function(){this._started=!1},e}();e.Meet=r;var h=function(){function e(e,i,n,s){this._started=!1,this._stopped=!1,this._actor=e,this._end=i,this._speed=n,this._rotationType=s||t.RotationType.ShortestPath}return e.prototype.update=function(){if(!this._started){this._started=!0,this._start=this._actor.rotation;var e=Math.abs(this._end-this._start),i=t.Util.TwoPI-e;switch(e>i?(this._shortDistance=i,this._longDistance=e):(this._shortDistance=e,this._longDistance=i),this._shortestPathIsPositive=(this._start-this._end+t.Util.TwoPI)%t.Util.TwoPI>=Math.PI,this._rotationType){case t.RotationType.ShortestPath:this._distance=this._shortDistance,this._direction=this._shortestPathIsPositive?1:-1;break;case t.RotationType.LongestPath:this._distance=this._longDistance,this._direction=this._shortestPathIsPositive?-1:1;break;case t.RotationType.Clockwise:this._direction=1,this._distance=this._shortestPathIsPositive?this._shortDistance:this._longDistance;break;case t.RotationType.CounterClockwise:this._direction=-1,this._distance=this._shortestPathIsPositive?this._longDistance:this._shortDistance}}this._actor.rx=this._direction*this._speed,this.isComplete(this._actor)&&(this._actor.rotation=this._end,this._actor.rx=0,this._stopped=!0)},e.prototype.isComplete=function(){var t=Math.abs(this._actor.rotation-this._start);return this._stopped||t>=Math.abs(this._distance)},e.prototype.stop=function(){this._actor.rx=0,this._stopped=!0},e.prototype.reset=function(){this._started=!1},e}();e.RotateTo=h;var a=function(){function e(e,i,n,s){this._started=!1,this._stopped=!1,this._actor=e,this._end=i,this._time=n,this._rotationType=s||t.RotationType.ShortestPath}return e.prototype.update=function(){if(!this._started){this._started=!0,this._start=this._actor.rotation;var e=Math.abs(this._end-this._start),i=t.Util.TwoPI-e;switch(e>i?(this._shortDistance=i,this._longDistance=e):(this._shortDistance=e,this._longDistance=i),this._shortestPathIsPositive=(this._start-this._end+t.Util.TwoPI)%t.Util.TwoPI>=Math.PI,this._rotationType){case t.RotationType.ShortestPath:this._distance=this._shortDistance,this._direction=this._shortestPathIsPositive?1:-1;break;case t.RotationType.LongestPath:this._distance=this._longDistance,this._direction=this._shortestPathIsPositive?-1:1;break;case t.RotationType.Clockwise:this._direction=1,this._distance=this._shortDistance>=0?this._shortDistance:this._longDistance;break;case t.RotationType.CounterClockwise:this._direction=-1,this._distance=0>=this._shortDistance?this._shortDistance:this._longDistance}this._speed=Math.abs(1e3*(this._distance/this._time))}this._actor.rx=this._direction*this._speed,this.isComplete(this._actor)&&(this._actor.rotation=this._end,this._actor.rx=0,this._stopped=!0)},e.prototype.isComplete=function(){var t=Math.abs(this._actor.rotation-this._start);return this._stopped||t>=Math.abs(this._distance)},e.prototype.stop=function(){this._actor.rx=0,this._stopped=!0},e.prototype.reset=function(){this._started=!1},e}();e.RotateBy=a;var c=function(){function t(t,e,i,n,s){this._started=!1,this._stopped=!1,this._actor=t,this._endX=e,this._endY=i,this._speedX=n,this._speedY=s}return t.prototype.update=function(){if(this._started||(this._started=!0,this._startX=this._actor.scale.x,this._startY=this._actor.scale.y,this._distanceX=Math.abs(this._endX-this._startX),this._distanceY=Math.abs(this._endY-this._startY)),Math.abs(this._actor.scale.x-this._startX)>=this._distanceX)this._actor.sx=0;else{var t=this._endY=this._distanceY)this._actor.sy=0;else{var e=this._endY=this._distanceX&&Math.abs(this._actor.scale.y-this._startY)>=this._distanceY},t.prototype.stop=function(){this._actor.sx=0,this._actor.sy=0,this._stopped=!0},t.prototype.reset=function(){this._started=!1},t}();e.ScaleTo=c;var l=function(){function t(t,e,i,n){this._started=!1,this._stopped=!1,this._actor=t,this._endX=e,this._endY=i,this._time=n,this._speedX=1e3*((this._endX-this._actor.scale.x)/n),this._speedY=1e3*((this._endY-this._actor.scale.y)/n)}return t.prototype.update=function(){this._started||(this._started=!0,this._startX=this._actor.scale.x,this._startY=this._actor.scale.y,this._distanceX=Math.abs(this._endX-this._startX),this._distanceY=Math.abs(this._endY-this._startY));var t=this._endX=this._distanceX&&Math.abs(this._actor.scale.y-this._startY)>=this._distanceY},t.prototype.stop=function(){this._actor.sx=0,this._actor.sy=0,this._stopped=!0},t.prototype.reset=function(){this._started=!1},t}();e.ScaleBy=l;var u=function(){function t(t,e){this._elapsedTime=0,this._started=!1,this._stopped=!1,this._actor=t,this._delay=e}return t.prototype.update=function(t){this._started||(this._started=!0),this.x=this._actor.x,this.y=this._actor.y,this._elapsedTime+=t},t.prototype.isComplete=function(){return this._stopped||this._elapsedTime>=this._delay},t.prototype.stop=function(){this._stopped=!0},t.prototype.reset=function(){this._elapsedTime=0,this._started=!1},t}();e.Delay=u;var p=function(){function t(t,e,i,n){void 0===n&&(n=1),this._timeVisible=0,this._timeNotVisible=0,this._elapsedTime=0,this._totalTime=0,this._stopped=!1,this._started=!1,this._actor=t,this._timeVisible=e,this._timeNotVisible=i,this._duration=(e+i)*n}return t.prototype.update=function(t){this._started||(this._started=!0),this._elapsedTime+=t,this._totalTime+=t,this._actor.visible&&this._elapsedTime>=this._timeVisible&&(this._actor.visible=!1,this._elapsedTime=0),!this._actor.visible&&this._elapsedTime>=this._timeNotVisible&&(this._actor.visible=!0,this._elapsedTime=0),this.isComplete(this._actor)&&(this._actor.visible=!0)},t.prototype.isComplete=function(){return this._stopped||this._totalTime>=this._duration},t.prototype.stop=function(){this._actor.visible=!0,this._stopped=!0},t.prototype.reset=function(){this._started=!1,this._elapsedTime=0,this._totalTime=0},t}();e.Blink=p;var d=function(){function e(t,e,i){this._multiplyer=1,this._started=!1,this._stopped=!1,this._actor=t,this._endOpacity=e,this._speed=i,t.opacity>e&&(this._multiplyer=-1)}return e.prototype.update=function(e){this._started||(this._started=!0),this._speed>0&&(this._actor.opacity+=this._multiplyer*Math.abs(this._actor.opacity-this._endOpacity)*e/this._speed),this._speed-=e,t.Logger.getInstance().debug("actor opacity: "+this._actor.opacity),this.isComplete(this._actor)&&(this._actor.opacity=this._endOpacity)},e.prototype.isComplete=function(){return this._stopped||.05>Math.abs(this._actor.opacity-this._endOpacity)},e.prototype.stop=function(){this._stopped=!0},e.prototype.reset=function(){this._started=!1},e}();e.Fade=d;var f=function(){function t(t){this._started=!1,this._stopped=!1,this._actor=t}return t.prototype.update=function(){this._actor.actionQueue.clearActions(),this._actor.kill(),this._stopped=!0},t.prototype.isComplete=function(){return this._stopped},t.prototype.stop=function(){},t.prototype.reset=function(){},t}();e.Die=f;var g=function(){function t(t,e){this._method=null,this._actor=null,this._hasBeenCalled=!1,this._actor=t,this._method=e}return t.prototype.update=function(){this._method.call(this._actor),this._hasBeenCalled=!0},t.prototype.isComplete=function(){return this._hasBeenCalled},t.prototype.reset=function(){this._hasBeenCalled=!1},t.prototype.stop=function(){this._hasBeenCalled=!0},t}();e.CallMethod=g;var _=function(){function t(t,e,i){this._stopped=!1,this._actor=t,this._actionQueue=new A(t),this._repeat=e,this._originalRepeat=e;var n=0,s=i.length;for(n;s>n;n++)i[n].reset(),this._actionQueue.add(i[n])}return t.prototype.update=function(t){this.x=this._actor.x,this.y=this._actor.y,this._actionQueue.hasNext()||(this._actionQueue.reset(),this._repeat--),this._actionQueue.update(t)},t.prototype.isComplete=function(){return this._stopped||0>=this._repeat},t.prototype.stop=function(){this._stopped=!0},t.prototype.reset=function(){this._repeat=this._originalRepeat},t}();e.Repeat=_;var y=function(){function t(t,e){this._stopped=!1,this._actor=t,this._actionQueue=new A(t);var i=0,n=e.length;for(i;n>i;i++)e[i].reset(),this._actionQueue.add(e[i])}return t.prototype.update=function(t){this.x=this._actor.x,this.y=this._actor.y,this._stopped||(this._actionQueue.hasNext()||this._actionQueue.reset(),this._actionQueue.update(t))},t.prototype.isComplete=function(){return this._stopped},t.prototype.stop=function(){this._stopped=!0,this._actionQueue.clearActions()},t.prototype.reset=function(){},t}();e.RepeatForever=y;var A=function(){function t(t){this._actions=[],this._completedActions=[],this._actor=t}return t.prototype.add=function(t){this._actions.push(t)},t.prototype.remove=function(t){var e=this._actions.indexOf(t);this._actions.splice(e,1)},t.prototype.clearActions=function(){this._actions.length=0,this._completedActions.length=0,this._currentAction&&this._currentAction.stop()},t.prototype.getActions=function(){return this._actions.concat(this._completedActions)},t.prototype.hasNext=function(){return this._actions.length>0},t.prototype.reset=function(){this._actions=this.getActions();var t=0,e=this._actions.length;for(t;e>t;t++)this._actions[t].reset();this._completedActions=[]},t.prototype.update=function(t){this._actions.length>0&&(this._currentAction=this._actions[0],this._currentAction.update(t),this._currentAction.isComplete(this._actor)&&this._completedActions.push(this._actions.shift()))},t}();e.ActionQueue=A})(i=e.Actions||(e.Actions={}))})(e=t.Internal||(t.Internal={}))})(ex||(ex={}));var ex;(function(t){var e=function(){function e(){this._actors=[],this._queues=[],null!==arguments&&(this._actors=Array.prototype.slice.call(arguments,0),this._queues=this._actors.map(function(t){return t.actionQueue}))}return e.prototype.clearActions=function(){var t=0,e=this._queues.length;for(t;e>t;t++)this._queues[t].clearActions()},e.prototype.addActorToContext=function(t){this._actors.push(t),this._queues.push(t.actionQueue)},e.prototype.removeActorFromContext=function(t){var e=this._actors.indexOf(t);e>-1&&(this._actors.splice(e,1),this._queues.splice(e,1))},e.prototype.easeTo=function(e,i,n,s){void 0===s&&(s=t.EasingFunctions.Linear);var o=0,r=this._queues.length;for(o;r>o;o++)this._queues[o].add(new t.Internal.Actions.EaseTo(this._actors[o],e,i,n,s));return this},e.prototype.moveTo=function(e,i,n){var s=0,o=this._queues.length;for(s;o>s;s++)this._queues[s].add(new t.Internal.Actions.MoveTo(this._actors[s],e,i,n));return this},e.prototype.moveBy=function(e,i,n){var s=0,o=this._queues.length;for(s;o>s;s++)this._queues[s].add(new t.Internal.Actions.MoveBy(this._actors[s],e,i,n));return this},e.prototype.rotateTo=function(e,i){var n=0,s=this._queues.length;for(n;s>n;n++)this._queues[n].add(new t.Internal.Actions.RotateTo(this._actors[n],e,i));return this},e.prototype.rotateBy=function(e,i){var n=0,s=this._queues.length;for(n;s>n;n++)this._queues[n].add(new t.Internal.Actions.RotateBy(this._actors[n],e,i));return this},e.prototype.scaleTo=function(e,i,n,s){var o=0,r=this._queues.length;for(o;r>o;o++)this._queues[o].add(new t.Internal.Actions.ScaleTo(this._actors[o],e,i,n,s));return this},e.prototype.scaleBy=function(e,i,n){var s=0,o=this._queues.length;for(s;o>s;s++)this._queues[s].add(new t.Internal.Actions.ScaleBy(this._actors[s],e,i,n));return this},e.prototype.blink=function(e,i,n){void 0===n&&(n=1);var s=0,o=this._queues.length;for(s;o>s;s++)this._queues[s].add(new t.Internal.Actions.Blink(this._actors[s],e,i,n));return this},e.prototype.fade=function(e,i){var n=0,s=this._queues.length;for(n;s>n;n++)this._queues[n].add(new t.Internal.Actions.Fade(this._actors[n],e,i));return this},e.prototype.delay=function(e){var i=0,n=this._queues.length;for(i;n>i;i++)this._queues[i].add(new t.Internal.Actions.Delay(this._actors[i],e));return this},e.prototype.die=function(){var e=0,i=this._queues.length;for(e;i>e;e++)this._queues[e].add(new t.Internal.Actions.Die(this._actors[e]));return this},e.prototype.callMethod=function(e){var i=0,n=this._queues.length;for(i;n>i;i++)this._queues[i].add(new t.Internal.Actions.CallMethod(this._actors[i],e));return this},e.prototype.repeat=function(e){if(!e)return this.repeatForever(),this;var i=0,n=this._queues.length;for(i;n>i;i++)this._queues[i].add(new t.Internal.Actions.Repeat(this._actors[i],e,this._actors[i].actionQueue.getActions())); +return this},e.prototype.repeatForever=function(){var e=0,i=this._queues.length;for(e;i>e;e++)this._queues[e].add(new t.Internal.Actions.RepeatForever(this._actors[e],this._actors[e].actionQueue.getActions()));return this},e.prototype.follow=function(e,i){var n=0,s=this._queues.length;for(n;s>n;n++)void 0===i?this._queues[n].add(new t.Internal.Actions.Follow(this._actors[n],e)):this._queues[n].add(new t.Internal.Actions.Follow(this._actors[n],e,i));return this},e.prototype.meet=function(e,i){var n=0,s=this._queues.length;for(n;s>n;n++)void 0===i?this._queues[n].add(new t.Internal.Actions.Meet(this._actors[n],e)):this._queues[n].add(new t.Internal.Actions.Meet(this._actors[n],e,i));return this},e.prototype.asPromise=function(){var e=this,i=this._queues.map(function(i,n){var s=new t.Promise;return i.add(new t.Internal.Actions.CallMethod(e._actors[n],function(){s.resolve()})),s});return t.Promise.join.apply(this,i)},e}();t.ActionContext=e})(ex||(ex={}));var ex;(function(t){var e=function(e){function i(i,n){if(e.call(this),this.name=i,this.scene=n,this._logger=t.Logger.getInstance(),this._members=[],this.actions=new t.ActionContext,null==n)this._logger.error("Invalid constructor arguments passed to Group: ",i,", scene must not be null!");else{var s=n.groups[i];s&&this._logger.warn("Group with name",i,"already exists. This new group will replace it."),n.groups[i]=this}}return __extends(i,e),i.prototype.add=function(e){e instanceof t.Actor&&(e=[].concat(e));var i,n=0,s=e.length;for(n;s>n;n++)i=this.getMembers().indexOf(e[n]),-1===i&&(this._members.push(e[n]),this.scene.add(e[n]),this.actions.addActorToContext(e[n]),this.eventDispatcher.wire(e[n].eventDispatcher))},i.prototype.remove=function(t){var e=this._members.indexOf(t);e>-1&&(this._members.splice(e,1),this.actions.removeActorFromContext(t),this.eventDispatcher.unwire(t.eventDispatcher))},i.prototype.move=function(e){var i=0,n=this.getMembers(),s=n.length;if(1===arguments.length&&e instanceof t.Vector)for(i;s>i;i++)n[i].x+=e.x,n[i].y+=e.y;else if("number"==typeof arguments[0]&&"number"==typeof arguments[1]){var o=arguments[0],r=arguments[1];for(i;s>i;i++)n[i].x+=o,n[i].y+=r}else this._logger.error("Invalid arguments passed to group move",this.name,"args:",arguments)},i.prototype.rotate=function(){if("number"==typeof arguments[0]){var t=arguments[0],e=0,i=this.getMembers(),n=i.length;for(e;n>e;e++)i[e].rotation+=t}else this._logger.error("Invalid arguments passed to group rotate",this.name,"args:",arguments)},i.prototype.on=function(t,e){this.eventDispatcher.subscribe(t,e)},i.prototype.off=function(t,e){this.eventDispatcher.unsubscribe(t,e)},i.prototype.emit=function(t,e){this.eventDispatcher.emit(t,e)},i.prototype.contains=function(t){return this.getMembers().indexOf(t)>-1},i.prototype.getMembers=function(){return this._members},i.prototype.getRandomMember=function(){return this._members[Math.floor(Math.random()*this._members.length)]},i.prototype.getBounds=function(){return this.getMembers().map(function(t){return t.getBounds()}).reduce(function(t,e){return t.combine(e)})},i}(t.Class);t.Group=e})(ex||(ex={}));var ex;(function(t){var e=function(){function t(t){this._getComparable=t}return t.prototype.find=function(t){return this._find(this._root,t)},t.prototype._find=function(t,e){return null==t?!1:this._getComparable.call(e)===t.getKey()?t.getData().indexOf(e)>-1?!0:!1:this._getComparable.call(e)e?this._get(t.getLeft(),e):this._get(t.getRight(),e)},t.prototype.add=function(t){return null==this._root?(this._root=new i(this._getComparable.call(t),[t],null,null),!0):this._insert(this._root,t)},t.prototype._insert=function(t,e){return null!=t?this._getComparable.call(e)===t.getKey()?t.getData().indexOf(e)>-1?!1:(t.getData().push(e),!0):this._getComparable.call(e)-1){if(t.getData().splice(i,1),0===t.getData().length){if(null==t.getLeft()&&null==t.getRight())return null;if(null==t.getLeft())return t.getRight();if(null==t.getRight())return t.getLeft();var n=this._findMinNode(t.getRight());return t.setKey(n.getKey()),t.setData(n.getData()),t.setRight(this._cleanup(t.getRight(),n)),t}return t}},t.prototype._cleanup=function(t,e){var i=e.getKey();if(null==t)return null;if(i===t.getKey()){if(null==t.getLeft()&&null==t.getRight())return null;if(null==t.getLeft())return t.getRight();if(null==t.getRight())return t.getLeft();var n=this._findMinNode(t.getRight());return t.setKey(n.getKey()),t.setData(n.getData()),t.setRight(this._cleanup(t.getRight(),n)),t}return this._getComparable.call(e)n;n++)this.uiActors[n].update(e,i);for(n=0,s=this.tileMaps.length;s>n;n++)this.tileMaps[n].update(e,i);for(n=0,s=this.children.length;s>n;n++)this.children[n].update(e,i);this._collisionResolver&&(this._collisionResolver.update(this.children),this._collisionResolver.evaluate(this.children));var o;for(n=0,s=this._killQueue.length;s>n;n++)o=this.children.indexOf(this._killQueue[n]),o>-1&&(this._sortedDrawingTree.removeByComparable(this._killQueue[n]),this.children.splice(o,1));for(this._killQueue.length=0,n=0,s=this._cancelQueue.length;s>n;n++)this.removeTimer(this._cancelQueue[n]);this._cancelQueue.length=0,this._timers=this._timers.filter(function(t){return t.update(i),!t.complete}),this.emit("postupdate",new t.PostUpdateEvent(e,i,this))},i.prototype.draw=function(e,i){this.emit("predraw",new t.PreDrawEvent(e,i,this)),e.save(),this.camera&&this.camera.update(e,i);var n,s;for(n=0,s=this.tileMaps.length;s>n;n++)this.tileMaps[n].draw(e,i);var o=this._sortedDrawingTree.list();for(n=0,s=o.length;s>n;n++)o[n].visible&&!o[n].isOffScreen&&o[n].draw(e,i);for(this.engine&&this.engine.isDebug&&(e.strokeStyle="yellow",this.debugDraw(e)),e.restore(),n=0,s=this.uiActors.length;s>n;n++)this.uiActors[n].visible&&this.uiActors[n].draw(e,i);if(this.engine&&this.engine.isDebug)for(n=0,s=this.uiActors.length;s>n;n++)this.uiActors[n].debugDraw(e);this.emit("postdraw",new t.PreDrawEvent(e,i,this))},i.prototype.debugDraw=function(e){this.emit("predebugdraw",new t.PreDebugDrawEvent(e,this));var i,n;for(i=0,n=this.tileMaps.length;n>i;i++)this.tileMaps[i].debugDraw(e);for(i=0,n=this.children.length;n>i;i++)this.children[i].debugDraw(e);this.camera.debugDraw(e),this.emit("postdebugdraw",new t.PostDebugDrawEvent(e,this))},i.prototype.contains=function(t){return this.children.indexOf(t)>-1},i.prototype.add=function(e){return e instanceof t.UIActor?(t.Util.contains(this.uiActors,e)||this.addUIActor(e),void 0):e instanceof t.Actor?(t.Util.contains(this.children,e)||(this.addChild(e),this._sortedDrawingTree.add(e)),void 0):e instanceof t.Timer?(t.Util.contains(this._timers,e)||this.addTimer(e),void 0):(e instanceof t.TileMap&&(t.Util.contains(this.tileMaps,e)||this.addTileMap(e)),void 0)},i.prototype.remove=function(e){return e instanceof t.UIActor?(this.removeUIActor(e),void 0):(e instanceof t.Actor&&(this._collisionResolver.remove(e),this.removeChild(e)),e instanceof t.Timer&&this.removeTimer(e),e instanceof t.TileMap&&this.removeTileMap(e),void 0)},i.prototype.addUIActor=function(t){this.uiActors.push(t),t.scene=this},i.prototype.removeUIActor=function(t){var e=this.uiActors.indexOf(t);e>-1&&this.uiActors.splice(e,1)},i.prototype.addChild=function(t){this._collisionResolver.register(t),t.scene=this,this.children.push(t),this._sortedDrawingTree.add(t),t.parent=this.actor},i.prototype.addTileMap=function(t){this.tileMaps.push(t)},i.prototype.removeTileMap=function(t){var e=this.tileMaps.indexOf(t);e>-1&&this.tileMaps.splice(e,1)},i.prototype.removeChild=function(t){this._collisionResolver.remove(t),this._killQueue.push(t),t.parent=null},i.prototype.addTimer=function(t){return this._timers.push(t),t.scene=this,t},i.prototype.removeTimer=function(t){var e=this._timers.indexOf(t);return-1!==e&&this._timers.splice(e,1),t},i.prototype.cancelTimer=function(t){return this._cancelQueue.push(t),t},i.prototype.isTimerActive=function(t){return this._timers.indexOf(t)>-1},i.prototype.createGroup=function(e){return new t.Group(e,this)},i.prototype.getGroup=function(t){return this.groups[t]},i.prototype.removeGroup=function(e){"string"==typeof e?delete this.groups[e]:e instanceof t.Group?delete this.groups[e.name]:this._logger.error("Invalid arguments to removeGroup",e)},i.prototype.cleanupDrawTree=function(t){this._sortedDrawingTree.removeByComparable(t)},i.prototype.updateDrawTree=function(t){this._sortedDrawingTree.add(t)},i}(t.Class);t.Scene=e})(ex||(ex={}));var ex;(function(t){var e=function(){function t(){}return t.Linear=function(t,e,i,n){return i-=e,i*t/n+e},t.EaseInQuad=function(t,e,i,n){t/=n},t.EaseOutQuad=function(t,e,i,n){return t/=n,-i*t*(t-2)+e},t.EaseInOutQuad=function(t,e,i,n){return i-=e,t/=n/2,1>t?i/2*t*t+e:(t--,-i/2*(t*(t-2)-1)+e)},t.EaseInCubic=function(t,e,i,n){return i-=e,t/=n,i*t*t*t+e},t.EaseOutCubic=function(t,e,i,n){return i-=e,t/=n,i*(t*t*t+1)+e},t.EaseInOutCubic=function(t,e,i,n){return i-=e,t/=n/2,1>t?i/2*t*t*t+e:(t-=2,i/2*(t*t*t+2)+e)},t}();t.EasingFunctions=e})(ex||(ex={}));var ex;(function(t){var e=function(e){function n(s,o,r,h,a){e.call(this),this.id=n.maxId++,this.x=0,this.y=0,this._height=0,this._width=0,this.rotation=0,this.rx=0,this.scale=new t.Vector(1,1),this.sx=0,this.sy=0,this.dx=0,this.dy=0,this.ax=0,this.ay=0,this.isOffScreen=!1,this.visible=!0,this.opacity=1,this.previousOpacity=1,this.actions=new t.ActionContext(this),this.logger=t.Logger.getInstance(),this.scene=null,this.parent=null,this.children=[],this.collisionType=i.PreventCollision,this.collisionGroups=[],this._collisionHandlers={},this._isInitialized=!1,this.frames={},this.currentDrawing=null,this.centerDrawingX=!0,this.centerDrawingY=!0,this.traits=[],this.enableCapturePointer=!1,this.capturePointer={captureMoveEvents:!1},this._zIndex=0,this._isKilled=!1,this.x=s||0,this.y=o||0,this._width=r||0,this._height=h||0,a&&(this.color=a.clone(),this.opacity=a.a),this.traits.push(new t.Traits.Movement),this.traits.push(new t.Traits.CollisionDetection),this.traits.push(new t.Traits.OffscreenCulling),this.traits.push(new t.Traits.CapturePointer),this.actionQueue=new t.Internal.Actions.ActionQueue(this),this.anchor=new t.Point(.5,.5)}return __extends(n,e),n.prototype.onInitialize=function(){},n.prototype._checkForPointerOptIn=function(t){!t||"pointerdown"!==t.toLowerCase()&&"pointerdown"!==t.toLowerCase()&&"pointermove"!==t.toLowerCase()||(this.enableCapturePointer=!0,"pointermove"===t.toLowerCase()&&(this.capturePointer.captureMoveEvents=!0))},n.prototype.addEventListener=function(t,i){this._checkForPointerOptIn(t),e.prototype.addEventListener.call(this,t,i)},n.prototype.on=function(t,e){this._checkForPointerOptIn(t),this.eventDispatcher.subscribe(t,e)},n.prototype.kill=function(){this.scene?(this.scene.remove(this),this._isKilled=!0):this.logger.warn("Cannot kill actor, it was never added to the Scene")},n.prototype.isKilled=function(){return this._isKilled},n.prototype.add=function(e){e.collisionType=i.PreventCollision,t.Util.addItemToArray(e,this.children)&&(e.parent=this)},n.prototype.remove=function(e){t.Util.removeItemToArray(e,this.children)&&(e.parent=null)},n.prototype.setDrawing=function(e){e=""+e,this.currentDrawing!==this.frames[e]&&(null!=this.frames[e]?(this.frames[e].reset(),this.currentDrawing=this.frames[e]):t.Logger.getInstance().error("the specified drawing key '"+e+"' does not exist"))},n.prototype.addDrawing=function(){2===arguments.length?(this.frames[arguments[0]]=arguments[1],this.currentDrawing||(this.currentDrawing=arguments[1])):(arguments[0]instanceof t.Sprite&&this.addDrawing("default",arguments[0]),arguments[0]instanceof t.Texture&&this.addDrawing("default",arguments[0].asSprite()))},n.prototype.getZIndex=function(){return this._zIndex},n.prototype.setZIndex=function(t){this.scene.cleanupDrawTree(this),this._zIndex=t,this.scene.updateDrawTree(this)},n.prototype.addCollisionGroup=function(t){this.collisionGroups.push(t)},n.prototype.removeCollisionGroup=function(t){var e=this.collisionGroups.indexOf(t);-1!==e&&this.collisionGroups.splice(e,1)},n.prototype.getCenter=function(){return new t.Vector(this.x+this.getWidth()/2-this.anchor.x*this.getWidth(),this.y+this.getHeight()/2-this.anchor.y*this.getHeight())},n.prototype.getWidth=function(){return this._width*this.scale.x},n.prototype.setWidth=function(t){this._width=t/this.scale.x},n.prototype.getHeight=function(){return this._height*this.scale.y},n.prototype.setHeight=function(t){this._height=t/this.scale.y},n.prototype.setCenterDrawing=function(t){this.centerDrawingY=t,this.centerDrawingX=t},n.prototype.getLeft=function(){return this.x},n.prototype.getRight=function(){return this.x+this.getWidth()},n.prototype.getTop=function(){return this.y},n.prototype.getBottom=function(){return this.y+this.getHeight()},n.prototype.getWorldX=function(){return this.parent?this.x*this.parent.scale.x+this.parent.getWorldX():this.x},n.prototype.getWorldY=function(){return this.parent?this.y*this.parent.scale.y+this.parent.getWorldY():this.y},n.prototype.getGlobalScale=function(){if(!this.parent)return new t.Point(this.scale.x,this.scale.y);var e=this.parent.getGlobalScale();return new t.Point(this.scale.x*e.x,this.scale.y*e.y)},n.prototype.getBounds=function(){var e=this._getCalculatedAnchor();return new t.BoundingBox(this.getWorldX()-e.x,this.getWorldY()-e.y,this.getWorldX()+this.getWidth()-e.x,this.getWorldY()+this.getHeight()-e.y)},n.prototype.contains=function(e,i,n){void 0===n&&(n=!1);var s=this.getBounds().contains(new t.Point(e,i));return n?s||this.children.some(function(t){return t.contains(e,i,!0)}):s},n.prototype.getSideFromIntersect=function(e){return e?Math.abs(e.x)>Math.abs(e.y)?0>e.x?t.Side.Right:t.Side.Left:0>e.y?t.Side.Bottom:t.Side.Top:t.Side.None},n.prototype.collidesWithSide=function(e){var i=this.collides(e);return i?Math.abs(i.x)>Math.abs(i.y)?this.x=Math.sqrt(Math.pow(this.x-t.x,2)+Math.pow(this.y-t.y,2))},n.prototype.clearActions=function(){this.actionQueue.clearActions()},n.prototype.easeTo=function(e,i,n,s){return void 0===s&&(s=t.EasingFunctions.Linear),this.actionQueue.add(new t.Internal.Actions.EaseTo(this,e,i,n,s)),this},n.prototype.moveTo=function(e,i,n){return this.actionQueue.add(new t.Internal.Actions.MoveTo(this,e,i,n)),this},n.prototype.moveBy=function(e,i,n){return this.actionQueue.add(new t.Internal.Actions.MoveBy(this,e,i,n)),this},n.prototype.rotateTo=function(e,i,n){return this.actionQueue.add(new t.Internal.Actions.RotateTo(this,e,i,n)),this},n.prototype.rotateBy=function(e,i,n){return this.actionQueue.add(new t.Internal.Actions.RotateBy(this,e,i,n)),this},n.prototype.scaleTo=function(e,i,n,s){return this.actionQueue.add(new t.Internal.Actions.ScaleTo(this,e,i,n,s)),this},n.prototype.scaleBy=function(e,i,n){return this.actionQueue.add(new t.Internal.Actions.ScaleBy(this,e,i,n)),this},n.prototype.blink=function(e,i,n){return void 0===n&&(n=1),this.actionQueue.add(new t.Internal.Actions.Blink(this,e,i,n)),this},n.prototype.fade=function(e,i){return this.actionQueue.add(new t.Internal.Actions.Fade(this,e,i)),this},n.prototype.delay=function(e){return this.actionQueue.add(new t.Internal.Actions.Delay(this,e)),this},n.prototype.die=function(){return this.actionQueue.add(new t.Internal.Actions.Die(this)),this},n.prototype.callMethod=function(e){return this.actionQueue.add(new t.Internal.Actions.CallMethod(this,e)),this},n.prototype.repeat=function(e){return e?(this.actionQueue.add(new t.Internal.Actions.Repeat(this,e,this.actionQueue.getActions())),this):(this.repeatForever(),this)},n.prototype.repeatForever=function(){return this.actionQueue.add(new t.Internal.Actions.RepeatForever(this,this.actionQueue.getActions())),this},n.prototype.follow=function(e,i){return i===void 0?this.actionQueue.add(new t.Internal.Actions.Follow(this,e)):this.actionQueue.add(new t.Internal.Actions.Follow(this,e,i)),this},n.prototype.meet=function(e,i){return i===void 0?this.actionQueue.add(new t.Internal.Actions.Meet(this,e)):this.actionQueue.add(new t.Internal.Actions.Meet(this,e,i)),this},n.prototype.asPromise=function(){var e=new t.Promise;return this.callMethod(function(){e.resolve()}),e},n.prototype._getCalculatedAnchor=function(){return new t.Point(this.getWidth()*this.anchor.x,this.getHeight()*this.anchor.y)},n.prototype.update=function(e,i){this._isInitialized||(this.onInitialize(e),this.eventDispatcher.emit("initialize",new t.InitializeEvent(e)),this._isInitialized=!0),this.emit("preupdate",new t.PreUpdateEvent(e,i,this));var n=this.eventDispatcher;this.actionQueue.update(i),this.color&&(this.color.a=this.opacity);for(var s=0;this.traits.length>s;s++)this.traits[s].update(this,e,i);n.emit("update",new t.UpdateEvent(i)),this.emit("postupdate",new t.PostUpdateEvent(e,i,this))},n.prototype.draw=function(e,i){var n=this._getCalculatedAnchor();if(e.save(),e.translate(this.x,this.y),e.scale(this.scale.x,this.scale.y),e.rotate(this.rotation),this.emit("predraw",new t.PreDrawEvent(e,i,this)),this.previousOpacity!==this.opacity){for(var s in this.frames)this.frames[s].addEffect(new t.Effects.Opacity(this.opacity));this.previousOpacity=this.opacity}if(this.currentDrawing){var o=0,r=0;this.centerDrawingX&&(o=(this.currentDrawing.naturalWidth*this.currentDrawing.scale.x-this.getWidth())/2-this.currentDrawing.naturalWidth*this.currentDrawing.scale.x*this.currentDrawing.anchor.x),this.centerDrawingY&&(r=(this.currentDrawing.naturalHeight*this.currentDrawing.scale.y-this.getHeight())/2-this.currentDrawing.naturalHeight*this.currentDrawing.scale.y*this.currentDrawing.anchor.y),this.currentDrawing.draw(e,-n.x-o,-n.y-r)}else this.color&&(e.fillStyle=""+this.color,e.fillRect(-n.x,-n.y,this._width,this._height));for(var h=0;this.children.length>h;h++)this.children[h].visible&&this.children[h].draw(e,i);this.emit("postdraw",new t.PostDrawEvent(e,i,this)),e.restore()},n.prototype.debugDraw=function(e){this.emit("predebugdraw",new t.PreDebugDrawEvent(e,this));var i=this.getBounds();i.debugDraw(e),e.fillText("id: "+this.id,i.left+3,i.top+10),e.fillStyle=""+t.Color.Yellow,e.beginPath(),e.arc(this.getWorldX(),this.getWorldY(),3,0,2*Math.PI),e.closePath(),e.fill();for(var n=0;this.traits.length>n;n++)this.traits[n]instanceof t.Traits.OffscreenCulling&&this.traits[n].cullingBox.debugDraw(e);e.strokeStyle=""+t.Color.Yellow,e.beginPath();var s=Math.min(this.getWidth(),this.getHeight());e.arc(this.getWorldX(),this.getWorldY(),s,0,2*Math.PI),e.closePath(),e.stroke();var o={"0 Pi":0,"Pi/2":Math.PI/2,Pi:Math.PI,"3/2 Pi":3*Math.PI/2},r=e.font;for(var h in o)e.fillStyle=""+t.Color.Yellow,e.font="14px",e.textAlign="center",e.fillText(h,this.getWorldX()+Math.cos(o[h])*(s+10),this.getWorldY()+Math.sin(o[h])*(s+10));e.font=r,e.save(),e.translate(this.x,this.y),e.rotate(this.rotation);for(var a=0;this.children.length>a;a++)this.children[a].debugDraw(e);e.restore(),this.emit("postdebugdraw",new t.PostDebugDrawEvent(e,this))},n.maxId=0,n}(t.Class);t.Actor=e,function(t){t[t.PreventCollision=0]="PreventCollision",t[t.Passive=1]="Passive",t[t.Active=2]="Active",t[t.Elastic=3]="Elastic",t[t.Fixed=4]="Fixed"}(t.CollisionType||(t.CollisionType={}));var i=t.CollisionType})(ex||(ex={}));var ex;(function(t){(function(t){t[t.Debug=0]="Debug",t[t.Info=1]="Info",t[t.Warn=2]="Warn",t[t.Error=3]="Error",t[t.Fatal=4]="Fatal"})(t.LogLevel||(t.LogLevel={}));var e=t.LogLevel,i=function(){function t(){if(this._appenders=[],this.defaultLevel=e.Info,t._instance)throw Error("Logger is a singleton");return t._instance=this,t._instance.addAppender(new n),t._instance}return t.getInstance=function(){return null==t._instance&&(t._instance=new t),t._instance},t.prototype.addAppender=function(t){this._appenders.push(t)},t.prototype.clearAppenders=function(){this._appenders.length=0},t.prototype._log=function(t,e){null==t&&(t=this.defaultLevel);var i=0,n=this._appenders.length;for(i;n>i;i++)t>=this.defaultLevel&&this._appenders[i].log(t,e)},t.prototype.debug=function(){for(var t=[],i=0;arguments.length>i;i++)t[i-0]=arguments[i];this._log(e.Debug,t)},t.prototype.info=function(){for(var t=[],i=0;arguments.length>i;i++)t[i-0]=arguments[i];this._log(e.Info,t)},t.prototype.warn=function(){for(var t=[],i=0;arguments.length>i;i++)t[i-0]=arguments[i];this._log(e.Warn,t)},t.prototype.error=function(){for(var t=[],i=0;arguments.length>i;i++)t[i-0]=arguments[i];this._log(e.Error,t)},t.prototype.fatal=function(){for(var t=[],i=0;arguments.length>i;i++)t[i-0]=arguments[i];this._log(e.Fatal,t)},t._instance=null,t}();t.Logger=i;var n=function(){function t(){}return t.prototype.log=function(t,i){if(console||console.log||!console.warn||!console.error){var n=[];n.unshift.apply(n,i),n.unshift("["+e[t]+"] : "),e.Warn>t?console.log.apply?console.log.apply(console,n):console.log(n.join(" ")):e.Error>t?console.warn.apply?console.warn.apply(console,n):console.warn(n.join(" ")):console.error.apply?console.error.apply(console,n):console.error(n.join(" "))}},t}();t.ConsoleAppender=n;var s=function(){function t(t,e){this._messages=[],this._canvas=document.createElement("canvas"),this._canvas.width=t||window.innerWidth,this._canvas.height=e||window.innerHeight,this._canvas.style.position="absolute",this._ctx=this._canvas.getContext("2d"),document.body.appendChild(this._canvas)}return t.prototype.log=function(t,i){var n=i.join(",");this._ctx.clearRect(0,0,this._canvas.width,this._canvas.height),this._messages.unshift("["+e[t]+"] : "+n);for(var s=10,o=1,r=0;this._messages.length>r;r++)this._ctx.fillStyle="rgba(255,255,255,"+o.toFixed(2)+")",this._ctx.fillText(this._messages[r],200,s),s+=10,o=o>0?o-.05:0},t}();t.ScreenAppender=s})(ex||(ex={}));var ex;(function(t){var e=function(){function t(){}return t}();t.GameEvent=e;var i=function(t){function e(e,i,n){t.call(this),this.ctx=e,this.delta=i,this.target=n}return __extends(e,t),e}(e);t.PreDrawEvent=i;var n=function(t){function e(e,i,n){t.call(this),this.ctx=e,this.delta=i,this.target=n}return __extends(e,t),e}(e);t.PostDrawEvent=n;var s=function(t){function e(e,i){t.call(this),this.ctx=e,this.target=i}return __extends(e,t),e}(e);t.PreDebugDrawEvent=s;var o=function(t){function e(e,i){t.call(this),this.ctx=e,this.target=i}return __extends(e,t),e}(e);t.PostDebugDrawEvent=o;var r=function(t){function e(e,i,n){t.call(this),this.engine=e,this.delta=i,this.target=n}return __extends(e,t),e}(e);t.PreUpdateEvent=r;var h=function(t){function e(e,i,n){t.call(this),this.engine=e,this.delta=i,this.target=n}return __extends(e,t),e}(e);t.PostUpdateEvent=h;var a=function(t){function e(e,i){t.call(this),this.index=e,this.gamepad=i}return __extends(e,t),e}(e);t.GamepadConnectEvent=a;var c=function(t){function e(e){t.call(this),this.index=e}return __extends(e,t),e}(e);t.GamepadDisconnectEvent=c;var l=function(t){function e(e,i){t.call(this),this.button=e,this.value=i}return __extends(e,t),e}(t.GameEvent);t.GamepadButtonEvent=l;var u=function(t){function e(e,i){t.call(this),this.axis=e,this.value=i}return __extends(e,t),e}(t.GameEvent);t.GamepadAxisEvent=u;var p=function(t){function e(e,i){t.call(this),this.topic=e,this.handler=i}return __extends(e,t),e}(e);t.SubscribeEvent=p;var d=function(t){function e(e,i){t.call(this),this.topic=e,this.handler=i}return __extends(e,t),e}(e);t.UnsubscribeEvent=d;var f=function(t){function e(){t.call(this)}return __extends(e,t),e}(e);t.VisibleEvent=f;var g=function(t){function e(){t.call(this)}return __extends(e,t),e}(e);t.HiddenEvent=g;var _=function(t){function e(e,i,n,s){t.call(this),this.actor=e,this.other=i,this.side=n,this.intersection=s}return __extends(e,t),e}(e);t.CollisionEvent=_;var y=function(t){function e(e){t.call(this),this.delta=e}return __extends(e,t),e}(e);t.UpdateEvent=y;var A=function(t){function e(e){t.call(this),this.engine=e}return __extends(e,t),e}(e);t.InitializeEvent=A;var v=function(t){function e(e){t.call(this),this.oldScene=e}return __extends(e,t),e}(e);t.ActivateEvent=v;var m=function(t){function e(e){t.call(this),this.newScene=e}return __extends(e,t),e}(e);t.DeactivateEvent=m;var x=function(t){function e(){t.call(this)}return __extends(e,t),e}(e);t.ExitViewPortEvent=x;var w=function(t){function e(){t.call(this)}return __extends(e,t),e}(e);t.EnterViewPortEvent=w})(ex||(ex={}));var ex;(function(t){var e=function(){function e(e){this._handlers={},this._wiredEventDispatchers=[],this._log=t.Logger.getInstance(),this._target=e}return e.prototype.publish=function(e,i){if(e){e=e.toLowerCase();var n=this._target;i||(i=new t.GameEvent),i.target=n;var s,o;if(this._handlers[e])for(s=0,o=this._handlers[e].length,s;o>s;s++)this._handlers[e][s].call(n,i);for(s=0,o=this._wiredEventDispatchers.length,s;o>s;s++)this._wiredEventDispatchers[s].emit(e,i)}},e.prototype.emit=function(t,e){this.publish(t,e)},e.prototype.subscribe=function(e,i){e=e.toLowerCase(),this._handlers[e]||(this._handlers[e]=[]),this._handlers[e].push(i),"unsubscribe"!==e&&"subscribe"!==e&&this.emit("subscribe",new t.SubscribeEvent(e,i))},e.prototype.unsubscribe=function(e,i){e=e.toLowerCase();var n=this._handlers[e];if(n)if(i){var s=n.indexOf(i);this._handlers[e].splice(s,1)}else this._handlers[e].length=0;"unsubscribe"!==e&&"subscribe"!==e&&this.emit("unsubscribe",new t.UnsubscribeEvent(e,i))},e.prototype.wire=function(t){t._wiredEventDispatchers.push(this)},e.prototype.unwire=function(t){var e=t._wiredEventDispatchers.indexOf(this);e>-1&&t._wiredEventDispatchers.splice(e,1)},e}();t.EventDispatcher=e})(ex||(ex={}));var ex;(function(t){var e=function(){function t(t,e,i,n){this.r=t,this.g=e,this.b=i,this.a=null!=n?n:1}return t.fromRGB=function(e,i,n,s){return new t(e,i,n,s)},t.fromHex=function(e){var i=/^#?([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})?$/i,n=null;if(n=e.match(i)){var s=parseInt(n[1],16),o=parseInt(n[2],16),r=parseInt(n[3],16),h=1;return n[4]&&(h=parseInt(n[4],16)/255),new t(s,o,r,h)}throw Error("Invalid hex string: "+e)},t.fromHSL=function(t,e,n,s){void 0===s&&(s=1);var o=new i(t,e,n,s);return o.toRGBA()},t.prototype.lighten=function(t){void 0===t&&(t=.1);var e=i.fromRGBA(this.r,this.g,this.b,this.a);return e.l+=e.l*t,e.toRGBA()},t.prototype.darken=function(t){void 0===t&&(t=.1);var e=i.fromRGBA(this.r,this.g,this.b,this.a);return e.l-=e.l*t,e.toRGBA()},t.prototype.saturate=function(t){void 0===t&&(t=.1);var e=i.fromRGBA(this.r,this.g,this.b,this.a);return e.s+=e.s*t,e.toRGBA()},t.prototype.desaturate=function(t){void 0===t&&(t=.1);var e=i.fromRGBA(this.r,this.g,this.b,this.a);return e.s-=e.s*t,e.toRGBA()},t.prototype.mulitiply=function(e){var i=255*(e.r/255*this.r/255),n=255*(e.g/255*this.g/255),s=255*(e.b/255*this.b/255),o=e.a*this.a;return new t(i,n,s,o)},t.prototype.screen=function(t){var e=t.invert(),i=t.invert();return e.mulitiply(i).invert()},t.prototype.invert=function(){return new t(255-this.r,255-this.g,255-this.b,1-this.a)},t.prototype.average=function(e){var i=(e.r+this.r)/2,n=(e.g+this.g)/2,s=(e.b+this.b)/2,o=(e.a+this.a)/2;return new t(i,n,s,o)},t.prototype.toString=function(){var t=this.r.toFixed(0)+""+", "+(this.g.toFixed(0)+"")+", "+(this.b.toFixed(0)+"");return void 0!==this.a||null!==this.a?"rgba("+t+", "+(this.a+"")+")":"rgb("+t+")"},t.prototype.fillStyle=function(){return""+this},t.prototype.clone=function(){return new t(this.r,this.g,this.b,this.a)},t.Black=t.fromHex("#000000"),t.White=t.fromHex("#FFFFFF"),t.Gray=t.fromHex("#808080"),t.LightGray=t.fromHex("#D3D3D3"),t.DarkGray=t.fromHex("#A9A9A9"),t.Yellow=t.fromHex("#FFFF00"),t.Orange=t.fromHex("#FFA500"),t.Red=t.fromHex("#FF0000"),t.Vermillion=t.fromHex("#FF5B31"),t.Rose=t.fromHex("#FF007F"),t.Magenta=t.fromHex("#FF00FF"),t.Violet=t.fromHex("#7F00FF"),t.Blue=t.fromHex("#0000FF"),t.Azure=t.fromHex("#007FFF"),t.Cyan=t.fromHex("#00FFFF"),t.Viridian=t.fromHex("#59978F"),t.Green=t.fromHex("#00FF00"),t.Chartreuse=t.fromHex("#7FFF00"),t.Transparent=t.fromHex("#FFFFFF00"),t}();t.Color=e;var i=function(){function t(t,e,i,n){this.h=t,this.s=e,this.l=i,this.a=n}return t.fromRGBA=function(e,i,n,s){e/=255,i/=255,n/=255;var o,r,h=Math.max(e,i,n),a=Math.min(e,i,n),c=(h+a)/2;if(h===a)o=r=0;else{var l=h-a;switch(r=c>.5?l/(2-h-a):l/(h+a),h){case e:o=(i-n)/l+(n>i?6:0);break;case i:o=(n-e)/l+2;break;case n:o=(e-i)/l+4}o/=6}return new t(o,r,c,s)},t.prototype.toRGBA=function(){function t(t,e,i){return 0>i&&(i+=1),i>1&&(i-=1),1/6>i?t+6*(e-t)*i:.5>i?e:2/3>i?t+6*(e-t)*(2/3-i):t}var i,n,s;if(0===this.s)i=n=s=this.l;else{var o=.5>this.l?this.l*(1+this.s):this.l+this.s-this.l*this.s,r=2*this.l-o;i=t(r,o,this.h+1/3),n=t(r,o,this.h),s=t(r,o,this.h-1/3)}return new e(255*i,255*n,255*s,this.a)},t}()})(ex||(ex={}));var ex;(function(t){var e=function(e){function i(i,n,s,o){e.call(this,i,n,s,o),this.traits=[],this.traits.push(new t.Traits.Movement),this.traits.push(new t.Traits.CapturePointer),this.anchor.setTo(0,0),this.collisionType=t.CollisionType.PreventCollision,this.enableCapturePointer=!0 +}return __extends(i,e),i.prototype.onInitialize=function(t){this._engine=t},i.prototype.contains=function(i,n,s){if(void 0===s&&(s=!0),s)return e.prototype.contains.call(this,i,n);var o=this._engine.worldToScreenCoordinates(new t.Point(i,n));return e.prototype.contains.call(this,o.x,o.y)},i}(t.Actor);t.UIActor=e})(ex||(ex={}));var ex;(function(t){var e=function(e){function i(i,n,s,o,r,h){e.call(this,i,n,s,o),this._action=function(){},this.repeats=1,this.target=null,this.repeats=h||this.repeats,this._action=r||this._action,this.collisionType=t.CollisionType.PreventCollision,this.eventDispatcher=new t.EventDispatcher(this),this.actionQueue=new t.Internal.Actions.ActionQueue(this)}return __extends(i,e),i.prototype.update=function(e,i){if(this.actionQueue.update(i),this.x+=this.dx*i/1e3,this.y+=this.dy*i/1e3,this.rotation+=this.rx*i/1e3,this.scale.x+=this.sx*i/1e3,this.scale.y+=this.sy*i/1e3,this.target)this.collides(this.target)&&this._dispatchAction();else for(var n=0;e.currentScene.children.length>n;n++){var s=e.currentScene.children[n];s!==this&&s.collisionType!==t.CollisionType.PreventCollision&&this.collides(s)&&this._dispatchAction()}0===this.repeats&&this.kill()},i.prototype._dispatchAction=function(){this._action.call(this),this.repeats--},i.prototype.draw=function(){},i.prototype.debugDraw=function(i){e.prototype.debugDraw.call(this,i),i.save(),i.translate(this.x,this.y);var n=this.getBounds();n.left=n.left-this.getWorldX(),n.right=n.right-this.getWorldX(),n.top=n.top-this.getWorldY(),n.bottom=n.bottom-this.getWorldY(),i.fillStyle=""+t.Color.Violet,i.strokeStyle=""+t.Color.Violet,i.fillText("Trigger",10,10),n.debugDraw(i),i.restore()},i}(t.Actor);t.Trigger=e})(ex||(ex={}));var ex;(function(t){(function(t){t[t.Circle=0]="Circle",t[t.Rectangle=1]="Rectangle"})(t.EmitterType||(t.EmitterType={}));var e=t.EmitterType,i=function(){function e(e,i,n,s,o,r,h,a,c,l){this.position=new t.Vector(0,0),this.velocity=new t.Vector(0,0),this.acceleration=new t.Vector(0,0),this.particleRotationalVelocity=0,this.currentRotation=0,this.focus=null,this.focusAccel=0,this.opacity=1,this.beginColor=t.Color.White.clone(),this.endColor=t.Color.White.clone(),this.life=300,this.fadeFlag=!1,this._rRate=1,this._gRate=1,this._bRate=1,this._aRate=0,this._currentColor=t.Color.White.clone(),this.emitter=null,this.particleSize=5,this.particleSprite=null,this.sizeRate=0,this.elapsedMultiplier=0,this.emitter=e,this.life=i||this.life,this.opacity=n||this.opacity,this.endColor=o||this.endColor.clone(),this.beginColor=s||this.beginColor.clone(),this._currentColor=this.beginColor.clone(),this.position=r||this.position,this.velocity=h||this.velocity,this.acceleration=a||this.acceleration,this._rRate=(this.endColor.r-this.beginColor.r)/this.life,this._gRate=(this.endColor.g-this.beginColor.g)/this.life,this._bRate=(this.endColor.b-this.beginColor.b)/this.life,this._aRate=this.opacity/this.life,this.startSize=c||0,this.endSize=l||0,this.endSize>0&&this.startSize>0&&(this.sizeRate=(this.endSize-this.startSize)/this.life,this.particleSize=this.startSize)}return e.prototype.kill=function(){this.emitter.removeParticle(this)},e.prototype.update=function(e){if(this.life=this.life-e,this.elapsedMultiplier=this.elapsedMultiplier+e,0>this.life&&this.kill(),this.fadeFlag&&(this.opacity=t.Util.clamp(this._aRate*this.life,1e-4,1)),this.startSize>0&&this.endSize>0&&(this.particleSize=t.Util.clamp(this.sizeRate*e+this.particleSize,Math.min(this.startSize,this.endSize),Math.max(this.startSize,this.endSize))),this._currentColor.r=t.Util.clamp(this._currentColor.r+this._rRate*e,0,255),this._currentColor.g=t.Util.clamp(this._currentColor.g+this._gRate*e,0,255),this._currentColor.b=t.Util.clamp(this._currentColor.b+this._bRate*e,0,255),this._currentColor.a=t.Util.clamp(this.opacity,1e-4,1),this.focus){var i=this.focus.minus(this.position).normalize().scale(this.focusAccel).scale(e/1e3);this.velocity=this.velocity.add(i)}else this.velocity=this.velocity.add(this.acceleration.scale(e/1e3));this.position=this.position.add(this.velocity.scale(e/1e3)),this.particleRotationalVelocity&&(this.currentRotation=(this.currentRotation+this.particleRotationalVelocity*e/1e3)%(2*Math.PI))},e.prototype.draw=function(e){return this.particleSprite?(this.particleSprite.rotation=this.currentRotation,this.particleSprite.scale.setTo(this.particleSize,this.particleSize),this.particleSprite.draw(e,this.position.x,this.position.y),void 0):(this._currentColor.a=t.Util.clamp(this.opacity,1e-4,1),e.fillStyle=""+this._currentColor,e.beginPath(),e.arc(this.position.x,this.position.y,this.particleSize,0,2*Math.PI),e.fill(),e.closePath(),void 0)},e}();t.Particle=i;var n=function(n){function s(i,s,o,r){n.call(this,i,s,o,r,t.Color.White),this._particlesToEmit=0,this.numParticles=0,this.isEmitting=!0,this.particles=null,this.deadParticles=null,this.minVel=0,this.maxVel=0,this.acceleration=new t.Vector(0,0),this.minAngle=0,this.maxAngle=0,this.emitRate=1,this.particleLife=2e3,this.opacity=1,this.fadeFlag=!1,this.focus=null,this.focusAccel=1,this.startSize=null,this.endSize=null,this.minSize=5,this.maxSize=5,this.beginColor=t.Color.White,this.endColor=t.Color.White,this.particleSprite=null,this.emitterType=e.Rectangle,this.radius=0,this.particleRotationalVelocity=0,this.randomRotation=!1,this.collisionType=t.CollisionType.PreventCollision,this.particles=new t.Util.Collection,this.deadParticles=new t.Util.Collection;for(var h in this.traits)this.traits[h]instanceof t.Traits.OffscreenCulling&&this.traits.splice(h,1)}return __extends(s,n),s.prototype.removeParticle=function(t){this.deadParticles.push(t)},s.prototype.emitParticles=function(t){for(var e=0;t>e;e++)this.particles.push(this._createParticle())},s.prototype.clearParticles=function(){this.particles.clear()},s.prototype._createParticle=function(){var n=0,s=0,o=t.Util.randomInRange(this.minAngle,this.maxAngle),r=t.Util.randomInRange(this.minVel,this.maxVel),h=this.startSize||t.Util.randomInRange(this.minSize,this.maxSize),a=r*Math.cos(o),c=r*Math.sin(o);if(this.emitterType===e.Rectangle)n=t.Util.randomInRange(this.x,this.x+this.getWidth()),s=t.Util.randomInRange(this.y,this.y+this.getHeight());else if(this.emitterType===e.Circle){var l=t.Util.randomInRange(0,this.radius);n=l*Math.cos(o)+this.x,s=l*Math.sin(o)+this.y}var u=new i(this,this.particleLife,this.opacity,this.beginColor,this.endColor,new t.Vector(n,s),new t.Vector(a,c),this.acceleration,this.startSize,this.endSize);return u.fadeFlag=this.fadeFlag,u.particleSize=h,this.particleSprite&&(u.particleSprite=this.particleSprite),u.particleRotationalVelocity=this.particleRotationalVelocity,this.randomRotation&&(u.currentRotation=t.Util.randomInRange(0,2*Math.PI)),this.focus&&(u.focus=this.focus.add(new t.Vector(this.x,this.y)),u.focusAccel=this.focusAccel),u},s.prototype.update=function(t,e){var i=this;n.prototype.update.call(this,t,e),this.isEmitting&&(this._particlesToEmit+=this.emitRate*(e/1e3),this._particlesToEmit>1&&(this.emitParticles(Math.floor(this._particlesToEmit)),this._particlesToEmit=this._particlesToEmit-Math.floor(this._particlesToEmit))),this.particles.forEach(function(t){return t.update(e)}),this.deadParticles.forEach(function(t){return i.particles.removeElement(t)}),this.deadParticles.clear()},s.prototype.draw=function(t){this.particles.forEach(function(e){return e.draw(t)})},s.prototype.debugDraw=function(e){n.prototype.debugDraw.call(this,e),e.fillStyle=""+t.Color.Black,e.fillText("Particles: "+this.particles.count(),this.x,this.y+20),this.focus&&(e.fillRect(this.focus.x+this.x,this.focus.y+this.y,3,3),t.Util.drawLine(e,"yellow",this.focus.x+this.x,this.focus.y+this.y,n.prototype.getCenter.call(this).x,n.prototype.getCenter.call(this).y),e.fillText("Focus",this.focus.x+this.x,this.focus.y+this.y))},s}(t.Actor);t.ParticleEmitter=n})(ex||(ex={}));var ex;(function(t){var e=function(){function e(e,i,n,s){this.currentFrame=0,this._oldTime=Date.now(),this.anchor=new t.Point(0,0),this.rotation=0,this.scale=new t.Point(1,1),this.loop=!1,this.freezeFrame=-1,this.flipVertical=!1,this.flipHorizontal=!1,this.width=0,this.height=0,this.naturalWidth=0,this.naturalHeight=0,this.sprites=i,this.speed=n,this._engine=e,null!=s&&(this.loop=s),i&&i[0]&&(this.height=i[0]?i[0].height:0,this.width=i[0]?i[0].width:0,this.naturalWidth=i[0]?i[0].naturalWidth:0,this.naturalHeight=i[0]?i[0].naturalHeight:0,this.freezeFrame=i.length-1)}return e.prototype.opacity=function(e){this.addEffect(new t.Effects.Opacity(e))},e.prototype.grayscale=function(){this.addEffect(new t.Effects.Grayscale)},e.prototype.invert=function(){this.addEffect(new t.Effects.Invert)},e.prototype.fill=function(e){this.addEffect(new t.Effects.Fill(e))},e.prototype.colorize=function(e){this.addEffect(new t.Effects.Colorize(e))},e.prototype.lighten=function(e){void 0===e&&(e=.1),this.addEffect(new t.Effects.Lighten(e))},e.prototype.darken=function(e){void 0===e&&(e=.1),this.addEffect(new t.Effects.Darken(e))},e.prototype.saturate=function(e){void 0===e&&(e=.1),this.addEffect(new t.Effects.Saturate(e))},e.prototype.desaturate=function(e){void 0===e&&(e=.1),this.addEffect(new t.Effects.Desaturate(e))},e.prototype.addEffect=function(t){for(var e in this.sprites)this.sprites[e].addEffect(t)},e.prototype.removeEffect=function(t){for(var e in this.sprites)this.sprites[e].removeEffect(t)},e.prototype.clearEffects=function(){for(var t in this.sprites)this.sprites[t].clearEffects()},e.prototype._setAnchor=function(t){for(var e in this.sprites)this.sprites[e].anchor.setTo(t.x,t.y)},e.prototype._setRotation=function(t){for(var e in this.sprites)this.sprites[e].rotation=t},e.prototype._setScale=function(t){for(var e in this.sprites)this.sprites[e].scale=t},e.prototype.reset=function(){this.currentFrame=0},e.prototype.isDone=function(){return!this.loop&&this.currentFrame>=this.sprites.length},e.prototype.tick=function(){var t=Date.now();t-this._oldTime>this.speed&&(this.currentFrame=this.loop?(this.currentFrame+1)%this.sprites.length:this.currentFrame+1,this._oldTime=t)},e.prototype._updateValues=function(){this._setAnchor(this.anchor),this._setRotation(this.rotation),this._setScale(this.scale)},e.prototype.skip=function(t){this.currentFrame=(this.currentFrame+t)%this.sprites.length},e.prototype.draw=function(e,i,n){this.tick(),this._updateValues();var s;this.currentFrame=this.sprites.length&&(s=this.sprites[t.Util.clamp(this.freezeFrame,0,this.sprites.length-1)],s.draw(e,i,n)),s&&(this.width=s.width,this.height=s.height)},e.prototype.play=function(t,e){this.reset(),this._engine.playAnimation(this,t,e)},e}();t.Animation=e})(ex||(ex={}));var ex;(function(t){var e;(function(e){var i=function(){function e(e,i){this._log=t.Logger.getInstance(),this.onload=function(){},this.onprogress=function(){},this.onerror=function(){},window.AudioContext?(this._log.debug("Using new Web Audio Api for "+e),this._soundImpl=new o(e,i)):(this._log.debug("Falling back to Audio Element for "+e),this._soundImpl=new n(e,i))}return e.prototype.setVolume=function(t){this._soundImpl.setVolume(t)},e.prototype.setLoop=function(t){this._soundImpl.setLoop(t)},e.prototype.load=function(){this._soundImpl.onload=this.onload,this._soundImpl.onprogress=this.onprogress,this._soundImpl.onerror=this.onerror,this._soundImpl.load()},e.prototype.isPlaying=function(){return this._soundImpl.isPlaying()},e.prototype.play=function(){return this._soundImpl.play()},e.prototype.pause=function(){this._soundImpl.pause()},e.prototype.stop=function(){this._soundImpl.stop()},e}();e.FallbackAudio=i;var n=function(){function e(e,i){var n=this;this.path=e,this._audioElements=Array(5),this._loadedAudio=null,this._isLoaded=!1,this._index=0,this._log=t.Logger.getInstance(),this._isPlaying=!1,this._currentOffset=0,this.onload=function(){},this.onprogress=function(){},this.onerror=function(){};for(var s=0;this._audioElements.length>s;s++)(function(t){n._audioElements[t]=new Audio})(s);i?this.setVolume(t.Util.clamp(i,0,1)):this.setVolume(1)}return e.prototype.isPlaying=function(){return this._isPlaying},e.prototype._audioLoaded=function(){this._isLoaded=!0},e.prototype.setVolume=function(t){var e=0,i=this._audioElements.length;for(e;i>e;e++)this._audioElements[e].volume=t},e.prototype.setLoop=function(t){var e=0,i=this._audioElements.length;for(e;i>e;e++)this._audioElements[e].loop=t},e.prototype.getLoop=function(){this._audioElements.some(function(t){return t.loop})},e.prototype.load=function(){var t=this,e=new XMLHttpRequest;e.open("GET",this.path,!0),e.responseType="blob",e.onprogress=this.onprogress,e.onerror=this.onerror,e.onload=function(i){return 200!==e.status?(t._log.error("Failed to load audio resource ",t.path," server responded with error code",e.status),t.onerror(e.response),t._isLoaded=!1,void 0):(t._loadedAudio=URL.createObjectURL(e.response),t._audioElements.forEach(function(e){e.src=t._loadedAudio}),t.onload(i),void 0)},e.send()},e.prototype.play=function(){var e=this;this._audioElements[this._index].load(),this._audioElements[this._index].play(),this._currentOffset=0;var i=new t.Promise;return this._isPlaying=!0,this.getLoop()||this._audioElements[this._index].addEventListener("ended",function(){e._isPlaying=!1,i.resolve(!0)}),this._index=(this._index+1)%this._audioElements.length,i},e.prototype.pause=function(){this._index=(this._index-1+this._audioElements.length)%this._audioElements.length,this._currentOffset=this._audioElements[this._index].currentTime,this._audioElements.forEach(function(t){t.pause()}),this._isPlaying=!1},e.prototype.stop=function(){this._audioElements.forEach(function(t){t.pause()}),this._isPlaying=!1},e}();if(e.AudioTag=n,window.AudioContext)var s=new window.AudioContext;var o=function(){function e(e,i){this._context=s,this._volume=this._context.createGain(),this._buffer=null,this._sound=null,this._path="",this._isLoaded=!1,this._loop=!1,this._isPlaying=!1,this._isPaused=!1,this._currentOffset=0,this._logger=t.Logger.getInstance(),this.onload=function(){},this.onprogress=function(){},this.onerror=function(){},this._path=e,this._volume.gain.value=i?t.Util.clamp(i,0,1):1}return e.prototype.setVolume=function(t){this._volume.gain.value=t},e.prototype.load=function(){var t=this,e=new XMLHttpRequest;e.open("GET",this._path),e.responseType="arraybuffer",e.onprogress=this.onprogress,e.onerror=this.onerror,e.onload=function(){return 200!==e.status?(t._logger.error("Failed to load audio resource ",t._path," server responded with error code",e.status),t.onerror(e.response),t._isLoaded=!1,void 0):(t._context.decodeAudioData(e.response,function(e){t._buffer=e,t._isLoaded=!0,t.onload(t)},function(){t._logger.error("Unable to decode "+t._path+" this browser may not fully support this format, or the file may be corrupt, "+"if this is an mp3 try removing id3 tags and album art from the file."),t._isLoaded=!1,t.onload(t)}),void 0)};try{e.send()}catch(i){console.error("Error loading sound! If this is a cross origin error, you must host your sound with your html and javascript.")}},e.prototype.setLoop=function(t){this._loop=t},e.prototype.isPlaying=function(){return this._isPlaying},e.prototype.play=function(){var e=this;if(this._isLoaded){this._sound=this._context.createBufferSource(),this._sound.buffer=this._buffer,this._sound.loop=this._loop,this._sound.connect(this._volume),this._volume.connect(this._context.destination),this._sound.start(0,this._currentOffset%this._buffer.duration),this._currentOffset=0;var i;return i=this._isPaused&&this._playPromise?this._playPromise:new t.Promise,this._isPaused=!1,this._isPlaying=!0,this._loop||(this._sound.onended=function(){e._isPlaying=!1,e._isPaused||i.resolve(!0)}.bind(this)),this._playPromise=i,i}return t.Promise.wrap(!0)},e.prototype.pause=function(){if(this._isPlaying)try{window.clearTimeout(this._playingTimer),this._sound.stop(0),this._currentOffset=this._context.currentTime,this._isPlaying=!1,this._isPaused=!0}catch(t){this._logger.warn("The sound clip",this._path,"has already been paused!")}},e.prototype.stop=function(){if(this._sound)try{window.clearTimeout(this._playingTimer),this._currentOffset=0,this._sound.stop(0),this._isPlaying=!1,this._isPaused=!1}catch(t){this._logger.warn("The sound clip",this._path,"has already been stopped!")}},e}();e.WebAudio=o})(e=t.Internal||(t.Internal={}))})(ex||(ex={}));var ex;(function(t){(function(t){t[t.Resolved=0]="Resolved",t[t.Rejected=1]="Rejected",t[t.Pending=2]="Pending"})(t.PromiseState||(t.PromiseState={}));var e=t.PromiseState,i=function(){function i(){this._state=e.Pending,this._successCallbacks=[],this._rejectCallback=function(){},this._logger=t.Logger.getInstance()}return i.wrap=function(t){var e=(new i).resolve(t);return e},i.join=function(){for(var t=[],e=0;arguments.length>e;e++)t[e-0]=arguments[e];var n=new i;if(!t||!t.length)return n.resolve();var s=t.length,o=0,r=0,h=[];return t.forEach(function(t){t.then(function(){o+=1,o===s?n.resolve():o+r+h.length===s&&n.reject(h)},function(){r+=1,o+r+h.length===s&&n.reject(h)}).error(function(t){h.push(t),h.length+o+r===s&&n.reject(h)})}),n},i.prototype.then=function(t,i){if(t&&(this._successCallbacks.push(t),this.state()===e.Resolved))try{t.call(this,this._value)}catch(n){this._handleError(n)}if(i&&(this._rejectCallback=i,this.state()===e.Rejected))try{i.call(this,this._value)}catch(n){this._handleError(n)}return this},i.prototype.error=function(t){return t&&(this._errorCallback=t),this},i.prototype.resolve=function(t){var i=this;if(this._state!==e.Pending)throw Error("Cannot resolve a promise that is not in a pending state!");this._value=t;try{this._state=e.Resolved,this._successCallbacks.forEach(function(t){t.call(i,i._value)})}catch(n){this._handleError(n)}return this},i.prototype.reject=function(t){if(this._state!==e.Pending)throw Error("Cannot reject a promise that is not in a pending state!");this._value=t;try{this._state=e.Rejected,this._rejectCallback.call(this,this._value)}catch(i){this._handleError(i)}return this},i.prototype.state=function(){return this._state},i.prototype._handleError=function(t){if(!this._errorCallback)throw t;this._errorCallback.call(this,t)},i}();t.Promise=i})(ex||(ex={}));var ex;(function(t){var e=function(){function e(e,i,n){void 0===n&&(n=!0),this.path=e,this.responseType=i,this.bustCache=n,this.data=null,this.logger=t.Logger.getInstance(),this.onprogress=function(){},this.oncomplete=function(){},this.onerror=function(){}}return e.prototype.isLoaded=function(){return!!this.data},e.prototype.wireEngine=function(t){this._engine=t},e.prototype._cacheBust=function(t){var e=/\?\w*=\w*/;return t+=e.test(t)?"&__="+Date.now():"?__="+Date.now()},e.prototype._start=function(){this.logger.debug("Started loading resource "+this.path)},e.prototype.load=function(){var e=this,i=new t.Promise,n=new XMLHttpRequest;return n.open("GET",this.bustCache?this._cacheBust(this.path):this.path,!0),n.responseType=this.responseType,n.onloadstart=function(t){e._start(t)},n.onprogress=this.onprogress,n.onerror=this.onerror,n.onload=function(){return 200!==n.status?(e.logger.error("Failed to load resource ",e.path," server responded with error code",n.status),e.onerror(n.response),i.resolve(n.response),void 0):(e.data=e.processDownload(n.response),e.oncomplete(),e.logger.debug("Completed loading resource",e.path),i.resolve(e.data),void 0)},n.send(),i},e.prototype.getData=function(){return this.data},e.prototype.processDownload=function(t){return URL.createObjectURL(t)},e}();t.Resource=e})(ex||(ex={}));var ex;(function(t){var e=function(e){function i(i,n){void 0===n&&(n=!0),e.call(this,i,"blob",n),this.path=i,this.bustCache=n,this.loaded=new t.Promise,this._isLoaded=!1,this._sprite=null,this._sprite=new t.Sprite(this,0,0,0,0)}return __extends(i,e),i.prototype.isLoaded=function(){return this._isLoaded},i.prototype.load=function(){var i=this,n=new t.Promise,s=e.prototype.load.call(this);return s.then(function(){i.image=new Image,i.image.addEventListener("load",function(){i._isLoaded=!0,i.width=i._sprite.swidth=i._sprite.naturalWidth=i._sprite.width=i.image.naturalWidth,i.height=i._sprite.sheight=i._sprite.naturalHeight=i._sprite.height=i.image.naturalHeight,i.loaded.resolve(i.image),n.resolve(i.image)}),i.image.src=e.prototype.getData.call(i)},function(){n.reject("Error loading texture.")}),n},i.prototype.asSprite=function(){return this._sprite},i}(t.Resource);t.Texture=e;var i=function(){function e(){for(var i=[],n=0;arguments.length>n;n++)i[n-0]=arguments[n];this._logger=t.Logger.getInstance(),this.onprogress=function(){},this.oncomplete=function(){},this.onerror=function(){},this.onload=function(){},this._isLoaded=!1,this._selectedFile="",this._wasPlayingOnHidden=!1,this._selectedFile="";for(var s=0;i.length>s;s++)if(e.canPlayFile(i[s])){this._selectedFile=i[s];break}this._selectedFile||(this._logger.warn("This browser does not support any of the audio files specified:",i.join(", ")),this._logger.warn("Attempting to use",i[0]),this._selectedFile=i[0]),this.sound=new t.Internal.FallbackAudio(this._selectedFile,1)}return e.canPlayFile=function(e){try{var i=new Audio,n=/.*\.([A-Za-z0-9]+)$/,s=e.match(n)[1];return i.canPlayType("audio/"+s)?!0:!1}catch(o){return t.Logger.getInstance().warn("Cannot determine audio support, assuming no support for the Audio Tag",o),!1}},e.prototype.wireEngine=function(t){var e=this;t&&(this._engine=t,this._engine.on("hidden",function(){t.pauseAudioWhenHidden&&e.isPlaying()&&(e._wasPlayingOnHidden=!0,e.pause())}),this._engine.on("visible",function(){t.pauseAudioWhenHidden&&e._wasPlayingOnHidden&&(e.play(),e._wasPlayingOnHidden=!1)}))},e.prototype.setVolume=function(t){this.sound&&this.sound.setVolume(t)},e.prototype.setLoop=function(t){this.sound&&this.sound.setLoop(t)},e.prototype.isPlaying=function(){return this.sound?this.sound.isPlaying():void 0},e.prototype.play=function(){return this.sound?this.sound.play():void 0},e.prototype.pause=function(){this.sound&&this.sound.pause()},e.prototype.stop=function(){this.sound&&this.sound.stop()},e.prototype.isLoaded=function(){return this._isLoaded},e.prototype.load=function(){var e=this,i=new t.Promise;return this._logger.debug("Started loading sound",this._selectedFile),this.sound.onprogress=this.onprogress,this.sound.onload=function(){e.oncomplete(),e._isLoaded=!0,e._logger.debug("Completed loading sound",e._selectedFile),i.resolve(e.sound)},this.sound.onerror=function(t){e.onerror(t),i.resolve(t)},this.sound.load(),i},e}();t.Sound=i;var n=function(){function e(t){this._resourceList=[],this._index=0,this._resourceCount=0,this._numLoaded=0,this._progressCounts={},this._totalCounts={},this.onprogress=function(){},this.oncomplete=function(){},this.onerror=function(){},t&&this.addResources(t)}return e.prototype.wireEngine=function(t){this._engine=t},e.prototype.addResource=function(t){var e=this._index++;this._resourceList.push(t),this._progressCounts[e]=0,this._totalCounts[e]=1,this._resourceCount++},e.prototype.addResources=function(t){var e=0,i=t.length;for(e;i>e;e++)this.addResource(t[e])},e.prototype._sumCounts=function(t){var e=0;for(var i in t)e+=0|t[i];return e},e.prototype.isLoaded=function(){return this._numLoaded===this._resourceCount},e.prototype.load=function(){function e(t,i){t[i]&&t[i].load().then(function(){e(t,i+1)})}var i=this,n=new t.Promise,s=this;if(0===this._resourceList.length)return s.oncomplete.call(s),n;var o=Array(this._resourceList.length),r=this._resourceList.length;return this._resourceList.forEach(function(t,e){i._engine&&t.wireEngine(i._engine),t.onprogress=function(t){var i=t.total,n=t.loaded;o[e]={loaded:n/i*(100/r),total:100};var h=o.reduce(function(t,e){return{loaded:t.loaded+e.loaded,total:100}},{loaded:0,total:100});s.onprogress.call(s,h)},t.oncomplete=t.onerror=function(){s._numLoaded++,s._numLoaded===s._resourceCount&&(s.onprogress.call(s,{loaded:100,total:100}),s.oncomplete.call(s),n.resolve())}}),e(this._resourceList,0),n},e}();t.Loader=n})(ex||(ex={}));var ex;(function(t){var e=function(){function e(){this.failedTests=[],this._criticalTests={canvasSupport:function(){var t=document.createElement("canvas");return!(!t.getContext||!t.getContext("2d"))},arrayBufferSupport:function(){var t=new XMLHttpRequest;t.open("GET","/");try{t.responseType="arraybuffer"}catch(e){return!1}return"arraybuffer"===t.responseType},dataUrlSupport:function(){var t=document.createElement("canvas");return 0===t.toDataURL("image/png").indexOf("data:image/png")},objectUrlSupport:function(){return"URL"in window&&"revokeObjectURL"in URL&&"createObjectURL"in URL},rgbaSupport:function(){var t=document.createElement("a").style;return t.cssText="background-color:rgba(150,255,150,.5)",(""+t.backgroundColor).indexOf("rgba")>-1}},this._warningTest={webAudioSupport:function(){return!!(window.AudioContext||window.webkitAudioContext||window.mozAudioContext||window.msAudioContext||window.oAudioContext)},webglSupport:function(){var t=document.createElement("canvas");return!(!t.getContext||!t.getContext("webgl"))}}}return e.prototype.test=function(){var e=!1;for(var i in this._criticalTests)this._criticalTests[i]()||(this.failedTests.push(i),t.Logger.getInstance().error("Critical browser feature missing, Excalibur requires:",i),e=!0);if(e)return!1;for(var n in this._warningTest)this._warningTest[n]()||t.Logger.getInstance().warn("Warning browser feature missing, Excalibur will have reduced performance:",n);return!0},e}();t.Detector=e})(ex||(ex={}));var ex;(function(t){var e=function(){function e(e){this.path=e,this._isLoaded=!1,this.logger=t.Logger.getInstance(),this.onprogress=function(){},this.oncomplete=function(){},this.onerror=function(){},this._innerElement=document.createElement("div"),this._innerElement.className="excalibur-template"}return e.prototype.wireEngine=function(t){this._engine=t},e.prototype.getTemplateString=function(){return this._isLoaded?this._htmlString:""},e.prototype._compile=function(){this._innerElement.innerHTML=this._htmlString,this._styleElements=this._innerElement.querySelectorAll("[data-style]"),this._textElements=this._innerElement.querySelectorAll("[data-text]")},e.prototype._evaluateExpresion=function(t,e){var i=Function("return "+t+";"),n=i.call(e);return n},e.prototype.apply=function(t){for(var e=this,i=0;this._styleElements.length>i;i++)(function(){var n={};e._styleElements[i].dataset.style.split(";").forEach(function(t){if(t){var e=t.split(":");n[e[0].trim()]=e[1].trim()}});for(var s in n)(function(){var o=n[s];e._styleElements[i].style[s]=e._evaluateExpresion(o,t)})()})();for(var n=0;this._textElements.length>n;n++)(function(){var i=e._textElements[n].dataset.text;e._textElements[n].innerText=e._evaluateExpresion(i,t)})();return 1===this._innerElement.children.length&&(this._innerElement=this._innerElement.firstChild),this._innerElement},e.prototype.load=function(){var e=this,i=new t.Promise,n=new XMLHttpRequest;return n.open("GET",this.path,!0),n.responseType="text",n.onprogress=this.onprogress,n.onerror=this.onerror,n.onload=function(){return 200!==n.status?(e.logger.error("Failed to load html template resource ",e.path," server responded with error code",n.status),e.onerror(n.response),e._isLoaded=!1,i.resolve("error"),void 0):(e._htmlString=n.response,e.oncomplete(),e.logger.debug("Completed loading template",e.path),e._compile(),e._isLoaded=!0,i.resolve(e._htmlString),void 0)},n.overrideMimeType&&n.overrideMimeType("text/plain; charset=x-user-defined"),n.send(),i},e.prototype.isLoaded=function(){return this._isLoaded},e}();t.Template=e;var i=function(){function t(t,e,i){this.parent=document.getElementById(t),this.template=e,this._ctx=i,this.update()}return t.prototype.listen=function(t,e,i){var n=this;i||(i=function(){n.update()}),t.addEventListener&&e.forEach(function(e){t.addEventListener(e,i)})},t.prototype.update=function(){var t=this._applyTemplate(this.template,this._ctx);t instanceof String&&(this.parent.innerHTML=t),t instanceof Node&&this.parent.lastChild!==t&&this.parent.appendChild(t)},t.prototype._applyTemplate=function(t,e){return t.isLoaded()?t.apply(e):void 0},t}();t.Binding=i})(ex||(ex={}));var ex;(function(t){(function(t){t[t.Em=0]="Em",t[t.Rem=1]="Rem",t[t.Px=2]="Px",t[t.Pt=3]="Pt",t[t.Percent=4]="Percent"})(t.FontUnit||(t.FontUnit={}));var e=t.FontUnit;(function(t){t[t.Left=0]="Left",t[t.Right=1]="Right",t[t.Center=2]="Center",t[t.Start=3]="Start",t[t.End=4]="End"})(t.TextAlign||(t.TextAlign={}));var i=t.TextAlign;(function(t){t[t.Top=0]="Top",t[t.Hanging=1]="Hanging",t[t.Middle=2]="Middle",t[t.Alphabetic=3]="Alphabetic",t[t.Ideographic=4]="Ideographic",t[t.Bottom=5]="Bottom"})(t.BaseAlign||(t.BaseAlign={}));var n=t.BaseAlign,s=function(s){function o(o,r,h,a,c){s.call(this,r,h),this.fontSize=10,this.fontUnit=e.Px,this.textAlign=i.Left,this.baseAlign=n.Bottom,this.letterSpacing=0,this.caseInsensitive=!0,this._textShadowOn=!1,this._shadowOffsetX=0,this._shadowOffsetY=0,this._shadowColor=t.Color.Black.clone(),this._shadowColorDirty=!1,this._textSprites={},this._shadowSprites={},this._color=t.Color.Black.clone(),this.text=o||"",this.color=t.Color.Black.clone(),this.spriteFont=c,this.collisionType=t.CollisionType.PreventCollision,this.fontFamily=a||"10px sans-serif"}return __extends(o,s),o.prototype.getTextWidth=function(t){var e=t.font;t.font=this.fontFamily;var i=t.measureText(this.text).width;return t.font=e,i},o.prototype._lookupFontUnit=function(t){switch(t){case e.Em:return"em";case e.Rem:return"rem";case e.Pt:return"pt";case e.Px:return"px";case e.Percent:return"%";default:return"px"}},o.prototype._lookupTextAlign=function(t){switch(t){case i.Left:return"left";case i.Right:return"right";case i.Center:return"center";case i.End:return"end";case i.Start:return"start";default:return"start"}},o.prototype._lookupBaseAlign=function(t){switch(t){case n.Alphabetic:return"alphabetic";case n.Bottom:return"bottom";case n.Hanging:return"hangin";case n.Ideographic:return"ideographic";case n.Middle:return"middle";case n.Top:return"top";default:return"alphabetic"}},o.prototype.setTextShadow=function(t,e,i){this.spriteFont.setTextShadow(t,e,i)},o.prototype.useTextShadow=function(t){this.spriteFont.useTextShadow(t)},o.prototype.clearTextShadow=function(){this._textShadowOn=!1,this._shadowOffsetX=0,this._shadowOffsetY=0,this._shadowColor=t.Color.Black.clone()},o.prototype.update=function(t,e){s.prototype.update.call(this,t,e)},o.prototype.draw=function(t,e){t.save(),t.translate(this.x,this.y),t.scale(this.scale.x,this.scale.y),t.rotate(this.rotation),this._textShadowOn&&(t.save(),t.translate(this._shadowOffsetX,this._shadowOffsetY),this._fontDraw(t,e,this._shadowSprites),t.restore()),this._fontDraw(t,e,this._textSprites),s.prototype.draw.call(this,t,e),t.restore()},o.prototype._fontDraw=function(t){if(this.spriteFont)this.spriteFont.draw(t,this.text,0,0,{color:this.color.clone(),baseAlign:this.baseAlign,textAlign:this.textAlign,fontSize:this.fontSize,letterSpacing:this.letterSpacing,opacity:this.opacity});else{var e=t.textAlign,i=t.textBaseline;t.textAlign=this._lookupTextAlign(this.textAlign),t.textBaseline=this._lookupBaseAlign(this.baseAlign),this.color&&(this.color.a=this.opacity),t.fillStyle=""+this.color,t.font=""+this.fontSize+this._lookupFontUnit(this.fontUnit)+" "+this.fontFamily,this.maxWidth?t.fillText(this.text,0,0,this.maxWidth):t.fillText(this.text,0,0),t.textAlign=e,t.textBaseline=i}},o.prototype.debugDraw=function(t){s.prototype.debugDraw.call(this,t)},o}(t.Actor);t.Label=s})(ex||(ex={}));var ex;(function(t){var e;(function(e){(function(t){t[t.Touch=0]="Touch",t[t.Mouse=1]="Mouse",t[t.Pen=2]="Pen",t[t.Unknown=3]="Unknown"})(e.PointerType||(e.PointerType={}));var i=e.PointerType;(function(t){t[t.Left=0]="Left",t[t.Middle=1]="Middle",t[t.Right=2]="Right",t[t.Unknown=3]="Unknown"})(e.PointerButton||(e.PointerButton={}));var n=e.PointerButton;(function(t){t[t.Canvas=0]="Canvas",t[t.Document=1]="Document" +})(e.PointerScope||(e.PointerScope={}));var s=e.PointerScope,o=function(t){function e(e,i,n,s,o,r){t.call(this),this.x=e,this.y=i,this.index=n,this.pointerType=s,this.button=o,this.ev=r}return __extends(e,t),e}(t.GameEvent);e.PointerEvent=o;var r=function(e){function r(t){e.call(this),this._pointerDown=[],this._pointerUp=[],this._pointerMove=[],this._pointerCancel=[],this._pointers=[],this._activePointers=[],this._engine=t,this._pointers.push(new h),this._activePointers=[-1],this.primary=this._pointers[0]}return __extends(r,e),r.prototype.init=function(t){void 0===t&&(t=s.Document);var e=document;e=t===s.Document?document:this._engine.canvas,e.addEventListener("touchstart",this._handleTouchEvent("down",this._pointerDown)),e.addEventListener("touchend",this._handleTouchEvent("up",this._pointerUp)),e.addEventListener("touchmove",this._handleTouchEvent("move",this._pointerMove)),e.addEventListener("touchcancel",this._handleTouchEvent("cancel",this._pointerCancel)),window.PointerEvent?(this._engine.canvas.style.touchAction="none",e.addEventListener("pointerdown",this._handlePointerEvent("down",this._pointerDown)),e.addEventListener("pointerup",this._handlePointerEvent("up",this._pointerUp)),e.addEventListener("pointermove",this._handlePointerEvent("move",this._pointerMove)),e.addEventListener("pointercancel",this._handlePointerEvent("cancel",this._pointerMove))):window.MSPointerEvent?(this._engine.canvas.style.msTouchAction="none",e.addEventListener("MSPointerDown",this._handlePointerEvent("down",this._pointerDown)),e.addEventListener("MSPointerUp",this._handlePointerEvent("up",this._pointerUp)),e.addEventListener("MSPointerMove",this._handlePointerEvent("move",this._pointerMove)),e.addEventListener("MSPointerCancel",this._handlePointerEvent("cancel",this._pointerMove))):(e.addEventListener("mousedown",this._handleMouseEvent("down",this._pointerDown)),e.addEventListener("mouseup",this._handleMouseEvent("up",this._pointerUp)),e.addEventListener("mousemove",this._handleMouseEvent("move",this._pointerMove)))},r.prototype.update=function(){this._pointerUp.length=0,this._pointerDown.length=0,this._pointerMove.length=0,this._pointerCancel.length=0},r.prototype.at=function(t){if(t>=this._pointers.length)for(var e=this._pointers.length-1,i=t;i>e;e++)this._pointers.push(new h),this._activePointers.push(-1);return this._pointers[t]},r.prototype.count=function(){return this._pointers.length},r.prototype.propogate=function(e){var i=e instanceof t.UIActor,n=0,s=this._pointerUp.length;for(n;s>n;n++)e.contains(this._pointerUp[n].x,this._pointerUp[n].y,!i)&&e.eventDispatcher.emit("pointerup",this._pointerUp[n]);for(n=0,s=this._pointerDown.length,n;s>n;n++)e.contains(this._pointerDown[n].x,this._pointerDown[n].y,!i)&&e.eventDispatcher.emit("pointerdown",this._pointerDown[n]);if(e.capturePointer.captureMoveEvents)for(n=0,s=this._pointerMove.length,n;s>n;n++)e.contains(this._pointerMove[n].x,this._pointerMove[n].y,!i)&&e.eventDispatcher.emit("pointermove",this._pointerMove[n]);for(n=0,s=this._pointerCancel.length,n;s>n;n++)e.contains(this._pointerCancel[n].x,this._pointerCancel[n].y,!i)&&e.eventDispatcher.emit("pointercancel",this._pointerCancel[n])},r.prototype._handleMouseEvent=function(e,n){var s=this;return function(r){r.preventDefault();var h=r.pageX-t.Util.getPosition(s._engine.canvas).x,a=r.pageY-t.Util.getPosition(s._engine.canvas).y,c=s._engine.screenToWorldCoordinates(new t.Point(h,a)),l=new o(c.x,c.y,0,i.Mouse,r.button,r);n.push(l),s.at(0).eventDispatcher.emit(e,l)}},r.prototype._handleTouchEvent=function(e,s){var r=this;return function(h){h.preventDefault();for(var a=0,c=h.changedTouches.length;c>a;a++){var l=r._pointers.length>1?r._getPointerIndex(h.changedTouches[a].identifier):0;if(-1!==l){var u=h.changedTouches[a].pageX-t.Util.getPosition(r._engine.canvas).x,p=h.changedTouches[a].pageY-t.Util.getPosition(r._engine.canvas).y,d=r._engine.screenToWorldCoordinates(new t.Point(u,p)),f=new o(d.x,d.y,l,i.Touch,n.Unknown,h);s.push(f),r.at(l).eventDispatcher.emit(e,f),r._pointers.length>1&&("up"===e?r._activePointers[l]=-1:"down"===e&&(r._activePointers[l]=h.changedTouches[a].identifier))}}}},r.prototype._handlePointerEvent=function(e,i){var n=this;return function(s){s.preventDefault();var r=n._pointers.length>1?n._getPointerIndex(s.pointerId):0;if(-1!==r){var h=s.pageX-t.Util.getPosition(n._engine.canvas).x,a=s.pageY-t.Util.getPosition(n._engine.canvas).y,c=n._engine.screenToWorldCoordinates(new t.Point(h,a)),l=new o(c.x,c.y,r,n._stringToPointerType(s.pointerType),s.button,s);i.push(l),n.at(r).eventDispatcher.emit(e,l),n._pointers.length>1&&("up"===e?n._activePointers[r]=-1:"down"===e&&(n._activePointers[r]=s.pointerId))}}},r.prototype._getPointerIndex=function(t){var e;if((e=this._activePointers.indexOf(t))>-1)return e;for(var i=0;this._activePointers.length>i;i++)if(-1===this._activePointers[i])return i;return-1},r.prototype._stringToPointerType=function(t){switch(t){case"touch":return i.Touch;case"mouse":return i.Mouse;case"pen":return i.Pen;default:return i.Unknown}},r}(t.Class);e.Pointers=r;var h=function(t){function e(){t.apply(this,arguments)}return __extends(e,t),e}(t.Class);e.Pointer=h})(e=t.Input||(t.Input={}))})(ex||(ex={}));var ex;(function(t){var e;(function(e){(function(t){t[t.Num1=97]="Num1",t[t.Num2=98]="Num2",t[t.Num3=99]="Num3",t[t.Num4=100]="Num4",t[t.Num5=101]="Num5",t[t.Num6=102]="Num6",t[t.Num7=103]="Num7",t[t.Num8=104]="Num8",t[t.Num9=105]="Num9",t[t.Num0=96]="Num0",t[t.Numlock=144]="Numlock",t[t.Semicolon=186]="Semicolon",t[t.A=65]="A",t[t.B=66]="B",t[t.C=67]="C",t[t.D=68]="D",t[t.E=69]="E",t[t.F=70]="F",t[t.G=71]="G",t[t.H=72]="H",t[t.I=73]="I",t[t.J=74]="J",t[t.K=75]="K",t[t.L=76]="L",t[t.M=77]="M",t[t.N=78]="N",t[t.O=79]="O",t[t.P=80]="P",t[t.Q=81]="Q",t[t.R=82]="R",t[t.S=83]="S",t[t.T=84]="T",t[t.U=85]="U",t[t.V=86]="V",t[t.W=87]="W",t[t.X=88]="X",t[t.Y=89]="Y",t[t.Z=90]="Z",t[t.Shift=16]="Shift",t[t.Alt=18]="Alt",t[t.Up=38]="Up",t[t.Down=40]="Down",t[t.Left=37]="Left",t[t.Right=39]="Right",t[t.Space=32]="Space",t[t.Esc=27]="Esc"})(e.Keys||(e.Keys={})),e.Keys;var i=function(t){function e(e){t.call(this),this.key=e}return __extends(e,t),e}(t.GameEvent);e.KeyEvent=i;var n=function(t){function e(e){t.call(this),this._keys=[],this._keysUp=[],this._keysDown=[],this._engine=e}return __extends(e,t),e.prototype.init=function(){var t=this;window.addEventListener("blur",function(){t._keys.length=0}),window.addEventListener("keyup",function(e){var n=t._keys.indexOf(e.keyCode);t._keys.splice(n,1),t._keysUp.push(e.keyCode);var s=new i(e.keyCode);t.eventDispatcher.emit("up",s),t.eventDispatcher.emit("release",s)}),window.addEventListener("keydown",function(e){if(-1===t._keys.indexOf(e.keyCode)){t._keys.push(e.keyCode),t._keysDown.push(e.keyCode);var n=new i(e.keyCode);t.eventDispatcher.emit("down",n),t.eventDispatcher.emit("press",n)}})},e.prototype.update=function(){this._keysDown.length=0,this._keysUp.length=0;for(var t=0;this._keys.length>t;t++)this.eventDispatcher.emit("hold",new i(this._keys[t]))},e.prototype.getKeys=function(){return this._keys},e.prototype.wasPressed=function(t){return this._keysDown.indexOf(t)>-1},e.prototype.isHeld=function(t){return this._keys.indexOf(t)>-1},e.prototype.wasReleased=function(t){return this._keysUp.indexOf(t)>-1},e}(t.Class);e.Keyboard=n})(e=t.Input||(t.Input={}))})(ex||(ex={}));var ex;(function(t){var e;(function(e){var i=function(e){function i(t){e.call(this),this.enabled=!1,this.supported=!!navigator.getGamepads,this._gamePadTimeStamps=[0,0,0,0],this._oldPads=[],this._pads=[],this._initSuccess=!1,this._navigator=navigator,this._minimumConfiguration=null,this._engine=t}return __extends(i,e),i.prototype.init=function(){this.supported&&(this._initSuccess||(this._oldPads=this._clonePads(this._navigator.getGamepads()),this._oldPads.length&&this._oldPads[0]&&(this._initSuccess=!0)))},i.prototype.setMinimumGamepadConfiguration=function(t){this._enableAndUpdate(),this._minimumConfiguration=t},i.prototype._enableAndUpdate=function(){this.enabled||(this.enabled=!0,this.update(100))},i.prototype._isGamepadValid=function(t){if(!this._minimumConfiguration)return!0;if(!t)return!1;var e=t.axes.filter(function(t){return void 0!==typeof t}).length,i=t.buttons.filter(function(t){return void 0!==typeof t}).length;return e>=this._minimumConfiguration.axis&&i>=this._minimumConfiguration.buttons&&t.connected},i.prototype.on=function(t,i){this._enableAndUpdate(),e.prototype.on.call(this,t,i)},i.prototype.off=function(t,i){this._enableAndUpdate(),e.prototype.off.call(this,t,i)},i.prototype.update=function(){if(this.enabled&&this.supported){this.init();for(var e=this._navigator.getGamepads(),i=0;e.length>i;i++)if(e[i]){if(!this.at(i).connected&&this._isGamepadValid(e[i])&&this.eventDispatcher.emit("connect",new t.GamepadConnectEvent(i,this.at(i))),this.at(i).connected=!0,!e[i].timestamp||e[i].timestamp!==this._gamePadTimeStamps[i]){this._gamePadTimeStamps[i]=e[i].timestamp,this.at(i).navigatorGamepad=e[i];var n,r,h,a,c;for(n in s)"number"==typeof s[n]&&(a=s[n],e[i].buttons[a]&&(h=e[i].buttons[a].value,h!==this._oldPads[i].getButton(a)&&(e[i].buttons[a].pressed?(this.at(i).updateButton(a,h),this.at(i).eventDispatcher.publish("button",new t.GamepadButtonEvent(a,h))):this.at(i).updateButton(a,0))));for(r in o)"number"==typeof o[r]&&(c=o[r],h=e[i].axes[c],h!==this._oldPads[i].getAxes(c)&&(this.at(i).updateAxes(c,h),this.at(i).eventDispatcher.emit("axis",new t.GamepadAxisEvent(c,h))));this._oldPads[i]=this._clonePad(e[i])}}else this.at(i).connected&&this.eventDispatcher.emit("disconnect",new t.GamepadDisconnectEvent(i)),this.at(i).connected=!1}},i.prototype.at=function(t){if(this._enableAndUpdate(),t>=this._pads.length)for(var e=this._pads.length-1,i=t;i>e;e++)this._pads.push(new n),this._oldPads.push(new n);return this._pads[t]},i.prototype.getValidGamepads=function(){this._enableAndUpdate();for(var t=[],e=0;this._pads.length>e;e++)this._isGamepadValid(this.at(e).navigatorGamepad)&&this.at(e).connected&&t.push(this.at(e));return t},i.prototype.count=function(){return this._pads.filter(function(t){return t.connected}).length},i.prototype._clonePads=function(t){for(var e=[],i=0,n=t.length;n>i;i++)e.push(this._clonePad(t[i]));return e},i.prototype._clonePad=function(t){var e,i,s=new n;if(!t)return s;for(e=0,i=t.buttons.length;i>e;e++)t.buttons[e]&&s.updateButton(e,t.buttons[e].value);for(e=0,i=t.axes.length;i>e;e++)s.updateAxes(e,t.axes[e]);return s},i.MinAxisMoveThreshold=.05,i}(t.Class);e.Gamepads=i;var n=function(t){function e(){t.call(this),this.connected=!1,this._buttons=Array(16),this._axes=Array(4);var e;for(e=0;this._buttons.length>e;e++)this._buttons[e]=0;for(e=0;this._axes.length>e;e++)this._axes[e]=0}return __extends(e,t),e.prototype.isButtonPressed=function(t,e){return void 0===e&&(e=1),this._buttons[t]>=e},e.prototype.getButton=function(t){return this._buttons[t]},e.prototype.getAxes=function(t){var e=this._axes[t];return Math.abs(e)n;n++)this._animations[n].animation.draw(i,this._animations[n].x,this._animations[n].y);if(this.fps=1/(e/1e3),this.isDebug){this.ctx.font="Consolas",this.ctx.fillStyle=""+this.debugColor;for(var o=this.input.keyboard.getKeys(),r=0;o.length>r;r++)this.ctx.fillText(""+o[r]+" : "+(t.Input.Keys[o[r]]?t.Input.Keys[o[r]]:"Not Mapped"),100,10*r+10);this.ctx.fillText("FPS:"+(""+this.fps.toFixed(2)),10,10)}for(var h=0;this.postProcessors.length>h;h++)this.postProcessors[h].process(this.ctx.getImageData(0,0,this.width,this.height),this.ctx);this.emit("postdraw",new t.PreDrawEvent(i,e,this))},s.prototype.start=function(e){if(!this._compatible){var i=new t.Promise;return i.reject("Excalibur is incompatible with your browser")}var n;if(e?(e.wireEngine(this),n=this.load(e)):n=t.Promise.wrap(),!this._hasStarted){this._hasStarted=!0,this._logger.debug("Starting game...");var s=Date.now(),o=this;(function r(){if(o._hasStarted)try{o._requestId=window.requestAnimationFrame(r);var t=Date.now(),e=Math.floor(t-s)||1;e>200&&(e=1),o._update(e),o._draw(e),s=t}catch(i){window.cancelAnimationFrame(o._requestId),o.stop(),o.onFatalException(i)}})(),this._logger.debug("Game started")}return n},s.prototype.stop=function(){this._hasStarted&&(this._hasStarted=!1,this._logger.debug("Game stopped"))},s.prototype.screenshot=function(){var t=new Image,e=this.canvas.toDataURL("image/png");return t.src=e,t},s.prototype._drawLoadingBar=function(t,e,i){if(this._loadingDraw)return this._loadingDraw(t,e,i),void 0;var n=this.canvas.height/2,s=this.canvas.width/3,o=s,r=new Image;r.src="data:image/png;base64,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"; +var h=3*s/8,a=this.getAntialiasing();this.setAntialiasing(!0),t.drawImage(r,0,0,800,300,o,n-h-20,s,h),t.strokeStyle="white",t.lineWidth=2,t.strokeRect(o,n,s,20);var c=s*(e/i);t.fillStyle="white";var l=5,u=c-2*l,p=20-2*l;t.fillRect(o+l,n+l,u>0?u:0,p),this.setAntialiasing(a)},s.prototype.setLoadingDrawFunction=function(t){this._loadingDraw=t},s.prototype.load=function(e){var i=this,n=new t.Promise;return this._isLoading=!0,e.onprogress=function(t){i._progress=t.loaded,i._total=t.total,i._logger.debug("Loading "+(100*i._progress/i._total).toFixed(0))},e.oncomplete=function(){setTimeout(function(){i._isLoading=!1,n.resolve()},500)},e.load(),n},s}(t.Class);t.Engine=e,function(t){t[t.FullScreen=0]="FullScreen",t[t.Container=1]="Container",t[t.Fixed=2]="Fixed"}(t.DisplayMode||(t.DisplayMode={}));var i=t.DisplayMode,n=function(){function t(t,e,i){this.animation=t,this.x=e,this.y=i}return t}()})(ex||(ex={})); +; +// Concatenated onto excalibur after build +// Exports the excalibur module so it can be used with browserify +// https://github.com/excaliburjs/Excalibur/issues/312 +if (typeof module !== 'undefined') {module.exports = ex;} \ No newline at end of file diff --git a/package.json b/package.json index b98f16ea2..e8068fd92 100644 --- a/package.json +++ b/package.json @@ -12,10 +12,7 @@ "bugs": { "url": "https://github.com/excaliburjs/Excalibur/issues" }, - "license": { - "type": "BSD-2-Clause", - "url": "https://github.com/excaliburjs/Excalibur/blob/master/LICENSE.md" - }, + "license": "BSD-2-Clause", "keywords": [ "excalibur", "game", @@ -37,6 +34,7 @@ "grunt-minified": "0.0.6", "grunt-shell": "0.6.1", "grunt-tslint": "~2.3.0-beta", + "tslint": "~2.3.0-beta", "jasmine-node": "1.10.2", "travis-ci": "2.0.3" } diff --git a/sandbox/web/Excalibur.js b/sandbox/web/Excalibur.js index 9730fd49e..1442266d5 100644 --- a/sandbox/web/Excalibur.js +++ b/sandbox/web/Excalibur.js @@ -1,885 +1,889 @@ -var __extends = (this && this.__extends) || function (d, b) { - for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; - function __() { this.constructor = d; } - d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); -}; +/*! excalibur - v0.6.0 - 2016-01-19 +* https://github.com/excaliburjs/Excalibur +* Copyright (c) 2016 ; Licensed BSD-2-Clause*/ +if (typeof window === 'undefined') { + window = { audioContext: function () { return; } }; +} +if (typeof window !== 'undefined' && !window.requestAnimationFrame) { + window.requestAnimationFrame = + window.webkitRequestAnimationFrame || + window.mozRequestAnimationFrame || + function (callback) { window.setInterval(callback, 1000 / 60); }; +} +if (typeof window !== 'undefined' && !window.cancelAnimationFrame) { + window.cancelAnimationFrame = + window.webkitCancelAnimationFrame || + window.mozCancelAnimationFrame || + function (callback) { return; }; +} +if (typeof window !== 'undefined' && !window.AudioContext) { + window.AudioContext = window.AudioContext || + window.webkitAudioContext || + window.mozAudioContext || + window.msAudioContext || + window.oAudioContext; +} +// Polyfill from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach +// Production steps of ECMA-262, Edition 5, 15.4.4.18 +// Reference: http://es5.github.io/#x15.4.4.18 +if (!Array.prototype.forEach) { + Array.prototype.forEach = function (callback, thisArg) { + var T, k; + if (this == null) { + throw new TypeError(' this is null or not defined'); + } + // 1. Let O be the result of calling ToObject passing the |this| value as the argument. + var O = Object(this); + // 2. Let lenValue be the result of calling the Get internal method of O with the argument "length". + // 3. Let len be ToUint32(lenValue). + var len = O.length >>> 0; + // 4. If IsCallable(callback) is false, throw a TypeError exception. + // See: http://es5.github.com/#x9.11 + if (typeof callback !== 'function') { + throw new TypeError(callback + ' is not a function'); + } + // 5. If thisArg was supplied, let T be thisArg; else let T be undefined. + if (arguments.length > 1) { + T = thisArg; + } + // 6. Let k be 0 + k = 0; + // 7. Repeat, while k < len + while (k < len) { + var kValue; + // a. Let Pk be ToString(k). + // This is implicit for LHS operands of the in operator + // b. Let kPresent be the result of calling the HasProperty internal method of O with argument Pk. + // This step can be combined with c + // c. If kPresent is true, then + if (k in O) { + // i. Let kValue be the result of calling the Get internal method of O with argument Pk. + kValue = O[k]; + // ii. Call the Call internal method of callback with T as the this value and + // argument list containing kValue, k, and O. + callback.call(T, kValue, k, O); + } + // d. Increase k by 1. + k++; + } + // 8. return undefined + }; +} +// Polyfill from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some +if (!Array.prototype.some) { + Array.prototype.some = function (fun /*, thisArg */) { + 'use strict'; + if (this === void 0 || this === null) { + throw new TypeError(); + } + var t = Object(this); + var len = t.length >>> 0; + if (typeof fun !== 'function') { + throw new TypeError(); + } + var thisArg = arguments.length >= 2 ? arguments[1] : void 0; + for (var i = 0; i < len; i++) { + if (i in t && fun.call(thisArg, t[i], i, t)) { + return true; + } + } + return false; + }; +} +// Polyfill from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind#Polyfill +if (!Function.prototype.bind) { + Function.prototype.bind = function (oThis) { + if (typeof this !== 'function') { + // closest thing possible to the ECMAScript 5 + // internal IsCallable function + throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable'); + } + var aArgs = Array.prototype.slice.call(arguments, 1), fToBind = this, fNOP = function () { return; }, fBound = function () { + return fToBind.apply(this instanceof fNOP && oThis + ? this + : oThis, aArgs.concat(Array.prototype.slice.call(arguments))); + }; + fNOP.prototype = this.prototype; + fBound.prototype = new fNOP(); + return fBound; + }; +} var ex; (function (ex) { /** - * A simple 2D point on a plane + * Effects + * + * These effects can be applied to any bitmap image but are mainly used + * for [[Sprite]] effects or [[Animation]] effects. + * + * Because these manipulate raw pixels, there is a performance impact to applying + * too many effects. Excalibur tries its best to by using caching to mitigate + * performance issues. + * + * Create your own effects by implementing [[ISpriteEffect]]. */ - var Point = (function () { - /** - * @param x X coordinate of the point - * @param y Y coordinate of the point - */ - function Point(x, y) { - this.x = x; - this.y = y; - } + var Effects; + (function (Effects) { /** - * Convert this point to a vector + * Applies the "Grayscale" effect to a sprite, removing color information. */ - Point.prototype.toVector = function () { - return new Vector(this.x, this.y); - }; + var Grayscale = (function () { + function Grayscale() { + } + Grayscale.prototype.updatePixel = function (x, y, imageData) { + var firstPixel = (x + y * imageData.width) * 4; + var pixel = imageData.data; + var avg = (pixel[firstPixel + 0] + pixel[firstPixel + 1] + pixel[firstPixel + 2]) / 3; + pixel[firstPixel + 0] = avg; + pixel[firstPixel + 1] = avg; + pixel[firstPixel + 2] = avg; + }; + return Grayscale; + })(); + Effects.Grayscale = Grayscale; /** - * Rotates the current point around another by a certain number of - * degrees in radians - * @param angle The angle in radians - * @param anchor The point to rotate around + * Applies the "Invert" effect to a sprite, inverting the pixel colors. */ - Point.prototype.rotate = function (angle, anchor) { - if (!anchor) { - anchor = new ex.Point(0, 0); + var Invert = (function () { + function Invert() { } - var sinAngle = Math.sin(angle); - var cosAngle = Math.cos(angle); - var x = cosAngle * (this.x - anchor.x) - sinAngle * (this.y - anchor.y) + anchor.x; - var y = sinAngle * (this.x - anchor.x) + cosAngle * (this.y - anchor.y) + anchor.y; - return new Point(x, y); - }; + Invert.prototype.updatePixel = function (x, y, imageData) { + var firstPixel = (x + y * imageData.width) * 4; + var pixel = imageData.data; + pixel[firstPixel + 0] = 255 - pixel[firstPixel + 0]; + pixel[firstPixel + 1] = 255 - pixel[firstPixel + 1]; + pixel[firstPixel + 2] = 255 - pixel[firstPixel + 2]; + }; + return Invert; + })(); + Effects.Invert = Invert; /** - * Translates the current point by a vector - * @param vector The other vector to add to + * Applies the "Opacity" effect to a sprite, setting the alpha of all pixels to a given value. */ - Point.prototype.add = function (vector) { - return new Point(this.x + vector.x, this.y + vector.y); - }; + var Opacity = (function () { + /** + * @param opacity The new opacity of the sprite from 0-1.0 + */ + function Opacity(opacity) { + this.opacity = opacity; + } + Opacity.prototype.updatePixel = function (x, y, imageData) { + var firstPixel = (x + y * imageData.width) * 4; + var pixel = imageData.data; + if (pixel[firstPixel + 3] !== 0) { + pixel[firstPixel + 3] = Math.round(this.opacity * 255); + } + }; + return Opacity; + })(); + Effects.Opacity = Opacity; /** - * Sets the x and y components at once + * Applies the "Colorize" effect to a sprite, changing the color channels of all the pixels to an + * average of the original color and the provided color */ - Point.prototype.setTo = function (x, y) { - this.x = x; - this.y = y; - }; + var Colorize = (function () { + /** + * @param color The color to apply to the sprite + */ + function Colorize(color) { + this.color = color; + } + Colorize.prototype.updatePixel = function (x, y, imageData) { + var firstPixel = (x + y * imageData.width) * 4; + var pixel = imageData.data; + if (pixel[firstPixel + 3] !== 0) { + pixel[firstPixel + 0] = (pixel[firstPixel + 0] + this.color.r) / 2; + pixel[firstPixel + 1] = (pixel[firstPixel + 1] + this.color.g) / 2; + pixel[firstPixel + 2] = (pixel[firstPixel + 2] + this.color.b) / 2; + } + }; + return Colorize; + })(); + Effects.Colorize = Colorize; /** - * Clones a new point that is a copy of this one. + * Applies the "Lighten" effect to a sprite, changes the lightness of the color according to HSL */ - Point.prototype.clone = function () { - return new Point(this.x, this.y); - }; + var Lighten = (function () { + /** + * @param factor The factor of the effect between 0-1 + */ + function Lighten(factor) { + if (factor === void 0) { factor = 0.1; } + this.factor = factor; + } + Lighten.prototype.updatePixel = function (x, y, imageData) { + var firstPixel = (x + y * imageData.width) * 4; + var pixel = imageData.data; + var color = ex.Color.fromRGB(pixel[firstPixel + 0], pixel[firstPixel + 1], pixel[firstPixel + 2], pixel[firstPixel + 3]).lighten(this.factor); + pixel[firstPixel + 0] = color.r; + pixel[firstPixel + 1] = color.g; + pixel[firstPixel + 2] = color.b; + pixel[firstPixel + 3] = color.a; + }; + return Lighten; + })(); + Effects.Lighten = Lighten; /** - * Compares this point against another and tests for equality - * @param point The other point to compare to + * Applies the "Darken" effect to a sprite, changes the darkness of the color according to HSL */ - Point.prototype.equals = function (point) { - return this.x === point.x && this.y === point.y; - }; - return Point; - })(); - ex.Point = Point; - /** - * A 2D vector on a plane. - */ - var Vector = (function (_super) { - __extends(Vector, _super); - /** - * @param x X component of the Vector - * @param y Y component of the Vector - */ - function Vector(x, y) { - _super.call(this, x, y); - this.x = x; - this.y = y; - } - /** - * Returns a vector of unit length in the direction of the specified angle. - * @param angle The angle to generate the vector - */ - Vector.fromAngle = function (angle) { - return new Vector(Math.cos(angle), Math.sin(angle)); - }; - /** - * The distance to another vector - * @param v The other vector - */ - Vector.prototype.distance = function (v) { - if (!v) { - v = new Vector(0.0, 0.0); + var Darken = (function () { + /** + * @param factor The factor of the effect between 0-1 + */ + function Darken(factor) { + if (factor === void 0) { factor = 0.1; } + this.factor = factor; } - return Math.sqrt(Math.pow(this.x - v.x, 2) + Math.pow(this.y - v.y, 2)); - }; + Darken.prototype.updatePixel = function (x, y, imageData) { + var firstPixel = (x + y * imageData.width) * 4; + var pixel = imageData.data; + var color = ex.Color.fromRGB(pixel[firstPixel + 0], pixel[firstPixel + 1], pixel[firstPixel + 2], pixel[firstPixel + 3]).darken(this.factor); + pixel[firstPixel + 0] = color.r; + pixel[firstPixel + 1] = color.g; + pixel[firstPixel + 2] = color.b; + pixel[firstPixel + 3] = color.a; + }; + return Darken; + })(); + Effects.Darken = Darken; /** - * Normalizes a vector to have a magnitude of 1. + * Applies the "Saturate" effect to a sprite, saturates the color acccording to HSL */ - Vector.prototype.normalize = function () { - var d = this.distance(); - if (d > 0) { - return new Vector(this.x / d, this.y / d); - } - else { - return new Vector(0, 1); + var Saturate = (function () { + /** + * @param factor The factor of the effect between 0-1 + */ + function Saturate(factor) { + if (factor === void 0) { factor = 0.1; } + this.factor = factor; } - }; - /** - * Scales a vector's by a factor of size - * @param size The factor to scale the magnitude by - */ - Vector.prototype.scale = function (size) { - return new Vector(this.x * size, this.y * size); - }; - /** - * Adds one vector to another, alias for add - * @param v The vector to add - */ - Vector.prototype.plus = function (v) { - return this.add(v); - }; - /** - * Adds one vector to another - * @param v The vector to add - */ - Vector.prototype.add = function (v) { - return new Vector(this.x + v.x, this.y + v.y); - }; - /** - * Subtracts a vector from another, alias for minus - * @param v The vector to subtract - */ - Vector.prototype.subtract = function (v) { - return this.minus(v); - }; - /** - * Subtracts a vector from the current vector - * @param v The vector to subtract - */ - Vector.prototype.minus = function (v) { - return new Vector(this.x - v.x, this.y - v.y); - }; - /** - * Performs a dot product with another vector - * @param v The vector to dot - */ - Vector.prototype.dot = function (v) { - return this.x * v.x + this.y * v.y; - }; - /** - * Performs a 2D cross product with another vector. 2D cross products return a scalar value not a vector. - * @param v The vector to cross - */ - Vector.prototype.cross = function (v) { - return this.x * v.y - this.y * v.x; - }; - /** - * Returns the perpendicular vector to this one - */ - Vector.prototype.perpendicular = function () { - return new Vector(this.y, -this.x); - }; - /** - * Returns the normal vector to this one - */ - Vector.prototype.normal = function () { - return this.perpendicular().normalize(); - }; - /** - * Returns the angle of this vector. - */ - Vector.prototype.toAngle = function () { - return Math.atan2(this.y, this.x); - }; - /** - * Returns the point represention of this vector - */ - Vector.prototype.toPoint = function () { - return new Point(this.x, this.y); - }; - /** - * Rotates the current vector around a point by a certain number of - * degrees in radians - */ - Vector.prototype.rotate = function (angle, anchor) { - return _super.prototype.rotate.call(this, angle, anchor).toVector(); - }; - /** - * Creates new vector that has the same values as the previous. - */ - Vector.prototype.clone = function () { - return new Vector(this.x, this.y); - }; - /** - * A (0, 0) vector - */ - Vector.Zero = new Vector(0, 0); - return Vector; - })(Point); - ex.Vector = Vector; - /** - * A 2D ray that can be cast into the scene to do collision detection - */ - var Ray = (function () { + Saturate.prototype.updatePixel = function (x, y, imageData) { + var firstPixel = (x + y * imageData.width) * 4; + var pixel = imageData.data; + var color = ex.Color.fromRGB(pixel[firstPixel + 0], pixel[firstPixel + 1], pixel[firstPixel + 2], pixel[firstPixel + 3]).saturate(this.factor); + pixel[firstPixel + 0] = color.r; + pixel[firstPixel + 1] = color.g; + pixel[firstPixel + 2] = color.b; + pixel[firstPixel + 3] = color.a; + }; + return Saturate; + })(); + Effects.Saturate = Saturate; /** - * @param pos The starting position for the ray - * @param dir The vector indicating the direction of the ray + * Applies the "Desaturate" effect to a sprite, desaturates the color acccording to HSL */ - function Ray(pos, dir) { - this.pos = pos; - this.dir = dir.normalize(); - } + var Desaturate = (function () { + /** + * @param factor The factor of the effect between 0-1 + */ + function Desaturate(factor) { + if (factor === void 0) { factor = 0.1; } + this.factor = factor; + } + Desaturate.prototype.updatePixel = function (x, y, imageData) { + var firstPixel = (x + y * imageData.width) * 4; + var pixel = imageData.data; + var color = ex.Color.fromRGB(pixel[firstPixel + 0], pixel[firstPixel + 1], pixel[firstPixel + 2], pixel[firstPixel + 3]).desaturate(this.factor); + pixel[firstPixel + 0] = color.r; + pixel[firstPixel + 1] = color.g; + pixel[firstPixel + 2] = color.b; + pixel[firstPixel + 3] = color.a; + }; + return Desaturate; + })(); + Effects.Desaturate = Desaturate; /** - * Tests a whether this ray intersects with a line segment. Returns a number greater than or equal to 0 on success. - * This number indicates the mathematical intersection time. - * @param line The line to test + * Applies the "Fill" effect to a sprite, changing the color channels of all non-transparent pixels to match + * a given color */ - Ray.prototype.intersect = function (line) { - var numerator = line.begin.toVector().minus(this.pos.toVector()); - // Test is line and ray are parallel and non intersecting - if (this.dir.cross(line.getSlope()) === 0 && numerator.cross(this.dir) !== 0) { - return -1; - } - // Lines are parallel - var divisor = (this.dir.cross(line.getSlope())); - if (divisor === 0) { - return -1; + var Fill = (function () { + /** + * @param color The color to apply to the sprite + */ + function Fill(color) { + this.color = color; } - var t = numerator.cross(line.getSlope()) / divisor; - if (t >= 0) { - var u = (numerator.cross(this.dir) / divisor) / line.getLength(); - if (u >= 0 && u <= 1) { - return t; + Fill.prototype.updatePixel = function (x, y, imageData) { + var firstPixel = (x + y * imageData.width) * 4; + var pixel = imageData.data; + if (pixel[firstPixel + 3] !== 0) { + pixel[firstPixel + 0] = this.color.r; + pixel[firstPixel + 1] = this.color.g; + pixel[firstPixel + 2] = this.color.b; } + }; + return Fill; + })(); + Effects.Fill = Fill; + })(Effects = ex.Effects || (ex.Effects = {})); +})(ex || (ex = {})); +/// +/// +var ex; +(function (ex) { + var Traits; + (function (Traits) { + var Movement = (function () { + function Movement() { } - return -1; - }; - /** - * Returns the point of intersection given the intersection time - */ - Ray.prototype.getPoint = function (time) { - return this.pos.toVector().add(this.dir.scale(time)).toPoint(); - }; - return Ray; - })(); - ex.Ray = Ray; - /** - * A 2D line segment - */ - var Line = (function () { - /** - * @param begin The starting point of the line segment - * @param end The ending point of the line segment - */ - function Line(begin, end) { - this.begin = begin; - this.end = end; + Movement.prototype.update = function (actor, engine, delta) { + // Update placements based on linear algebra + actor.x += actor.dx * delta / 1000; + actor.y += actor.dy * delta / 1000; + actor.dx += actor.ax * delta / 1000; + actor.dy += actor.ay * delta / 1000; + actor.rotation += actor.rx * delta / 1000; + actor.scale.x += actor.sx * delta / 1000; + actor.scale.y += actor.sy * delta / 1000; + }; + return Movement; + })(); + Traits.Movement = Movement; + })(Traits = ex.Traits || (ex.Traits = {})); +})(ex || (ex = {})); +var ex; +(function (ex) { + var CullingBox = (function () { + function CullingBox() { + this._topLeft = new ex.Point(0, 0); + this._topRight = new ex.Point(0, 0); + this._bottomLeft = new ex.Point(0, 0); + this._bottomRight = new ex.Point(0, 0); } - /** - * Returns the slope of the line in the form of a vector - */ - Line.prototype.getSlope = function () { - var begin = this.begin.toVector(); - var end = this.end.toVector(); - var distance = begin.distance(end); - return end.minus(begin).scale(1 / distance); + CullingBox.prototype.isSpriteOffScreen = function (actor, engine) { + var drawingWidth = actor.currentDrawing.width * actor.currentDrawing.scale.x; + var drawingHeight = actor.currentDrawing.height * actor.currentDrawing.scale.y; + var rotation = actor.rotation; + var anchor = actor.getCenter().toPoint(); + this._topLeft.x = actor.getWorldX() - (drawingWidth / 2); + this._topLeft.y = actor.getWorldY() - (drawingHeight / 2); + this._topLeft = this._topLeft.rotate(rotation, anchor); + this._topRight.x = actor.getWorldX() + (drawingWidth / 2); + this._topRight.y = actor.getWorldY() - (drawingHeight / 2); + this._topRight = this._topRight.rotate(rotation, anchor); + this._bottomLeft.x = actor.getWorldX() - (drawingWidth / 2); + this._bottomLeft.y = actor.getWorldY() + (drawingHeight / 2); + this._bottomLeft = this._bottomLeft.rotate(rotation, anchor); + this._bottomRight.x = actor.getWorldX() + (drawingWidth / 2); + this._bottomRight.y = actor.getWorldY() + (drawingHeight / 2); + this._bottomRight = this._bottomRight.rotate(rotation, anchor); + /// + var topLeftScreen = engine.worldToScreenCoordinates(this._topLeft); + var topRightScreen = engine.worldToScreenCoordinates(this._topRight); + var bottomLeftScreen = engine.worldToScreenCoordinates(this._bottomLeft); + var bottomRightScreen = engine.worldToScreenCoordinates(this._bottomRight); + this._xCoords = []; + this._yCoords = []; + this._xCoords.push(topLeftScreen.x, topRightScreen.x, bottomLeftScreen.x, bottomRightScreen.x); + this._yCoords.push(topLeftScreen.y, topRightScreen.y, bottomLeftScreen.y, bottomRightScreen.y); + this._xMin = Math.min.apply(null, this._xCoords); + this._yMin = Math.min.apply(null, this._yCoords); + this._xMax = Math.max.apply(null, this._xCoords); + this._yMax = Math.max.apply(null, this._yCoords); + var minWorld = engine.screenToWorldCoordinates(new ex.Point(this._xMin, this._yMin)); + var maxWorld = engine.screenToWorldCoordinates(new ex.Point(this._xMax, this._yMax)); + this._xMinWorld = minWorld.x; + this._yMinWorld = minWorld.y; + this._xMaxWorld = maxWorld.x; + this._yMaxWorld = maxWorld.y; + var boundingPoints = new Array(); + boundingPoints.push(new ex.Point(this._xMin, this._yMin), new ex.Point(this._xMax, this._yMin), new ex.Point(this._xMin, this._yMax), new ex.Point(this._xMax, this._yMax)); + for (var i = 0; i < boundingPoints.length; i++) { + if (boundingPoints[i].x > 0 && + boundingPoints[i].y > 0 && + boundingPoints[i].x < engine.canvas.clientWidth && + boundingPoints[i].y < engine.canvas.clientHeight) { + return false; + } + } + return true; }; - /** - * Returns the length of the line segment in pixels - */ - Line.prototype.getLength = function () { - var begin = this.begin.toVector(); - var end = this.end.toVector(); - var distance = begin.distance(end); - return distance; + CullingBox.prototype.debugDraw = function (ctx) { + // bounding rectangle + ctx.beginPath(); + ctx.strokeStyle = ex.Color.White.toString(); + ctx.rect(this._xMinWorld, this._yMinWorld, this._xMaxWorld - this._xMinWorld, this._yMaxWorld - this._yMinWorld); + ctx.stroke(); + ctx.fillStyle = ex.Color.Red.toString(); + ctx.beginPath(); + ctx.arc(this._topLeft.x, this._topLeft.y, 5, 0, Math.PI * 2); + ctx.closePath(); + ctx.fill(); + ctx.fillStyle = ex.Color.Green.toString(); + ctx.beginPath(); + ctx.arc(this._topRight.x, this._topRight.y, 5, 0, Math.PI * 2); + ctx.closePath(); + ctx.fill(); + ctx.fillStyle = ex.Color.Blue.toString(); + ctx.beginPath(); + ctx.arc(this._bottomLeft.x, this._bottomLeft.y, 5, 0, Math.PI * 2); + ctx.closePath(); + ctx.fill(); + ctx.fillStyle = ex.Color.Magenta.toString(); + ctx.beginPath(); + ctx.arc(this._bottomRight.x, this._bottomRight.y, 5, 0, Math.PI * 2); + ctx.closePath(); + ctx.fill(); }; - return Line; + return CullingBox; })(); - ex.Line = Line; - /** - * A projection - * @todo - */ - var Projection = (function () { - function Projection(min, max) { - this.min = min; - this.max = max; - } - Projection.prototype.overlaps = function (projection) { - return this.max > projection.min && projection.max > this.min; - }; - Projection.prototype.getOverlap = function (projection) { - if (this.overlaps(projection)) { - if (this.max > projection.max) { - return projection.max - this.min; + ex.CullingBox = CullingBox; +})(ex || (ex = {})); +/// +/// +var ex; +(function (ex) { + var Traits; + (function (Traits) { + var OffscreenCulling = (function () { + function OffscreenCulling() { + this.cullingBox = new ex.CullingBox(); + } + OffscreenCulling.prototype.update = function (actor, engine, delta) { + var eventDispatcher = actor.eventDispatcher; + var anchor = actor.anchor; + var globalScale = actor.getGlobalScale(); + var width = globalScale.x * actor.getWidth() / actor.scale.x; + var height = globalScale.y * actor.getHeight() / actor.scale.y; + var actorScreenCoords = engine.worldToScreenCoordinates(new ex.Point(actor.getWorldX() - anchor.x * width, actor.getWorldY() - anchor.y * height)); + var zoom = 1.0; + if (actor.scene && actor.scene.camera) { + zoom = actor.scene.camera.getZoom(); + } + var isSpriteOffScreen = true; + if (actor.currentDrawing != null) { + isSpriteOffScreen = this.cullingBox.isSpriteOffScreen(actor, engine); + } + if (!actor.isOffScreen) { + if ((actorScreenCoords.x + width * zoom < 0 || + actorScreenCoords.y + height * zoom < 0 || + actorScreenCoords.x > engine.width || + actorScreenCoords.y > engine.height) && + isSpriteOffScreen) { + eventDispatcher.emit('exitviewport', new ex.ExitViewPortEvent()); + actor.isOffScreen = true; + } } else { - return this.max - projection.min; + if ((actorScreenCoords.x + width * zoom > 0 && + actorScreenCoords.y + height * zoom > 0 && + actorScreenCoords.x < engine.width && + actorScreenCoords.y < engine.height) || + !isSpriteOffScreen) { + eventDispatcher.emit('enterviewport', new ex.EnterViewPortEvent()); + actor.isOffScreen = false; + } } + }; + return OffscreenCulling; + })(); + Traits.OffscreenCulling = OffscreenCulling; + })(Traits = ex.Traits || (ex.Traits = {})); +})(ex || (ex = {})); +/// +var ex; +(function (ex) { + var Traits; + (function (Traits) { + /** + * Propogates pointer events to the actor + */ + var CapturePointer = (function () { + function CapturePointer() { } - return 0; - }; - return Projection; - })(); - ex.Projection = Projection; + CapturePointer.prototype.update = function (actor, engine, delta) { + if (!actor.enableCapturePointer) { + return; + } + if (actor.isKilled()) { + return; + } + engine.input.pointers.propogate(actor); + }; + return CapturePointer; + })(); + Traits.CapturePointer = CapturePointer; + })(Traits = ex.Traits || (ex.Traits = {})); })(ex || (ex = {})); -if (typeof window === 'undefined') { - window = { audioContext: function () { return; } }; -} -if (typeof window !== 'undefined' && !window.requestAnimationFrame) { - window.requestAnimationFrame = - window.webkitRequestAnimationFrame || - window.mozRequestAnimationFrame || - function (callback) { window.setInterval(callback, 1000 / 60); }; -} -if (typeof window !== 'undefined' && !window.cancelAnimationFrame) { - window.cancelAnimationFrame = - window.webkitCancelAnimationFrame || - window.mozCancelAnimationFrame || - function (callback) { return; }; -} -if (typeof window !== 'undefined' && !window.AudioContext) { - window.AudioContext = window.AudioContext || - window.webkitAudioContext || - window.mozAudioContext || - window.msAudioContext || - window.oAudioContext; -} -// Polyfill from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach -// Production steps of ECMA-262, Edition 5, 15.4.4.18 -// Reference: http://es5.github.io/#x15.4.4.18 -if (!Array.prototype.forEach) { - Array.prototype.forEach = function (callback, thisArg) { - var T, k; - if (this == null) { - throw new TypeError(' this is null or not defined'); - } - // 1. Let O be the result of calling ToObject passing the |this| value as the argument. - var O = Object(this); - // 2. Let lenValue be the result of calling the Get internal method of O with the argument "length". - // 3. Let len be ToUint32(lenValue). - var len = O.length >>> 0; - // 4. If IsCallable(callback) is false, throw a TypeError exception. - // See: http://es5.github.com/#x9.11 - if (typeof callback !== 'function') { - throw new TypeError(callback + ' is not a function'); - } - // 5. If thisArg was supplied, let T be thisArg; else let T be undefined. - if (arguments.length > 1) { - T = thisArg; - } - // 6. Let k be 0 - k = 0; - // 7. Repeat, while k < len - while (k < len) { - var kValue; - // a. Let Pk be ToString(k). - // This is implicit for LHS operands of the in operator - // b. Let kPresent be the result of calling the HasProperty internal method of O with argument Pk. - // This step can be combined with c - // c. If kPresent is true, then - if (k in O) { - // i. Let kValue be the result of calling the Get internal method of O with argument Pk. - kValue = O[k]; - // ii. Call the Call internal method of callback with T as the this value and - // argument list containing kValue, k, and O. - callback.call(T, kValue, k, O); - } - // d. Increase k by 1. - k++; - } - // 8. return undefined - }; -} -// Polyfill from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some -if (!Array.prototype.some) { - Array.prototype.some = function (fun /*, thisArg */) { - 'use strict'; - if (this === void 0 || this === null) { - throw new TypeError(); - } - var t = Object(this); - var len = t.length >>> 0; - if (typeof fun !== 'function') { - throw new TypeError(); - } - var thisArg = arguments.length >= 2 ? arguments[1] : void 0; - for (var i = 0; i < len; i++) { - if (i in t && fun.call(thisArg, t[i], i, t)) { - return true; +/// +var ex; +(function (ex) { + var Traits; + (function (Traits) { + var CollisionDetection = (function () { + function CollisionDetection() { } - } - return false; - }; -} -// Polyfill from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind#Polyfill -if (!Function.prototype.bind) { - Function.prototype.bind = function (oThis) { - if (typeof this !== 'function') { - // closest thing possible to the ECMAScript 5 - // internal IsCallable function - throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable'); - } - var aArgs = Array.prototype.slice.call(arguments, 1), fToBind = this, fNOP = function () { return; }, fBound = function () { - return fToBind.apply(this instanceof fNOP && oThis - ? this - : oThis, aArgs.concat(Array.prototype.slice.call(arguments))); - }; - fNOP.prototype = this.prototype; - fBound.prototype = new fNOP(); - return fBound; - }; -} + CollisionDetection.prototype.update = function (actor, engine, delta) { + var eventDispatcher = actor.eventDispatcher; + if (actor.collisionType !== ex.CollisionType.PreventCollision && engine.currentScene && engine.currentScene.tileMaps) { + for (var j = 0; j < engine.currentScene.tileMaps.length; j++) { + var map = engine.currentScene.tileMaps[j]; + var intersectMap; + var side = ex.Side.None; + var max = 2; + var hasBounced = false; + while (intersectMap = map.collides(actor)) { + if (max-- < 0) { + break; + } + side = actor.getSideFromIntersect(intersectMap); + eventDispatcher.emit('collision', new ex.CollisionEvent(actor, null, side, intersectMap)); + if ((actor.collisionType === ex.CollisionType.Active || actor.collisionType === ex.CollisionType.Elastic)) { + actor.y += intersectMap.y; + actor.x += intersectMap.x; + // Naive elastic bounce + if (actor.collisionType === ex.CollisionType.Elastic && !hasBounced) { + hasBounced = true; + if (side === ex.Side.Left) { + actor.dx = Math.abs(actor.dx); + } + else if (side === ex.Side.Right) { + actor.dx = -Math.abs(actor.dx); + } + else if (side === ex.Side.Top) { + actor.dy = Math.abs(actor.dy); + } + else if (side === ex.Side.Bottom) { + actor.dy = -Math.abs(actor.dy); + } + } + } + } + } + } + }; + return CollisionDetection; + })(); + Traits.CollisionDetection = CollisionDetection; + })(Traits = ex.Traits || (ex.Traits = {})); +})(ex || (ex = {})); var ex; (function (ex) { /** - * Effects - * - * These effects can be applied to any bitmap image but are mainly used - * for [[Sprite]] effects or [[Animation]] effects. - * - * Because these manipulate raw pixels, there is a performance impact to applying - * too many effects. Excalibur tries its best to by using caching to mitigate - * performance issues. - * - * Create your own effects by implementing [[ISpriteEffect]]. + * An enum that describes the sides of an Actor for collision */ - var Effects; - (function (Effects) { + (function (Side) { + Side[Side["None"] = 0] = "None"; + Side[Side["Top"] = 1] = "Top"; + Side[Side["Bottom"] = 2] = "Bottom"; + Side[Side["Left"] = 3] = "Left"; + Side[Side["Right"] = 4] = "Right"; + })(ex.Side || (ex.Side = {})); + var Side = ex.Side; +})(ex || (ex = {})); +var __extends = (this && this.__extends) || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); +}; +var ex; +(function (ex) { + /** + * A simple 2D point on a plane + * @obsolete Use [[Vector|vector]]s instead of [[Point|points]] + */ + var Point = (function () { /** - * Applies the "Grayscale" effect to a sprite, removing color information. + * @param x X coordinate of the point + * @param y Y coordinate of the point */ - var Grayscale = (function () { - function Grayscale() { - } - Grayscale.prototype.updatePixel = function (x, y, imageData) { - var firstPixel = (x + y * imageData.width) * 4; - var pixel = imageData.data; - var avg = (pixel[firstPixel + 0] + pixel[firstPixel + 1] + pixel[firstPixel + 2]) / 3; - pixel[firstPixel + 0] = avg; - pixel[firstPixel + 1] = avg; - pixel[firstPixel + 2] = avg; - }; - return Grayscale; - })(); - Effects.Grayscale = Grayscale; + function Point(x, y) { + this.x = x; + this.y = y; + } /** - * Applies the "Invert" effect to a sprite, inverting the pixel colors. + * Convert this point to a vector */ - var Invert = (function () { - function Invert() { - } - Invert.prototype.updatePixel = function (x, y, imageData) { - var firstPixel = (x + y * imageData.width) * 4; - var pixel = imageData.data; - pixel[firstPixel + 0] = 255 - pixel[firstPixel + 0]; - pixel[firstPixel + 1] = 255 - pixel[firstPixel + 1]; - pixel[firstPixel + 2] = 255 - pixel[firstPixel + 2]; - }; - return Invert; - })(); - Effects.Invert = Invert; + Point.prototype.toVector = function () { + return new Vector(this.x, this.y); + }; /** - * Applies the "Opacity" effect to a sprite, setting the alpha of all pixels to a given value. + * Rotates the current point around another by a certain number of + * degrees in radians + * @param angle The angle in radians + * @param anchor The point to rotate around */ - var Opacity = (function () { - /** - * @param opacity The new opacity of the sprite from 0-1.0 - */ - function Opacity(opacity) { - this.opacity = opacity; + Point.prototype.rotate = function (angle, anchor) { + if (!anchor) { + anchor = new ex.Point(0, 0); } - Opacity.prototype.updatePixel = function (x, y, imageData) { - var firstPixel = (x + y * imageData.width) * 4; - var pixel = imageData.data; - if (pixel[firstPixel + 3] !== 0) { - pixel[firstPixel + 3] = Math.round(this.opacity * 255); - } - }; - return Opacity; - })(); - Effects.Opacity = Opacity; + var sinAngle = Math.sin(angle); + var cosAngle = Math.cos(angle); + var x = cosAngle * (this.x - anchor.x) - sinAngle * (this.y - anchor.y) + anchor.x; + var y = sinAngle * (this.x - anchor.x) + cosAngle * (this.y - anchor.y) + anchor.y; + return new Point(x, y); + }; /** - * Applies the "Colorize" effect to a sprite, changing the color channels of all the pixels to an - * average of the original color and the provided color + * Translates the current point by a vector + * @param vector The other vector to add to */ - var Colorize = (function () { - /** - * @param color The color to apply to the sprite - */ - function Colorize(color) { - this.color = color; - } - Colorize.prototype.updatePixel = function (x, y, imageData) { - var firstPixel = (x + y * imageData.width) * 4; - var pixel = imageData.data; - if (pixel[firstPixel + 3] !== 0) { - pixel[firstPixel + 0] = (pixel[firstPixel + 0] + this.color.r) / 2; - pixel[firstPixel + 1] = (pixel[firstPixel + 1] + this.color.g) / 2; - pixel[firstPixel + 2] = (pixel[firstPixel + 2] + this.color.b) / 2; - } - }; - return Colorize; - })(); - Effects.Colorize = Colorize; + Point.prototype.add = function (vector) { + return new Point(this.x + vector.x, this.y + vector.y); + }; /** - * Applies the "Lighten" effect to a sprite, changes the lightness of the color according to HSL + * Sets the x and y components at once */ - var Lighten = (function () { - /** - * @param factor The factor of the effect between 0-1 - */ - function Lighten(factor) { - if (factor === void 0) { factor = 0.1; } - this.factor = factor; - } - Lighten.prototype.updatePixel = function (x, y, imageData) { - var firstPixel = (x + y * imageData.width) * 4; - var pixel = imageData.data; - var color = ex.Color.fromRGB(pixel[firstPixel + 0], pixel[firstPixel + 1], pixel[firstPixel + 2], pixel[firstPixel + 3]).lighten(this.factor); - pixel[firstPixel + 0] = color.r; - pixel[firstPixel + 1] = color.g; - pixel[firstPixel + 2] = color.b; - pixel[firstPixel + 3] = color.a; - }; - return Lighten; - })(); - Effects.Lighten = Lighten; + Point.prototype.setTo = function (x, y) { + this.x = x; + this.y = y; + }; /** - * Applies the "Darken" effect to a sprite, changes the darkness of the color according to HSL + * Clones a new point that is a copy of this one. */ - var Darken = (function () { - /** - * @param factor The factor of the effect between 0-1 - */ - function Darken(factor) { - if (factor === void 0) { factor = 0.1; } - this.factor = factor; - } - Darken.prototype.updatePixel = function (x, y, imageData) { - var firstPixel = (x + y * imageData.width) * 4; - var pixel = imageData.data; - var color = ex.Color.fromRGB(pixel[firstPixel + 0], pixel[firstPixel + 1], pixel[firstPixel + 2], pixel[firstPixel + 3]).darken(this.factor); - pixel[firstPixel + 0] = color.r; - pixel[firstPixel + 1] = color.g; - pixel[firstPixel + 2] = color.b; - pixel[firstPixel + 3] = color.a; - }; - return Darken; - })(); - Effects.Darken = Darken; + Point.prototype.clone = function () { + return new Point(this.x, this.y); + }; /** - * Applies the "Saturate" effect to a sprite, saturates the color acccording to HSL + * Compares this point against another and tests for equality + * @param point The other point to compare to */ - var Saturate = (function () { - /** - * @param factor The factor of the effect between 0-1 - */ - function Saturate(factor) { - if (factor === void 0) { factor = 0.1; } - this.factor = factor; - } - Saturate.prototype.updatePixel = function (x, y, imageData) { - var firstPixel = (x + y * imageData.width) * 4; - var pixel = imageData.data; - var color = ex.Color.fromRGB(pixel[firstPixel + 0], pixel[firstPixel + 1], pixel[firstPixel + 2], pixel[firstPixel + 3]).saturate(this.factor); - pixel[firstPixel + 0] = color.r; - pixel[firstPixel + 1] = color.g; - pixel[firstPixel + 2] = color.b; - pixel[firstPixel + 3] = color.a; - }; - return Saturate; - })(); - Effects.Saturate = Saturate; + Point.prototype.equals = function (point) { + return this.x === point.x && this.y === point.y; + }; + return Point; + })(); + ex.Point = Point; + /** + * A 2D vector on a plane. + */ + var Vector = (function (_super) { + __extends(Vector, _super); /** - * Applies the "Desaturate" effect to a sprite, desaturates the color acccording to HSL + * @param x X component of the Vector + * @param y Y component of the Vector */ - var Desaturate = (function () { - /** - * @param factor The factor of the effect between 0-1 - */ - function Desaturate(factor) { - if (factor === void 0) { factor = 0.1; } - this.factor = factor; - } - Desaturate.prototype.updatePixel = function (x, y, imageData) { - var firstPixel = (x + y * imageData.width) * 4; - var pixel = imageData.data; - var color = ex.Color.fromRGB(pixel[firstPixel + 0], pixel[firstPixel + 1], pixel[firstPixel + 2], pixel[firstPixel + 3]).desaturate(this.factor); - pixel[firstPixel + 0] = color.r; - pixel[firstPixel + 1] = color.g; - pixel[firstPixel + 2] = color.b; - pixel[firstPixel + 3] = color.a; - }; - return Desaturate; - })(); - Effects.Desaturate = Desaturate; + function Vector(x, y) { + _super.call(this, x, y); + this.x = x; + this.y = y; + } /** - * Applies the "Fill" effect to a sprite, changing the color channels of all non-transparent pixels to match - * a given color + * Returns a vector of unit length in the direction of the specified angle. + * @param angle The angle to generate the vector */ - var Fill = (function () { - /** - * @param color The color to apply to the sprite - */ - function Fill(color) { - this.color = color; + Vector.fromAngle = function (angle) { + return new Vector(Math.cos(angle), Math.sin(angle)); + }; + /** + * The distance to another vector + * @param v The other vector + */ + Vector.prototype.distance = function (v) { + if (!v) { + v = new Vector(0.0, 0.0); } - Fill.prototype.updatePixel = function (x, y, imageData) { - var firstPixel = (x + y * imageData.width) * 4; - var pixel = imageData.data; - if (pixel[firstPixel + 3] !== 0) { - pixel[firstPixel + 0] = this.color.r; - pixel[firstPixel + 1] = this.color.g; - pixel[firstPixel + 2] = this.color.b; - } - }; - return Fill; - })(); - Effects.Fill = Fill; - })(Effects = ex.Effects || (ex.Effects = {})); -})(ex || (ex = {})); -/// -/// -var ex; -(function (ex) { - var Traits; - (function (Traits) { - var Movement = (function () { - function Movement() { + return Math.sqrt(Math.pow(this.x - v.x, 2) + Math.pow(this.y - v.y, 2)); + }; + /** + * Normalizes a vector to have a magnitude of 1. + */ + Vector.prototype.normalize = function () { + var d = this.distance(); + if (d > 0) { + return new Vector(this.x / d, this.y / d); } - Movement.prototype.update = function (actor, engine, delta) { - // Update placements based on linear algebra - actor.x += actor.dx * delta / 1000; - actor.y += actor.dy * delta / 1000; - actor.dx += actor.ax * delta / 1000; - actor.dy += actor.ay * delta / 1000; - actor.rotation += actor.rx * delta / 1000; - actor.scale.x += actor.sx * delta / 1000; - actor.scale.y += actor.sy * delta / 1000; - }; - return Movement; - })(); - Traits.Movement = Movement; - })(Traits = ex.Traits || (ex.Traits = {})); -})(ex || (ex = {})); -var ex; -(function (ex) { - var CullingBox = (function () { - function CullingBox() { - this._topLeft = new ex.Point(0, 0); - this._topRight = new ex.Point(0, 0); - this._bottomLeft = new ex.Point(0, 0); - this._bottomRight = new ex.Point(0, 0); - } - CullingBox.prototype.isSpriteOffScreen = function (actor, engine) { - var drawingWidth = actor.currentDrawing.width * actor.currentDrawing.scale.x; - var drawingHeight = actor.currentDrawing.height * actor.currentDrawing.scale.y; - var rotation = actor.rotation; - var anchor = actor.getCenter().toPoint(); - this._topLeft.x = actor.getWorldX() - (drawingWidth / 2); - this._topLeft.y = actor.getWorldY() - (drawingHeight / 2); - this._topLeft = this._topLeft.rotate(rotation, anchor); - this._topRight.x = actor.getWorldX() + (drawingWidth / 2); - this._topRight.y = actor.getWorldY() - (drawingHeight / 2); - this._topRight = this._topRight.rotate(rotation, anchor); - this._bottomLeft.x = actor.getWorldX() - (drawingWidth / 2); - this._bottomLeft.y = actor.getWorldY() + (drawingHeight / 2); - this._bottomLeft = this._bottomLeft.rotate(rotation, anchor); - this._bottomRight.x = actor.getWorldX() + (drawingWidth / 2); - this._bottomRight.y = actor.getWorldY() + (drawingHeight / 2); - this._bottomRight = this._bottomRight.rotate(rotation, anchor); - /// - var topLeftScreen = engine.worldToScreenCoordinates(this._topLeft); - var topRightScreen = engine.worldToScreenCoordinates(this._topRight); - var bottomLeftScreen = engine.worldToScreenCoordinates(this._bottomLeft); - var bottomRightScreen = engine.worldToScreenCoordinates(this._bottomRight); - this._xCoords = []; - this._yCoords = []; - this._xCoords.push(topLeftScreen.x, topRightScreen.x, bottomLeftScreen.x, bottomRightScreen.x); - this._yCoords.push(topLeftScreen.y, topRightScreen.y, bottomLeftScreen.y, bottomRightScreen.y); - this._xMin = Math.min.apply(null, this._xCoords); - this._yMin = Math.min.apply(null, this._yCoords); - this._xMax = Math.max.apply(null, this._xCoords); - this._yMax = Math.max.apply(null, this._yCoords); - var minWorld = engine.screenToWorldCoordinates(new ex.Point(this._xMin, this._yMin)); - var maxWorld = engine.screenToWorldCoordinates(new ex.Point(this._xMax, this._yMax)); - this._xMinWorld = minWorld.x; - this._yMinWorld = minWorld.y; - this._xMaxWorld = maxWorld.x; - this._yMaxWorld = maxWorld.y; - var boundingPoints = new Array(); - boundingPoints.push(new ex.Point(this._xMin, this._yMin), new ex.Point(this._xMax, this._yMin), new ex.Point(this._xMin, this._yMax), new ex.Point(this._xMax, this._yMax)); - for (var i = 0; i < boundingPoints.length; i++) { - if (boundingPoints[i].x > 0 && - boundingPoints[i].y > 0 && - boundingPoints[i].x < engine.canvas.clientWidth && - boundingPoints[i].y < engine.canvas.clientHeight) { - return false; - } + else { + return new Vector(0, 1); } - return true; }; - CullingBox.prototype.debugDraw = function (ctx) { - // bounding rectangle - ctx.beginPath(); - ctx.strokeStyle = ex.Color.White.toString(); - ctx.rect(this._xMinWorld, this._yMinWorld, this._xMaxWorld - this._xMinWorld, this._yMaxWorld - this._yMinWorld); - ctx.stroke(); - ctx.fillStyle = ex.Color.Red.toString(); - ctx.beginPath(); - ctx.arc(this._topLeft.x, this._topLeft.y, 5, 0, Math.PI * 2); - ctx.closePath(); - ctx.fill(); - ctx.fillStyle = ex.Color.Green.toString(); - ctx.beginPath(); - ctx.arc(this._topRight.x, this._topRight.y, 5, 0, Math.PI * 2); - ctx.closePath(); - ctx.fill(); - ctx.fillStyle = ex.Color.Blue.toString(); - ctx.beginPath(); - ctx.arc(this._bottomLeft.x, this._bottomLeft.y, 5, 0, Math.PI * 2); - ctx.closePath(); - ctx.fill(); - ctx.fillStyle = ex.Color.Magenta.toString(); - ctx.beginPath(); - ctx.arc(this._bottomRight.x, this._bottomRight.y, 5, 0, Math.PI * 2); - ctx.closePath(); - ctx.fill(); + /** + * Scales a vector's by a factor of size + * @param size The factor to scale the magnitude by + */ + Vector.prototype.scale = function (size) { + return new Vector(this.x * size, this.y * size); }; - return CullingBox; - })(); - ex.CullingBox = CullingBox; -})(ex || (ex = {})); -/// -/// -var ex; -(function (ex) { - var Traits; - (function (Traits) { - var OffscreenCulling = (function () { - function OffscreenCulling() { - this.cullingBox = new ex.CullingBox(); + /** + * Adds one vector to another, alias for add + * @param v The vector to add + */ + Vector.prototype.plus = function (v) { + return this.add(v); + }; + /** + * Adds one vector to another + * @param v The vector to add + */ + Vector.prototype.add = function (v) { + return new Vector(this.x + v.x, this.y + v.y); + }; + /** + * Subtracts a vector from another, alias for minus + * @param v The vector to subtract + */ + Vector.prototype.subtract = function (v) { + return this.minus(v); + }; + /** + * Subtracts a vector from the current vector + * @param v The vector to subtract + */ + Vector.prototype.minus = function (v) { + return new Vector(this.x - v.x, this.y - v.y); + }; + /** + * Performs a dot product with another vector + * @param v The vector to dot + */ + Vector.prototype.dot = function (v) { + return this.x * v.x + this.y * v.y; + }; + /** + * Performs a 2D cross product with another vector. 2D cross products return a scalar value not a vector. + * @param v The vector to cross + */ + Vector.prototype.cross = function (v) { + return this.x * v.y - this.y * v.x; + }; + /** + * Returns the perpendicular vector to this one + */ + Vector.prototype.perpendicular = function () { + return new Vector(this.y, -this.x); + }; + /** + * Returns the normal vector to this one + */ + Vector.prototype.normal = function () { + return this.perpendicular().normalize(); + }; + /** + * Returns the angle of this vector. + */ + Vector.prototype.toAngle = function () { + return Math.atan2(this.y, this.x); + }; + /** + * Returns the point represention of this vector + */ + Vector.prototype.toPoint = function () { + return new Point(this.x, this.y); + }; + /** + * Rotates the current vector around a point by a certain number of + * degrees in radians + */ + Vector.prototype.rotate = function (angle, anchor) { + return _super.prototype.rotate.call(this, angle, anchor).toVector(); + }; + /** + * Creates new vector that has the same values as the previous. + */ + Vector.prototype.clone = function () { + return new Vector(this.x, this.y); + }; + /** + * A (0, 0) vector + */ + Vector.Zero = new Vector(0, 0); + return Vector; + })(Point); + ex.Vector = Vector; + /** + * A 2D ray that can be cast into the scene to do collision detection + */ + var Ray = (function () { + /** + * @param pos The starting position for the ray + * @param dir The vector indicating the direction of the ray + */ + function Ray(pos, dir) { + this.pos = pos; + this.dir = dir.normalize(); + } + /** + * Tests a whether this ray intersects with a line segment. Returns a number greater than or equal to 0 on success. + * This number indicates the mathematical intersection time. + * @param line The line to test + */ + Ray.prototype.intersect = function (line) { + var numerator = line.begin.toVector().minus(this.pos.toVector()); + // Test is line and ray are parallel and non intersecting + if (this.dir.cross(line.getSlope()) === 0 && numerator.cross(this.dir) !== 0) { + return -1; } - OffscreenCulling.prototype.update = function (actor, engine, delta) { - var eventDispatcher = actor.eventDispatcher; - var anchor = actor.anchor; - var globalScale = actor.getGlobalScale(); - var width = globalScale.x * actor.getWidth() / actor.scale.x; - var height = globalScale.y * actor.getHeight() / actor.scale.y; - var actorScreenCoords = engine.worldToScreenCoordinates(new ex.Point(actor.getWorldX() - anchor.x * width, actor.getWorldY() - anchor.y * height)); - var zoom = 1.0; - if (actor.scene && actor.scene.camera) { - zoom = actor.scene.camera.getZoom(); - } - var isSpriteOffScreen = true; - if (actor.currentDrawing != null) { - isSpriteOffScreen = this.cullingBox.isSpriteOffScreen(actor, engine); + // Lines are parallel + var divisor = (this.dir.cross(line.getSlope())); + if (divisor === 0) { + return -1; + } + var t = numerator.cross(line.getSlope()) / divisor; + if (t >= 0) { + var u = (numerator.cross(this.dir) / divisor) / line.getLength(); + if (u >= 0 && u <= 1) { + return t; } - if (!actor.isOffScreen) { - if ((actorScreenCoords.x + width * zoom < 0 || - actorScreenCoords.y + height * zoom < 0 || - actorScreenCoords.x > engine.width || - actorScreenCoords.y > engine.height) && - isSpriteOffScreen) { - eventDispatcher.emit('exitviewport', new ex.ExitViewPortEvent()); - actor.isOffScreen = true; - } + } + return -1; + }; + /** + * Returns the point of intersection given the intersection time + */ + Ray.prototype.getPoint = function (time) { + return this.pos.toVector().add(this.dir.scale(time)).toPoint(); + }; + return Ray; + })(); + ex.Ray = Ray; + /** + * A 2D line segment + */ + var Line = (function () { + /** + * @param begin The starting point of the line segment + * @param end The ending point of the line segment + */ + function Line(begin, end) { + this.begin = begin; + this.end = end; + } + /** + * Returns the slope of the line in the form of a vector + */ + Line.prototype.getSlope = function () { + var begin = this.begin.toVector(); + var end = this.end.toVector(); + var distance = begin.distance(end); + return end.minus(begin).scale(1 / distance); + }; + /** + * Returns the length of the line segment in pixels + */ + Line.prototype.getLength = function () { + var begin = this.begin.toVector(); + var end = this.end.toVector(); + var distance = begin.distance(end); + return distance; + }; + return Line; + })(); + ex.Line = Line; + /** + * A projection + * @todo + */ + var Projection = (function () { + function Projection(min, max) { + this.min = min; + this.max = max; + } + Projection.prototype.overlaps = function (projection) { + return this.max > projection.min && projection.max > this.min; + }; + Projection.prototype.getOverlap = function (projection) { + if (this.overlaps(projection)) { + if (this.max > projection.max) { + return projection.max - this.min; } else { - if ((actorScreenCoords.x + width * zoom > 0 && - actorScreenCoords.y + height * zoom > 0 && - actorScreenCoords.x < engine.width && - actorScreenCoords.y < engine.height) || - !isSpriteOffScreen) { - eventDispatcher.emit('enterviewport', new ex.EnterViewPortEvent()); - actor.isOffScreen = false; - } + return this.max - projection.min; } - }; - return OffscreenCulling; - })(); - Traits.OffscreenCulling = OffscreenCulling; - })(Traits = ex.Traits || (ex.Traits = {})); -})(ex || (ex = {})); -/// -var ex; -(function (ex) { - var Traits; - (function (Traits) { - /** - * Propogates pointer events to the actor - */ - var CapturePointer = (function () { - function CapturePointer() { } - CapturePointer.prototype.update = function (actor, engine, delta) { - if (!actor.enableCapturePointer) { - return; - } - if (actor.isKilled()) { - return; - } - engine.input.pointers.propogate(actor); - }; - return CapturePointer; - })(); - Traits.CapturePointer = CapturePointer; - })(Traits = ex.Traits || (ex.Traits = {})); -})(ex || (ex = {})); -/// -var ex; -(function (ex) { - var Traits; - (function (Traits) { - var CollisionDetection = (function () { - function CollisionDetection() { - } - CollisionDetection.prototype.update = function (actor, engine, delta) { - var eventDispatcher = actor.eventDispatcher; - if (actor.collisionType !== ex.CollisionType.PreventCollision) { - for (var j = 0; j < engine.currentScene.tileMaps.length; j++) { - var map = engine.currentScene.tileMaps[j]; - var intersectMap; - var side = ex.Side.None; - var max = 2; - var hasBounced = false; - while (intersectMap = map.collides(actor)) { - if (max-- < 0) { - break; - } - side = actor.getSideFromIntersect(intersectMap); - eventDispatcher.emit('collision', new ex.CollisionEvent(actor, null, side, intersectMap)); - if ((actor.collisionType === ex.CollisionType.Active || actor.collisionType === ex.CollisionType.Elastic)) { - actor.y += intersectMap.y; - actor.x += intersectMap.x; - // Naive elastic bounce - if (actor.collisionType === ex.CollisionType.Elastic && !hasBounced) { - hasBounced = true; - if (side === ex.Side.Left) { - actor.dx = Math.abs(actor.dx); - } - else if (side === ex.Side.Right) { - actor.dx = -Math.abs(actor.dx); - } - else if (side === ex.Side.Top) { - actor.dy = Math.abs(actor.dy); - } - else if (side === ex.Side.Bottom) { - actor.dy = -Math.abs(actor.dy); - } - } - } - } - } - } - }; - return CollisionDetection; - })(); - Traits.CollisionDetection = CollisionDetection; - })(Traits = ex.Traits || (ex.Traits = {})); -})(ex || (ex = {})); -var ex; -(function (ex) { - /** - * An enum that describes the sides of an Actor for collision - */ - (function (Side) { - Side[Side["None"] = 0] = "None"; - Side[Side["Top"] = 1] = "Top"; - Side[Side["Bottom"] = 2] = "Bottom"; - Side[Side["Left"] = 3] = "Left"; - Side[Side["Right"] = 4] = "Right"; - })(ex.Side || (ex.Side = {})); - var Side = ex.Side; + return 0; + }; + return Projection; + })(); + ex.Projection = Projection; })(ex || (ex = {})); /// /// @@ -1207,10 +1211,38 @@ var ex; * * Excalibur offers many sprite effects such as [[Effects.Colorize]] to let you manipulate * sprites. Keep in mind, more effects requires more power and can lead to memory or CPU - * constraints and hurt performance. + * constraints and hurt performance. Each effect must be reprocessed every frame for each sprite. * * It's still recommended to create an [[Animation]] or build in your effects to the sprites * for optimal performance. + * + * There are a number of convenience methods available to perform sprite effects. Sprite effects are + * side-effecting. + * + * ```typescript + * + * var playerSprite = new ex.Sprite(txPlayer, 0, 0, 80, 80); + * + * // darken a sprite by a percentage + * playerSprite.darken(.2); // 20% + * + * // lighten a sprite by a percentage + * playerSprite.lighten(.2); // 20% + * + * // saturate a sprite by a percentage + * playerSprite.saturate(.2); // 20% + * + * // implement a custom effect + * class CustomEffect implements ex.EffectsISpriteEffect { + * + * updatePixel(x: number, y: number, imageData: ImageData) { + * // modify ImageData + * } + * } + * + * playerSprite.addEffect(new CustomEffect()); + * + * ``` */ var Sprite = (function () { /** @@ -2608,6 +2640,14 @@ var ex; Class.prototype.off = function (eventName, handler) { this.eventDispatcher.unsubscribe(eventName, handler); }; + /** + * Emits a new event + * @param eventName Name of the event to emit + * @param eventObject Data associated with this event + */ + Class.prototype.emit = function (eventName, eventObject) { + this.eventDispatcher.emit(eventName, eventObject); + }; /** * You may wish to extend native Excalibur functionality in vanilla Javascript. * Any method on a class inheriting [[Class]] may be extended to support @@ -3410,8 +3450,20 @@ var ex; */ var BaseCamera = (function () { function BaseCamera() { - this._focus = new ex.Point(0, 0); - this._lerp = false; + this.focus = new ex.Point(0, 0); + this.lerp = false; + // camera physical quantities + this.x = 0; + this.y = 0; + this.z = 1; + this.dx = 0; + this.dy = 0; + this.dz = 0; + this.ax = 0; + this.ay = 0; + this.az = 0; + this.rotation = 0; + this.rx = 0; this._cameraMoving = false; this._currentLerpTime = 0; this._lerpDuration = 1 * 1000; // 5 seconds @@ -3448,23 +3500,24 @@ var ex; this._follow = actor; }; /** - * Returns the focal point of the camera + * Returns the focal point of the camera, a new point giving the x and y position of the camera */ BaseCamera.prototype.getFocus = function () { - return this._focus; + return new ex.Point(this.x, this.y); }; /** * Sets the focal point of the camera. This value can only be set if there is no actor to be followed. * @param x The x coordinate of the focal point * @param y The y coordinate of the focal point + * @deprecated */ BaseCamera.prototype.setFocus = function (x, y) { - if (!this._follow && !this._lerp) { - this._focus.x = x; - this._focus.y = y; + if (!this._follow && !this.lerp) { + this.x = x; + this.y = y; } - if (this._lerp) { - this._lerpStart = this._focus.clone(); + if (this.lerp) { + this._lerpStart = this.getFocus().clone(); this._lerpEnd = new ex.Point(x, y); this._currentLerpTime = 0; this._cameraMoving = true; @@ -3516,16 +3569,24 @@ var ex; * Gets the current zoom scale */ BaseCamera.prototype.getZoom = function () { - return this._currentZoomScale; + return this.z; }; BaseCamera.prototype._setCurrentZoomScale = function (zoomScale) { - this._currentZoomScale = zoomScale; + this.z = zoomScale; }; /** * Applies the relevant transformations to the game canvas to "move" or apply effects to the Camera * @param delta The number of milliseconds since the last update */ BaseCamera.prototype.update = function (ctx, delta) { + // Update placements based on linear algebra + this.x += this.dx * delta / 1000; + this.y += this.dy * delta / 1000; + this.z += this.dz * delta / 1000; + this.dx += this.ax * delta / 1000; + this.dy += this.ay * delta / 1000; + this.dz += this.az * delta / 1000; + this.rotation += this.rx * delta / 1000; var focus = this.getFocus(); var xShake = 0; var yShake = 0; @@ -3535,19 +3596,19 @@ var ex; // if zoom is .5x then canvas is 2x as high var newCanvasWidth = canvasWidth / this.getZoom(); var newCanvasHeight = canvasHeight / this.getZoom(); - if (this._lerp) { + if (this.lerp) { if (this._currentLerpTime < this._lerpDuration && this._cameraMoving) { if (this._lerpEnd.x < this._lerpStart.x) { - this._focus.x = this._lerpStart.x - (this._easeInOutCubic(this._currentLerpTime, this._lerpEnd.x, this._lerpStart.x, this._lerpDuration) - this._lerpEnd.x); + this.x = this._lerpStart.x - (this._easeInOutCubic(this._currentLerpTime, this._lerpEnd.x, this._lerpStart.x, this._lerpDuration) - this._lerpEnd.x); } else { - this._focus.x = this._easeInOutCubic(this._currentLerpTime, this._lerpStart.x, this._lerpEnd.x, this._lerpDuration); + this.x = this._easeInOutCubic(this._currentLerpTime, this._lerpStart.x, this._lerpEnd.x, this._lerpDuration); } if (this._lerpEnd.y < this._lerpStart.y) { - this._focus.y = this._lerpStart.y - (this._easeInOutCubic(this._currentLerpTime, this._lerpEnd.y, this._lerpStart.y, this._lerpDuration) - this._lerpEnd.y); + this.y = this._lerpStart.y - (this._easeInOutCubic(this._currentLerpTime, this._lerpEnd.y, this._lerpStart.y, this._lerpDuration) - this._lerpEnd.y); } else { - this._focus.y = this._easeInOutCubic(this._currentLerpTime, this._lerpStart.y, this._lerpEnd.y, this._lerpDuration); + this.y = this._easeInOutCubic(this._currentLerpTime, this._lerpStart.y, this._lerpEnd.y, this._lerpDuration); } this._currentLerpTime += delta; } @@ -3570,16 +3631,17 @@ var ex; xShake = (Math.random() * this._shakeMagnitudeX | 0) + 1; yShake = (Math.random() * this._shakeMagnitudeY | 0) + 1; } - if (this._isDoneZooming()) { - this._isZooming = false; - this._elapsedZoomTime = 0; - this._zoomDuration = 0; - this._setCurrentZoomScale(this._maxZoomScale); - } - else { - this._elapsedZoomTime += delta; - this._setCurrentZoomScale(this.getZoom() + this._zoomIncrement * delta / 1000); - } + /*if (this._isDoneZooming()) { + this._isZooming = false; + this._elapsedZoomTime = 0; + this._zoomDuration = 0; + this._setCurrentZoomScale(this._maxZoomScale); + + } else { + this._elapsedZoomTime += delta; + + this._setCurrentZoomScale(this.getZoom() + this._zoomIncrement * delta / 1000); + }*/ ctx.scale(this.getZoom(), this.getZoom()); ctx.translate(-focus.x + newCanvasWidth / 2 + xShake, -focus.y + newCanvasHeight / 2 + yShake); }; @@ -3628,10 +3690,10 @@ var ex; } SideCamera.prototype.getFocus = function () { if (this._follow) { - return new ex.Point(this._follow.x + this._follow.getWidth() / 2, this._focus.y); + return new ex.Point(this._follow.x + this._follow.getWidth() / 2, this.focus.y); } else { - return this._focus; + return this.focus; } }; return SideCamera; @@ -3654,9077 +3716,9070 @@ var ex; return new ex.Point(this._follow.x + this._follow.getWidth() / 2, this._follow.y + this._follow.getHeight() / 2); } else { - return this._focus; + return this.focus; } }; return LockedCamera; })(BaseCamera); ex.LockedCamera = LockedCamera; })(ex || (ex = {})); -/// var ex; (function (ex) { /** - * Action API - * - * The fluent Action API allows you to perform "actions" on - * [[Actor|Actors]] such as following, moving, rotating, and - * more. You can implement your own actions by implementing - * the [[IAction]] interface. - * - * Actions can be chained together and can be set to repeat, - * or can be interrupted to change. - * - * ## Chaining Actions - * - * You can chain actions to create a script because the action - * methods return the context, allowing you to build a queue of - * actions that get executed as part of an [[ActionQueue]]. - * - * ```ts - * class Enemy extends ex.Actor { - * - * public patrol() { - * - * // clear existing queue - * this.clearActions(); - * - * // guard a choke point - * // move to 100, 100 and take 1.2s - * // wait for 3s - * // move back to 0, 100 and take 1.2s - * // wait for 3s - * // repeat - * this.moveTo(100, 100, 1200) - * .delay(3000) - * .moveTo(0, 100, 1200) - * .delay(3000) - * .repeatForever(); - * } - * } - * ``` - * - * ## Example: Follow a Path - * - * You can use [[Actor.moveTo]] to move to a specific point, - * allowing you to chain together actions to form a path. - * - * This example has a `Ship` follow a path that it guards by - * spawning at the start point, moving to the end, then reversing - * itself and repeating that forever. - * - * ```ts - * public Ship extends ex.Actor { - * - * public onInitialize() { - * var path = [ - * new ex.Point(20, 20), - * new ex.Point(50, 40), - * new ex.Point(25, 30), - * new ex.Point(75, 80) - * ]; - * - * // spawn at start point - * this.x = path[0].x; - * this.y = path[0].y; - * - * // create action queue - * - * // forward path (skip first spawn point) - * for (var i = 1; i < path.length; i++) { - * this.moveTo(path[i].x, path[i].y, 300); - * } - * - * // reverse path (skip last point) - * for (var j = path.length - 2; j >= 0; j--) { - * this.moveTo(path[j].x, path[j].y, 300); - * } - * - * // repeat - * this.repeatForever(); - * } - * } - * ``` - * - * While this is a trivial example, the Action API allows complex - * routines to be programmed for Actors. For example, using the - * [Tiled Map Editor](http://mapeditor.org) you can create a map that - * uses polylines to create paths, load in the JSON using a - * [[Resource|Generic Resource]], create a [[TileMap]], - * and spawn ships programmatically while utilizing the polylines - * to automatically generate the actions needed to do pathing. - * - * ## Custom Actions - * - * The API does allow you to implement new actions by implementing the [[IAction]] - * interface, but this will be improved in future versions as right now it - * is meant for the Excalibur team and can be advanced to implement. - * - * You can manually manipulate an Actor's [[ActionQueue]] using - * [[Actor.actionQueue]]. For example, using [[ActionQueue.add]] for - * custom actions. - * - * ## Future Plans - * - * The Excalibur team is working on extending and rebuilding the Action API - * in future versions to support multiple timelines/scripts, better eventing, - * and a more robust API to allow for complex and customized actions. - * - * ## Known Issues - * - * **Rotation actions do not use shortest angle** - * [Issue #282](https://github.com/excaliburjs/Excalibur/issues/282) - * + * An enum that describes the strategies that rotation actions can use */ - var ActionContext = (function () { - function ActionContext() { - this._actors = []; - this._queues = []; - if (arguments !== null) { - this._actors = Array.prototype.slice.call(arguments, 0); - this._queues = this._actors.map(function (a) { - return a.actionQueue; - }); - } - } + (function (RotationType) { /** - * Clears all queued actions from the Actor + * Rotation via `ShortestPath` will use the smallest angle + * between the starting and ending points. This strategy is the default behavior. */ - ActionContext.prototype.clearActions = function () { - var i = 0, len = this._queues.length; - for (i; i < len; i++) { - this._queues[i].clearActions(); - } - }; - ActionContext.prototype.addActorToContext = function (actor) { - this._actors.push(actor); - // if we run into problems replace the line below with: - this._queues.push(actor.actionQueue); - }; - ActionContext.prototype.removeActorFromContext = function (actor) { - var index = this._actors.indexOf(actor); - if (index > -1) { - this._actors.splice(index, 1); - this._queues.splice(index, 1); - } - }; - /** - * This method will move an actor to the specified x and y position at the - * speed specified (in pixels per second) and return back the actor. This - * method is part of the actor 'Action' fluent API allowing action chaining. - * @param x The x location to move the actor to - * @param y The y location to move the actor to - * @param speed The speed in pixels per second to move - */ - ActionContext.prototype.moveTo = function (x, y, speed) { - var i = 0, len = this._queues.length; - for (i; i < len; i++) { - this._queues[i].add(new ex.Internal.Actions.MoveTo(this._actors[i], x, y, speed)); - } - return this; - }; - /** - * This method will move an actor to the specified x and y position by a - * certain time (in milliseconds). This method is part of the actor - * 'Action' fluent API allowing action chaining. - * @param x The x location to move the actor to - * @param y The y location to move the actor to - * @param time The time it should take the actor to move to the new location in milliseconds - */ - ActionContext.prototype.moveBy = function (x, y, time) { - var i = 0, len = this._queues.length; - for (i; i < len; i++) { - this._queues[i].add(new ex.Internal.Actions.MoveBy(this._actors[i], x, y, time)); - } - return this; - }; - /** - * This method will rotate an actor to the specified angle at the speed - * specified (in radians per second) and return back the actor. This - * method is part of the actor 'Action' fluent API allowing action chaining. - * @param angleRadians The angle to rotate to in radians - * @param speed The angular velocity of the rotation specified in radians per second - */ - ActionContext.prototype.rotateTo = function (angleRadians, speed) { - var i = 0, len = this._queues.length; - for (i; i < len; i++) { - this._queues[i].add(new ex.Internal.Actions.RotateTo(this._actors[i], angleRadians, speed)); - } - return this; - }; - /** - * This method will rotate an actor to the specified angle by a certain - * time (in milliseconds) and return back the actor. This method is part - * of the actor 'Action' fluent API allowing action chaining. - * @param angleRadians The angle to rotate to in radians - * @param time The time it should take the actor to complete the rotation in milliseconds - */ - ActionContext.prototype.rotateBy = function (angleRadians, time) { - var i = 0, len = this._queues.length; - for (i; i < len; i++) { - this._queues[i].add(new ex.Internal.Actions.RotateBy(this._actors[i], angleRadians, time)); - } - return this; - }; - /** - * This method will scale an actor to the specified size at the speed - * specified (in magnitude increase per second) and return back the - * actor. This method is part of the actor 'Action' fluent API allowing - * action chaining. - * @param size The scaling factor to apply - * @param speed The speed of scaling specified in magnitude increase per second - */ - ActionContext.prototype.scaleTo = function (sizeX, sizeY, speedX, speedY) { - var i = 0, len = this._queues.length; - for (i; i < len; i++) { - this._queues[i].add(new ex.Internal.Actions.ScaleTo(this._actors[i], sizeX, sizeY, speedX, speedY)); - } - return this; - }; - /** - * This method will scale an actor to the specified size by a certain time - * (in milliseconds) and return back the actor. This method is part of the - * actor 'Action' fluent API allowing action chaining. - * @param size The scaling factor to apply - * @param time The time it should take to complete the scaling in milliseconds - */ - ActionContext.prototype.scaleBy = function (sizeX, sizeY, time) { - var i = 0, len = this._queues.length; - for (i; i < len; i++) { - this._queues[i].add(new ex.Internal.Actions.ScaleBy(this._actors[i], sizeX, sizeY, time)); - } - return this; - }; - /** - * This method will cause an actor to blink (become visible and not - * visible). Optionally, you may specify the number of blinks. Specify the amount of time - * the actor should be visible per blink, and the amount of time not visible. - * This method is part of the actor 'Action' fluent API allowing action chaining. - * @param timeVisible The amount of time to stay visible per blink in milliseconds - * @param timeNotVisible The amount of time to stay not visible per blink in milliseconds - * @param numBlinks The number of times to blink - */ - ActionContext.prototype.blink = function (timeVisible, timeNotVisible, numBlinks) { - if (numBlinks === void 0) { numBlinks = 1; } - var i = 0, len = this._queues.length; - for (i; i < len; i++) { - this._queues[i].add(new ex.Internal.Actions.Blink(this._actors[i], timeVisible, timeNotVisible, numBlinks)); - } - return this; - }; - /** - * This method will cause an actor's opacity to change from its current value - * to the provided value by a specified time (in milliseconds). This method is - * part of the actor 'Action' fluent API allowing action chaining. - * @param opacity The ending opacity - * @param time The time it should take to fade the actor (in milliseconds) - */ - ActionContext.prototype.fade = function (opacity, time) { - var i = 0, len = this._queues.length; - for (i; i < len; i++) { - this._queues[i].add(new ex.Internal.Actions.Fade(this._actors[i], opacity, time)); - } - return this; - }; - /** - * This method will delay the next action from executing for a certain - * amount of time (in milliseconds). This method is part of the actor - * 'Action' fluent API allowing action chaining. - * @param time The amount of time to delay the next action in the queue from executing in milliseconds - */ - ActionContext.prototype.delay = function (time) { - var i = 0, len = this._queues.length; - for (i; i < len; i++) { - this._queues[i].add(new ex.Internal.Actions.Delay(this._actors[i], time)); - } - return this; - }; - /** - * This method will add an action to the queue that will remove the actor from the - * scene once it has completed its previous actions. Any actions on the - * action queue after this action will not be executed. - */ - ActionContext.prototype.die = function () { - var i = 0, len = this._queues.length; - for (i; i < len; i++) { - this._queues[i].add(new ex.Internal.Actions.Die(this._actors[i])); - } - return this; - }; - /** - * This method allows you to call an arbitrary method as the next action in the - * action queue. This is useful if you want to execute code in after a specific - * action, i.e An actor arrives at a destinatino after traversing a path - */ - ActionContext.prototype.callMethod = function (method) { - var i = 0, len = this._queues.length; - for (i; i < len; i++) { - this._queues[i].add(new ex.Internal.Actions.CallMethod(this._actors[i], method)); - } - return this; - }; - /** - * This method will cause the actor to repeat all of the previously - * called actions a certain number of times. If the number of repeats - * is not specified it will repeat forever. This method is part of - * the actor 'Action' fluent API allowing action chaining - * @param times The number of times to repeat all the previous actions in the action queue. If nothing is specified the actions - * will repeat forever - */ - ActionContext.prototype.repeat = function (times) { - if (!times) { - this.repeatForever(); - return this; - } - var i = 0, len = this._queues.length; - for (i; i < len; i++) { - this._queues[i].add(new ex.Internal.Actions.Repeat(this._actors[i], times, this._actors[i].actionQueue.getActions())); - } - return this; - }; - /** - * This method will cause the actor to repeat all of the previously - * called actions forever. This method is part of the actor 'Action' - * fluent API allowing action chaining. - */ - ActionContext.prototype.repeatForever = function () { - var i = 0, len = this._queues.length; - for (i; i < len; i++) { - this._queues[i].add(new ex.Internal.Actions.RepeatForever(this._actors[i], this._actors[i].actionQueue.getActions())); - } - return this; - }; + RotationType[RotationType["ShortestPath"] = 0] = "ShortestPath"; /** - * This method will cause the actor to follow another at a specified distance - * @param actor The actor to follow - * @param followDistance The distance to maintain when following, if not specified the actor will follow at the current distance. + * Rotation via `LongestPath` will use the largest angle + * between the starting and ending points. */ - ActionContext.prototype.follow = function (actor, followDistance) { - var i = 0, len = this._queues.length; - for (i; i < len; i++) { - if (followDistance === undefined) { - this._queues[i].add(new ex.Internal.Actions.Follow(this._actors[i], actor)); - } - else { - this._queues[i].add(new ex.Internal.Actions.Follow(this._actors[i], actor, followDistance)); - } - } - return this; - }; + RotationType[RotationType["LongestPath"] = 1] = "LongestPath"; /** - * This method will cause the actor to move towards another until they - * collide "meet" at a specified speed. - * @param actor The actor to meet - * @param speed The speed in pixels per second to move, if not specified it will match the speed of the other actor + * Rotation via `Clockwise` will travel in a clockwise direction, + * regardless of the starting and ending points. */ - ActionContext.prototype.meet = function (actor, speed) { - var i = 0, len = this._queues.length; - for (i; i < len; i++) { - if (speed === undefined) { - this._queues[i].add(new ex.Internal.Actions.Meet(this._actors[i], actor)); - } - else { - this._queues[i].add(new ex.Internal.Actions.Meet(this._actors[i], actor, speed)); - } - } - return this; - }; + RotationType[RotationType["Clockwise"] = 2] = "Clockwise"; /** - * Returns a promise that resolves when the current action queue up to now - * is finished. + * Rotation via `CounterClockwise` will travel in a counterclockwise direction, + * regardless of the starting and ending points. */ - ActionContext.prototype.asPromise = function () { - var _this = this; - var promises = this._queues.map(function (q, i) { - var temp = new ex.Promise(); - q.add(new ex.Internal.Actions.CallMethod(_this._actors[i], function () { - temp.resolve(); - })); - return temp; - }); - return ex.Promise.join.apply(this, promises); - }; - return ActionContext; - })(); - ex.ActionContext = ActionContext; -})(ex || (ex = {})); -/// -/// -/// -var ex; -(function (ex) { - /** - * Grouping - * - * Groups are used for logically grouping Actors so they can be acted upon - * in bulk. - * - * @todo Document this - */ - var Group = (function (_super) { - __extends(Group, _super); - function Group(name, scene) { - _super.call(this); - this.name = name; - this.scene = scene; - this._logger = ex.Logger.getInstance(); - this._members = []; - this.actions = new ex.ActionContext(); - if (scene == null) { - this._logger.error('Invalid constructor arguments passed to Group: ', name, ', scene must not be null!'); - } - else { - var existingGroup = scene.groups[name]; - if (existingGroup) { - this._logger.warn('Group with name', name, 'already exists. This new group will replace it.'); - } - scene.groups[name] = this; - } - } - Group.prototype.add = function (actorOrActors) { - if (actorOrActors instanceof ex.Actor) { - actorOrActors = [].concat(actorOrActors); - } - var i = 0, len = actorOrActors.length, groupIdx; - for (i; i < len; i++) { - groupIdx = this.getMembers().indexOf(actorOrActors[i]); - if (groupIdx === -1) { - this._members.push(actorOrActors[i]); - this.scene.add(actorOrActors[i]); - this.actions.addActorToContext(actorOrActors[i]); - this.eventDispatcher.wire(actorOrActors[i].eventDispatcher); - } - } - }; - Group.prototype.remove = function (actor) { - var index = this._members.indexOf(actor); - if (index > -1) { - this._members.splice(index, 1); - this.actions.removeActorFromContext(actor); - this.eventDispatcher.unwire(actor.eventDispatcher); - } - }; - Group.prototype.move = function (args) { - var i = 0, members = this.getMembers(), len = members.length; - if (arguments.length === 1 && args instanceof ex.Vector) { - for (i; i < len; i++) { - members[i].x += args.x; - members[i].y += args.y; - } - } - else if (typeof arguments[0] === 'number' && typeof arguments[1] === 'number') { - var x = arguments[0]; - var y = arguments[1]; - for (i; i < len; i++) { - members[i].x += x; - members[i].y += y; - } - } - else { - this._logger.error('Invalid arguments passed to group move', this.name, 'args:', arguments); - } - }; - Group.prototype.rotate = function (angle) { - if (typeof arguments[0] === 'number') { - var r = arguments[0], i = 0, members = this.getMembers(), len = members.length; - for (i; i < len; i++) { - members[i].rotation += r; - } - } - else { - this._logger.error('Invalid arguments passed to group rotate', this.name, 'args:', arguments); - } - }; - Group.prototype.on = function (eventName, handler) { - this.eventDispatcher.subscribe(eventName, handler); - }; - Group.prototype.off = function (eventName, handler) { - this.eventDispatcher.unsubscribe(eventName, handler); - }; - Group.prototype.emit = function (topic, event) { - this.eventDispatcher.emit(topic, event); - }; - Group.prototype.contains = function (actor) { - return this.getMembers().indexOf(actor) > -1; - }; - Group.prototype.getMembers = function () { - return this._members; - }; - Group.prototype.getRandomMember = function () { - return this._members[Math.floor(Math.random() * this._members.length)]; - }; - Group.prototype.getBounds = function () { - return this.getMembers().map(function (a) { return a.getBounds(); }).reduce(function (prev, curr) { - return prev.combine(curr); - }); - }; - return Group; - })(ex.Class); - ex.Group = Group; + RotationType[RotationType["CounterClockwise"] = 3] = "CounterClockwise"; + })(ex.RotationType || (ex.RotationType = {})); + var RotationType = ex.RotationType; })(ex || (ex = {})); +/// +/// +/// +/// +/** + * See [[ActionContext|Action API]] for more information about Actions. + */ var ex; (function (ex) { - // NOTE: this implementation is not self-balancing - var SortedList = (function () { - function SortedList(getComparable) { - this._getComparable = getComparable; - } - SortedList.prototype.find = function (element) { - return this._find(this._root, element); - }; - SortedList.prototype._find = function (node, element) { - if (node == null) { - return false; - } - else if (this._getComparable.call(element) === node.getKey()) { - if (node.getData().indexOf(element) > -1) { - return true; - } - else { - return false; + var Internal; + (function (Internal) { + var Actions; + (function (Actions) { + var EaseTo = (function () { + function EaseTo(actor, x, y, duration, easingFcn) { + this.actor = actor; + this.easingFcn = easingFcn; + this._currentLerpTime = 0; + this._lerpDuration = 1 * 1000; // 5 seconds + this._lerpStart = new ex.Point(0, 0); + this._lerpEnd = new ex.Point(0, 0); + this._initialized = false; + this._stopped = false; + this._distance = 0; + this._lerpDuration = duration; + this._lerpEnd = new ex.Point(x, y); } - } - else if (this._getComparable.call(element) < node.getKey()) { - return this._find(node.getLeft(), element); - } - else { - return this._find(node.getRight(), element); - } - }; - // returns the array of elements at a specific key value - SortedList.prototype.get = function (key) { - return this._get(this._root, key); - }; - SortedList.prototype._get = function (node, key) { - if (node == null) { - return []; - } - else if (key === node.getKey()) { - return node.getData(); - } - else if (key < node.getKey()) { - return this._get(node.getLeft(), key); - } - else { - return this._get(node.getRight(), key); - } - }; - SortedList.prototype.add = function (element) { - if (this._root == null) { - this._root = new BinaryTreeNode(this._getComparable.call(element), [element], null, null); - return true; - } - else { - return this._insert(this._root, element); - } - return false; - }; - SortedList.prototype._insert = function (node, element) { - if (node != null) { - if (this._getComparable.call(element) === node.getKey()) { - if (node.getData().indexOf(element) > -1) { - return false; // the element we're trying to insert already exists - } - else { - node.getData().push(element); - return true; + EaseTo.prototype._initialize = function () { + this._lerpStart = new ex.Point(this.actor.x, this.actor.y); + this._currentLerpTime = 0; + this._distance = this._lerpStart.toVector().distance(this._lerpEnd.toVector()); + }; + EaseTo.prototype.update = function (delta) { + if (!this._initialized) { + this._initialize(); + this._initialized = true; } - } - else if (this._getComparable.call(element) < node.getKey()) { - if (node.getLeft() == null) { - node.setLeft(new BinaryTreeNode(this._getComparable.call(element), [element], null, null)); - return true; + var newX = this.actor.x; + var newY = this.actor.y; + if (this._currentLerpTime < this._lerpDuration) { + if (this._lerpEnd.x < this._lerpStart.x) { + newX = this._lerpStart.x - (this.easingFcn(this._currentLerpTime, this._lerpEnd.x, this._lerpStart.x, this._lerpDuration) - this._lerpEnd.x); + } + else { + newX = this.easingFcn(this._currentLerpTime, this._lerpStart.x, this._lerpEnd.x, this._lerpDuration); + } + if (this._lerpEnd.y < this._lerpStart.y) { + newY = this._lerpStart.y - (this.easingFcn(this._currentLerpTime, this._lerpEnd.y, this._lerpStart.y, this._lerpDuration) - this._lerpEnd.y); + } + else { + newY = this.easingFcn(this._currentLerpTime, this._lerpStart.y, this._lerpEnd.y, this._lerpDuration); + } + this.actor.x = newX; + this.actor.y = newY; + this._currentLerpTime += delta; } else { - return this._insert(node.getLeft(), element); + this.actor.x = this._lerpEnd.x; + this.actor.y = this._lerpEnd.y; } + }; + EaseTo.prototype.isComplete = function (actor) { + return this._stopped || (new ex.Vector(actor.x, actor.y)).distance(this._lerpStart.toVector()) >= this._distance; + }; + EaseTo.prototype.reset = function () { + this._initialized = false; + }; + EaseTo.prototype.stop = function () { + this._stopped = true; + }; + return EaseTo; + })(); + Actions.EaseTo = EaseTo; + var MoveTo = (function () { + function MoveTo(actor, destx, desty, speed) { + this._started = false; + this._stopped = false; + this._actor = actor; + this._end = new ex.Vector(destx, desty); + this._speed = speed; } - else { - if (node.getRight() == null) { - node.setRight(new BinaryTreeNode(this._getComparable.call(element), [element], null, null)); - return true; + MoveTo.prototype.update = function (delta) { + if (!this._started) { + this._started = true; + this._start = new ex.Vector(this._actor.x, this._actor.y); + this._distance = this._start.distance(this._end); + this._dir = this._end.minus(this._start).normalize(); } - else { - return this._insert(node.getRight(), element); + var m = this._dir.scale(this._speed); + this._actor.dx = m.x; + this._actor.dy = m.y; + if (this.isComplete(this._actor)) { + this._actor.x = this._end.x; + this._actor.y = this._end.y; + this._actor.dy = 0; + this._actor.dx = 0; + } + }; + MoveTo.prototype.isComplete = function (actor) { + return this._stopped || (new ex.Vector(actor.x, actor.y)).distance(this._start) >= this._distance; + }; + MoveTo.prototype.stop = function () { + this._actor.dy = 0; + this._actor.dx = 0; + this._stopped = true; + }; + MoveTo.prototype.reset = function () { + this._started = false; + }; + return MoveTo; + })(); + Actions.MoveTo = MoveTo; + var MoveBy = (function () { + function MoveBy(actor, destx, desty, time) { + this._started = false; + this._stopped = false; + this._actor = actor; + this._end = new ex.Vector(destx, desty); + if (time <= 0) { + ex.Logger.getInstance().error('Attempted to moveBy time less than or equal to zero : ' + time); + throw new Error('Cannot move in time <= 0'); } + this._time = time; } - } - return false; - }; - SortedList.prototype.removeByComparable = function (element) { - this._root = this._remove(this._root, element); - }; - SortedList.prototype._remove = function (node, element) { - if (node == null) { - return null; - } - else if (this._getComparable.call(element) === node.getKey()) { - var elementIndex = node.getData().indexOf(element); - // if the node contains the element, remove the element - if (elementIndex > -1) { - node.getData().splice(elementIndex, 1); - // if we have removed the last element at this node, remove the node - if (node.getData().length === 0) { - // if the node is a leaf - if (node.getLeft() == null && node.getRight() == null) { - return null; - } - else if (node.getLeft() == null) { - return node.getRight(); - } - else if (node.getRight() == null) { - return node.getLeft(); - } - // if node has 2 children - var temp = this._findMinNode(node.getRight()); - node.setKey(temp.getKey()); - node.setData(temp.getData()); - node.setRight(this._cleanup(node.getRight(), temp)); //"cleanup nodes" (move them up recursively) - return node; + MoveBy.prototype.update = function (delta) { + if (!this._started) { + this._started = true; + this._start = new ex.Vector(this._actor.x, this._actor.y); + this._distance = this._start.distance(this._end); + this._dir = this._end.minus(this._start).normalize(); + this._speed = this._distance / (this._time / 1000); } - else { - // this prevents the node from being removed since it still contains elements - return node; + var m = this._dir.scale(this._speed); + this._actor.dx = m.x; + this._actor.dy = m.y; + if (this.isComplete(this._actor)) { + this._actor.x = this._end.x; + this._actor.y = this._end.y; + this._actor.dy = 0; + this._actor.dx = 0; } + }; + MoveBy.prototype.isComplete = function (actor) { + return this._stopped || (new ex.Vector(actor.x, actor.y)).distance(this._start) >= this._distance; + }; + MoveBy.prototype.stop = function () { + this._actor.dy = 0; + this._actor.dx = 0; + this._stopped = true; + }; + MoveBy.prototype.reset = function () { + this._started = false; + }; + return MoveBy; + })(); + Actions.MoveBy = MoveBy; + var Follow = (function () { + function Follow(actor, actorToFollow, followDistance) { + this._started = false; + this._stopped = false; + this._actor = actor; + this._actorToFollow = actorToFollow; + this._current = new ex.Vector(this._actor.x, this._actor.y); + this._end = new ex.Vector(actorToFollow.x, actorToFollow.y); + this._maximumDistance = (followDistance !== undefined) ? followDistance : this._current.distance(this._end); + this._speed = 0; } - } - else if (this._getComparable.call(element) < node.getKey()) { - node.setLeft(this._remove(node.getLeft(), element)); - return node; - } - else { - node.setRight(this._remove(node.getRight(), element)); - return node; - } - }; - // called once we have successfully removed the element we wanted, recursively corrects the part of the tree below the removed node - SortedList.prototype._cleanup = function (node, element) { - var comparable = element.getKey(); - if (node == null) { - return null; - } - else if (comparable === node.getKey()) { - // if the node is a leaf - if (node.getLeft() == null && node.getRight() == null) { - return null; - } - else if (node.getLeft() == null) { - return node.getRight(); + Follow.prototype.update = function (delta) { + if (!this._started) { + this._started = true; + this._distanceBetween = this._current.distance(this._end); + this._dir = this._end.minus(this._current).normalize(); + } + var actorToFollowSpeed = Math.sqrt(Math.pow(this._actorToFollow.dx, 2) + Math.pow(this._actorToFollow.dy, 2)); + if (actorToFollowSpeed !== 0) { + this._speed = actorToFollowSpeed; + } + this._current.x = this._actor.x; + this._current.y = this._actor.y; + this._end.x = this._actorToFollow.x; + this._end.y = this._actorToFollow.y; + this._distanceBetween = this._current.distance(this._end); + this._dir = this._end.minus(this._current).normalize(); + if (this._distanceBetween >= this._maximumDistance) { + var m = this._dir.scale(this._speed); + this._actor.dx = m.x; + this._actor.dy = m.y; + } + else { + this._actor.dx = 0; + this._actor.dy = 0; + } + if (this.isComplete(this._actor)) { + // TODO this should never occur + this._actor.x = this._end.x; + this._actor.y = this._end.y; + this._actor.dy = 0; + this._actor.dx = 0; + } + }; + Follow.prototype.stop = function () { + this._actor.dy = 0; + this._actor.dx = 0; + this._stopped = true; + }; + Follow.prototype.isComplete = function (actor) { + // the actor following should never stop unless specified to do so + return this._stopped; + }; + Follow.prototype.reset = function () { + this._started = false; + }; + return Follow; + })(); + Actions.Follow = Follow; + var Meet = (function () { + function Meet(actor, actorToMeet, speed) { + this._started = false; + this._stopped = false; + this._speedWasSpecified = false; + this._actor = actor; + this._actorToMeet = actorToMeet; + this._current = new ex.Vector(this._actor.x, this._actor.y); + this._end = new ex.Vector(actorToMeet.x, actorToMeet.y); + this._speed = speed || 0; + if (speed !== undefined) { + this._speedWasSpecified = true; + } } - else if (node.getRight() == null) { - return node.getLeft(); + Meet.prototype.update = function (delta) { + if (!this._started) { + this._started = true; + this._distanceBetween = this._current.distance(this._end); + this._dir = this._end.minus(this._current).normalize(); + } + var actorToMeetSpeed = Math.sqrt(Math.pow(this._actorToMeet.dx, 2) + Math.pow(this._actorToMeet.dy, 2)); + if ((actorToMeetSpeed !== 0) && (!this._speedWasSpecified)) { + this._speed = actorToMeetSpeed; + } + this._current.x = this._actor.x; + this._current.y = this._actor.y; + this._end.x = this._actorToMeet.x; + this._end.y = this._actorToMeet.y; + this._distanceBetween = this._current.distance(this._end); + this._dir = this._end.minus(this._current).normalize(); + var m = this._dir.scale(this._speed); + this._actor.dx = m.x; + this._actor.dy = m.y; + if (this.isComplete(this._actor)) { + this._actor.x = this._end.x; + this._actor.y = this._end.y; + this._actor.dy = 0; + this._actor.dx = 0; + } + }; + Meet.prototype.isComplete = function (actor) { + return this._stopped || (this._distanceBetween <= 1); + }; + Meet.prototype.stop = function () { + this._actor.dy = 0; + this._actor.dx = 0; + this._stopped = true; + }; + Meet.prototype.reset = function () { + this._started = false; + }; + return Meet; + })(); + Actions.Meet = Meet; + var RotateTo = (function () { + function RotateTo(actor, angleRadians, speed, rotationType) { + this._started = false; + this._stopped = false; + this._actor = actor; + this._end = angleRadians; + this._speed = speed; + this._rotationType = rotationType || ex.RotationType.ShortestPath; } - // if node has 2 children - var temp = this._findMinNode(node.getRight()); - node.setKey(temp.getKey()); - node.setData(temp.getData()); - node.setRight(this._cleanup(node.getRight(), temp)); - return node; - } - else if (this._getComparable.call(element) < node.getKey()) { - node.setLeft(this._cleanup(node.getLeft(), element)); - return node; - } - else { - node.setRight(this._cleanup(node.getRight(), element)); - return node; - } - }; - SortedList.prototype._findMinNode = function (node) { - var current = node; - while (current.getLeft() != null) { - current = current.getLeft(); - } - return current; - }; - SortedList.prototype.list = function () { - var results = new Array(); - this._list(this._root, results); - return results; - }; - SortedList.prototype._list = function (treeNode, results) { - if (treeNode != null) { - this._list(treeNode.getLeft(), results); - treeNode.getData().forEach(function (element) { - results.push(element); - }); - this._list(treeNode.getRight(), results); - } - }; - return SortedList; - })(); - ex.SortedList = SortedList; - var BinaryTreeNode = (function () { - function BinaryTreeNode(key, data, left, right) { - this._key = key; - this._data = data; - this._left = left; - this._right = right; - } - BinaryTreeNode.prototype.getKey = function () { - return this._key; - }; - BinaryTreeNode.prototype.setKey = function (key) { - this._key = key; - }; - BinaryTreeNode.prototype.getData = function () { - return this._data; - }; - BinaryTreeNode.prototype.setData = function (data) { - this._data = data; - }; - BinaryTreeNode.prototype.getLeft = function () { - return this._left; - }; - BinaryTreeNode.prototype.setLeft = function (left) { - this._left = left; - }; - BinaryTreeNode.prototype.getRight = function () { - return this._right; - }; - BinaryTreeNode.prototype.setRight = function (right) { - this._right = right; - }; - return BinaryTreeNode; - })(); - ex.BinaryTreeNode = BinaryTreeNode; - var MockedElement = (function () { - function MockedElement(key) { - this._key = 0; - this._key = key; - } - MockedElement.prototype.getTheKey = function () { - return this._key; - }; - MockedElement.prototype.setKey = function (key) { - this._key = key; - }; - return MockedElement; - })(); - ex.MockedElement = MockedElement; -})(ex || (ex = {})); -/// -/// -/// -/// -/// -/// -/// -/// -var ex; -(function (ex) { - /** - * Scenes - * - * [[Actor|Actors]] are composed together into groupings called Scenes in - * Excalibur. The metaphor models the same idea behind real world - * actors in a scene. Only actors in scenes will be updated and drawn. - * - * Typical usages of a scene include: levels, menus, loading screens, etc. - * - * ## Adding actors to the scene - * - * For an [[Actor]] to be drawn and updated, it needs to be part of the "scene graph". - * The [[Engine]] provides several easy ways to quickly add/remove actors from the - * current scene. - * - * ```js - * var game = new ex.Engine(...); - * - * var player = new ex.Actor(); - * var enemy = new ex.Actor(); - * - * // add them to the "root" scene - * - * game.add(player); - * game.add(enemy); - * - * // start game - * game.start(); - * ``` - * - * You can also add actors to a [[Scene]] instance specifically. - * - * ```js - * var game = new ex.Engine(); - * var level1 = new ex.Scene(); - * - * var player = new ex.Actor(); - * var enemy = new ex.Actor(); - * - * // add actors to level1 - * level1.add(player); - * level1.add(enemy); - * - * // add level1 to the game - * game.add("level1", level1); - * - * // start the game - * game.start(); - * - * // after player clicks start game, for example - * game.goToScene("level1"); - * - * ``` - * - * ## Extending scenes - * - * For more complex games, you might want more control over a scene in which - * case you can extend [[Scene]]. This is useful for menus, custom loaders, - * and levels. - * - * Just use [[Engine.add]] to add a new scene to the game. You can then use - * [[Engine.goToScene]] to switch scenes which calls [[Scene.onActivate]] for the - * new scene and [[Scene.onDeactivate]] for the old scene. Use [[Scene.onInitialize]] - * to perform any start-up logic, which is called once. - * - * **TypeScript** - * - * ```ts - * class MainMenu extends ex.Scene { - * - * // start-up logic, called once - * public onInitialize(engine: ex.Engine) { } - * - * // each time the scene is entered (Engine.goToScene) - * public onActivate() { } - * - * // each time the scene is exited (Engine.goToScene) - * public onDeactivate() { } - * } - * - * // add to game and activate it - * game.add("mainmenu", new MainMenu()); - * game.goToScene("mainmenu"); - * ``` - * - * **Javascript** - * - * ```js - * var MainMenu = ex.Scene.extend({ - * // start-up logic, called once - * onInitialize: function (engine) { }, - * - * // each time the scene is activated by Engine.goToScene - * onActivate: function () { }, - * - * // each time the scene is deactivated by Engine.goToScene - * onDeactivate: function () { } - * }); - * - * game.add("mainmenu", new MainMenu()); - * game.goToScene("mainmenu"); - * ``` - * - * ## Scene camera - * - * By default, a [[Scene]] is initialized with a [[BaseCamera]] which - * does not move and centers the game world. - * - * Learn more about [[BaseCamera|Cameras]] and how to modify them to suit - * your game. - */ - var Scene = (function (_super) { - __extends(Scene, _super); - function Scene(engine) { - _super.call(this); - /** - * The actors in the current scene - */ - this.children = []; - /** - * The [[TileMap]]s in the scene, if any - */ - this.tileMaps = []; - /** - * The [[Group]]s in the scene, if any - */ - this.groups = {}; - /** - * The [[UIActor]]s in a scene, if any; these are drawn last - */ - this.uiActors = []; - /** - * Whether or the [[Scene]] has been initialized - */ - this.isInitialized = false; - this._sortedDrawingTree = new ex.SortedList(ex.Actor.prototype.getZIndex); - this._collisionResolver = new ex.DynamicTreeCollisionResolver(); - this._killQueue = []; - this._timers = []; - this._cancelQueue = []; - this._logger = ex.Logger.getInstance(); - this.camera = new ex.BaseCamera(); - if (engine) { - this.camera.setFocus(engine.width / 2, engine.height / 2); - } - } - /** - * This is called before the first update of the [[Scene]]. Initializes scene members like the camera. This method is meant to be - * overridden. This is where initialization of child actors should take place. - */ - Scene.prototype.onInitialize = function (engine) { - // will be overridden - if (this.camera) { - this.camera.setFocus(engine.width / 2, engine.height / 2); - } - this._logger.debug('Scene.onInitialize', this, engine); - }; - /** - * This is called when the scene is made active and started. It is meant to be overriden, - * this is where you should setup any DOM UI or event handlers needed for the scene. - */ - Scene.prototype.onActivate = function () { - // will be overridden - this._logger.debug('Scene.onActivate', this); - }; - /** - * This is called when the scene is made transitioned away from and stopped. It is meant to be overriden, - * this is where you should cleanup any DOM UI or event handlers needed for the scene. - */ - Scene.prototype.onDeactivate = function () { - // will be overridden - this._logger.debug('Scene.onDeactivate', this); - }; - /** - * Publish an event to all actors in the scene - * @param eventType The name of the event to publish - * @param event The event object to send - * - * @obsolete Use [[emit]] instead. - */ - Scene.prototype.publish = function (eventType, event) { - var i = 0, len = this.children.length; - for (i; i < len; i++) { - this.children[i].emit(eventType, event); - } - }; - /** - * Alias for `emit`. Publish an event to all actors in the scene - * @param eventType The name of the event to publish - * @param event The event object to send - */ - Scene.prototype.emit = function (eventType, event) { - this.publish(eventType, event); - }; - /** - * Updates all the actors and timers in the scene. Called by the [[Engine]]. - * @param engine Reference to the current Engine - * @param delta The number of milliseconds since the last update - */ - Scene.prototype.update = function (engine, delta) { - var i, len; - // Cycle through actors updating UI actors - for (i = 0, len = this.uiActors.length; i < len; i++) { - this.uiActors[i].update(engine, delta); - } - // Cycle through actors updating tile maps - for (i = 0, len = this.tileMaps.length; i < len; i++) { - this.tileMaps[i].update(engine, delta); - } - // Cycle through actors updating actors - for (i = 0, len = this.children.length; i < len; i++) { - this.children[i].update(engine, delta); - } - // Run collision resolution strategy - if (this._collisionResolver) { - this._collisionResolver.update(this.children); - this._collisionResolver.evaluate(this.children); - } - // Remove actors from scene graph after being killed - var actorIndex; - for (i = 0, len = this._killQueue.length; i < len; i++) { - actorIndex = this.children.indexOf(this._killQueue[i]); - if (actorIndex > -1) { - this._sortedDrawingTree.removeByComparable(this._killQueue[i]); - this.children.splice(actorIndex, 1); - } - } - this._killQueue.length = 0; - // Remove timers in the cancel queue before updating them - for (i = 0, len = this._cancelQueue.length; i < len; i++) { - this.removeTimer(this._cancelQueue[i]); - } - this._cancelQueue.length = 0; - // Cycle through timers updating timers - this._timers = this._timers.filter(function (timer) { - timer.update(delta); - return !timer.complete; - }); - }; - /** - * Draws all the actors in the Scene. Called by the [[Engine]]. - * @param ctx The current rendering context - * @param delta The number of milliseconds since the last draw - */ - Scene.prototype.draw = function (ctx, delta) { - ctx.save(); - if (this.camera) { - this.camera.update(ctx, delta); - } - var i, len; - for (i = 0, len = this.tileMaps.length; i < len; i++) { - this.tileMaps[i].draw(ctx, delta); - } - var sortedChildren = this._sortedDrawingTree.list(); - for (i = 0, len = sortedChildren.length; i < len; i++) { - // only draw actors that are visible and on screen - if (sortedChildren[i].visible && !sortedChildren[i].isOffScreen) { - sortedChildren[i].draw(ctx, delta); - } - } - if (this.engine && this.engine.isDebug) { - ctx.strokeStyle = 'yellow'; - this.debugDraw(ctx); - } - ctx.restore(); - for (i = 0, len = this.uiActors.length; i < len; i++) { - // only draw ui actors that are visible and on screen - if (this.uiActors[i].visible) { - this.uiActors[i].draw(ctx, delta); - } - } - if (this.engine && this.engine.isDebug) { - for (i = 0, len = this.uiActors.length; i < len; i++) { - this.uiActors[i].debugDraw(ctx); - } - } - }; - /** - * Draws all the actors' debug information in the Scene. Called by the [[Engine]]. - * @param ctx The current rendering context - */ - Scene.prototype.debugDraw = function (ctx) { - var i, len; - for (i = 0, len = this.tileMaps.length; i < len; i++) { - this.tileMaps[i].debugDraw(ctx); - } - for (i = 0, len = this.children.length; i < len; i++) { - this.children[i].debugDraw(ctx); - } - // todo possibly enable this with excalibur flags features? - //this._collisionResolver.debugDraw(ctx, 20); - this.camera.debugDraw(ctx); - }; - /** - * Checks whether an actor is contained in this scene or not - */ - Scene.prototype.contains = function (actor) { - return this.children.indexOf(actor) > -1; - }; - Scene.prototype.add = function (entity) { - if (entity instanceof ex.UIActor) { - if (!ex.Util.contains(this.uiActors, entity)) { - this.addUIActor(entity); - } - return; - } - if (entity instanceof ex.Actor) { - if (!ex.Util.contains(this.children, entity)) { - this.addChild(entity); - this._sortedDrawingTree.add(entity); - } - return; - } - if (entity instanceof ex.Timer) { - if (!ex.Util.contains(this._timers, entity)) { - this.addTimer(entity); - } - return; - } - if (entity instanceof ex.TileMap) { - if (!ex.Util.contains(this.tileMaps, entity)) { - this.addTileMap(entity); - } - } - }; - Scene.prototype.remove = function (entity) { - if (entity instanceof ex.UIActor) { - this.removeUIActor(entity); - return; - } - if (entity instanceof ex.Actor) { - this._collisionResolver.remove(entity); - this.removeChild(entity); - } - if (entity instanceof ex.Timer) { - this.removeTimer(entity); - } - if (entity instanceof ex.TileMap) { - this.removeTileMap(entity); - } - }; - /** - * Adds (any) actor to act as a piece of UI, meaning it is always positioned - * in screen coordinates. UI actors do not participate in collisions. - * @todo Should this be `UIActor` only? - */ - Scene.prototype.addUIActor = function (actor) { - this.uiActors.push(actor); - actor.scene = this; - }; - /** - * Removes an actor as a piece of UI - */ - Scene.prototype.removeUIActor = function (actor) { - var index = this.uiActors.indexOf(actor); - if (index > -1) { - this.uiActors.splice(index, 1); - } - }; - /** - * Adds an actor to the scene, once this is done the actor will be drawn and updated. - * - * @obsolete Use [[add]] instead. - */ - Scene.prototype.addChild = function (actor) { - this._collisionResolver.register(actor); - actor.scene = this; - this.children.push(actor); - this._sortedDrawingTree.add(actor); - actor.parent = this.actor; - }; - /** - * Adds a [[TileMap]] to the scene, once this is done the TileMap will be drawn and updated. - */ - Scene.prototype.addTileMap = function (tileMap) { - this.tileMaps.push(tileMap); - }; - /** - * Removes a [[TileMap]] from the scene, it will no longer be drawn or updated. - */ - Scene.prototype.removeTileMap = function (tileMap) { - var index = this.tileMaps.indexOf(tileMap); - if (index > -1) { - this.tileMaps.splice(index, 1); - } - }; - /** - * Removes an actor from the scene, it will no longer be drawn or updated. - */ - Scene.prototype.removeChild = function (actor) { - this._collisionResolver.remove(actor); - this._killQueue.push(actor); - actor.parent = null; - }; - /** - * Adds a [[Timer]] to the scene - * @param timer The timer to add - */ - Scene.prototype.addTimer = function (timer) { - this._timers.push(timer); - timer.scene = this; - return timer; - }; - /** - * Removes a [[Timer]] from the scene. - * @warning Can be dangerous, use [[cancelTimer]] instead - * @param timer The timer to remove - */ - Scene.prototype.removeTimer = function (timer) { - var i = this._timers.indexOf(timer); - if (i !== -1) { - this._timers.splice(i, 1); - } - return timer; - }; - /** - * Cancels a [[Timer]], removing it from the scene nicely - * @param timer The timer to cancel - */ - Scene.prototype.cancelTimer = function (timer) { - this._cancelQueue.push(timer); - return timer; - }; - /** - * Tests whether a [[Timer]] is active in the scene - */ - Scene.prototype.isTimerActive = function (timer) { - return (this._timers.indexOf(timer) > -1); - }; - /** - * Creates and adds a [[Group]] to the scene with a name - */ - Scene.prototype.createGroup = function (name) { - return new ex.Group(name, this); - }; - /** - * Returns a [[Group]] by name - */ - Scene.prototype.getGroup = function (name) { - return this.groups[name]; - }; - Scene.prototype.removeGroup = function (group) { - if (typeof group === 'string') { - delete this.groups[group]; - } - else if (group instanceof ex.Group) { - delete this.groups[group.name]; - } - else { - this._logger.error('Invalid arguments to removeGroup', group); - } - }; - /** - * Removes the given actor from the sorted drawing tree - */ - Scene.prototype.cleanupDrawTree = function (actor) { - this._sortedDrawingTree.removeByComparable(actor); - }; - /** - * Updates the given actor's position in the sorted drawing tree - */ - Scene.prototype.updateDrawTree = function (actor) { - this._sortedDrawingTree.add(actor); - }; - return Scene; - })(ex.Class); - ex.Scene = Scene; -})(ex || (ex = {})); -var ex; -(function (ex) { - /** - * Standard easing functions for motion in Excalibur - * - * easeInQuad: function (t) { return t * t }, - * // decelerating to zero velocity - * easeOutQuad: function (t) { return t * (2 - t) }, - * // acceleration until halfway, then deceleration - * easeInOutQuad: function (t) { return t < .5 ? 2 * t * t : -1 + (4 - 2 * t) * t }, - * // accelerating from zero velocity - * easeInCubic: function (t) { return t * t * t }, - * // decelerating to zero velocity - * easeOutCubic: function (t) { return (--t) * t * t + 1 }, - * // acceleration until halfway, then deceleration - * easeInOutCubic: function (t) { return t < .5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1 }, - * // accelerating from zero velocity - * easeInQuart: function (t) { return t * t * t * t }, - * // decelerating to zero velocity - * easeOutQuart: function (t) { return 1 - (--t) * t * t * t }, - * // acceleration until halfway, then deceleration - * easeInOutQuart: function (t) { return t < .5 ? 8 * t * t * t * t : 1 - 8 * (--t) * t * t * t }, - * // accelerating from zero velocity - * easeInQuint: function (t) { return t * t * t * t * t }, - * // decelerating to zero velocity - * easeOutQuint: function (t) { return 1 + (--t) * t * t * t * t }, - * // acceleration until halfway, then deceleration - * easeInOutQuint: function (t) { return t < .5 ? 16 * t * t * t * t * t : 1 + 16 * (--t) * t * t * t * t } - * - */ - var EasingFunctions = (function () { - function EasingFunctions() { - } - EasingFunctions.Linear = function (currentTime, startValue, endValue, duration) { - endValue = (endValue - startValue); - return endValue * currentTime / duration + startValue; - }; - EasingFunctions.EaseInQuad = function (currentTime, startValue, endValue, duration) { - //endValue = (endValue - startValue); - currentTime /= duration; - }; - EasingFunctions.EaseOutQuad = function (currentTime, startValue, endValue, duration) { - //endValue = (endValue - startValue); - currentTime /= duration; - return -endValue * currentTime * (currentTime - 2) + startValue; - }; - EasingFunctions.EaseInOutQuad = function (currentTime, startValue, endValue, duration) { - endValue = (endValue - startValue); - currentTime /= duration / 2; - if (currentTime < 1) { - return endValue / 2 * currentTime * currentTime + startValue; - } - currentTime--; - return -endValue / 2 * (currentTime * (currentTime - 2) - 1) + startValue; - }; - EasingFunctions.EaseInCubic = function (currentTime, startValue, endValue, duration) { - endValue = (endValue - startValue); - currentTime /= duration; - return endValue * currentTime * currentTime * currentTime + startValue; - }; - EasingFunctions.EaseOutCubic = function (currentTime, startValue, endValue, duration) { - endValue = (endValue - startValue); - currentTime /= duration; - return endValue * (currentTime * currentTime * currentTime + 1) + startValue; - }; - EasingFunctions.EaseInOutCubic = function (currentTime, startValue, endValue, duration) { - endValue = (endValue - startValue); - currentTime /= duration / 2; - if (currentTime < 1) { - return endValue / 2 * currentTime * currentTime * currentTime + startValue; - } - currentTime -= 2; - return endValue / 2 * (currentTime * currentTime * currentTime + 2) + startValue; - }; - return EasingFunctions; - })(); - ex.EasingFunctions = EasingFunctions; -})(ex || (ex = {})); -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -var ex; -(function (ex) { - /** - * Actors - * - * The most important primitive in Excalibur is an `Actor`. Anything that - * can move on the screen, collide with another `Actor`, respond to events, - * or interact with the current scene, must be an actor. An `Actor` **must** - * be part of a [[Scene]] for it to be drawn to the screen. - * - * ## Basic actors - * - * For quick and dirty games, you can just create an instance of an `Actor` - * and manipulate it directly. - * - * Actors (and other entities) must be added to a [[Scene]] to be drawn - * and updated on-screen. - * - * ```ts - * var player = new ex.Actor(); - * - * // move the player - * player.dx = 5; - * - * // add player to the current scene - * game.add(player); - * ``` - * - * ## Extending actors - * - * For "real-world" games, you'll want to `extend` the `Actor` class. - * This gives you much greater control and encapsulates logic for that - * actor. - * - * You can override the [[onInitialize]] method to perform any startup logic - * for an actor (such as configuring state). [[onInitialize]] gets called - * **once** before the first frame an actor is drawn/updated. It is passed - * an instance of [[Engine]] to access global state or perform coordinate math. - * - * **TypeScript** - * - * ```ts - * class Player extends ex.Actor { - * - * public level = 1; - * public endurance = 0; - * public fortitude = 0; - * - * constructor() { - * super(); - * } - * - * public onInitialize(engine: ex.Engine) { - * this.endurance = 20; - * this.fortitude = 16; - * } - * - * public getMaxHealth() { - * return (0.4 * this.endurance) + (0.9 * this.fortitude) + (this.level * 1.2); - * } - * } - * ``` - * - * **Javascript** - * - * In Javascript you can use the [[extend]] method to override or add - * methods to an `Actor`. - * - * ```js - * var Player = ex.Actor.extend({ - * - * level: 1, - * endurance: 0, - * fortitude: 0, - * - * onInitialize: function (engine) { - * this.endurance = 20; - * this.fortitude = 16; - * }, - * - * getMaxHealth: function () { - * return (0.4 * this.endurance) + (0.9 * this.fortitude) + (this.level * 1.2); - * } - * }); - * ``` - * - * ## Updating actors + RotateTo.prototype.update = function (delta) { + if (!this._started) { + this._started = true; + this._start = this._actor.rotation; + var distance1 = Math.abs(this._end - this._start); + var distance2 = ex.Util.TwoPI - distance1; + if (distance1 > distance2) { + this._shortDistance = distance2; + this._longDistance = distance1; + } + else { + this._shortDistance = distance1; + this._longDistance = distance2; + } + this._shortestPathIsPositive = (this._start - this._end + ex.Util.TwoPI) % ex.Util.TwoPI >= Math.PI; + switch (this._rotationType) { + case ex.RotationType.ShortestPath: + this._distance = this._shortDistance; + if (this._shortestPathIsPositive) { + this._direction = 1; + } + else { + this._direction = -1; + } + break; + case ex.RotationType.LongestPath: + this._distance = this._longDistance; + if (this._shortestPathIsPositive) { + this._direction = -1; + } + else { + this._direction = 1; + } + break; + case ex.RotationType.Clockwise: + this._direction = 1; + if (this._shortestPathIsPositive) { + this._distance = this._shortDistance; + } + else { + this._distance = this._longDistance; + } + break; + case ex.RotationType.CounterClockwise: + this._direction = -1; + if (!this._shortestPathIsPositive) { + this._distance = this._shortDistance; + } + else { + this._distance = this._longDistance; + } + break; + } + } + this._actor.rx = this._direction * this._speed; + if (this.isComplete(this._actor)) { + this._actor.rotation = this._end; + this._actor.rx = 0; + this._stopped = true; + } + }; + RotateTo.prototype.isComplete = function (actor) { + var distanceTravelled = Math.abs(this._actor.rotation - this._start); + return this._stopped || (distanceTravelled >= Math.abs(this._distance)); + }; + RotateTo.prototype.stop = function () { + this._actor.rx = 0; + this._stopped = true; + }; + RotateTo.prototype.reset = function () { + this._started = false; + }; + return RotateTo; + })(); + Actions.RotateTo = RotateTo; + var RotateBy = (function () { + function RotateBy(actor, angleRadians, time, rotationType) { + this._started = false; + this._stopped = false; + this._actor = actor; + this._end = angleRadians; + this._time = time; + this._rotationType = rotationType || ex.RotationType.ShortestPath; + } + RotateBy.prototype.update = function (delta) { + if (!this._started) { + this._started = true; + this._start = this._actor.rotation; + var distance1 = Math.abs(this._end - this._start); + var distance2 = ex.Util.TwoPI - distance1; + if (distance1 > distance2) { + this._shortDistance = distance2; + this._longDistance = distance1; + } + else { + this._shortDistance = distance1; + this._longDistance = distance2; + } + this._shortestPathIsPositive = (this._start - this._end + ex.Util.TwoPI) % ex.Util.TwoPI >= Math.PI; + switch (this._rotationType) { + case ex.RotationType.ShortestPath: + this._distance = this._shortDistance; + if (this._shortestPathIsPositive) { + this._direction = 1; + } + else { + this._direction = -1; + } + break; + case ex.RotationType.LongestPath: + this._distance = this._longDistance; + if (this._shortestPathIsPositive) { + this._direction = -1; + } + else { + this._direction = 1; + } + break; + case ex.RotationType.Clockwise: + this._direction = 1; + if (this._shortDistance >= 0) { + this._distance = this._shortDistance; + } + else { + this._distance = this._longDistance; + } + break; + case ex.RotationType.CounterClockwise: + this._direction = -1; + if (this._shortDistance <= 0) { + this._distance = this._shortDistance; + } + else { + this._distance = this._longDistance; + } + break; + } + this._speed = Math.abs(this._distance / this._time * 1000); + } + this._actor.rx = this._direction * this._speed; + if (this.isComplete(this._actor)) { + this._actor.rotation = this._end; + this._actor.rx = 0; + this._stopped = true; + } + }; + RotateBy.prototype.isComplete = function (actor) { + var distanceTravelled = Math.abs(this._actor.rotation - this._start); + return this._stopped || (distanceTravelled >= Math.abs(this._distance)); + }; + RotateBy.prototype.stop = function () { + this._actor.rx = 0; + this._stopped = true; + }; + RotateBy.prototype.reset = function () { + this._started = false; + }; + return RotateBy; + })(); + Actions.RotateBy = RotateBy; + var ScaleTo = (function () { + function ScaleTo(actor, scaleX, scaleY, speedX, speedY) { + this._started = false; + this._stopped = false; + this._actor = actor; + this._endX = scaleX; + this._endY = scaleY; + this._speedX = speedX; + this._speedY = speedY; + } + ScaleTo.prototype.update = function (delta) { + if (!this._started) { + this._started = true; + this._startX = this._actor.scale.x; + this._startY = this._actor.scale.y; + this._distanceX = Math.abs(this._endX - this._startX); + this._distanceY = Math.abs(this._endY - this._startY); + } + if (!(Math.abs(this._actor.scale.x - this._startX) >= this._distanceX)) { + var directionX = this._endY < this._startY ? -1 : 1; + this._actor.sx = this._speedX * directionX; + } + else { + this._actor.sx = 0; + } + if (!(Math.abs(this._actor.scale.y - this._startY) >= this._distanceY)) { + var directionY = this._endY < this._startY ? -1 : 1; + this._actor.sy = this._speedY * directionY; + } + else { + this._actor.sy = 0; + } + if (this.isComplete(this._actor)) { + this._actor.scale.x = this._endX; + this._actor.scale.y = this._endY; + this._actor.sx = 0; + this._actor.sy = 0; + } + }; + ScaleTo.prototype.isComplete = function (actor) { + return this._stopped || ((Math.abs(this._actor.scale.y - this._startX) >= this._distanceX) && + (Math.abs(this._actor.scale.y - this._startY) >= this._distanceY)); + }; + ScaleTo.prototype.stop = function () { + this._actor.sx = 0; + this._actor.sy = 0; + this._stopped = true; + }; + ScaleTo.prototype.reset = function () { + this._started = false; + }; + return ScaleTo; + })(); + Actions.ScaleTo = ScaleTo; + var ScaleBy = (function () { + function ScaleBy(actor, scaleX, scaleY, time) { + this._started = false; + this._stopped = false; + this._actor = actor; + this._endX = scaleX; + this._endY = scaleY; + this._time = time; + this._speedX = (this._endX - this._actor.scale.x) / time * 1000; + this._speedY = (this._endY - this._actor.scale.y) / time * 1000; + } + ScaleBy.prototype.update = function (delta) { + if (!this._started) { + this._started = true; + this._startX = this._actor.scale.x; + this._startY = this._actor.scale.y; + this._distanceX = Math.abs(this._endX - this._startX); + this._distanceY = Math.abs(this._endY - this._startY); + } + var directionX = this._endX < this._startX ? -1 : 1; + var directionY = this._endY < this._startY ? -1 : 1; + this._actor.sx = this._speedX * directionX; + this._actor.sy = this._speedY * directionY; + if (this.isComplete(this._actor)) { + this._actor.scale.x = this._endX; + this._actor.scale.y = this._endY; + this._actor.sx = 0; + this._actor.sy = 0; + } + }; + ScaleBy.prototype.isComplete = function (actor) { + return this._stopped || ((Math.abs(this._actor.scale.x - this._startX) >= this._distanceX) && + (Math.abs(this._actor.scale.y - this._startY) >= this._distanceY)); + }; + ScaleBy.prototype.stop = function () { + this._actor.sx = 0; + this._actor.sy = 0; + this._stopped = true; + }; + ScaleBy.prototype.reset = function () { + this._started = false; + }; + return ScaleBy; + })(); + Actions.ScaleBy = ScaleBy; + var Delay = (function () { + function Delay(actor, delay) { + this._elapsedTime = 0; + this._started = false; + this._stopped = false; + this._actor = actor; + this._delay = delay; + } + Delay.prototype.update = function (delta) { + if (!this._started) { + this._started = true; + } + this.x = this._actor.x; + this.y = this._actor.y; + this._elapsedTime += delta; + }; + Delay.prototype.isComplete = function (actor) { + return this._stopped || (this._elapsedTime >= this._delay); + }; + Delay.prototype.stop = function () { + this._stopped = true; + }; + Delay.prototype.reset = function () { + this._elapsedTime = 0; + this._started = false; + }; + return Delay; + })(); + Actions.Delay = Delay; + var Blink = (function () { + function Blink(actor, timeVisible, timeNotVisible, numBlinks) { + if (numBlinks === void 0) { numBlinks = 1; } + this._timeVisible = 0; + this._timeNotVisible = 0; + this._elapsedTime = 0; + this._totalTime = 0; + this._stopped = false; + this._started = false; + this._actor = actor; + this._timeVisible = timeVisible; + this._timeNotVisible = timeNotVisible; + this._duration = (timeVisible + timeNotVisible) * numBlinks; + } + Blink.prototype.update = function (delta) { + if (!this._started) { + this._started = true; + } + this._elapsedTime += delta; + this._totalTime += delta; + if (this._actor.visible && this._elapsedTime >= this._timeVisible) { + this._actor.visible = false; + this._elapsedTime = 0; + } + if (!this._actor.visible && this._elapsedTime >= this._timeNotVisible) { + this._actor.visible = true; + this._elapsedTime = 0; + } + if (this.isComplete(this._actor)) { + this._actor.visible = true; + } + }; + Blink.prototype.isComplete = function (actor) { + return this._stopped || (this._totalTime >= this._duration); + }; + Blink.prototype.stop = function () { + this._actor.visible = true; + this._stopped = true; + }; + Blink.prototype.reset = function () { + this._started = false; + this._elapsedTime = 0; + this._totalTime = 0; + }; + return Blink; + })(); + Actions.Blink = Blink; + var Fade = (function () { + function Fade(actor, endOpacity, speed) { + this._multiplyer = 1; + this._started = false; + this._stopped = false; + this._actor = actor; + this._endOpacity = endOpacity; + this._speed = speed; + if (endOpacity < actor.opacity) { + this._multiplyer = -1; + } + } + Fade.prototype.update = function (delta) { + if (!this._started) { + this._started = true; + } + if (this._speed > 0) { + this._actor.opacity += this._multiplyer * (Math.abs(this._actor.opacity - this._endOpacity) * delta) / this._speed; + } + this._speed -= delta; + ex.Logger.getInstance().debug('actor opacity: ' + this._actor.opacity); + if (this.isComplete(this._actor)) { + this._actor.opacity = this._endOpacity; + } + }; + Fade.prototype.isComplete = function (actor) { + return this._stopped || (Math.abs(this._actor.opacity - this._endOpacity) < 0.05); + }; + Fade.prototype.stop = function () { + this._stopped = true; + }; + Fade.prototype.reset = function () { + this._started = false; + }; + return Fade; + })(); + Actions.Fade = Fade; + var Die = (function () { + function Die(actor) { + this._started = false; + this._stopped = false; + this._actor = actor; + } + Die.prototype.update = function (delta) { + this._actor.actionQueue.clearActions(); + this._actor.kill(); + this._stopped = true; + }; + Die.prototype.isComplete = function () { + return this._stopped; + }; + Die.prototype.stop = function () { return; }; + Die.prototype.reset = function () { return; }; + return Die; + })(); + Actions.Die = Die; + var CallMethod = (function () { + function CallMethod(actor, method) { + this._method = null; + this._actor = null; + this._hasBeenCalled = false; + this._actor = actor; + this._method = method; + } + CallMethod.prototype.update = function (delta) { + this._method.call(this._actor); + this._hasBeenCalled = true; + }; + CallMethod.prototype.isComplete = function (actor) { + return this._hasBeenCalled; + }; + CallMethod.prototype.reset = function () { + this._hasBeenCalled = false; + }; + CallMethod.prototype.stop = function () { + this._hasBeenCalled = true; + }; + return CallMethod; + })(); + Actions.CallMethod = CallMethod; + var Repeat = (function () { + function Repeat(actor, repeat, actions) { + this._stopped = false; + this._actor = actor; + this._actionQueue = new ActionQueue(actor); + this._repeat = repeat; + this._originalRepeat = repeat; + var i = 0, len = actions.length; + for (i; i < len; i++) { + actions[i].reset(); + this._actionQueue.add(actions[i]); + } + ; + } + Repeat.prototype.update = function (delta) { + this.x = this._actor.x; + this.y = this._actor.y; + if (!this._actionQueue.hasNext()) { + this._actionQueue.reset(); + this._repeat--; + } + this._actionQueue.update(delta); + }; + Repeat.prototype.isComplete = function () { + return this._stopped || (this._repeat <= 0); + }; + Repeat.prototype.stop = function () { + this._stopped = true; + }; + Repeat.prototype.reset = function () { + this._repeat = this._originalRepeat; + }; + return Repeat; + })(); + Actions.Repeat = Repeat; + var RepeatForever = (function () { + function RepeatForever(actor, actions) { + this._stopped = false; + this._actor = actor; + this._actionQueue = new ActionQueue(actor); + var i = 0, len = actions.length; + for (i; i < len; i++) { + actions[i].reset(); + this._actionQueue.add(actions[i]); + } + ; + } + RepeatForever.prototype.update = function (delta) { + this.x = this._actor.x; + this.y = this._actor.y; + if (this._stopped) { + return; + } + if (!this._actionQueue.hasNext()) { + this._actionQueue.reset(); + } + this._actionQueue.update(delta); + }; + RepeatForever.prototype.isComplete = function () { + return this._stopped; + }; + RepeatForever.prototype.stop = function () { + this._stopped = true; + this._actionQueue.clearActions(); + }; + RepeatForever.prototype.reset = function () { return; }; + return RepeatForever; + })(); + Actions.RepeatForever = RepeatForever; + /** + * Action Queues + * + * Action queues are part of the [[ActionContext|Action API]] and + * store the list of actions to be executed for an [[Actor]]. + * + * Actors implement [[Action.actionQueue]] which can be manipulated by + * advanced users to adjust the actions currently being executed in the + * queue. + */ + var ActionQueue = (function () { + function ActionQueue(actor) { + this._actions = []; + this._completedActions = []; + this._actor = actor; + } + ActionQueue.prototype.add = function (action) { + this._actions.push(action); + }; + ActionQueue.prototype.remove = function (action) { + var index = this._actions.indexOf(action); + this._actions.splice(index, 1); + }; + ActionQueue.prototype.clearActions = function () { + this._actions.length = 0; + this._completedActions.length = 0; + if (this._currentAction) { + this._currentAction.stop(); + } + }; + ActionQueue.prototype.getActions = function () { + return this._actions.concat(this._completedActions); + }; + ActionQueue.prototype.hasNext = function () { + return this._actions.length > 0; + }; + ActionQueue.prototype.reset = function () { + this._actions = this.getActions(); + var i = 0, len = this._actions.length; + for (i; i < len; i++) { + this._actions[i].reset(); + } + this._completedActions = []; + }; + ActionQueue.prototype.update = function (delta) { + if (this._actions.length > 0) { + this._currentAction = this._actions[0]; + this._currentAction.update(delta); + if (this._currentAction.isComplete(this._actor)) { + this._completedActions.push(this._actions.shift()); + } + } + }; + return ActionQueue; + })(); + Actions.ActionQueue = ActionQueue; + })(Actions = Internal.Actions || (Internal.Actions = {})); + })(Internal = ex.Internal || (ex.Internal = {})); +})(ex || (ex = {})); +/// +var ex; +(function (ex) { + /** + * Action API * - * Override the [[update]] method to update the state of your actor each frame. - * Typically things that need to be updated include state, drawing, or position. + * The fluent Action API allows you to perform "actions" on + * [[Actor|Actors]] such as following, moving, rotating, and + * more. You can implement your own actions by implementing + * the [[IAction]] interface. * - * Remember to call `super.update` to ensure the base update logic is performed. - * You can then write your own logic for what happens after that. + * Actions can be chained together and can be set to repeat, + * or can be interrupted to change. * - * The [[update]] method is passed an instance of the Excalibur engine, which - * can be used to perform coordinate math or access global state. It is also - * passed `delta` which is the time since the last frame, which can be used - * to perform time-based movement or time-based math (such as a timer). + * ## Chaining Actions * - * **TypeScript** + * You can chain actions to create a script because the action + * methods return the context, allowing you to build a queue of + * actions that get executed as part of an [[ActionQueue]]. * * ```ts - * class Player extends Actor { - * public update(engine: ex.Engine, delta: number) { - * super.update(engine, delta); // call base update logic - * - * // check if player died - * if (this.health <= 0) { - * this.emit("death"); - * this.onDeath(); - * return; - * } - * } - * } - * ``` + * class Enemy extends ex.Actor { * - * **Javascript** + * public patrol() { * - * ```js - * var Player = ex.Actor.extend({ - * update: function (engine, delta) { - * ex.Actor.prototype.update.call(this, engine, delta); // call base update logic + * // clear existing queue + * this.clearActions(); * - * // check if player died - * if (this.health <= 0) { - * this.emit("death"); - * this.onDeath(); - * return; - * } + * // guard a choke point + * // move to 100, 100 and take 1.2s + * // wait for 3s + * // move back to 0, 100 and take 1.2s + * // wait for 3s + * // repeat + * this.moveTo(100, 100, 1200) + * .delay(3000) + * .moveTo(0, 100, 1200) + * .delay(3000) + * .repeatForever(); * } - * }); - * ``` - * - * ## Drawing actors - * - * Override the [[draw]] method to perform any custom drawing. For simple games, - * you don't need to override `draw`, instead you can use [[addDrawing]] and [[setDrawing]] - * to manipulate the textures/animations that the actor is using. - * - * ### Working with Textures & Sprites - * - * A common usage is to use a [[Texture]] or [[Sprite]] for an actor. If you are using the [[Loader]] to - * pre-load assets, you can simply assign an actor a [[Texture]] to draw. You can - * also create a [[Texture.asSprite|sprite from a Texture]] to quickly create a [[Sprite]] instance. - * - * ```ts - * // assume Resources.TxPlayer is a 80x80 png image - * - * public onInitialize(engine: ex.Engine) { - * - * // set as the "default" drawing - * this.addDrawing(Resources.TxPlayer); - * - * // you can also set a Sprite instance to draw - * this.addDrawing(Resources.TxPlayer.asSprite()); - * } - * ``` - * - * ### Working with Animations - * - * A [[SpriteSheet]] holds a collection of sprites from a single [[Texture]]. - * Use [[SpriteSheet.getAnimationForAll]] to easily generate an [[Animation]]. - * - * ```ts - * // assume Resources.TxPlayerIdle is a texture containing several frames of an animation - * - * public onInitialize(engine: ex.Engine) { - * - * // create a SpriteSheet for the animation - * var playerIdleSheet = new ex.SpriteSheet(Resources.TxPlayerIdle, 5, 1, 80, 80); - * - * // create an animation - * var playerIdleAnimation = playerIdleSheet.getAnimationForAll(engine, 120); - * - * // the first drawing is always the current - * this.addDrawing("idle", playerIdleAnimation); * } * ``` * - * ### Custom drawing + * ## Example: Follow a Path * - * You can always override the default drawing logic for an actor in the [[draw]] method, - * for example, to draw complex shapes or to use the raw Canvas API. + * You can use [[Actor.moveTo]] to move to a specific point, + * allowing you to chain together actions to form a path. * - * Usually you should call `super.draw` to perform the base drawing logic, but other times - * you may want to take over the drawing completely. + * This example has a `Ship` follow a path that it guards by + * spawning at the start point, moving to the end, then reversing + * itself and repeating that forever. * * ```ts - * public draw(ctx: Canvas2DRenderingContext, delta: number) { - * - * super.draw(ctx, delta); // perform base drawing logic - * - * // custom drawing - * ctx.lineTo(...); - * } - * ``` - * - * ## Actions - * - * You can use the [[ActionContext|Action API]] to create chains of - * actions and script actors into doing your bidding for your game. - * - * Actions can be simple or can be chained together to create complex - * AI routines. In the future, it will be easier to create timelines or - * scripts to run depending on the state of your actor, such as an - * enemy ship that is Guarding a path and then is Alerted when a Player - * draws near. + * public Ship extends ex.Actor { * - * Learn more about the [[ActionContext|Action API]]. + * public onInitialize() { + * var path = [ + * new ex.Point(20, 20), + * new ex.Point(50, 40), + * new ex.Point(25, 30), + * new ex.Point(75, 80) + * ]; * - * ## Collision Detection + * // spawn at start point + * this.x = path[0].x; + * this.y = path[0].y; * - * By default Actors do not participate in collisions. If you wish to make - * an actor participate, you need to enable the [[CollisionDetectionModule]] + * // create action queue * - * ```ts - * public Player extends ex.Actor { - * constructor() { - * super(); + * // forward path (skip first spawn point) + * for (var i = 1; i < path.length; i++) { + * this.moveTo(path[i].x, path[i].y, 300); + * } * - * // enable the pipeline - * this.pipelines.push(new ex.CollisionDetectionModule()); + * // reverse path (skip last point) + * for (var j = path.length - 2; j >= 0; j--) { + * this.moveTo(path[j].x, path[j].y, 300); + * } * - * // set preferred CollisionType - * this.collisionType = ex.CollisionType.Active; + * // repeat + * this.repeatForever(); * } * } * ``` * - * ### Collision Groups + * While this is a trivial example, the Action API allows complex + * routines to be programmed for Actors. For example, using the + * [Tiled Map Editor](http://mapeditor.org) you can create a map that + * uses polylines to create paths, load in the JSON using a + * [[Resource|Generic Resource]], create a [[TileMap]], + * and spawn ships programmatically while utilizing the polylines + * to automatically generate the actions needed to do pathing. * - * TODO, needs more information. + * ## Custom Actions * - * ## Known Issues + * The API does allow you to implement new actions by implementing the [[IAction]] + * interface, but this will be improved in future versions as right now it + * is meant for the Excalibur team and can be advanced to implement. * - * **Actor bounding boxes do not rotate** - * [Issue #68](https://github.com/excaliburjs/Excalibur/issues/68) + * You can manually manipulate an Actor's [[ActionQueue]] using + * [[Actor.actionQueue]]. For example, using [[ActionQueue.add]] for + * custom actions. + * + * ## Future Plans + * + * The Excalibur team is working on extending and rebuilding the Action API + * in future versions to support multiple timelines/scripts, better eventing, + * and a more robust API to allow for complex and customized actions. * - * **Setting opacity when using a color doesn't do anything** - * [Issue #364](https://github.com/excaliburjs/Excalibur/issues/364) */ - var Actor = (function (_super) { - __extends(Actor, _super); + var ActionContext = (function () { + function ActionContext() { + this._actors = []; + this._queues = []; + if (arguments !== null) { + this._actors = Array.prototype.slice.call(arguments, 0); + this._queues = this._actors.map(function (a) { + return a.actionQueue; + }); + } + } + /** + * Clears all queued actions from the Actor + */ + ActionContext.prototype.clearActions = function () { + var i = 0, len = this._queues.length; + for (i; i < len; i++) { + this._queues[i].clearActions(); + } + }; + ActionContext.prototype.addActorToContext = function (actor) { + this._actors.push(actor); + // if we run into problems replace the line below with: + this._queues.push(actor.actionQueue); + }; + ActionContext.prototype.removeActorFromContext = function (actor) { + var index = this._actors.indexOf(actor); + if (index > -1) { + this._actors.splice(index, 1); + this._queues.splice(index, 1); + } + }; + /** + * This method will move an actor to the specified `x` and `y` position over the + * specified duration using a given [[EasingFunctions]] and return back the actor. This + * method is part of the actor 'Action' fluent API allowing action chaining. + * @param x The x location to move the actor to + * @param y The y location to move the actor to + * @param duration The time it should take the actor to move to the new location in milliseconds + * @param easingFcn Use [[EasingFunctions]] or a custom function to use to calculate position + */ + ActionContext.prototype.easeTo = function (x, y, duration, easingFcn) { + if (easingFcn === void 0) { easingFcn = ex.EasingFunctions.Linear; } + var i = 0, len = this._queues.length; + for (i; i < len; i++) { + this._queues[i].add(new ex.Internal.Actions.EaseTo(this._actors[i], x, y, duration, easingFcn)); + } + return this; + }; /** - * @param x The starting x coordinate of the actor - * @param y The starting y coordinate of the actor - * @param width The starting width of the actor - * @param height The starting height of the actor - * @param color The starting color of the actor. Leave null to draw a transparent actor. The opacity of the color will be used as the - * initial [[opacity]]. + * This method will move an actor to the specified x and y position at the + * speed specified (in pixels per second) and return back the actor. This + * method is part of the actor 'Action' fluent API allowing action chaining. + * @param x The x location to move the actor to + * @param y The y location to move the actor to + * @param speed The speed in pixels per second to move */ - function Actor(x, y, width, height, color) { - _super.call(this); - /** - * The unique identifier for the actor - */ - this.id = Actor.maxId++; - /** - * The x coordinate of the actor (left edge) - */ - this.x = 0; - /** - * The y coordinate of the actor (top edge) - */ - this.y = 0; - this._height = 0; - this._width = 0; - /** - * The rotation of the actor in radians - */ - this.rotation = 0; // radians - /** - * The rotational velocity of the actor in radians/second - */ - this.rx = 0; //radions/sec - /** - * The scale vector of the actor - */ - this.scale = new ex.Vector(1, 1); - /** - * The x scalar velocity of the actor in scale/second - */ - this.sx = 0; //scale/sec - /** - * The y scalar velocity of the actor in scale/second - */ - this.sy = 0; //scale/sec - /** - * The x velocity of the actor in pixels/second - */ - this.dx = 0; // pixels/sec - /** - * The x velocity of the actor in pixels/second - */ - this.dy = 0; - /** - * The x acceleration of the actor in pixels/second^2 - */ - this.ax = 0; // pixels/sec/sec - /** - * The y acceleration of the actor in pixels/second^2 - */ - this.ay = 0; - /** - * Indicates whether the actor is physically in the viewport - */ - this.isOffScreen = false; - /** - * The visibility of an actor - */ - this.visible = true; - /** - * The opacity of an actor. Passing in a color in the [[constructor]] will use the - * color's opacity. - */ - this.opacity = 1; - this.previousOpacity = 1; - this.actions = new ex.ActionContext(this); - /** - * Convenience reference to the global logger - */ - this.logger = ex.Logger.getInstance(); - /** - * The scene that the actor is in - */ - this.scene = null; - /** - * The parent of this actor - */ - this.parent = null; - // TODO: Replace this with the new actor collection once z-indexing is built - /** - * The children of this actor - */ - this.children = []; - /** - * Gets or sets the current collision type of this actor. By - * default it is ([[CollisionType.PreventCollision]]). - */ - this.collisionType = CollisionType.PreventCollision; - this.collisionGroups = []; - this._collisionHandlers = {}; - this._isInitialized = false; - this.frames = {}; - /** - * Access to the current drawing for the actor, this can be - * an [[Animation]], [[Sprite]], or [[Polygon]]. - * Set drawings with [[setDrawing]]. - */ - this.currentDrawing = null; - this.centerDrawingX = true; - this.centerDrawingY = true; - /** - * Modify the current actor update pipeline. - */ - this.traits = []; - /** - * Whether or not to enable the [[CapturePointer]] trait that propogates - * pointer events to this actor - */ - this.enableCapturePointer = false; - /** - * Configuration for [[CapturePointer]] trait - */ - this.capturePointer = { - captureMoveEvents: false - }; - this._zIndex = 0; - this._isKilled = false; - this.x = x || 0; - this.y = y || 0; - this._width = width || 0; - this._height = height || 0; - if (color) { - this.color = color.clone(); - // set default opacity of an actor to the color - this.opacity = color.a; + ActionContext.prototype.moveTo = function (x, y, speed) { + var i = 0, len = this._queues.length; + for (i; i < len; i++) { + this._queues[i].add(new ex.Internal.Actions.MoveTo(this._actors[i], x, y, speed)); } - // Build default pipeline - this.traits.push(new ex.Traits.Movement()); - //this.pipeline.push(new ex.CollisionDetectionModule()); - this.traits.push(new ex.Traits.OffscreenCulling()); - this.traits.push(new ex.Traits.CapturePointer()); - this.actionQueue = new ex.Internal.Actions.ActionQueue(this); - this.anchor = new ex.Point(.5, .5); - } + return this; + }; /** - * This is called before the first update of the actor. This method is meant to be - * overridden. This is where initialization of child actors should take place. + * This method will move an actor to the specified x and y position by a + * certain time (in milliseconds). This method is part of the actor + * 'Action' fluent API allowing action chaining. + * @param x The x location to move the actor to + * @param y The y location to move the actor to + * @param time The time it should take the actor to move to the new location in milliseconds */ - Actor.prototype.onInitialize = function (engine) { - // Override me + ActionContext.prototype.moveBy = function (x, y, time) { + var i = 0, len = this._queues.length; + for (i; i < len; i++) { + this._queues[i].add(new ex.Internal.Actions.MoveBy(this._actors[i], x, y, time)); + } + return this; }; - Actor.prototype._checkForPointerOptIn = function (eventName) { - if (eventName && (eventName.toLowerCase() === 'pointerdown' || - eventName.toLowerCase() === 'pointerdown' || - eventName.toLowerCase() === 'pointermove')) { - this.enableCapturePointer = true; - if (eventName.toLowerCase() === 'pointermove') { - this.capturePointer.captureMoveEvents = true; - } + /** + * This method will rotate an actor to the specified angle at the speed + * specified (in radians per second) and return back the actor. This + * method is part of the actor 'Action' fluent API allowing action chaining. + * @param angleRadians The angle to rotate to in radians + * @param speed The angular velocity of the rotation specified in radians per second + */ + ActionContext.prototype.rotateTo = function (angleRadians, speed) { + var i = 0, len = this._queues.length; + for (i; i < len; i++) { + this._queues[i].add(new ex.Internal.Actions.RotateTo(this._actors[i], angleRadians, speed)); + } + return this; + }; + /** + * This method will rotate an actor to the specified angle by a certain + * time (in milliseconds) and return back the actor. This method is part + * of the actor 'Action' fluent API allowing action chaining. + * @param angleRadians The angle to rotate to in radians + * @param time The time it should take the actor to complete the rotation in milliseconds + */ + ActionContext.prototype.rotateBy = function (angleRadians, time) { + var i = 0, len = this._queues.length; + for (i; i < len; i++) { + this._queues[i].add(new ex.Internal.Actions.RotateBy(this._actors[i], angleRadians, time)); + } + return this; + }; + /** + * This method will scale an actor to the specified size at the speed + * specified (in magnitude increase per second) and return back the + * actor. This method is part of the actor 'Action' fluent API allowing + * action chaining. + * @param size The scaling factor to apply + * @param speed The speed of scaling specified in magnitude increase per second + */ + ActionContext.prototype.scaleTo = function (sizeX, sizeY, speedX, speedY) { + var i = 0, len = this._queues.length; + for (i; i < len; i++) { + this._queues[i].add(new ex.Internal.Actions.ScaleTo(this._actors[i], sizeX, sizeY, speedX, speedY)); + } + return this; + }; + /** + * This method will scale an actor to the specified size by a certain time + * (in milliseconds) and return back the actor. This method is part of the + * actor 'Action' fluent API allowing action chaining. + * @param size The scaling factor to apply + * @param time The time it should take to complete the scaling in milliseconds + */ + ActionContext.prototype.scaleBy = function (sizeX, sizeY, time) { + var i = 0, len = this._queues.length; + for (i; i < len; i++) { + this._queues[i].add(new ex.Internal.Actions.ScaleBy(this._actors[i], sizeX, sizeY, time)); + } + return this; + }; + /** + * This method will cause an actor to blink (become visible and not + * visible). Optionally, you may specify the number of blinks. Specify the amount of time + * the actor should be visible per blink, and the amount of time not visible. + * This method is part of the actor 'Action' fluent API allowing action chaining. + * @param timeVisible The amount of time to stay visible per blink in milliseconds + * @param timeNotVisible The amount of time to stay not visible per blink in milliseconds + * @param numBlinks The number of times to blink + */ + ActionContext.prototype.blink = function (timeVisible, timeNotVisible, numBlinks) { + if (numBlinks === void 0) { numBlinks = 1; } + var i = 0, len = this._queues.length; + for (i; i < len; i++) { + this._queues[i].add(new ex.Internal.Actions.Blink(this._actors[i], timeVisible, timeNotVisible, numBlinks)); + } + return this; + }; + /** + * This method will cause an actor's opacity to change from its current value + * to the provided value by a specified time (in milliseconds). This method is + * part of the actor 'Action' fluent API allowing action chaining. + * @param opacity The ending opacity + * @param time The time it should take to fade the actor (in milliseconds) + */ + ActionContext.prototype.fade = function (opacity, time) { + var i = 0, len = this._queues.length; + for (i; i < len; i++) { + this._queues[i].add(new ex.Internal.Actions.Fade(this._actors[i], opacity, time)); } + return this; }; /** - * Add an event listener. You can listen for a variety of - * events off of the engine; see [[GameEvent]] - * @param eventName Name of the event to listen for - * @param handler Event handler for the thrown event - * @obsolete Use [[on]] instead. + * This method will delay the next action from executing for a certain + * amount of time (in milliseconds). This method is part of the actor + * 'Action' fluent API allowing action chaining. + * @param time The amount of time to delay the next action in the queue from executing in milliseconds */ - Actor.prototype.addEventListener = function (eventName, handler) { - this._checkForPointerOptIn(eventName); - _super.prototype.addEventListener.call(this, eventName, handler); + ActionContext.prototype.delay = function (time) { + var i = 0, len = this._queues.length; + for (i; i < len; i++) { + this._queues[i].add(new ex.Internal.Actions.Delay(this._actors[i], time)); + } + return this; }; /** - * Alias for `addEventListener`. You can listen for a variety of - * events off of the engine; see [[GameEvent]] - * @param eventName Name of the event to listen for - * @param handler Event handler for the thrown event + * This method will add an action to the queue that will remove the actor from the + * scene once it has completed its previous actions. Any actions on the + * action queue after this action will not be executed. */ - Actor.prototype.on = function (eventName, handler) { - this._checkForPointerOptIn(eventName); - this.eventDispatcher.subscribe(eventName, handler); + ActionContext.prototype.die = function () { + var i = 0, len = this._queues.length; + for (i; i < len; i++) { + this._queues[i].add(new ex.Internal.Actions.Die(this._actors[i])); + } + return this; }; /** - * If the current actor is a member of the scene, this will remove - * it from the scene graph. It will no longer be drawn or updated. + * This method allows you to call an arbitrary method as the next action in the + * action queue. This is useful if you want to execute code in after a specific + * action, i.e An actor arrives at a destinatino after traversing a path */ - Actor.prototype.kill = function () { - if (this.scene) { - this.scene.remove(this); - this._isKilled = true; - } - else { - this.logger.warn('Cannot kill actor, it was never added to the Scene'); + ActionContext.prototype.callMethod = function (method) { + var i = 0, len = this._queues.length; + for (i; i < len; i++) { + this._queues[i].add(new ex.Internal.Actions.CallMethod(this._actors[i], method)); } + return this; }; /** - * Indicates wether the actor has been killed. + * This method will cause the actor to repeat all of the previously + * called actions a certain number of times. If the number of repeats + * is not specified it will repeat forever. This method is part of + * the actor 'Action' fluent API allowing action chaining + * @param times The number of times to repeat all the previous actions in the action queue. If nothing is specified the actions + * will repeat forever */ - Actor.prototype.isKilled = function () { - return this._isKilled; + ActionContext.prototype.repeat = function (times) { + if (!times) { + this.repeatForever(); + return this; + } + var i = 0, len = this._queues.length; + for (i; i < len; i++) { + this._queues[i].add(new ex.Internal.Actions.Repeat(this._actors[i], times, this._actors[i].actionQueue.getActions())); + } + return this; }; /** - * Adds a child actor to this actor. All movement of the child actor will be - * relative to the parent actor. Meaning if the parent moves the child will - * move with it. - * @param actor The child actor to add + * This method will cause the actor to repeat all of the previously + * called actions forever. This method is part of the actor 'Action' + * fluent API allowing action chaining. */ - Actor.prototype.add = function (actor) { - actor.collisionType = CollisionType.PreventCollision; - if (ex.Util.addItemToArray(actor, this.children)) { - actor.parent = this; + ActionContext.prototype.repeatForever = function () { + var i = 0, len = this._queues.length; + for (i; i < len; i++) { + this._queues[i].add(new ex.Internal.Actions.RepeatForever(this._actors[i], this._actors[i].actionQueue.getActions())); } + return this; }; /** - * Removes a child actor from this actor. - * @param actor The child actor to remove + * This method will cause the actor to follow another at a specified distance + * @param actor The actor to follow + * @param followDistance The distance to maintain when following, if not specified the actor will follow at the current distance. */ - Actor.prototype.remove = function (actor) { - if (ex.Util.removeItemToArray(actor, this.children)) { - actor.parent = null; - } - }; - Actor.prototype.setDrawing = function (key) { - key = key.toString(); - if (this.currentDrawing !== this.frames[key]) { - if (this.frames[key] != null) { - this.frames[key].reset(); - this.currentDrawing = this.frames[key]; + ActionContext.prototype.follow = function (actor, followDistance) { + var i = 0, len = this._queues.length; + for (i; i < len; i++) { + if (followDistance === undefined) { + this._queues[i].add(new ex.Internal.Actions.Follow(this._actors[i], actor)); } else { - ex.Logger.getInstance().error('the specified drawing key \'' + key + '\' does not exist'); + this._queues[i].add(new ex.Internal.Actions.Follow(this._actors[i], actor, followDistance)); } } + return this; }; - Actor.prototype.addDrawing = function (args) { - if (arguments.length === 2) { - this.frames[arguments[0]] = arguments[1]; - if (!this.currentDrawing) { - this.currentDrawing = arguments[1]; - } - } - else { - if (arguments[0] instanceof ex.Sprite) { - this.addDrawing('default', arguments[0]); + /** + * This method will cause the actor to move towards another until they + * collide "meet" at a specified speed. + * @param actor The actor to meet + * @param speed The speed in pixels per second to move, if not specified it will match the speed of the other actor + */ + ActionContext.prototype.meet = function (actor, speed) { + var i = 0, len = this._queues.length; + for (i; i < len; i++) { + if (speed === undefined) { + this._queues[i].add(new ex.Internal.Actions.Meet(this._actors[i], actor)); } - if (arguments[0] instanceof ex.Texture) { - this.addDrawing('default', arguments[0].asSprite()); + else { + this._queues[i].add(new ex.Internal.Actions.Meet(this._actors[i], actor, speed)); } } + return this; }; /** - * Gets the z-index of an actor. The z-index determines the relative order an actor is drawn in. - * Actors with a higher z-index are drawn on top of actors with a lower z-index - */ - Actor.prototype.getZIndex = function () { - return this._zIndex; - }; - /** - * Sets the z-index of an actor and updates it in the drawing list for the scene. - * The z-index determines the relative order an actor is drawn in. - * Actors with a higher z-index are drawn on top of actors with a lower z-index - * @param actor The child actor to remove + * Returns a promise that resolves when the current action queue up to now + * is finished. */ - Actor.prototype.setZIndex = function (newIndex) { - this.scene.cleanupDrawTree(this); - this._zIndex = newIndex; - this.scene.updateDrawTree(this); + ActionContext.prototype.asPromise = function () { + var _this = this; + var promises = this._queues.map(function (q, i) { + var temp = new ex.Promise(); + q.add(new ex.Internal.Actions.CallMethod(_this._actors[i], function () { + temp.resolve(); + })); + return temp; + }); + return ex.Promise.join.apply(this, promises); }; - /** - * Artificially trigger an event on an actor, useful when creating custom events. - * @param eventName The name of the event to trigger - * @param event The event object to pass to the callback - * - * @obsolete Use [[emit]] instead. - */ - Actor.prototype.triggerEvent = function (eventName, event) { - this.eventDispatcher.emit(eventName, event); + return ActionContext; + })(); + ex.ActionContext = ActionContext; +})(ex || (ex = {})); +/// +/// +/// +var ex; +(function (ex) { + /** + * Grouping + * + * Groups are used for logically grouping Actors so they can be acted upon + * in bulk. + * + * ## Using Groups + * + * Groups can be used to detect collisions across a large nubmer of actors. For example + * perhaps a large group of "enemy" actors. + * + * ```typescript + * var enemyShips = engine.currentScene.createGroup("enemy"); + * var enemies = [...]; // Large array of enemies; + * enemyShips.add(enemies); + * + * var player = new Actor(); + * engine.currentScene.add(player); + * + * enemyShips.on('collision', function(ev: CollisionEvent){ + * if (e.other === player) { + * //console.log("collision with player!"); + * } + * }); + * + * ``` + */ + var Group = (function (_super) { + __extends(Group, _super); + function Group(name, scene) { + _super.call(this); + this.name = name; + this.scene = scene; + this._logger = ex.Logger.getInstance(); + this._members = []; + this.actions = new ex.ActionContext(); + if (scene == null) { + this._logger.error('Invalid constructor arguments passed to Group: ', name, ', scene must not be null!'); + } + else { + var existingGroup = scene.groups[name]; + if (existingGroup) { + this._logger.warn('Group with name', name, 'already exists. This new group will replace it.'); + } + scene.groups[name] = this; + } + } + Group.prototype.add = function (actorOrActors) { + if (actorOrActors instanceof ex.Actor) { + actorOrActors = [].concat(actorOrActors); + } + var i = 0, len = actorOrActors.length, groupIdx; + for (i; i < len; i++) { + groupIdx = this.getMembers().indexOf(actorOrActors[i]); + if (groupIdx === -1) { + this._members.push(actorOrActors[i]); + this.scene.add(actorOrActors[i]); + this.actions.addActorToContext(actorOrActors[i]); + this.eventDispatcher.wire(actorOrActors[i].eventDispatcher); + } + } }; - /** - * Alias for `emit`. Artificially trigger an event on an actor, useful when creating custom events. - * @param eventName The name of the event to trigger - * @param event The event object to pass to the callback - */ - Actor.prototype.emit = function (eventName, event) { - this.eventDispatcher.emit(eventName, event); + Group.prototype.remove = function (actor) { + var index = this._members.indexOf(actor); + if (index > -1) { + this._members.splice(index, 1); + this.actions.removeActorFromContext(actor); + this.eventDispatcher.unwire(actor.eventDispatcher); + } }; - /** - * Adds an actor to a collision group. Actors with no named collision groups are - * considered to be in every collision group. - * - * Once in a collision group(s) actors will only collide with other actors in - * that group. - * - * @param name The name of the collision group - */ - Actor.prototype.addCollisionGroup = function (name) { - this.collisionGroups.push(name); + Group.prototype.move = function (args) { + var i = 0, members = this.getMembers(), len = members.length; + if (arguments.length === 1 && args instanceof ex.Vector) { + for (i; i < len; i++) { + members[i].x += args.x; + members[i].y += args.y; + } + } + else if (typeof arguments[0] === 'number' && typeof arguments[1] === 'number') { + var x = arguments[0]; + var y = arguments[1]; + for (i; i < len; i++) { + members[i].x += x; + members[i].y += y; + } + } + else { + this._logger.error('Invalid arguments passed to group move', this.name, 'args:', arguments); + } }; - /** - * Removes an actor from a collision group. - * @param name The name of the collision group - */ - Actor.prototype.removeCollisionGroup = function (name) { - var index = this.collisionGroups.indexOf(name); - if (index !== -1) { - this.collisionGroups.splice(index, 1); + Group.prototype.rotate = function (angle) { + if (typeof arguments[0] === 'number') { + var r = arguments[0], i = 0, members = this.getMembers(), len = members.length; + for (i; i < len; i++) { + members[i].rotation += r; + } + } + else { + this._logger.error('Invalid arguments passed to group rotate', this.name, 'args:', arguments); } }; - /** - * Get the center point of an actor - */ - Actor.prototype.getCenter = function () { - return new ex.Vector(this.x + this.getWidth() / 2 - this.anchor.x * this.getWidth(), this.y + this.getHeight() / 2 - this.anchor.y * this.getHeight()); + Group.prototype.on = function (eventName, handler) { + this.eventDispatcher.subscribe(eventName, handler); }; - /** - * Gets the calculated width of an actor, factoring in scale - */ - Actor.prototype.getWidth = function () { - return this._width * this.scale.x; + Group.prototype.off = function (eventName, handler) { + this.eventDispatcher.unsubscribe(eventName, handler); }; - /** - * Sets the width of an actor, factoring in the current scale - */ - Actor.prototype.setWidth = function (width) { - this._width = width / this.scale.x; + Group.prototype.emit = function (topic, event) { + this.eventDispatcher.emit(topic, event); }; - /** - * Gets the calculated height of an actor, factoring in scale - */ - Actor.prototype.getHeight = function () { - return this._height * this.scale.y; + Group.prototype.contains = function (actor) { + return this.getMembers().indexOf(actor) > -1; }; - /** - * Sets the height of an actor, factoring in the current scale - */ - Actor.prototype.setHeight = function (height) { - this._height = height / this.scale.y; + Group.prototype.getMembers = function () { + return this._members; }; - /** - * Centers the actor's drawing around the center of the actor's bounding box - * @param center Indicates to center the drawing around the actor - */ - Actor.prototype.setCenterDrawing = function (center) { - this.centerDrawingY = center; - this.centerDrawingX = center; + Group.prototype.getRandomMember = function () { + return this._members[Math.floor(Math.random() * this._members.length)]; }; - /** - * Gets the left edge of the actor - */ - Actor.prototype.getLeft = function () { - return this.x; + Group.prototype.getBounds = function () { + return this.getMembers().map(function (a) { return a.getBounds(); }).reduce(function (prev, curr) { + return prev.combine(curr); + }); }; - /** - * Gets the right edge of the actor - */ - Actor.prototype.getRight = function () { - return this.x + this.getWidth(); + return Group; + })(ex.Class); + ex.Group = Group; +})(ex || (ex = {})); +var ex; +(function (ex) { + // NOTE: this implementation is not self-balancing + var SortedList = (function () { + function SortedList(getComparable) { + this._getComparable = getComparable; + } + SortedList.prototype.find = function (element) { + return this._find(this._root, element); }; - /** - * Gets the top edge of the actor - */ - Actor.prototype.getTop = function () { - return this.y; + SortedList.prototype._find = function (node, element) { + if (node == null) { + return false; + } + else if (this._getComparable.call(element) === node.getKey()) { + if (node.getData().indexOf(element) > -1) { + return true; + } + else { + return false; + } + } + else if (this._getComparable.call(element) < node.getKey()) { + return this._find(node.getLeft(), element); + } + else { + return this._find(node.getRight(), element); + } }; - /** - * Gets the bottom edge of the actor - */ - Actor.prototype.getBottom = function () { - return this.y + this.getHeight(); + // returns the array of elements at a specific key value + SortedList.prototype.get = function (key) { + return this._get(this._root, key); }; - /** - * Gets the x value of the Actor in global coordinates - */ - Actor.prototype.getWorldX = function () { - if (!this.parent) { - return this.x; + SortedList.prototype._get = function (node, key) { + if (node == null) { + return []; + } + else if (key === node.getKey()) { + return node.getData(); + } + else if (key < node.getKey()) { + return this._get(node.getLeft(), key); + } + else { + return this._get(node.getRight(), key); } - return this.x * this.parent.scale.x + this.parent.getWorldX(); }; - /** - * Gets the y value of the Actor in global coordinates - */ - Actor.prototype.getWorldY = function () { - if (!this.parent) { - return this.y; + SortedList.prototype.add = function (element) { + if (this._root == null) { + this._root = new BinaryTreeNode(this._getComparable.call(element), [element], null, null); + return true; } - return this.y * this.parent.scale.y + this.parent.getWorldY(); + else { + return this._insert(this._root, element); + } + return false; }; - /** - * Gets the global scale of the Actor - */ - Actor.prototype.getGlobalScale = function () { - if (!this.parent) { - return new ex.Point(this.scale.x, this.scale.y); + SortedList.prototype._insert = function (node, element) { + if (node != null) { + if (this._getComparable.call(element) === node.getKey()) { + if (node.getData().indexOf(element) > -1) { + return false; // the element we're trying to insert already exists + } + else { + node.getData().push(element); + return true; + } + } + else if (this._getComparable.call(element) < node.getKey()) { + if (node.getLeft() == null) { + node.setLeft(new BinaryTreeNode(this._getComparable.call(element), [element], null, null)); + return true; + } + else { + return this._insert(node.getLeft(), element); + } + } + else { + if (node.getRight() == null) { + node.setRight(new BinaryTreeNode(this._getComparable.call(element), [element], null, null)); + return true; + } + else { + return this._insert(node.getRight(), element); + } + } } - var parentScale = this.parent.getGlobalScale(); - return new ex.Point(this.scale.x * parentScale.x, this.scale.y * parentScale.y); + return false; }; - /** - * Returns the actor's [[BoundingBox]] calculated for this instant. - */ - Actor.prototype.getBounds = function () { - var anchor = this._getCalculatedAnchor(); - return new ex.BoundingBox(this.getWorldX() - anchor.x, this.getWorldY() - anchor.y, this.getWorldX() + this.getWidth() - anchor.x, this.getWorldY() + this.getHeight() - anchor.y); + SortedList.prototype.removeByComparable = function (element) { + this._root = this._remove(this._root, element); }; - /** - * Tests whether the x/y specified are contained in the actor - * @param x X coordinate to test (in world coordinates) - * @param y Y coordinate to test (in world coordinates) - * @param recurse checks whether the x/y are contained in any child actors (if they exist). - */ - Actor.prototype.contains = function (x, y, recurse) { - if (recurse === void 0) { recurse = false; } - var containment = this.getBounds().contains(new ex.Point(x, y)); - if (recurse) { - return containment || this.children.some(function (child) { - return child.contains(x, y, true); - }); + SortedList.prototype._remove = function (node, element) { + if (node == null) { + return null; } - return containment; - }; - /** - * Returns the side of the collision based on the intersection - * @param intersect The displacement vector returned by a collision - */ - Actor.prototype.getSideFromIntersect = function (intersect) { - if (intersect) { - if (Math.abs(intersect.x) > Math.abs(intersect.y)) { - if (intersect.x < 0) { - return ex.Side.Right; + else if (this._getComparable.call(element) === node.getKey()) { + var elementIndex = node.getData().indexOf(element); + // if the node contains the element, remove the element + if (elementIndex > -1) { + node.getData().splice(elementIndex, 1); + // if we have removed the last element at this node, remove the node + if (node.getData().length === 0) { + // if the node is a leaf + if (node.getLeft() == null && node.getRight() == null) { + return null; + } + else if (node.getLeft() == null) { + return node.getRight(); + } + else if (node.getRight() == null) { + return node.getLeft(); + } + // if node has 2 children + var temp = this._findMinNode(node.getRight()); + node.setKey(temp.getKey()); + node.setData(temp.getData()); + node.setRight(this._cleanup(node.getRight(), temp)); //"cleanup nodes" (move them up recursively) + return node; } - return ex.Side.Left; - } - else { - if (intersect.y < 0) { - return ex.Side.Bottom; + else { + // this prevents the node from being removed since it still contains elements + return node; } - return ex.Side.Top; } } - return ex.Side.None; + else if (this._getComparable.call(element) < node.getKey()) { + node.setLeft(this._remove(node.getLeft(), element)); + return node; + } + else { + node.setRight(this._remove(node.getRight(), element)); + return node; + } }; - /** - * Test whether the actor has collided with another actor, returns the side of the current actor that collided. - * @param actor The other actor to test - */ - Actor.prototype.collidesWithSide = function (actor) { - var separationVector = this.collides(actor); - if (!separationVector) { - return ex.Side.None; + // called once we have successfully removed the element we wanted, recursively corrects the part of the tree below the removed node + SortedList.prototype._cleanup = function (node, element) { + var comparable = element.getKey(); + if (node == null) { + return null; } - if (Math.abs(separationVector.x) > Math.abs(separationVector.y)) { - if (this.x < actor.x) { - return ex.Side.Right; + else if (comparable === node.getKey()) { + // if the node is a leaf + if (node.getLeft() == null && node.getRight() == null) { + return null; } - else { - return ex.Side.Left; + else if (node.getLeft() == null) { + return node.getRight(); + } + else if (node.getRight() == null) { + return node.getLeft(); } + // if node has 2 children + var temp = this._findMinNode(node.getRight()); + node.setKey(temp.getKey()); + node.setData(temp.getData()); + node.setRight(this._cleanup(node.getRight(), temp)); + return node; + } + else if (this._getComparable.call(element) < node.getKey()) { + node.setLeft(this._cleanup(node.getLeft(), element)); + return node; } else { - if (this.y < actor.y) { - return ex.Side.Bottom; - } - else { - return ex.Side.Top; - } + node.setRight(this._cleanup(node.getRight(), element)); + return node; } - return ex.Side.None; - }; - /** - * Test whether the actor has collided with another actor, returns the intersection vector on collision. Returns - * `null` when there is no collision; - * @param actor The other actor to test - */ - Actor.prototype.collides = function (actor) { - var bounds = this.getBounds(); - var otherBounds = actor.getBounds(); - var intersect = bounds.collides(otherBounds); - return intersect; }; - /** - * Register a handler to fire when this actor collides with another in a specified group - * @param group The group name to listen for - * @param func The callback to fire on collision with another actor from the group. The callback is passed the other actor. - */ - Actor.prototype.onCollidesWith = function (group, func) { - if (!this._collisionHandlers[group]) { - this._collisionHandlers[group] = []; + SortedList.prototype._findMinNode = function (node) { + var current = node; + while (current.getLeft() != null) { + current = current.getLeft(); } - this._collisionHandlers[group].push(func); - }; - Actor.prototype.getCollisionHandlers = function () { - return this._collisionHandlers; - }; - /** - * Removes all collision handlers for this group on this actor - * @param group Group to remove all handlers for on this actor. - */ - Actor.prototype.removeCollidesWith = function (group) { - this._collisionHandlers[group] = []; - }; - /** - * Returns true if the two actors are less than or equal to the distance specified from each other - * @param actor Actor to test - * @param distance Distance in pixels to test - */ - Actor.prototype.within = function (actor, distance) { - return Math.sqrt(Math.pow(this.x - actor.x, 2) + Math.pow(this.y - actor.y, 2)) <= distance; - }; - /** - * Clears all queued actions from the Actor - */ - Actor.prototype.clearActions = function () { - this.actionQueue.clearActions(); - }; - /** - * This method will move an actor to the specified `x` and `y` position over the - * specified duration using a given [[EasingFunctions]] and return back the actor. This - * method is part of the actor 'Action' fluent API allowing action chaining. - * @param x The x location to move the actor to - * @param y The y location to move the actor to - * @param duration The time it should take the actor to move to the new location in milliseconds - * @param easingFcn Use [[EasingFunctions]] or a custom function to use to calculate position - */ - Actor.prototype.easeTo = function (x, y, duration, easingFcn) { - if (easingFcn === void 0) { easingFcn = ex.EasingFunctions.Linear; } - this.actionQueue.add(new ex.Internal.Actions.EaseTo(this, x, y, duration, easingFcn)); - return this; - }; - /** - * This method will move an actor to the specified `x` and `y` position at the - * `speed` specified (in pixels per second) and return back the actor. This - * method is part of the actor 'Action' fluent API allowing action chaining. - * @param x The x location to move the actor to - * @param y The y location to move the actor to - * @param speed The speed in pixels per second to move - */ - Actor.prototype.moveTo = function (x, y, speed) { - this.actionQueue.add(new ex.Internal.Actions.MoveTo(this, x, y, speed)); - return this; - }; - /** - * This method will move an actor to the specified `x` and `y` position by a - * certain `duration` (in milliseconds). This method is part of the actor - * 'Action' fluent API allowing action chaining. - * @param x The x location to move the actor to - * @param y The y location to move the actor to - * @param duration The time it should take the actor to move to the new location in milliseconds - */ - Actor.prototype.moveBy = function (x, y, duration) { - this.actionQueue.add(new ex.Internal.Actions.MoveBy(this, x, y, duration)); - return this; - }; - /** - * This method will rotate an actor to the specified angle (in radians) at the `speed` - * specified (in radians per second) and return back the actor. This - * method is part of the actor 'Action' fluent API allowing action chaining. - * @param angleRadians The angle to rotate to in radians - * @param speed The angular velocity of the rotation specified in radians per second - */ - Actor.prototype.rotateTo = function (angleRadians, speed, rotationType) { - this.actionQueue.add(new ex.Internal.Actions.RotateTo(this, angleRadians, speed, rotationType)); - return this; + return current; }; - /** - * This method will rotate an actor to the specified angle by a certain - * `duration` (in milliseconds) and return back the actor. This method is part - * of the actor 'Action' fluent API allowing action chaining. - * @param angleRadians The angle to rotate to in radians - * @param duration The time it should take the actor to complete the rotation in milliseconds - */ - Actor.prototype.rotateBy = function (angleRadians, duration, rotationType) { - this.actionQueue.add(new ex.Internal.Actions.RotateBy(this, angleRadians, duration, rotationType)); - return this; + SortedList.prototype.list = function () { + var results = new Array(); + this._list(this._root, results); + return results; }; - /** - * This method will scale an actor to the specified size at the speed - * specified (in magnitude increase per second) and return back the - * actor. This method is part of the actor 'Action' fluent API allowing - * action chaining. - * @param sizeX The scaling factor in the x direction to apply - * @param sizeY The scaling factor in the y direction to apply - * @param speedX The speed of scaling in the x direction specified in magnitude increase per second - * @param speedY The speed of scaling in the y direction specified in magnitude increase per second - */ - Actor.prototype.scaleTo = function (sizeX, sizeY, speedX, speedY) { - this.actionQueue.add(new ex.Internal.Actions.ScaleTo(this, sizeX, sizeY, speedX, speedY)); - return this; + SortedList.prototype._list = function (treeNode, results) { + if (treeNode != null) { + this._list(treeNode.getLeft(), results); + treeNode.getData().forEach(function (element) { + results.push(element); + }); + this._list(treeNode.getRight(), results); + } }; - /** - * This method will scale an actor to the specified size by a certain duration - * (in milliseconds) and return back the actor. This method is part of the - * actor 'Action' fluent API allowing action chaining. - * @param sizeX The scaling factor in the x direction to apply - * @param sizeY The scaling factor in the y direction to apply - * @param duration The time it should take to complete the scaling in milliseconds - */ - Actor.prototype.scaleBy = function (sizeX, sizeY, duration) { - this.actionQueue.add(new ex.Internal.Actions.ScaleBy(this, sizeX, sizeY, duration)); - return this; + return SortedList; + })(); + ex.SortedList = SortedList; + var BinaryTreeNode = (function () { + function BinaryTreeNode(key, data, left, right) { + this._key = key; + this._data = data; + this._left = left; + this._right = right; + } + BinaryTreeNode.prototype.getKey = function () { + return this._key; }; - /** - * This method will cause an actor to blink (become visible and not - * visible). Optionally, you may specify the number of blinks. Specify the amount of time - * the actor should be visible per blink, and the amount of time not visible. - * This method is part of the actor 'Action' fluent API allowing action chaining. - * @param timeVisible The amount of time to stay visible per blink in milliseconds - * @param timeNotVisible The amount of time to stay not visible per blink in milliseconds - * @param numBlinks The number of times to blink - */ - Actor.prototype.blink = function (timeVisible, timeNotVisible, numBlinks) { - if (numBlinks === void 0) { numBlinks = 1; } - this.actionQueue.add(new ex.Internal.Actions.Blink(this, timeVisible, timeNotVisible, numBlinks)); - return this; + BinaryTreeNode.prototype.setKey = function (key) { + this._key = key; }; - /** - * This method will cause an actor's opacity to change from its current value - * to the provided value by a specified `duration` (in milliseconds). This method is - * part of the actor 'Action' fluent API allowing action chaining. - * @param opacity The ending opacity - * @param duration The time it should take to fade the actor (in milliseconds) - */ - Actor.prototype.fade = function (opacity, duration) { - this.actionQueue.add(new ex.Internal.Actions.Fade(this, opacity, duration)); - return this; + BinaryTreeNode.prototype.getData = function () { + return this._data; }; - /** - * This method will delay the next action from executing for the specified - * `duration` (in milliseconds). This method is part of the actor - * 'Action' fluent API allowing action chaining. - * @param duration The amount of time to delay the next action in the queue from executing in milliseconds - */ - Actor.prototype.delay = function (duration) { - this.actionQueue.add(new ex.Internal.Actions.Delay(this, duration)); - return this; + BinaryTreeNode.prototype.setData = function (data) { + this._data = data; }; - /** - * This method will add an action to the queue that will remove the actor from the - * scene once it has completed its previous actions. Any actions on the - * action queue after this action will not be executed. - */ - Actor.prototype.die = function () { - this.actionQueue.add(new ex.Internal.Actions.Die(this)); - return this; + BinaryTreeNode.prototype.getLeft = function () { + return this._left; }; - /** - * This method allows you to call an arbitrary method as the next action in the - * action queue. This is useful if you want to execute code in after a specific - * action, i.e An actor arrives at a destination after traversing a path - */ - Actor.prototype.callMethod = function (method) { - this.actionQueue.add(new ex.Internal.Actions.CallMethod(this, method)); - return this; + BinaryTreeNode.prototype.setLeft = function (left) { + this._left = left; }; - /** - * This method will cause the actor to repeat all of the previously - * called actions a certain number of times. If the number of repeats - * is not specified it will repeat forever. This method is part of - * the actor 'Action' fluent API allowing action chaining - * @param times The number of times to repeat all the previous actions in the action queue. If nothing is specified the actions will - * repeat forever - */ - Actor.prototype.repeat = function (times) { - if (!times) { - this.repeatForever(); - return this; - } - this.actionQueue.add(new ex.Internal.Actions.Repeat(this, times, this.actionQueue.getActions())); - return this; + BinaryTreeNode.prototype.getRight = function () { + return this._right; }; - /** - * This method will cause the actor to repeat all of the previously - * called actions forever. This method is part of the actor 'Action' - * fluent API allowing action chaining. - */ - Actor.prototype.repeatForever = function () { - this.actionQueue.add(new ex.Internal.Actions.RepeatForever(this, this.actionQueue.getActions())); - return this; + BinaryTreeNode.prototype.setRight = function (right) { + this._right = right; }; - /** - * This method will cause the actor to follow another at a specified distance - * @param actor The actor to follow - * @param followDistance The distance to maintain when following, if not specified the actor will follow at the current distance. - */ - Actor.prototype.follow = function (actor, followDistance) { - if (typeof followDistance === 'undefined') { - this.actionQueue.add(new ex.Internal.Actions.Follow(this, actor)); - } - else { - this.actionQueue.add(new ex.Internal.Actions.Follow(this, actor, followDistance)); - } - return this; + return BinaryTreeNode; + })(); + ex.BinaryTreeNode = BinaryTreeNode; + var MockedElement = (function () { + function MockedElement(key) { + this._key = 0; + this._key = key; + } + MockedElement.prototype.getTheKey = function () { + return this._key; }; - /** - * This method will cause the actor to move towards another Actor until they - * collide ("meet") at a specified speed. - * @param actor The actor to meet - * @param speed The speed in pixels per second to move, if not specified it will match the speed of the other actor - */ - Actor.prototype.meet = function (actor, speed) { - if (typeof speed === 'undefined') { - this.actionQueue.add(new ex.Internal.Actions.Meet(this, actor)); + MockedElement.prototype.setKey = function (key) { + this._key = key; + }; + return MockedElement; + })(); + ex.MockedElement = MockedElement; +})(ex || (ex = {})); +/// +/// +/// +/// +/// +/// +/// +/// +var ex; +(function (ex) { + /** + * Scenes + * + * [[Actor|Actors]] are composed together into groupings called Scenes in + * Excalibur. The metaphor models the same idea behind real world + * actors in a scene. Only actors in scenes will be updated and drawn. + * + * Typical usages of a scene include: levels, menus, loading screens, etc. + * + * ## Adding actors to the scene + * + * For an [[Actor]] to be drawn and updated, it needs to be part of the "scene graph". + * The [[Engine]] provides several easy ways to quickly add/remove actors from the + * current scene. + * + * ```js + * var game = new ex.Engine(...); + * + * var player = new ex.Actor(); + * var enemy = new ex.Actor(); + * + * // add them to the "root" scene + * + * game.add(player); + * game.add(enemy); + * + * // start game + * game.start(); + * ``` + * + * You can also add actors to a [[Scene]] instance specifically. + * + * ```js + * var game = new ex.Engine(); + * var level1 = new ex.Scene(); + * + * var player = new ex.Actor(); + * var enemy = new ex.Actor(); + * + * // add actors to level1 + * level1.add(player); + * level1.add(enemy); + * + * // add level1 to the game + * game.add("level1", level1); + * + * // start the game + * game.start(); + * + * // after player clicks start game, for example + * game.goToScene("level1"); + * + * ``` + * + * ## Scene Lifecycle + * + * A [[Scene|scene]] has a basic lifecycle that dictacts how it is initialized, updated, and drawn. Once a [[Scene|scene]] is added to + * the [[Engine|engine]] it will follow this lifecycle. + * + * ![Scene Lifecycle](/assets/images/docs/SceneLifeCycle.png) + * + * ## Extending scenes + * + * For more complex games, you might want more control over a scene in which + * case you can extend [[Scene]]. This is useful for menus, custom loaders, + * and levels. + * + * Just use [[Engine.add]] to add a new scene to the game. You can then use + * [[Engine.goToScene]] to switch scenes which calls [[Scene.onActivate]] for the + * new scene and [[Scene.onDeactivate]] for the old scene. Use [[Scene.onInitialize]] + * to perform any start-up logic, which is called once. + * + * **TypeScript** + * + * ```ts + * class MainMenu extends ex.Scene { + * + * // start-up logic, called once + * public onInitialize(engine: ex.Engine) { } + * + * // each time the scene is entered (Engine.goToScene) + * public onActivate() { } + * + * // each time the scene is exited (Engine.goToScene) + * public onDeactivate() { } + * } + * + * // add to game and activate it + * game.add("mainmenu", new MainMenu()); + * game.goToScene("mainmenu"); + * ``` + * + * **Javascript** + * + * ```js + * var MainMenu = ex.Scene.extend({ + * // start-up logic, called once + * onInitialize: function (engine) { }, + * + * // each time the scene is activated by Engine.goToScene + * onActivate: function () { }, + * + * // each time the scene is deactivated by Engine.goToScene + * onDeactivate: function () { } + * }); + * + * game.add("mainmenu", new MainMenu()); + * game.goToScene("mainmenu"); + * ``` + * + * ## Scene camera + * + * By default, a [[Scene]] is initialized with a [[BaseCamera]] which + * does not move and centers the game world. + * + * Learn more about [[BaseCamera|Cameras]] and how to modify them to suit + * your game. + */ + var Scene = (function (_super) { + __extends(Scene, _super); + function Scene(engine) { + _super.call(this); + /** + * The actors in the current scene + */ + this.children = []; + /** + * The [[TileMap]]s in the scene, if any + */ + this.tileMaps = []; + /** + * The [[Group]]s in the scene, if any + */ + this.groups = {}; + /** + * The [[UIActor]]s in a scene, if any; these are drawn last + */ + this.uiActors = []; + /** + * Whether or the [[Scene]] has been initialized + */ + this.isInitialized = false; + this._sortedDrawingTree = new ex.SortedList(ex.Actor.prototype.getZIndex); + this._collisionResolver = new ex.DynamicTreeCollisionResolver(); + this._killQueue = []; + this._timers = []; + this._cancelQueue = []; + this._logger = ex.Logger.getInstance(); + this.camera = new ex.BaseCamera(); + if (engine) { + this.camera.setFocus(engine.width / 2, engine.height / 2); } - else { - this.actionQueue.add(new ex.Internal.Actions.Meet(this, actor, speed)); + } + /** + * This is called before the first update of the [[Scene]]. Initializes scene members like the camera. This method is meant to be + * overridden. This is where initialization of child actors should take place. + */ + Scene.prototype.onInitialize = function (engine) { + // will be overridden + if (this.camera) { + this.camera.setFocus(engine.width / 2, engine.height / 2); } - return this; + this._logger.debug('Scene.onInitialize', this, engine); }; /** - * Returns a promise that resolves when the current action queue up to now - * is finished. + * This is called when the scene is made active and started. It is meant to be overriden, + * this is where you should setup any DOM UI or event handlers needed for the scene. */ - Actor.prototype.asPromise = function () { - var complete = new ex.Promise(); - this.callMethod(function () { - complete.resolve(); - }); - return complete; - }; - Actor.prototype._getCalculatedAnchor = function () { - return new ex.Point(this.getWidth() * this.anchor.x, this.getHeight() * this.anchor.y); + Scene.prototype.onActivate = function () { + // will be overridden + this._logger.debug('Scene.onActivate', this); }; /** - * Called by the Engine, updates the state of the actor - * @param engine The reference to the current game engine - * @param delta The time elapsed since the last update in milliseconds + * This is called when the scene is made transitioned away from and stopped. It is meant to be overriden, + * this is where you should cleanup any DOM UI or event handlers needed for the scene. */ - Actor.prototype.update = function (engine, delta) { - if (!this._isInitialized) { - this.onInitialize(engine); - this.eventDispatcher.emit('initialize', new ex.InitializeEvent(engine)); - this._isInitialized = true; - } - var eventDispatcher = this.eventDispatcher; - // Update action queue - this.actionQueue.update(delta); - // Update color only opacity - if (this.color) { - this.color.a = this.opacity; - } - // Update actor pipeline (movement, collision detection, event propagation, offscreen culling) - for (var i = 0; i < this.traits.length; i++) { - this.traits[i].update(this, engine, delta); - } - eventDispatcher.emit(ex.EventType[ex.EventType.Update], new ex.UpdateEvent(delta)); + Scene.prototype.onDeactivate = function () { + // will be overridden + this._logger.debug('Scene.onDeactivate', this); }; /** - * Called by the Engine, draws the actor to the screen - * @param ctx The rendering context - * @param delta The time since the last draw in milliseconds + * Updates all the actors and timers in the scene. Called by the [[Engine]]. + * @param engine Reference to the current Engine + * @param delta The number of milliseconds since the last update */ - Actor.prototype.draw = function (ctx, delta) { - var anchorPoint = this._getCalculatedAnchor(); - ctx.save(); - ctx.scale(this.scale.x, this.scale.y); - ctx.translate(this.x, this.y); - ctx.rotate(this.rotation); - // calculate changing opacity - if (this.previousOpacity !== this.opacity) { - for (var drawing in this.frames) { - this.frames[drawing].addEffect(new ex.Effects.Opacity(this.opacity)); - } - this.previousOpacity = this.opacity; + Scene.prototype.update = function (engine, delta) { + this.emit('preupdate', new ex.PreUpdateEvent(engine, delta, this)); + var i, len; + // Cycle through actors updating UI actors + for (i = 0, len = this.uiActors.length; i < len; i++) { + this.uiActors[i].update(engine, delta); } - if (this.currentDrawing) { - var xDiff = 0; - var yDiff = 0; - if (this.centerDrawingX) { - xDiff = (this.currentDrawing.naturalWidth * this.currentDrawing.scale.x - this.getWidth()) / 2 - - this.currentDrawing.naturalWidth * this.currentDrawing.scale.x * this.currentDrawing.anchor.x; - } - if (this.centerDrawingY) { - yDiff = (this.currentDrawing.naturalHeight * this.currentDrawing.scale.y - this.getHeight()) / 2 - - this.currentDrawing.naturalHeight * this.currentDrawing.scale.y * this.currentDrawing.anchor.y; - } - this.currentDrawing.draw(ctx, -anchorPoint.x - xDiff, -anchorPoint.y - yDiff); + // Cycle through actors updating tile maps + for (i = 0, len = this.tileMaps.length; i < len; i++) { + this.tileMaps[i].update(engine, delta); } - else { - if (this.color) { - ctx.fillStyle = this.color.toString(); - ctx.fillRect(-anchorPoint.x, -anchorPoint.y, this._width, this._height); - } + // Cycle through actors updating actors + for (i = 0, len = this.children.length; i < len; i++) { + this.children[i].update(engine, delta); } - // Draw child actors - for (var i = 0; i < this.children.length; i++) { - if (this.children[i].visible) { - this.children[i].draw(ctx, delta); - } + // Run collision resolution strategy + if (this._collisionResolver) { + this._collisionResolver.update(this.children); + this._collisionResolver.evaluate(this.children); } - ctx.restore(); - }; - /** - * Called by the Engine, draws the actors debugging to the screen - * @param ctx The rendering context - */ - Actor.prototype.debugDraw = function (ctx) { - // Draw actor bounding box - var bb = this.getBounds(); - bb.debugDraw(ctx); - // Draw actor Id - ctx.fillText('id: ' + this.id, bb.left + 3, bb.top + 10); - // Draw actor anchor point - ctx.fillStyle = ex.Color.Yellow.toString(); - ctx.beginPath(); - ctx.arc(this.getWorldX(), this.getWorldY(), 3, 0, Math.PI * 2); - ctx.closePath(); - ctx.fill(); - // Culling Box debug draw - for (var j = 0; j < this.traits.length; j++) { - if (this.traits[j] instanceof ex.Traits.OffscreenCulling) { - this.traits[j].cullingBox.debugDraw(ctx); + // Remove actors from scene graph after being killed + var actorIndex; + for (i = 0, len = this._killQueue.length; i < len; i++) { + actorIndex = this.children.indexOf(this._killQueue[i]); + if (actorIndex > -1) { + this._sortedDrawingTree.removeByComparable(this._killQueue[i]); + this.children.splice(actorIndex, 1); } } - // Unit Circle debug draw - ctx.strokeStyle = ex.Color.Yellow.toString(); - ctx.beginPath(); - var radius = Math.min(this.getWidth(), this.getHeight()); - ctx.arc(this.getWorldX(), this.getWorldY(), radius, 0, Math.PI * 2); - ctx.closePath(); - ctx.stroke(); - var ticks = { '0 Pi': 0, - 'Pi/2': Math.PI / 2, - 'Pi': Math.PI, - '3/2 Pi': 3 * Math.PI / 2 }; - var oldFont = ctx.font; - for (var tick in ticks) { - ctx.fillStyle = ex.Color.Yellow.toString(); - ctx.font = '14px'; - ctx.textAlign = 'center'; - ctx.fillText(tick, this.getWorldX() + Math.cos(ticks[tick]) * (radius + 10), this.getWorldY() + Math.sin(ticks[tick]) * (radius + 10)); - } - ctx.font = oldFont; - // Draw child actors - ctx.save(); - ctx.translate(this.x, this.y); - ctx.rotate(this.rotation); - // Draw child actors - for (var i = 0; i < this.children.length; i++) { - this.children[i].debugDraw(ctx); - } - ctx.restore(); - }; - /** - * Indicates the next id to be set - */ - Actor.maxId = 0; - return Actor; - })(ex.Class); - ex.Actor = Actor; - /** - * An enum that describes the types of collisions actors can participate in - */ - (function (CollisionType) { - /** - * Actors with the `PreventCollision` setting do not participate in any - * collisions and do not raise collision events. - */ - CollisionType[CollisionType["PreventCollision"] = 0] = "PreventCollision"; - /** - * Actors with the `Passive` setting only raise collision events, but are not - * influenced or moved by other actors and do not influence or move other actors. - */ - CollisionType[CollisionType["Passive"] = 1] = "Passive"; - /** - * Actors with the `Active` setting raise collision events and participate - * in collisions with other actors and will be push or moved by actors sharing - * the `Active` or `Fixed` setting. - */ - CollisionType[CollisionType["Active"] = 2] = "Active"; - /** - * Actors with the `Elastic` setting will behave the same as `Active`, except that they will - * "bounce" in the opposite direction given their velocity dx/dy. This is a naive implementation meant for - * prototyping, for a more robust elastic collision listen to the "collision" event and perform your custom logic. - */ - CollisionType[CollisionType["Elastic"] = 3] = "Elastic"; - /** - * Actors with the `Fixed` setting raise collision events and participate in - * collisions with other actors. Actors with the `Fixed` setting will not be - * pushed or moved by other actors sharing the `Fixed`. Think of Fixed - * actors as "immovable/onstoppable" objects. If two `Fixed` actors meet they will - * not be pushed or moved by each other, they will not interact except to throw - * collision events. - */ - CollisionType[CollisionType["Fixed"] = 4] = "Fixed"; - })(ex.CollisionType || (ex.CollisionType = {})); - var CollisionType = ex.CollisionType; -})(ex || (ex = {})); -var ex; -(function (ex) { - /** - * Logging level that Excalibur will tag - */ - (function (LogLevel) { - LogLevel[LogLevel["Debug"] = 0] = "Debug"; - LogLevel[LogLevel["Info"] = 1] = "Info"; - LogLevel[LogLevel["Warn"] = 2] = "Warn"; - LogLevel[LogLevel["Error"] = 3] = "Error"; - LogLevel[LogLevel["Fatal"] = 4] = "Fatal"; - })(ex.LogLevel || (ex.LogLevel = {})); - var LogLevel = ex.LogLevel; - /** - * Static singleton that represents the logging facility for Excalibur. - * Excalibur comes built-in with a [[ConsoleAppender]] and [[ScreenAppender]]. - * Derive from [[IAppender]] to create your own logging appenders. - * - * ## Example: Logging - * - * ```js - * // set default log level (default: Info) - * ex.Logger.getInstance().defaultLevel = ex.LogLevel.Warn; - * - * // this will not be shown because it is below Warn - * ex.Logger.getInstance().info("This will be logged as Info"); - * // this will show because it is Warn - * ex.Logger.getInstance().warn("This will be logged as Warn"); - * // this will show because it is above Warn - * ex.Logger.getInstance().error("This will be logged as Error"); - * // this will show because it is above Warn - * ex.Logger.getInstance().fatal("This will be logged as Fatal"); - * ``` - */ - var Logger = (function () { - function Logger() { - this._appenders = []; - /** - * Gets or sets the default logging level. Excalibur will only log - * messages if equal to or above this level. Default: [[LogLevel.Info]] - */ - this.defaultLevel = LogLevel.Info; - if (Logger._instance) { - throw new Error('Logger is a singleton'); + this._killQueue.length = 0; + // Remove timers in the cancel queue before updating them + for (i = 0, len = this._cancelQueue.length; i < len; i++) { + this.removeTimer(this._cancelQueue[i]); } - Logger._instance = this; - // Default console appender - Logger._instance.addAppender(new ConsoleAppender()); - return Logger._instance; - } + this._cancelQueue.length = 0; + // Cycle through timers updating timers + this._timers = this._timers.filter(function (timer) { + timer.update(delta); + return !timer.complete; + }); + this.emit('postupdate', new ex.PostUpdateEvent(engine, delta, this)); + }; /** - * Gets the current static instance of Logger + * Draws all the actors in the Scene. Called by the [[Engine]]. + * @param ctx The current rendering context + * @param delta The number of milliseconds since the last draw */ - Logger.getInstance = function () { - if (Logger._instance == null) { - Logger._instance = new Logger(); + Scene.prototype.draw = function (ctx, delta) { + this.emit('predraw', new ex.PreDrawEvent(ctx, delta, this)); + ctx.save(); + if (this.camera) { + this.camera.update(ctx, delta); } - return Logger._instance; + var i, len; + for (i = 0, len = this.tileMaps.length; i < len; i++) { + this.tileMaps[i].draw(ctx, delta); + } + var sortedChildren = this._sortedDrawingTree.list(); + for (i = 0, len = sortedChildren.length; i < len; i++) { + // only draw actors that are visible and on screen + if (sortedChildren[i].visible && !sortedChildren[i].isOffScreen) { + sortedChildren[i].draw(ctx, delta); + } + } + if (this.engine && this.engine.isDebug) { + ctx.strokeStyle = 'yellow'; + this.debugDraw(ctx); + } + ctx.restore(); + for (i = 0, len = this.uiActors.length; i < len; i++) { + // only draw ui actors that are visible and on screen + if (this.uiActors[i].visible) { + this.uiActors[i].draw(ctx, delta); + } + } + if (this.engine && this.engine.isDebug) { + for (i = 0, len = this.uiActors.length; i < len; i++) { + this.uiActors[i].debugDraw(ctx); + } + } + this.emit('postdraw', new ex.PreDrawEvent(ctx, delta, this)); }; /** - * Adds a new [[IAppender]] to the list of appenders to write to + * Draws all the actors' debug information in the Scene. Called by the [[Engine]]. + * @param ctx The current rendering context */ - Logger.prototype.addAppender = function (appender) { - this._appenders.push(appender); + Scene.prototype.debugDraw = function (ctx) { + this.emit('predebugdraw', new ex.PreDebugDrawEvent(ctx, this)); + var i, len; + for (i = 0, len = this.tileMaps.length; i < len; i++) { + this.tileMaps[i].debugDraw(ctx); + } + for (i = 0, len = this.children.length; i < len; i++) { + this.children[i].debugDraw(ctx); + } + // todo possibly enable this with excalibur flags features? + //this._collisionResolver.debugDraw(ctx, 20); + this.camera.debugDraw(ctx); + this.emit('postdebugdraw', new ex.PostDebugDrawEvent(ctx, this)); }; /** - * Clears all appenders from the logger + * Checks whether an actor is contained in this scene or not */ - Logger.prototype.clearAppenders = function () { - this._appenders.length = 0; + Scene.prototype.contains = function (actor) { + return this.children.indexOf(actor) > -1; }; - /** - * Logs a message at a given LogLevel - * @param level The LogLevel`to log the message at - * @param args An array of arguments to write to an appender - */ - Logger.prototype._log = function (level, args) { - if (level == null) { - level = this.defaultLevel; + Scene.prototype.add = function (entity) { + if (entity instanceof ex.UIActor) { + if (!ex.Util.contains(this.uiActors, entity)) { + this.addUIActor(entity); + } + return; } - var i = 0, len = this._appenders.length; - for (i; i < len; i++) { - if (level >= this.defaultLevel) { - this._appenders[i].log(level, args); + if (entity instanceof ex.Actor) { + if (!ex.Util.contains(this.children, entity)) { + this.addChild(entity); + this._sortedDrawingTree.add(entity); + } + return; + } + if (entity instanceof ex.Timer) { + if (!ex.Util.contains(this._timers, entity)) { + this.addTimer(entity); + } + return; + } + if (entity instanceof ex.TileMap) { + if (!ex.Util.contains(this.tileMaps, entity)) { + this.addTileMap(entity); } } }; + Scene.prototype.remove = function (entity) { + if (entity instanceof ex.UIActor) { + this.removeUIActor(entity); + return; + } + if (entity instanceof ex.Actor) { + this._collisionResolver.remove(entity); + this.removeChild(entity); + } + if (entity instanceof ex.Timer) { + this.removeTimer(entity); + } + if (entity instanceof ex.TileMap) { + this.removeTileMap(entity); + } + }; /** - * Writes a log message at the [[LogLevel.Debug]] level - * @param args Accepts any number of arguments + * Adds (any) actor to act as a piece of UI, meaning it is always positioned + * in screen coordinates. UI actors do not participate in collisions. + * @todo Should this be `UIActor` only? */ - Logger.prototype.debug = function () { - var args = []; - for (var _i = 0; _i < arguments.length; _i++) { - args[_i - 0] = arguments[_i]; - } - this._log(LogLevel.Debug, args); + Scene.prototype.addUIActor = function (actor) { + this.uiActors.push(actor); + actor.scene = this; }; /** - * Writes a log message at the [[LogLevel.Info]] level - * @param args Accepts any number of arguments + * Removes an actor as a piece of UI */ - Logger.prototype.info = function () { - var args = []; - for (var _i = 0; _i < arguments.length; _i++) { - args[_i - 0] = arguments[_i]; + Scene.prototype.removeUIActor = function (actor) { + var index = this.uiActors.indexOf(actor); + if (index > -1) { + this.uiActors.splice(index, 1); } - this._log(LogLevel.Info, args); }; /** - * Writes a log message at the [[LogLevel.Warn]] level - * @param args Accepts any number of arguments + * Adds an actor to the scene, once this is done the actor will be drawn and updated. + * + * @obsolete Use [[add]] instead. */ - Logger.prototype.warn = function () { - var args = []; - for (var _i = 0; _i < arguments.length; _i++) { - args[_i - 0] = arguments[_i]; - } - this._log(LogLevel.Warn, args); + Scene.prototype.addChild = function (actor) { + this._collisionResolver.register(actor); + actor.scene = this; + this.children.push(actor); + this._sortedDrawingTree.add(actor); + actor.parent = this.actor; }; /** - * Writes a log message at the [[LogLevel.Error]] level - * @param args Accepts any number of arguments + * Adds a [[TileMap]] to the scene, once this is done the TileMap will be drawn and updated. */ - Logger.prototype.error = function () { - var args = []; - for (var _i = 0; _i < arguments.length; _i++) { - args[_i - 0] = arguments[_i]; - } - this._log(LogLevel.Error, args); + Scene.prototype.addTileMap = function (tileMap) { + this.tileMaps.push(tileMap); }; /** - * Writes a log message at the [[LogLevel.Fatal]] level - * @param args Accepts any number of arguments + * Removes a [[TileMap]] from the scene, it will no longer be drawn or updated. */ - Logger.prototype.fatal = function () { - var args = []; - for (var _i = 0; _i < arguments.length; _i++) { - args[_i - 0] = arguments[_i]; + Scene.prototype.removeTileMap = function (tileMap) { + var index = this.tileMaps.indexOf(tileMap); + if (index > -1) { + this.tileMaps.splice(index, 1); } - this._log(LogLevel.Fatal, args); }; - Logger._instance = null; - return Logger; - })(); - ex.Logger = Logger; - /** - * Console appender for browsers (i.e. `console.log`) - */ - var ConsoleAppender = (function () { - function ConsoleAppender() { - } /** - * Logs a message at the given [[LogLevel]] - * @param level Level to log at - * @param args Arguments to log + * Removes an actor from the scene, it will no longer be drawn or updated. */ - ConsoleAppender.prototype.log = function (level, args) { - // Check for console support - if (!console && !console.log && console.warn && console.error) { - // todo maybe do something better than nothing - return; - } - // Create a new console args array - var consoleArgs = []; - consoleArgs.unshift.apply(consoleArgs, args); - consoleArgs.unshift('[' + LogLevel[level] + '] : '); - if (level < LogLevel.Warn) { - // Call .log for Debug/Info - if (console.log.apply) { - // this is required on some older browsers that don't support apply on console.log :( - console.log.apply(console, consoleArgs); - } - else { - console.log(consoleArgs.join(' ')); - } - } - else if (level < LogLevel.Error) { - // Call .warn for Warn - if (console.warn.apply) { - console.warn.apply(console, consoleArgs); - } - else { - console.warn(consoleArgs.join(' ')); - } - } - else { - // Call .error for Error/Fatal - if (console.error.apply) { - console.error.apply(console, consoleArgs); - } - else { - console.error(consoleArgs.join(' ')); - } - } + Scene.prototype.removeChild = function (actor) { + this._collisionResolver.remove(actor); + this._killQueue.push(actor); + actor.parent = null; }; - return ConsoleAppender; - })(); - ex.ConsoleAppender = ConsoleAppender; - /** - * On-screen (canvas) appender - */ - var ScreenAppender = (function () { /** - * @param width Width of the screen appender in pixels - * @param height Height of the screen appender in pixels + * Adds a [[Timer]] to the scene + * @param timer The timer to add */ - function ScreenAppender(width, height) { - // @todo Clean this up - this._messages = []; - this._canvas = document.createElement('canvas'); - this._canvas.width = width || window.innerWidth; - this._canvas.height = height || window.innerHeight; - this._canvas.style.position = 'absolute'; - this._ctx = this._canvas.getContext('2d'); - document.body.appendChild(this._canvas); - } + Scene.prototype.addTimer = function (timer) { + this._timers.push(timer); + timer.scene = this; + return timer; + }; /** - * Logs a message at the given [[LogLevel]] - * @param level Level to log at - * @param args Arguments to log + * Removes a [[Timer]] from the scene. + * @warning Can be dangerous, use [[cancelTimer]] instead + * @param timer The timer to remove */ - ScreenAppender.prototype.log = function (level, args) { - var message = args.join(','); - this._ctx.clearRect(0, 0, this._canvas.width, this._canvas.height); - this._messages.unshift('[' + LogLevel[level] + '] : ' + message); - var pos = 10; - var opacity = 1.0; - for (var i = 0; i < this._messages.length; i++) { - this._ctx.fillStyle = 'rgba(255,255,255,' + opacity.toFixed(2) + ')'; - this._ctx.fillText(this._messages[i], 200, pos); - pos += 10; - opacity = opacity > 0 ? opacity - .05 : 0; + Scene.prototype.removeTimer = function (timer) { + var i = this._timers.indexOf(timer); + if (i !== -1) { + this._timers.splice(i, 1); } + return timer; }; - return ScreenAppender; - })(); - ex.ScreenAppender = ScreenAppender; -})(ex || (ex = {})); -/// -/// -/// -var ex; -(function (ex) { - /** - * An enum representing all of the built in event types for Excalibur - * @obsolete Phasing this out in favor of classes - */ - (function (EventType) { - EventType[EventType["Collision"] = 0] = "Collision"; - EventType[EventType["EnterViewPort"] = 1] = "EnterViewPort"; - EventType[EventType["ExitViewPort"] = 2] = "ExitViewPort"; - EventType[EventType["Blur"] = 3] = "Blur"; - EventType[EventType["Focus"] = 4] = "Focus"; - EventType[EventType["Update"] = 5] = "Update"; - EventType[EventType["Activate"] = 6] = "Activate"; - EventType[EventType["Deactivate"] = 7] = "Deactivate"; - EventType[EventType["Initialize"] = 8] = "Initialize"; - })(ex.EventType || (ex.EventType = {})); - var EventType = ex.EventType; - /** - * Base event type in Excalibur that all other event types derive from. - */ - var GameEvent = (function () { - function GameEvent() { - } - return GameEvent; - })(); - ex.GameEvent = GameEvent; - /** - * Subscribe event thrown when handlers for events other than subscribe are added - */ - var SubscribeEvent = (function (_super) { - __extends(SubscribeEvent, _super); - function SubscribeEvent(topic, handler) { - _super.call(this); - this.topic = topic; - this.handler = handler; - } - return SubscribeEvent; - })(GameEvent); - ex.SubscribeEvent = SubscribeEvent; - /** - * Unsubscribe event thrown when handlers for events other than unsubscribe are removed - */ - var UnsubscribeEvent = (function (_super) { - __extends(UnsubscribeEvent, _super); - function UnsubscribeEvent(topic, handler) { - _super.call(this); - this.topic = topic; - this.handler = handler; - } - return UnsubscribeEvent; - })(GameEvent); - ex.UnsubscribeEvent = UnsubscribeEvent; - /** - * Event received by the Engine when the browser window is visible - */ - var VisibleEvent = (function (_super) { - __extends(VisibleEvent, _super); - function VisibleEvent() { - _super.call(this); - } - return VisibleEvent; - })(GameEvent); - ex.VisibleEvent = VisibleEvent; - /** - * Event received by the Engine when the browser window is hidden - */ - var HiddenEvent = (function (_super) { - __extends(HiddenEvent, _super); - function HiddenEvent() { - _super.call(this); - } - return HiddenEvent; - })(GameEvent); - ex.HiddenEvent = HiddenEvent; - /** - * Event thrown on an actor when a collision has occured - */ - var CollisionEvent = (function (_super) { - __extends(CollisionEvent, _super); /** - * @param actor The actor the event was thrown on - * @param other The actor that was collided with - * @param side The side that was collided with + * Cancels a [[Timer]], removing it from the scene nicely + * @param timer The timer to cancel */ - function CollisionEvent(actor, other, side, intersection) { - _super.call(this); - this.actor = actor; - this.other = other; - this.side = side; - this.intersection = intersection; - } - return CollisionEvent; - })(GameEvent); - ex.CollisionEvent = CollisionEvent; - /** - * Event thrown on a game object on Excalibur update - */ - var UpdateEvent = (function (_super) { - __extends(UpdateEvent, _super); + Scene.prototype.cancelTimer = function (timer) { + this._cancelQueue.push(timer); + return timer; + }; /** - * @param delta The number of milliseconds since the last update + * Tests whether a [[Timer]] is active in the scene */ - function UpdateEvent(delta) { - _super.call(this); - this.delta = delta; - } - return UpdateEvent; - })(GameEvent); - ex.UpdateEvent = UpdateEvent; - /** - * Event thrown on an Actor only once before the first update call - */ - var InitializeEvent = (function (_super) { - __extends(InitializeEvent, _super); + Scene.prototype.isTimerActive = function (timer) { + return (this._timers.indexOf(timer) > -1); + }; /** - * @param engine The reference to the current engine + * Creates and adds a [[Group]] to the scene with a name */ - function InitializeEvent(engine) { - _super.call(this); - this.engine = engine; - } - return InitializeEvent; - })(GameEvent); - ex.InitializeEvent = InitializeEvent; - /** - * Event thrown on a Scene on activation - */ - var ActivateEvent = (function (_super) { - __extends(ActivateEvent, _super); + Scene.prototype.createGroup = function (name) { + return new ex.Group(name, this); + }; /** - * @param oldScene The reference to the old scene + * Returns a [[Group]] by name */ - function ActivateEvent(oldScene) { - _super.call(this); - this.oldScene = oldScene; - } - return ActivateEvent; - })(GameEvent); - ex.ActivateEvent = ActivateEvent; - /** - * Event thrown on a Scene on deactivation - */ - var DeactivateEvent = (function (_super) { - __extends(DeactivateEvent, _super); + Scene.prototype.getGroup = function (name) { + return this.groups[name]; + }; + Scene.prototype.removeGroup = function (group) { + if (typeof group === 'string') { + delete this.groups[group]; + } + else if (group instanceof ex.Group) { + delete this.groups[group.name]; + } + else { + this._logger.error('Invalid arguments to removeGroup', group); + } + }; /** - * @param newScene The reference to the new scene + * Removes the given actor from the sorted drawing tree */ - function DeactivateEvent(newScene) { - _super.call(this); - this.newScene = newScene; - } - return DeactivateEvent; - })(GameEvent); - ex.DeactivateEvent = DeactivateEvent; - /** - * Event thrown on an Actor when it completely leaves the screen. - */ - var ExitViewPortEvent = (function (_super) { - __extends(ExitViewPortEvent, _super); - function ExitViewPortEvent() { - _super.call(this); - } - return ExitViewPortEvent; - })(GameEvent); - ex.ExitViewPortEvent = ExitViewPortEvent; + Scene.prototype.cleanupDrawTree = function (actor) { + this._sortedDrawingTree.removeByComparable(actor); + }; + /** + * Updates the given actor's position in the sorted drawing tree + */ + Scene.prototype.updateDrawTree = function (actor) { + this._sortedDrawingTree.add(actor); + }; + return Scene; + })(ex.Class); + ex.Scene = Scene; +})(ex || (ex = {})); +var ex; +(function (ex) { /** - * Event thrown on an Actor when it completely leaves the screen. + * Standard easing functions for motion in Excalibur, defined on a domain of [0, duration] and a range from [+startValue,+endValue] + * Given a time, the function will return a value from postive startValue to postive endValue. + * + * ```js + * function Linear (t) { + * return t * t; + * } + * + * // accelerating from zero velocity + * function EaseInQuad (t) { + * return t * t; + * } + * + * // decelerating to zero velocity + * function EaseOutQuad (t) { + * return t * (2 - t); + * } + * + * // acceleration until halfway, then deceleration + * function EaseInOutQuad (t) { + * return t < .5 ? 2 * t * t : -1 + (4 - 2 * t) * t; + * } + * + * // accelerating from zero velocity + * function EaseInCubic (t) { + * return t * t * t; + * } + * + * // decelerating to zero velocity + * function EaseOutCubic (t) { + * return (--t) * t * t + 1; + * } + * + * // acceleration until halfway, then deceleration + * function EaseInOutCubic (t) { + * return t < .5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1; + * } + * ``` */ - var EnterViewPortEvent = (function (_super) { - __extends(EnterViewPortEvent, _super); - function EnterViewPortEvent() { - _super.call(this); + var EasingFunctions = (function () { + function EasingFunctions() { } - return EnterViewPortEvent; - })(GameEvent); - ex.EnterViewPortEvent = EnterViewPortEvent; + EasingFunctions.Linear = function (currentTime, startValue, endValue, duration) { + endValue = (endValue - startValue); + return endValue * currentTime / duration + startValue; + }; + EasingFunctions.EaseInQuad = function (currentTime, startValue, endValue, duration) { + //endValue = (endValue - startValue); + currentTime /= duration; + }; + EasingFunctions.EaseOutQuad = function (currentTime, startValue, endValue, duration) { + //endValue = (endValue - startValue); + currentTime /= duration; + return -endValue * currentTime * (currentTime - 2) + startValue; + }; + EasingFunctions.EaseInOutQuad = function (currentTime, startValue, endValue, duration) { + endValue = (endValue - startValue); + currentTime /= duration / 2; + if (currentTime < 1) { + return endValue / 2 * currentTime * currentTime + startValue; + } + currentTime--; + return -endValue / 2 * (currentTime * (currentTime - 2) - 1) + startValue; + }; + EasingFunctions.EaseInCubic = function (currentTime, startValue, endValue, duration) { + endValue = (endValue - startValue); + currentTime /= duration; + return endValue * currentTime * currentTime * currentTime + startValue; + }; + EasingFunctions.EaseOutCubic = function (currentTime, startValue, endValue, duration) { + endValue = (endValue - startValue); + currentTime /= duration; + return endValue * (currentTime * currentTime * currentTime + 1) + startValue; + }; + EasingFunctions.EaseInOutCubic = function (currentTime, startValue, endValue, duration) { + endValue = (endValue - startValue); + currentTime /= duration / 2; + if (currentTime < 1) { + return endValue / 2 * currentTime * currentTime * currentTime + startValue; + } + currentTime -= 2; + return endValue / 2 * (currentTime * currentTime * currentTime + 2) + startValue; + }; + return EasingFunctions; + })(); + ex.EasingFunctions = EasingFunctions; })(ex || (ex = {})); -/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// var ex; (function (ex) { /** - * Excalibur's internal event dispatcher implementation. - * Callbacks are fired immediately after an event is published. - * Typically you'd use [[Class.eventDispatcher]] since most classes in - * Excalibur inherit from [[Class]]. You'd rarely create an `EventDispatcher` - * yourself. + * Actors * - * When working with events, be sure to keep in mind the order of subscriptions - * and try not to create a situation that requires specific things to happen in - * order. Events are best used for input events, tying together disparate objects, - * or for UI updates. + * The most important primitive in Excalibur is an `Actor`. Anything that + * can move on the screen, collide with another `Actor`, respond to events, + * or interact with the current scene, must be an actor. An `Actor` **must** + * be part of a [[Scene]] for it to be drawn to the screen. * - * ## Example: Actor events + * ## Basic actors + * + * For quick and dirty games, you can just create an instance of an `Actor` + * and manipulate it directly. + * + * Actors (and other entities) must be added to a [[Scene]] to be drawn + * and updated on-screen. + * + * ```ts + * var player = new ex.Actor(); + * + * // move the player + * player.dx = 5; + * + * // add player to the current scene + * game.add(player); + * + * ``` + * `game.add` is a convenience method for adding an `Actor` to the current scene. The equivalent verbose call is `game.currentScene.add`. + * + * ## Actor Lifecycle + * + * An [[Actor|actor]] has a basic lifecycle that dictacts how it is initialized, updated, and drawn. Once an actor is part of a + * [[Scene|scene]], it will follow this lifecycle. + * + * ![Actor Lifecycle](/assets/images/docs/ActorLifeCycle.png) + * + * ## Extending actors + * + * For "real-world" games, you'll want to `extend` the `Actor` class. + * This gives you much greater control and encapsulates logic for that + * actor. + * + * You can override the [[onInitialize]] method to perform any startup logic + * for an actor (such as configuring state). [[onInitialize]] gets called + * **once** before the first frame an actor is drawn/updated. It is passed + * an instance of [[Engine]] to access global state or perform coordinate math. + * + * **TypeScript** + * + * ```ts + * class Player extends ex.Actor { + * + * public level = 1; + * public endurance = 0; + * public fortitude = 0; + * + * constructor() { + * super(); + * } + * + * public onInitialize(engine: ex.Engine) { + * this.endurance = 20; + * this.fortitude = 16; + * } + * + * public getMaxHealth() { + * return (0.4 * this.endurance) + (0.9 * this.fortitude) + (this.level * 1.2); + * } + * } + * ``` + * + * **Javascript** + * + * In Javascript you can use the [[extend]] method to override or add + * methods to an `Actor`. + * + * ```js + * var Player = ex.Actor.extend({ + * + * level: 1, + * endurance: 0, + * fortitude: 0, + * + * onInitialize: function (engine) { + * this.endurance = 20; + * this.fortitude = 16; + * }, + * + * getMaxHealth: function () { + * return (0.4 * this.endurance) + (0.9 * this.fortitude) + (this.level * 1.2); + * } + * }); + * ``` + * + * ## Updating actors + * + * Override the [[update]] method to update the state of your actor each frame. + * Typically things that need to be updated include state, drawing, or position. + * + * Remember to call `super.update` to ensure the base update logic is performed. + * You can then write your own logic for what happens after that. + * + * The [[update]] method is passed an instance of the Excalibur engine, which + * can be used to perform coordinate math or access global state. It is also + * passed `delta` which is the time in milliseconds since the last frame, which can be used + * to perform time-based movement or time-based math (such as a timer). + * + * **TypeScript** + * + * ```ts + * class Player extends Actor { + * public update(engine: ex.Engine, delta: number) { + * super.update(engine, delta); // call base update logic + * + * // check if player died + * if (this.health <= 0) { + * this.emit("death"); + * this.onDeath(); + * return; + * } + * } + * } + * ``` + * + * **Javascript** + * + * ```js + * var Player = ex.Actor.extend({ + * update: function (engine, delta) { + * ex.Actor.prototype.update.call(this, engine, delta); // call base update logic + * + * // check if player died + * if (this.health <= 0) { + * this.emit("death"); + * this.onDeath(); + * return; + * } + * } + * }); + * ``` + * + * ## Drawing actors + * + * Override the [[draw]] method to perform any custom drawing. For simple games, + * you don't need to override `draw`, instead you can use [[addDrawing]] and [[setDrawing]] + * to manipulate the [[Sprite|sprites]]/[[Animation|animations]] that the actor is using. + * + * ### Working with Textures & Sprites + * + * Think of a [[Texture|texture]] as the raw image file that will be loaded into Excalibur. In order for it to be drawn + * it must be converted to a [[Sprite.sprite]]. + * + * A common usage is to load a [[Texture]] and convert it to a [[Sprite]] for an actor. If you are using the [[Loader]] to + * pre-load assets, you can simply assign an actor a [[Sprite]] to draw. You can also create a + * [[Texture.asSprite|sprite from a Texture]] to quickly create a [[Sprite]] instance. + * + * ```ts + * // assume Resources.TxPlayer is a 80x80 png image + * + * public onInitialize(engine: ex.Engine) { + * + * // set as the "default" drawing + * this.addDrawing(Resources.TxPlayer); + * + * // you can also set a Sprite instance to draw + * this.addDrawing(Resources.TxPlayer.asSprite()); + * } + * ``` + * + * ### Working with Animations + * + * A [[SpriteSheet]] holds a collection of sprites from a single [[Texture]]. + * Use [[SpriteSheet.getAnimationForAll]] to easily generate an [[Animation]]. + * + * ```ts + * // assume Resources.TxPlayerIdle is a texture containing several frames of an animation + * + * public onInitialize(engine: ex.Engine) { + * + * // create a SpriteSheet for the animation + * var playerIdleSheet = new ex.SpriteSheet(Resources.TxPlayerIdle, 5, 1, 80, 80); + * + * // create an animation + * var playerIdleAnimation = playerIdleSheet.getAnimationForAll(engine, 120); + * + * // the first drawing is always the current + * this.addDrawing("idle", playerIdleAnimation); + * } + * ``` + * + * ### Custom drawing + * + * You can always override the default drawing logic for an actor in the [[draw]] method, + * for example, to draw complex shapes or to use the raw + * [[https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D|Canvas API]]. + * + * Usually you should call `super.draw` to perform the base drawing logic, but other times + * you may want to take over the drawing completely. + * + * ```ts + * public draw(ctx: Canvas2DRenderingContext, delta: number) { + * + * super.draw(ctx, delta); // perform base drawing logic + * + * // custom drawing + * ctx.lineTo(...); + * } + * ``` + * + * ## Actions * - * Actors implement an EventDispatcher ([[Actor.eventDispatcher]]) so they can - * send and receive events. For example, they can enable Pointer events (mouse/touch) - * and you can respond to them by subscribing to the event names. + * You can use the [[ActionContext|Action API]] to create chains of + * actions and script actors into doing your bidding for your game. * - * You can also emit any other kind of event for your game just by using a custom - * `string` value and implementing a class that inherits from [[GameEvent]]. + * Actions can be simple or can be chained together to create complex + * AI routines. In the future, it will be easier to create timelines or + * scripts to run depending on the state of your actor, such as an + * enemy ship that is Guarding a path and then is Alerted when a Player + * draws near. * - * ```js - * var player = new ex.Actor(...); + * Learn more about the [[ActionContext|Action API]]. * - * // Enable pointer events for this actor - * player.enableCapturePointer = true; + * ## Collision Detection * - * // subscribe to pointerdown event - * player.on("pointerdown", function (evt: ex.Input.PointerEvent) { - * console.log("Player was clicked!"); - * }); + * By default Actors do not participate in collisions. If you wish to make + * an actor participate, you need to switch from the default [[CollisionType.PreventCollision|prevent collision]] + * to [[CollisionType.Active|active]], [[CollisionType.Fixed|fixed]], or [[CollisionType.Passive|passive]] collision type. * - * // turn off subscription - * player.off("pointerdown"); + * ```ts + * public Player extends ex.Actor { + * constructor() { + * super(); + * // set preferred CollisionType + * this.collisionType = ex.CollisionType.Active; + * } + * } * - * // subscribe to custom event - * player.on("death", function (evt) { - * console.log("Player died:", evt); - * }); + * // or set the collisionType * - * // trigger custom event - * player.emit("death", new DeathEvent()); + * var actor = new ex.Actor(); + * actor.collisionType = ex.CollisionType.Active; * * ``` + * ### Collision Groups + * TODO, needs more information. * - * ## Example: Pub/Sub with Excalibur + * ## Traits * - * You can also create an EventDispatcher for any arbitrary object, for example - * a global game event aggregator (`vent`). Anything in your game can subscribe to - * it, if the event aggregator is in the global scope. + * Traits describe actor behavior that occurs every update. If you wish to build a generic behavior + * without needing to extend every actor you can do it with a trait, a good example of this may be + * plugging in an external collision detection library like [[https://github.com/kripken/box2d.js/|Box2D]] or + * [[http://wellcaffeinated.net/PhysicsJS/|PhysicsJS]] by wrapping it in a trait. Removing traits can also make your + * actors more efficient. * - * *Warning:* This can easily get out of hand. Avoid this usage, it just serves as - * an example. + * Default traits provided by Excalibur are [[Traits.CapturePointer|pointer capture]], + * [[Traits.CollisionDetection|tile map collision]], [[Traits.Movement|Euler style movement]], + * and [[Traits.OffscreenCulling|offscreen culling]]. * - * ```js - * // create a publisher on an empty object - * var vent = new ex.EventDispatcher({}); * - * // handler for an event - * var subscription = function (event) { - * console.log(event); - * } + * ## Known Issues * - * // add a subscription - * vent.subscribe("someevent", subscription); + * **Actor bounding boxes do not rotate** + * [Issue #68](https://github.com/excaliburjs/Excalibur/issues/68) * - * // publish an event somewhere in the game - * vent.emit("someevent", new ex.GameEvent()); - * ``` */ - var EventDispatcher = (function () { - /** - * @param target The object that will be the recipient of events from this event dispatcher - */ - function EventDispatcher(target) { - this._handlers = {}; - this._wiredEventDispatchers = []; - this._log = ex.Logger.getInstance(); - this._target = target; - } - /** - * Publish an event for target - * @param eventName The name of the event to publish - * @param event Optionally pass an event data object to the handler - * - * @obsolete Use [[emit]] instead. - */ - EventDispatcher.prototype.publish = function (eventName, event) { - if (!eventName) { - // key not mapped - return; - } - eventName = eventName.toLowerCase(); - var target = this._target; - if (!event) { - event = new ex.GameEvent(); - } - event.target = target; - var i, len; - if (this._handlers[eventName]) { - i = 0; - len = this._handlers[eventName].length; - for (i; i < len; i++) { - this._handlers[eventName][i].call(target, event); - } - } - i = 0; - len = this._wiredEventDispatchers.length; - for (i; i < len; i++) { - this._wiredEventDispatchers[i].emit(eventName, event); - } - }; - /** - * Alias for [[publish]], publishes an event for target - * @param eventName The name of the event to publish - * @param event Optionally pass an event data object to the handler - */ - EventDispatcher.prototype.emit = function (eventName, event) { - this.publish(eventName, event); - }; - /** - * Subscribe an event handler to a particular event name, multiple handlers per event name are allowed. - * @param eventName The name of the event to subscribe to - * @param handler The handler callback to fire on this event - */ - EventDispatcher.prototype.subscribe = function (eventName, handler) { - eventName = eventName.toLowerCase(); - if (!this._handlers[eventName]) { - this._handlers[eventName] = []; - } - this._handlers[eventName].push(handler); - // meta event handlers - if (eventName !== 'unsubscribe' && eventName !== 'subscribe') { - this.emit('subscribe', new ex.SubscribeEvent(eventName, handler)); - } - }; - /** - * Unsubscribe an event handler(s) from an event. If a specific handler - * is specified for an event, only that handler will be unsubscribed. - * Otherwise all handlers will be unsubscribed for that event. - * - * @param eventName The name of the event to unsubscribe - * @param handler Optionally the specific handler to unsubscribe - * - */ - EventDispatcher.prototype.unsubscribe = function (eventName, handler) { - eventName = eventName.toLowerCase(); - var eventHandlers = this._handlers[eventName]; - if (eventHandlers) { - // if no explicit handler is give with the event name clear all handlers - if (!handler) { - this._handlers[eventName].length = 0; - } - else { - var index = eventHandlers.indexOf(handler); - this._handlers[eventName].splice(index, 1); - } - } - // meta event handlers - if (eventName !== 'unsubscribe' && eventName !== 'subscribe') { - this.emit('unsubscribe', new ex.UnsubscribeEvent(eventName, handler)); - } - }; - /** - * Wires this event dispatcher to also recieve events from another - */ - EventDispatcher.prototype.wire = function (eventDispatcher) { - eventDispatcher._wiredEventDispatchers.push(this); - }; + var Actor = (function (_super) { + __extends(Actor, _super); /** - * Unwires this event dispatcher from another + * @param x The starting x coordinate of the actor + * @param y The starting y coordinate of the actor + * @param width The starting width of the actor + * @param height The starting height of the actor + * @param color The starting color of the actor. Leave null to draw a transparent actor. The opacity of the color will be used as the + * initial [[opacity]]. */ - EventDispatcher.prototype.unwire = function (eventDispatcher) { - var index = eventDispatcher._wiredEventDispatchers.indexOf(this); - if (index > -1) { - eventDispatcher._wiredEventDispatchers.splice(index, 1); + function Actor(x, y, width, height, color) { + _super.call(this); + /** + * The unique identifier for the actor + */ + this.id = Actor.maxId++; + /** + * The x coordinate of the actor (middle if anchor is (0.5, 0.5) left edge if anchor is (0, 0)) + */ + this.x = 0; + /** + * The y coordinate of the actor (middle if anchor is (0.5, 0.5) and top edge if anchor is (0, 0)) + */ + this.y = 0; + this._height = 0; + this._width = 0; + /** + * The rotation of the actor in radians + */ + this.rotation = 0; // radians + /** + * The rotational velocity of the actor in radians/second + */ + this.rx = 0; //radions/sec + /** + * The scale vector of the actor + */ + this.scale = new ex.Vector(1, 1); + /** + * The x scalar velocity of the actor in scale/second + */ + this.sx = 0; //scale/sec + /** + * The y scalar velocity of the actor in scale/second + */ + this.sy = 0; //scale/sec + /** + * The x velocity of the actor in pixels/second + */ + this.dx = 0; // pixels/sec + /** + * The x velocity of the actor in pixels/second + */ + this.dy = 0; + /** + * The x acceleration of the actor in pixels/second^2 + */ + this.ax = 0; // pixels/sec/sec + /** + * The y acceleration of the actor in pixels/second^2 + */ + this.ay = 0; + /** + * Indicates whether the actor is physically in the viewport + */ + this.isOffScreen = false; + /** + * The visibility of an actor + */ + this.visible = true; + /** + * The opacity of an actor. Passing in a color in the [[constructor]] will use the + * color's opacity. + */ + this.opacity = 1; + this.previousOpacity = 1; + this.actions = new ex.ActionContext(this); + /** + * Convenience reference to the global logger + */ + this.logger = ex.Logger.getInstance(); + /** + * The scene that the actor is in + */ + this.scene = null; + /** + * The parent of this actor + */ + this.parent = null; + // TODO: Replace this with the new actor collection once z-indexing is built + /** + * The children of this actor + */ + this.children = []; + /** + * Gets or sets the current collision type of this actor. By + * default it is ([[CollisionType.PreventCollision]]). + */ + this.collisionType = CollisionType.PreventCollision; + this.collisionGroups = []; + this._collisionHandlers = {}; + this._isInitialized = false; + this.frames = {}; + /** + * Access to the current drawing for the actor, this can be + * an [[Animation]], [[Sprite]], or [[Polygon]]. + * Set drawings with [[setDrawing]]. + */ + this.currentDrawing = null; + this.centerDrawingX = true; + this.centerDrawingY = true; + /** + * Modify the current actor update pipeline. + */ + this.traits = []; + /** + * Whether or not to enable the [[CapturePointer]] trait that propogates + * pointer events to this actor + */ + this.enableCapturePointer = false; + /** + * Configuration for [[CapturePointer]] trait + */ + this.capturePointer = { + captureMoveEvents: false + }; + this._zIndex = 0; + this._isKilled = false; + this.x = x || 0; + this.y = y || 0; + this._width = width || 0; + this._height = height || 0; + if (color) { + this.color = color.clone(); + // set default opacity of an actor to the color + this.opacity = color.a; } - }; - return EventDispatcher; - })(); - ex.EventDispatcher = EventDispatcher; -})(ex || (ex = {})); -var ex; -(function (ex) { - /** - * Provides standard colors (e.g. [[Color.Black]]) - * but you can also create custom colors using RGB, HSL, or Hex. Also provides - * useful color operations like [[Color.lighten]], [[Color.darken]], and more. - * - * ## Creating colors - * - * ```js - * // RGBA - * new ex.Color(r, g, b, a); - * ex.Color.fromRGB(r, g, b, a); - * - * // HSLA - * ex.Color.fromHSL(h, s, l, a); - * - * // Hex, alpha optional - * ex.Color.fromHex("#000000"); - * ex.Color.fromHex("#000000FF"); - * ``` - * - * ## Working with colors - * - * Since Javascript does not support structs, if you change a color "constant" like [[Color.Black]] - * it will change it across the entire game. You can safely use the color operations - * like [[Color.lighten]] and [[Color.darken]] because they `clone` the color to - * return a new color. However, be aware that this can use up memory if used excessively. - * - * Just be aware that if you directly alter properties (i.e. [[Color.r]], etc.) , this will change it - * for all the code that uses that instance of Color. - */ - var Color = (function () { - /** - * Creates a new instance of Color from an r, g, b, a - * - * @param r The red component of color (0-255) - * @param g The green component of color (0-255) - * @param b The blue component of color (0-255) - * @param a The alpha component of color (0-1.0) - */ - function Color(r, g, b, a) { - this.r = r; - this.g = g; - this.b = b; - this.a = (a != null ? a : 1); + // Build default pipeline + this.traits.push(new ex.Traits.Movement()); + this.traits.push(new ex.Traits.CollisionDetection()); + this.traits.push(new ex.Traits.OffscreenCulling()); + this.traits.push(new ex.Traits.CapturePointer()); + this.actionQueue = new ex.Internal.Actions.ActionQueue(this); + this.anchor = new ex.Point(.5, .5); } /** - * Creates a new instance of Color from an r, g, b, a - * - * @param r The red component of color (0-255) - * @param g The green component of color (0-255) - * @param b The blue component of color (0-255) - * @param a The alpha component of color (0-1.0) + * This is called before the first update of the actor. This method is meant to be + * overridden. This is where initialization of child actors should take place. */ - Color.fromRGB = function (r, g, b, a) { - return new Color(r, g, b, a); + Actor.prototype.onInitialize = function (engine) { + // Override me }; - /** - * Creates a new inscance of Color from a hex string - * - * @param hex CSS color string of the form #ffffff, the alpha component is optional - */ - Color.fromHex = function (hex) { - var hexRegEx = /^#?([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})?$/i; - var match = null; - if (match = hex.match(hexRegEx)) { - var r = parseInt(match[1], 16); - var g = parseInt(match[2], 16); - var b = parseInt(match[3], 16); - var a = 1; - if (match[4]) { - a = parseInt(match[4], 16) / 255; + Actor.prototype._checkForPointerOptIn = function (eventName) { + if (eventName && (eventName.toLowerCase() === 'pointerdown' || + eventName.toLowerCase() === 'pointerdown' || + eventName.toLowerCase() === 'pointermove')) { + this.enableCapturePointer = true; + if (eventName.toLowerCase() === 'pointermove') { + this.capturePointer.captureMoveEvents = true; } - return new Color(r, g, b, a); - } - else { - throw new Error('Invalid hex string: ' + hex); - } - }; - /** - * Creats a new instance of Color from hsla values - * - * @param h Hue is represented [0-1] - * @param s Saturation is represented [0-1] - * @param l Luminance is represented [0-1] - * @param a Alpha is represented [0-1] - */ - Color.fromHSL = function (h, s, l, a) { - if (a === void 0) { a = 1.0; } - var temp = new HSLColor(h, s, l, a); - return temp.toRGBA(); - }; - /** - * Lightens the current color by a specified amount - * - * @param factor The amount to lighten by [0-1] - */ - Color.prototype.lighten = function (factor) { - if (factor === void 0) { factor = 0.1; } - var temp = HSLColor.fromRGBA(this.r, this.g, this.b, this.a); - temp.l += (temp.l * factor); - return temp.toRGBA(); - }; - /** - * Darkens the current color by a specified amount - * - * @param factor The amount to darken by [0-1] - */ - Color.prototype.darken = function (factor) { - if (factor === void 0) { factor = 0.1; } - var temp = HSLColor.fromRGBA(this.r, this.g, this.b, this.a); - temp.l -= (temp.l * factor); - return temp.toRGBA(); - }; - /** - * Saturates the current color by a specified amount - * - * @param factor The amount to saturate by [0-1] - */ - Color.prototype.saturate = function (factor) { - if (factor === void 0) { factor = 0.1; } - var temp = HSLColor.fromRGBA(this.r, this.g, this.b, this.a); - temp.s += (temp.s * factor); - return temp.toRGBA(); - }; - /** - * Desaturates the current color by a specified amount - * - * @param factor The amount to desaturate by [0-1] - */ - Color.prototype.desaturate = function (factor) { - if (factor === void 0) { factor = 0.1; } - var temp = HSLColor.fromRGBA(this.r, this.g, this.b, this.a); - temp.s -= (temp.s * factor); - return temp.toRGBA(); - }; - /** - * Multiplies a color by another, results in a darker color - * - * @param color The other color - */ - Color.prototype.mulitiply = function (color) { - var newR = ((color.r / 255 * this.r / 255) * 255); - var newG = ((color.g / 255 * this.g / 255) * 255); - var newB = ((color.b / 255 * this.b / 255) * 255); - var newA = (color.a * this.a); - return new Color(newR, newG, newB, newA); - }; - /** - * Screens a color by another, results in a lighter color - * - * @param color The other color - */ - Color.prototype.screen = function (color) { - var color1 = color.invert(); - var color2 = color.invert(); - return color1.mulitiply(color2).invert(); - }; - /** - * Inverts the current color - */ - Color.prototype.invert = function () { - return new Color(255 - this.r, 255 - this.g, 255 - this.b, 1.0 - this.a); - }; - /** - * Averages the current color with another - * - * @param color The other color - */ - Color.prototype.average = function (color) { - var newR = (color.r + this.r) / 2; - var newG = (color.g + this.g) / 2; - var newB = (color.b + this.b) / 2; - var newA = (color.a + this.a) / 2; - return new Color(newR, newG, newB, newA); - }; - /** - * Returns a CSS string representation of a color. - */ - Color.prototype.toString = function () { - var result = String(this.r.toFixed(0)) + ', ' + String(this.g.toFixed(0)) + ', ' + String(this.b.toFixed(0)); - if (this.a !== undefined || this.a !== null) { - return 'rgba(' + result + ', ' + String(this.a) + ')'; } - return 'rgb(' + result + ')'; - }; - /** - * Returns a CSS string representation of a color. - */ - Color.prototype.fillStyle = function () { - return this.toString(); - }; - /** - * Returns a clone of the current color. - */ - Color.prototype.clone = function () { - return new Color(this.r, this.g, this.b, this.a); }; /** - * Black (#000000) - */ - Color.Black = Color.fromHex('#000000'); - /** - * White (#FFFFFF) + * Add an event listener. You can listen for a variety of + * events off of the engine; see [[GameEvent]] + * @param eventName Name of the event to listen for + * @param handler Event handler for the thrown event + * @obsolete Use [[on]] instead. */ - Color.White = Color.fromHex('#FFFFFF'); + Actor.prototype.addEventListener = function (eventName, handler) { + this._checkForPointerOptIn(eventName); + _super.prototype.addEventListener.call(this, eventName, handler); + }; /** - * Gray (#808080) + * Alias for `addEventListener`. You can listen for a variety of + * events off of the engine; see [[GameEvent]] + * @param eventName Name of the event to listen for + * @param handler Event handler for the thrown event */ - Color.Gray = Color.fromHex('#808080'); + Actor.prototype.on = function (eventName, handler) { + this._checkForPointerOptIn(eventName); + this.eventDispatcher.subscribe(eventName, handler); + }; /** - * Light gray (#D3D3D3) + * If the current actor is a member of the scene, this will remove + * it from the scene graph. It will no longer be drawn or updated. */ - Color.LightGray = Color.fromHex('#D3D3D3'); + Actor.prototype.kill = function () { + if (this.scene) { + this.scene.remove(this); + this._isKilled = true; + } + else { + this.logger.warn('Cannot kill actor, it was never added to the Scene'); + } + }; /** - * Dark gray (#A9A9A9) + * Indicates wether the actor has been killed. */ - Color.DarkGray = Color.fromHex('#A9A9A9'); + Actor.prototype.isKilled = function () { + return this._isKilled; + }; /** - * Yellow (#FFFF00) + * Adds a child actor to this actor. All movement of the child actor will be + * relative to the parent actor. Meaning if the parent moves the child will + * move with it. + * @param actor The child actor to add */ - Color.Yellow = Color.fromHex('#FFFF00'); + Actor.prototype.add = function (actor) { + actor.collisionType = CollisionType.PreventCollision; + if (ex.Util.addItemToArray(actor, this.children)) { + actor.parent = this; + } + }; /** - * Orange (#FFA500) + * Removes a child actor from this actor. + * @param actor The child actor to remove */ - Color.Orange = Color.fromHex('#FFA500'); + Actor.prototype.remove = function (actor) { + if (ex.Util.removeItemToArray(actor, this.children)) { + actor.parent = null; + } + }; + Actor.prototype.setDrawing = function (key) { + key = key.toString(); + if (this.currentDrawing !== this.frames[key]) { + if (this.frames[key] != null) { + this.frames[key].reset(); + this.currentDrawing = this.frames[key]; + } + else { + ex.Logger.getInstance().error('the specified drawing key \'' + key + '\' does not exist'); + } + } + }; + Actor.prototype.addDrawing = function (args) { + if (arguments.length === 2) { + this.frames[arguments[0]] = arguments[1]; + if (!this.currentDrawing) { + this.currentDrawing = arguments[1]; + } + } + else { + if (arguments[0] instanceof ex.Sprite) { + this.addDrawing('default', arguments[0]); + } + if (arguments[0] instanceof ex.Texture) { + this.addDrawing('default', arguments[0].asSprite()); + } + } + }; /** - * Red (#FF0000) + * Gets the z-index of an actor. The z-index determines the relative order an actor is drawn in. + * Actors with a higher z-index are drawn on top of actors with a lower z-index */ - Color.Red = Color.fromHex('#FF0000'); + Actor.prototype.getZIndex = function () { + return this._zIndex; + }; /** - * Vermillion (#FF5B31) + * Sets the z-index of an actor and updates it in the drawing list for the scene. + * The z-index determines the relative order an actor is drawn in. + * Actors with a higher z-index are drawn on top of actors with a lower z-index + * @param actor The child actor to remove */ - Color.Vermillion = Color.fromHex('#FF5B31'); + Actor.prototype.setZIndex = function (newIndex) { + this.scene.cleanupDrawTree(this); + this._zIndex = newIndex; + this.scene.updateDrawTree(this); + }; /** - * Rose (#FF007F) + * Adds an actor to a collision group. Actors with no named collision groups are + * considered to be in every collision group. + * + * Once in a collision group(s) actors will only collide with other actors in + * that group. + * + * @param name The name of the collision group */ - Color.Rose = Color.fromHex('#FF007F'); + Actor.prototype.addCollisionGroup = function (name) { + this.collisionGroups.push(name); + }; /** - * Magenta (#FF00FF) + * Removes an actor from a collision group. + * @param name The name of the collision group */ - Color.Magenta = Color.fromHex('#FF00FF'); + Actor.prototype.removeCollisionGroup = function (name) { + var index = this.collisionGroups.indexOf(name); + if (index !== -1) { + this.collisionGroups.splice(index, 1); + } + }; /** - * Violet (#7F00FF) + * Get the center point of an actor */ - Color.Violet = Color.fromHex('#7F00FF'); + Actor.prototype.getCenter = function () { + return new ex.Vector(this.x + this.getWidth() / 2 - this.anchor.x * this.getWidth(), this.y + this.getHeight() / 2 - this.anchor.y * this.getHeight()); + }; /** - * Blue (#0000FF) + * Gets the calculated width of an actor, factoring in scale */ - Color.Blue = Color.fromHex('#0000FF'); + Actor.prototype.getWidth = function () { + return this._width * this.scale.x; + }; /** - * Azure (#007FFF) + * Sets the width of an actor, factoring in the current scale */ - Color.Azure = Color.fromHex('#007FFF'); + Actor.prototype.setWidth = function (width) { + this._width = width / this.scale.x; + }; /** - * Cyan (#00FFFF) + * Gets the calculated height of an actor, factoring in scale */ - Color.Cyan = Color.fromHex('#00FFFF'); + Actor.prototype.getHeight = function () { + return this._height * this.scale.y; + }; /** - * Viridian (#59978F) + * Sets the height of an actor, factoring in the current scale */ - Color.Viridian = Color.fromHex('#59978F'); + Actor.prototype.setHeight = function (height) { + this._height = height / this.scale.y; + }; /** - * Green (#00FF00) + * Centers the actor's drawing around the center of the actor's bounding box + * @param center Indicates to center the drawing around the actor */ - Color.Green = Color.fromHex('#00FF00'); + Actor.prototype.setCenterDrawing = function (center) { + this.centerDrawingY = center; + this.centerDrawingX = center; + }; /** - * Chartreuse (#7FFF00) + * Gets the left edge of the actor */ - Color.Chartreuse = Color.fromHex('#7FFF00'); + Actor.prototype.getLeft = function () { + return this.x; + }; /** - * Transparent (#FFFFFF00) + * Gets the right edge of the actor */ - Color.Transparent = Color.fromHex('#FFFFFF00'); - return Color; - })(); - ex.Color = Color; - /** - * Internal HSL Color representation - * - * http://en.wikipedia.org/wiki/HSL_and_HSV - * http://axonflux.com/handy-rgb-to-hsl-and-rgb-to-hsv-color-model-c - */ - var HSLColor = (function () { - function HSLColor(h, s, l, a) { - this.h = h; - this.s = s; - this.l = l; - this.a = a; - } - HSLColor.fromRGBA = function (r, g, b, a) { - r /= 255; - g /= 255; - b /= 255; - var max = Math.max(r, g, b), min = Math.min(r, g, b); - var h, s, l = (max + min) / 2; - if (max === min) { - h = s = 0; // achromatic - } - else { - var d = max - min; - s = l > 0.5 ? d / (2 - max - min) : d / (max + min); - switch (max) { - case r: - h = (g - b) / d + (g < b ? 6 : 0); - break; - case g: - h = (b - r) / d + 2; - break; - case b: - h = (r - g) / d + 4; - break; - } - h /= 6; - } - return new HSLColor(h, s, l, a); + Actor.prototype.getRight = function () { + return this.x + this.getWidth(); }; - HSLColor.prototype.toRGBA = function () { - var r, g, b; - if (this.s === 0) { - r = g = b = this.l; // achromatic - } - else { - function hue2rgb(p, q, t) { - if (t < 0) { - t += 1; - } - if (t > 1) { - t -= 1; - } - if (t < 1 / 6) { - return p + (q - p) * 6 * t; - } - if (t < 1 / 2) { - return q; - } - if (t < 2 / 3) { - return p + (q - p) * (2 / 3 - t) * 6; - } - return p; - } - var q = this.l < 0.5 ? this.l * (1 + this.s) : this.l + this.s - this.l * this.s; - var p = 2 * this.l - q; - r = hue2rgb(p, q, this.h + 1 / 3); - g = hue2rgb(p, q, this.h); - b = hue2rgb(p, q, this.h - 1 / 3); - } - return new Color(r * 255, g * 255, b * 255, this.a); + /** + * Gets the top edge of the actor + */ + Actor.prototype.getTop = function () { + return this.y; }; - return HSLColor; - })(); -})(ex || (ex = {})); -/// -var ex; -(function (ex) { - /** - * Helper [[Actor]] primitive for drawing UI's, optimized for UI drawing. Does - * not participate in collisions. Drawn on top of all other actors. - */ - var UIActor = (function (_super) { - __extends(UIActor, _super); /** - * @param x The starting x coordinate of the actor - * @param y The starting y coordinate of the actor - * @param width The starting width of the actor - * @param height The starting height of the actor + * Gets the bottom edge of the actor */ - function UIActor(x, y, width, height) { - _super.call(this, x, y, width, height); - this.traits = []; - this.traits.push(new ex.Traits.Movement()); - this.traits.push(new ex.Traits.CapturePointer()); - this.anchor.setTo(0, 0); - this.collisionType = ex.CollisionType.PreventCollision; - this.enableCapturePointer = true; - } - UIActor.prototype.onInitialize = function (engine) { - this._engine = engine; + Actor.prototype.getBottom = function () { + return this.y + this.getHeight(); }; - UIActor.prototype.contains = function (x, y, useWorld) { - if (useWorld === void 0) { useWorld = true; } - if (useWorld) { - return _super.prototype.contains.call(this, x, y); + /** + * Gets the x value of the Actor in global coordinates + */ + Actor.prototype.getWorldX = function () { + if (!this.parent) { + return this.x; } - var coords = this._engine.worldToScreenCoordinates(new ex.Point(x, y)); - return _super.prototype.contains.call(this, coords.x, coords.y); + return this.x * this.parent.scale.x + this.parent.getWorldX(); }; - return UIActor; - })(ex.Actor); - ex.UIActor = UIActor; -})(ex || (ex = {})); -/// -/// -var ex; -(function (ex) { - /** - * Triggers - * - * Triggers are a method of firing arbitrary code on collision. These are useful - * as 'buttons', 'switches', or to trigger effects in a game. By default triggers - * are invisible, and can only be seen when [[Engine.isDebug]] is set to `true`. - * - * ## Creating a trigger - * - * ```js - * var game = new ex.Game(); - * - * // create a handler - * function onTrigger() { - * - * // `this` will be the Trigger instance - * ex.Logger.getInstance().info("Trigger was triggered!", this); - * } - * - * // set a trigger at (100, 100) that is 40x40px - * var trigger = new ex.Trigger(100, 100, 40, 40, onTrigger, 1); - * - * // create an actor across from the trigger - * var actor = new ex.Actor(100, 0, 40, 40, ex.Color.Red); - * - * // tell the actor to move towards the trigger over 3 seconds - * actor.moveTo(100, 200, 3000); - * - * game.add(trigger); - * game.add(actor); - * - * game.start(); - * ``` - */ - var Trigger = (function (_super) { - __extends(Trigger, _super); /** - * @param x The x position of the trigger - * @param y The y position of the trigger - * @param width The width of the trigger - * @param height The height of the trigger - * @param action Callback to fire when trigger is activated, `this` will be bound to the Trigger instance - * @param repeats The number of times that this trigger should fire, by default it is 1, if -1 is supplied it will fire indefinitely + * Gets the y value of the Actor in global coordinates */ - function Trigger(x, y, width, height, action, repeats) { - _super.call(this, x, y, width, height); - this._action = function () { return; }; - this.repeats = 1; - this.target = null; - this.repeats = repeats || this.repeats; - this._action = action || this._action; - this.collisionType = ex.CollisionType.PreventCollision; - this.eventDispatcher = new ex.EventDispatcher(this); - this.actionQueue = new ex.Internal.Actions.ActionQueue(this); - } - Trigger.prototype.update = function (engine, delta) { - // Update action queue - this.actionQueue.update(delta); - // Update placements based on linear algebra - this.x += this.dx * delta / 1000; - this.y += this.dy * delta / 1000; - this.rotation += this.rx * delta / 1000; - this.scale.x += this.sx * delta / 1000; - this.scale.y += this.sy * delta / 1000; - // check for trigger collisions - if (this.target) { - if (this.collides(this.target)) { - this._dispatchAction(); - } - } - else { - for (var i = 0; i < engine.currentScene.children.length; i++) { - var other = engine.currentScene.children[i]; - if (other !== this && - other.collisionType !== ex.CollisionType.PreventCollision && - this.collides(other)) { - this._dispatchAction(); - } - } - } - // remove trigger if its done, -1 repeat forever - if (this.repeats === 0) { - this.kill(); + Actor.prototype.getWorldY = function () { + if (!this.parent) { + return this.y; } + return this.y * this.parent.scale.y + this.parent.getWorldY(); }; - Trigger.prototype._dispatchAction = function () { - this._action.call(this); - this.repeats--; - }; - Trigger.prototype.draw = function (ctx, delta) { - // does not draw - return; - }; - Trigger.prototype.debugDraw = function (ctx) { - _super.prototype.debugDraw.call(this, ctx); - // Meant to draw debug information about actors - ctx.save(); - ctx.translate(this.x, this.y); - var bb = this.getBounds(); - bb.left = bb.left - this.getWorldX(); - bb.right = bb.right - this.getWorldX(); - bb.top = bb.top - this.getWorldY(); - bb.bottom = bb.bottom - this.getWorldY(); - // Currently collision primitives cannot rotate - // ctx.rotate(this.rotation); - ctx.fillStyle = ex.Color.Violet.toString(); - ctx.strokeStyle = ex.Color.Violet.toString(); - ctx.fillText('Trigger', 10, 10); - bb.debugDraw(ctx); - ctx.restore(); + /** + * Gets the global scale of the Actor + */ + Actor.prototype.getGlobalScale = function () { + if (!this.parent) { + return new ex.Point(this.scale.x, this.scale.y); + } + var parentScale = this.parent.getGlobalScale(); + return new ex.Point(this.scale.x * parentScale.x, this.scale.y * parentScale.y); }; - return Trigger; - })(ex.Actor); - ex.Trigger = Trigger; -})(ex || (ex = {})); -/// -/// -/// -/// -var ex; -(function (ex) { - /** - * An enum that represents the types of emitter nozzles - */ - (function (EmitterType) { /** - * Constant for the circular emitter type + * Returns the actor's [[BoundingBox]] calculated for this instant. */ - EmitterType[EmitterType["Circle"] = 0] = "Circle"; + Actor.prototype.getBounds = function () { + var anchor = this._getCalculatedAnchor(); + return new ex.BoundingBox(this.getWorldX() - anchor.x, this.getWorldY() - anchor.y, this.getWorldX() + this.getWidth() - anchor.x, this.getWorldY() + this.getHeight() - anchor.y); + }; /** - * Constant for the rectangular emitter type + * Tests whether the x/y specified are contained in the actor + * @param x X coordinate to test (in world coordinates) + * @param y Y coordinate to test (in world coordinates) + * @param recurse checks whether the x/y are contained in any child actors (if they exist). */ - EmitterType[EmitterType["Rectangle"] = 1] = "Rectangle"; - })(ex.EmitterType || (ex.EmitterType = {})); - var EmitterType = ex.EmitterType; - /** - * Particle is used in a [[ParticleEmitter]] - */ - var Particle = (function () { - function Particle(emitter, life, opacity, beginColor, endColor, position, velocity, acceleration, startSize, endSize) { - this.position = new ex.Vector(0, 0); - this.velocity = new ex.Vector(0, 0); - this.acceleration = new ex.Vector(0, 0); - this.particleRotationalVelocity = 0; - this.currentRotation = 0; - this.focus = null; - this.focusAccel = 0; - this.opacity = 1; - this.beginColor = ex.Color.White.clone(); - this.endColor = ex.Color.White.clone(); - // Life is counted in ms - this.life = 300; - this.fadeFlag = false; - // Color transitions - this._rRate = 1; - this._gRate = 1; - this._bRate = 1; - this._aRate = 0; - this._currentColor = ex.Color.White.clone(); - this.emitter = null; - this.particleSize = 5; - this.particleSprite = null; - this.sizeRate = 0; - this.elapsedMultiplier = 0; - this.emitter = emitter; - this.life = life || this.life; - this.opacity = opacity || this.opacity; - this.endColor = endColor || this.endColor.clone(); - this.beginColor = beginColor || this.beginColor.clone(); - this._currentColor = this.beginColor.clone(); - this.position = position || this.position; - this.velocity = velocity || this.velocity; - this.acceleration = acceleration || this.acceleration; - this._rRate = (this.endColor.r - this.beginColor.r) / this.life; - this._gRate = (this.endColor.g - this.beginColor.g) / this.life; - this._bRate = (this.endColor.b - this.beginColor.b) / this.life; - this._aRate = this.opacity / this.life; - this.startSize = startSize || 0; - this.endSize = endSize || 0; - if ((this.endSize > 0) && (this.startSize > 0)) { - this.sizeRate = (this.endSize - this.startSize) / this.life; - this.particleSize = this.startSize; + Actor.prototype.contains = function (x, y, recurse) { + if (recurse === void 0) { recurse = false; } + var containment = this.getBounds().contains(new ex.Point(x, y)); + if (recurse) { + return containment || this.children.some(function (child) { + return child.contains(x, y, true); + }); } - } - Particle.prototype.kill = function () { - this.emitter.removeParticle(this); + return containment; }; - Particle.prototype.update = function (delta) { - this.life = this.life - delta; - this.elapsedMultiplier = this.elapsedMultiplier + delta; - if (this.life < 0) { - this.kill(); - } - if (this.fadeFlag) { - this.opacity = ex.Util.clamp(this._aRate * this.life, 0.0001, 1); + /** + * Returns the side of the collision based on the intersection + * @param intersect The displacement vector returned by a collision + */ + Actor.prototype.getSideFromIntersect = function (intersect) { + if (intersect) { + if (Math.abs(intersect.x) > Math.abs(intersect.y)) { + if (intersect.x < 0) { + return ex.Side.Right; + } + return ex.Side.Left; + } + else { + if (intersect.y < 0) { + return ex.Side.Bottom; + } + return ex.Side.Top; + } } - if ((this.startSize > 0) && (this.endSize > 0)) { - this.particleSize = ex.Util.clamp(this.sizeRate * delta + this.particleSize, Math.min(this.startSize, this.endSize), Math.max(this.startSize, this.endSize)); + return ex.Side.None; + }; + /** + * Test whether the actor has collided with another actor, returns the side of the current actor that collided. + * @param actor The other actor to test + */ + Actor.prototype.collidesWithSide = function (actor) { + var separationVector = this.collides(actor); + if (!separationVector) { + return ex.Side.None; } - this._currentColor.r = ex.Util.clamp(this._currentColor.r + this._rRate * delta, 0, 255); - this._currentColor.g = ex.Util.clamp(this._currentColor.g + this._gRate * delta, 0, 255); - this._currentColor.b = ex.Util.clamp(this._currentColor.b + this._bRate * delta, 0, 255); - this._currentColor.a = ex.Util.clamp(this.opacity, 0.0001, 1); - if (this.focus) { - var accel = this.focus.minus(this.position).normalize().scale(this.focusAccel).scale(delta / 1000); - this.velocity = this.velocity.add(accel); + if (Math.abs(separationVector.x) > Math.abs(separationVector.y)) { + if (this.x < actor.x) { + return ex.Side.Right; + } + else { + return ex.Side.Left; + } } else { - this.velocity = this.velocity.add(this.acceleration.scale(delta / 1000)); - } - this.position = this.position.add(this.velocity.scale(delta / 1000)); - if (this.particleRotationalVelocity) { - this.currentRotation = (this.currentRotation + this.particleRotationalVelocity * delta / 1000) % (2 * Math.PI); + if (this.y < actor.y) { + return ex.Side.Bottom; + } + else { + return ex.Side.Top; + } } + return ex.Side.None; }; - Particle.prototype.draw = function (ctx) { - if (this.particleSprite) { - this.particleSprite.rotation = this.currentRotation; - this.particleSprite.scale.setTo(this.particleSize, this.particleSize); - this.particleSprite.draw(ctx, this.position.x, this.position.y); - return; - } - this._currentColor.a = ex.Util.clamp(this.opacity, 0.0001, 1); - ctx.fillStyle = this._currentColor.toString(); - ctx.beginPath(); - ctx.arc(this.position.x, this.position.y, this.particleSize, 0, Math.PI * 2); - ctx.fill(); - ctx.closePath(); + /** + * Test whether the actor has collided with another actor, returns the intersection vector on collision. Returns + * `null` when there is no collision; + * @param actor The other actor to test + */ + Actor.prototype.collides = function (actor) { + var bounds = this.getBounds(); + var otherBounds = actor.getBounds(); + var intersect = bounds.collides(otherBounds); + return intersect; }; - return Particle; - })(); - ex.Particle = Particle; - /** - * Particle Emitters - * - * Using a particle emitter is a great way to create interesting effects - * in your game, like smoke, fire, water, explosions, etc. `ParticleEmitter` - * extend [[Actor]] allowing you to use all of the features that come with. - * - * The easiest way to create a `ParticleEmitter` is to use the - * [Particle Tester](http://excaliburjs.com/particle-tester/). - * - * ## Example: Adding an emitter - * - * ```js - * var actor = new ex.Actor(...); - * var emitter = new ex.ParticleEmitter(...); - * - * // set emitter settings - * emitter.isEmitting = true; - * - * // add the emitter as a child actor, it will draw on top of the parent actor - * // and move with the parent - * actor.add(emitter); - * - * // or, alternatively, add it to the current scene - * engine.add(emitter); - * ``` - */ - var ParticleEmitter = (function (_super) { - __extends(ParticleEmitter, _super); /** - * @param x The x position of the emitter - * @param y The y position of the emitter - * @param width The width of the emitter - * @param height The height of the emitter + * Register a handler to fire when this actor collides with another in a specified group + * @param group The group name to listen for + * @param func The callback to fire on collision with another actor from the group. The callback is passed the other actor. */ - function ParticleEmitter(x, y, width, height) { - _super.call(this, x, y, width, height, ex.Color.White); - this._particlesToEmit = 0; - this.numParticles = 0; - /** - * Gets or sets the isEmitting flag - */ - this.isEmitting = true; - /** - * Gets or sets the backing particle collection - */ - this.particles = null; - /** - * Gets or sets the backing deadParticle collection - */ - this.deadParticles = null; - /** - * Gets or sets the minimum partical velocity - */ - this.minVel = 0; - /** - * Gets or sets the maximum partical velocity - */ - this.maxVel = 0; - /** - * Gets or sets the acceleration vector for all particles - */ - this.acceleration = new ex.Vector(0, 0); - /** - * Gets or sets the minimum angle in radians - */ - this.minAngle = 0; - /** - * Gets or sets the maximum angle in radians - */ - this.maxAngle = 0; - /** - * Gets or sets the emission rate for particles (particles/sec) - */ - this.emitRate = 1; //particles/sec - /** - * Gets or sets the life of each particle in milliseconds - */ - this.particleLife = 2000; - /** - * Gets or sets the opacity of each particle from 0 to 1.0 - */ - this.opacity = 1; - /** - * Gets or sets the fade flag which causes particles to gradually fade out over the course of their life. - */ - this.fadeFlag = false; - /** - * Gets or sets the optional focus where all particles should accelerate towards - */ - this.focus = null; - /** - * Gets or sets the acceleration for focusing particles if a focus has been specified - */ - this.focusAccel = 1; - /* - * Gets or sets the optional starting size for the particles - */ - this.startSize = null; - /* - * Gets or sets the optional ending size for the particles - */ - this.endSize = null; - /** - * Gets or sets the minimum size of all particles - */ - this.minSize = 5; - /** - * Gets or sets the maximum size of all particles - */ - this.maxSize = 5; - /** - * Gets or sets the beginning color of all particles - */ - this.beginColor = ex.Color.White; - /** - * Gets or sets the ending color of all particles - */ - this.endColor = ex.Color.White; - /** - * Gets or sets the sprite that a particle should use - * @warning Performance intensive - */ - this.particleSprite = null; - /** - * Gets or sets the emitter type for the particle emitter - */ - this.emitterType = EmitterType.Rectangle; - /** - * Gets or sets the emitter radius, only takes effect when the [[emitterType]] is [[EmitterType.Circle]] - */ - this.radius = 0; - /** - * Gets or sets the particle rotational speed velocity - */ - this.particleRotationalVelocity = 0; - /** - * Indicates whether particles should start with a random rotation - */ - this.randomRotation = false; - this.collisionType = ex.CollisionType.PreventCollision; - this.particles = new ex.Util.Collection(); - this.deadParticles = new ex.Util.Collection(); - // Remove offscreen culling from particle emitters - for (var trait in this.traits) { - if (this.traits[trait] instanceof ex.Traits.OffscreenCulling) { - this.traits.splice(trait, 1); - } + Actor.prototype.onCollidesWith = function (group, func) { + if (!this._collisionHandlers[group]) { + this._collisionHandlers[group] = []; } - } - ParticleEmitter.prototype.removeParticle = function (particle) { - this.deadParticles.push(particle); + this._collisionHandlers[group].push(func); + }; + Actor.prototype.getCollisionHandlers = function () { + return this._collisionHandlers; + }; + /** + * Removes all collision handlers for this group on this actor + * @param group Group to remove all handlers for on this actor. + */ + Actor.prototype.removeCollidesWith = function (group) { + this._collisionHandlers[group] = []; }; /** - * Causes the emitter to emit particles - * @param particleCount Number of particles to emit right now + * Returns true if the two actors are less than or equal to the distance specified from each other + * @param actor Actor to test + * @param distance Distance in pixels to test */ - ParticleEmitter.prototype.emitParticles = function (particleCount) { - for (var i = 0; i < particleCount; i++) { - this.particles.push(this._createParticle()); - } + Actor.prototype.within = function (actor, distance) { + return Math.sqrt(Math.pow(this.x - actor.x, 2) + Math.pow(this.y - actor.y, 2)) <= distance; }; - ParticleEmitter.prototype.clearParticles = function () { - this.particles.clear(); + /** + * Clears all queued actions from the Actor + * @obsolete Use [[ActionContext.clearActions|Actor.actions.clearActions]] + */ + Actor.prototype.clearActions = function () { + this.actionQueue.clearActions(); }; - // Creates a new particle given the contraints of the emitter - ParticleEmitter.prototype._createParticle = function () { - // todo implement emitter contraints; - var ranX = 0; - var ranY = 0; - var angle = ex.Util.randomInRange(this.minAngle, this.maxAngle); - var vel = ex.Util.randomInRange(this.minVel, this.maxVel); - var size = this.startSize || ex.Util.randomInRange(this.minSize, this.maxSize); - var dx = vel * Math.cos(angle); - var dy = vel * Math.sin(angle); - if (this.emitterType === EmitterType.Rectangle) { - ranX = ex.Util.randomInRange(this.x, this.x + this.getWidth()); - ranY = ex.Util.randomInRange(this.y, this.y + this.getHeight()); - } - else if (this.emitterType === EmitterType.Circle) { - var radius = ex.Util.randomInRange(0, this.radius); - ranX = radius * Math.cos(angle) + this.x; - ranY = radius * Math.sin(angle) + this.y; - } - var p = new Particle(this, this.particleLife, this.opacity, this.beginColor, this.endColor, new ex.Vector(ranX, ranY), new ex.Vector(dx, dy), this.acceleration, this.startSize, this.endSize); - p.fadeFlag = this.fadeFlag; - p.particleSize = size; - if (this.particleSprite) { - p.particleSprite = this.particleSprite; - } - p.particleRotationalVelocity = this.particleRotationalVelocity; - if (this.randomRotation) { - p.currentRotation = ex.Util.randomInRange(0, Math.PI * 2); - } - if (this.focus) { - p.focus = this.focus.add(new ex.Vector(this.x, this.y)); - p.focusAccel = this.focusAccel; - } - return p; + /** + * This method will move an actor to the specified `x` and `y` position over the + * specified duration using a given [[EasingFunctions]] and return back the actor. This + * method is part of the actor 'Action' fluent API allowing action chaining. + * @param x The x location to move the actor to + * @param y The y location to move the actor to + * @param duration The time it should take the actor to move to the new location in milliseconds + * @param easingFcn Use [[EasingFunctions]] or a custom function to use to calculate position + * @obsolete Use [[ActionContext.easeTo|Actor.actions.easeTo]] + */ + Actor.prototype.easeTo = function (x, y, duration, easingFcn) { + if (easingFcn === void 0) { easingFcn = ex.EasingFunctions.Linear; } + this.actionQueue.add(new ex.Internal.Actions.EaseTo(this, x, y, duration, easingFcn)); + return this; }; - ParticleEmitter.prototype.update = function (engine, delta) { - var _this = this; - _super.prototype.update.call(this, engine, delta); - if (this.isEmitting) { - this._particlesToEmit += this.emitRate * (delta / 1000); - //var numParticles = Math.ceil(this.emitRate * delta / 1000); - if (this._particlesToEmit > 1.0) { - this.emitParticles(Math.floor(this._particlesToEmit)); - this._particlesToEmit = this._particlesToEmit - Math.floor(this._particlesToEmit); - } - } - this.particles.forEach(function (p) { return p.update(delta); }); - this.deadParticles.forEach(function (p) { return _this.particles.removeElement(p); }); - this.deadParticles.clear(); + /** + * This method will move an actor to the specified `x` and `y` position at the + * `speed` specified (in pixels per second) and return back the actor. This + * method is part of the actor 'Action' fluent API allowing action chaining. + * @param x The x location to move the actor to + * @param y The y location to move the actor to + * @param speed The speed in pixels per second to move + * @obsolete Use [[ActionContext.moveTo|Actor.actions.moveTo]] + */ + Actor.prototype.moveTo = function (x, y, speed) { + this.actionQueue.add(new ex.Internal.Actions.MoveTo(this, x, y, speed)); + return this; }; - ParticleEmitter.prototype.draw = function (ctx, delta) { - // todo is there a more efficient to draw - // possibly use a webgl offscreen canvas and shaders to do particles? - this.particles.forEach(function (p) { return p.draw(ctx); }); + /** + * This method will move an actor to the specified `x` and `y` position by a + * certain `duration` (in milliseconds). This method is part of the actor + * 'Action' fluent API allowing action chaining. + * @param x The x location to move the actor to + * @param y The y location to move the actor to + * @param duration The time it should take the actor to move to the new location in milliseconds + * @obsolete Use [[ActionContext.moveBy|Actor.actions.moveBy]] + */ + Actor.prototype.moveBy = function (x, y, duration) { + this.actionQueue.add(new ex.Internal.Actions.MoveBy(this, x, y, duration)); + return this; }; - ParticleEmitter.prototype.debugDraw = function (ctx) { - _super.prototype.debugDraw.call(this, ctx); - ctx.fillStyle = ex.Color.Black.toString(); - ctx.fillText('Particles: ' + this.particles.count(), this.x, this.y + 20); - if (this.focus) { - ctx.fillRect(this.focus.x + this.x, this.focus.y + this.y, 3, 3); - ex.Util.drawLine(ctx, 'yellow', this.focus.x + this.x, this.focus.y + this.y, _super.prototype.getCenter.call(this).x, _super.prototype.getCenter.call(this).y); - ctx.fillText('Focus', this.focus.x + this.x, this.focus.y + this.y); - } + /** + * This method will rotate an actor to the specified angle (in radians) at the `speed` + * specified (in radians per second) and return back the actor. This + * method is part of the actor 'Action' fluent API allowing action chaining. + * @param angleRadians The angle to rotate to in radians + * @param speed The angular velocity of the rotation specified in radians per second + * @obsolete Use [[ActionContext.rotateTo|Actor.actions.rotateTo]] + */ + Actor.prototype.rotateTo = function (angleRadians, speed, rotationType) { + this.actionQueue.add(new ex.Internal.Actions.RotateTo(this, angleRadians, speed, rotationType)); + return this; }; - return ParticleEmitter; - })(ex.Actor); - ex.ParticleEmitter = ParticleEmitter; -})(ex || (ex = {})); -var ex; -(function (ex) { - /** - * Animations - * - * Animations allow you to display a series of images one after another, - * creating the illusion of change. Generally these images will come from a [[SpriteSheet]] source. - * - * ## Creating an animation - * - * Create a [[Texture]] that contains the frames of your animation. Once the texture - * is [[Loader|loaded]], you can then generate an [[Animation]] by creating a [[SpriteSheet]] - * and using [[SpriteSheet.getAnimationForAll]]. - * - * ```js - * var game = new ex.Engine(); - * var txAnimPlayerIdle = new ex.Texture("/assets/tx/anim-player-idle.png"); - * - * // load assets - * var loader = new ex.Loader(txAnimPlayerIdle); - * - * // start game - * game.start(loader).then(function () { - * var player = new ex.Actor(); - * - * // create sprite sheet with 5 columns, 1 row, 80x80 frames - * var playerIdleSheet = new ex.SpriteSheet(txAnimPlayerIdle, 5, 1, 80, 80); - * - * // create animation (125ms frame speed) - * var playerIdleAnimation = playerIdleSheet.getAnimationForAll(game, 125); - * - * // add drawing to player as "idle" - * player.addDrawing("idle", playerIdleAnimation); - * - * // add player to game - * game.add(player); - * }); - * ``` - * - * ## Sprite effects - * - * You can add [[SpriteEffect|sprite effects]] to an animation through methods - * like [[Animation.invert]] or [[Animation.lighten]]. Keep in mind, since this - * manipulates the raw pixel values of a [[Sprite]], it can have a performance impact. - */ - var Animation = (function () { /** - * Typically you will use a [[SpriteSheet]] to generate an [[Animation]]. - * - * @param engine Reference to the current game engine - * @param images An array of sprites to create the frames for the animation - * @param speed The number in milliseconds to display each frame in the animation - * @param loop Indicates whether the animation should loop after it is completed + * This method will rotate an actor to the specified angle by a certain + * `duration` (in milliseconds) and return back the actor. This method is part + * of the actor 'Action' fluent API allowing action chaining. + * @param angleRadians The angle to rotate to in radians + * @param duration The time it should take the actor to complete the rotation in milliseconds + * @obsolete Use [[ActionContext.rotateBy|ex.Actor.actions.rotateBy]] */ - function Animation(engine, images, speed, loop) { - /** - * Current frame index being shown - */ - this.currentFrame = 0; - this._oldTime = Date.now(); - this.anchor = new ex.Point(0.0, 0.0); - this.rotation = 0.0; - this.scale = new ex.Point(1, 1); - /** - * Indicates whether the animation should loop after it is completed - */ - this.loop = false; - /** - * Indicates the frame index the animation should freeze on for a non-looping - * animation. By default it is the last frame. - */ - this.freezeFrame = -1; - /** - * Flip each frame vertically. Sets [[Sprite.flipVertical]]. - */ - this.flipVertical = false; - /** - * Flip each frame horizontally. Sets [[Sprite.flipHorizontal]]. - */ - this.flipHorizontal = false; - this.width = 0; - this.height = 0; - this.naturalWidth = 0; - this.naturalHeight = 0; - this.sprites = images; - this.speed = speed; - this._engine = engine; - if (loop != null) { - this.loop = loop; - } - if (images && images[0]) { - this.height = images[0] ? images[0].height : 0; - this.width = images[0] ? images[0].width : 0; - this.naturalWidth = images[0] ? images[0].naturalWidth : 0; - this.naturalHeight = images[0] ? images[0].naturalHeight : 0; - this.freezeFrame = images.length - 1; - } - } + Actor.prototype.rotateBy = function (angleRadians, duration, rotationType) { + this.actionQueue.add(new ex.Internal.Actions.RotateBy(this, angleRadians, duration, rotationType)); + return this; + }; /** - * Applies the opacity effect to a sprite, setting the alpha of all pixels to a given value + * This method will scale an actor to the specified size at the speed + * specified (in magnitude increase per second) and return back the + * actor. This method is part of the actor 'Action' fluent API allowing + * action chaining. + * @param sizeX The scaling factor in the x direction to apply + * @param sizeY The scaling factor in the y direction to apply + * @param speedX The speed of scaling in the x direction specified in magnitude increase per second + * @param speedY The speed of scaling in the y direction specified in magnitude increase per second + * @obsolete Use [[ActionContext.scaleTo|Actor.actions.scaleTo]] + */ + Actor.prototype.scaleTo = function (sizeX, sizeY, speedX, speedY) { + this.actionQueue.add(new ex.Internal.Actions.ScaleTo(this, sizeX, sizeY, speedX, speedY)); + return this; + }; + /** + * This method will scale an actor to the specified size by a certain duration + * (in milliseconds) and return back the actor. This method is part of the + * actor 'Action' fluent API allowing action chaining. + * @param sizeX The scaling factor in the x direction to apply + * @param sizeY The scaling factor in the y direction to apply + * @param duration The time it should take to complete the scaling in milliseconds + * @obsolete Use [[ActionContext.scaleBy|Actor.actions.scaleBy]] */ - Animation.prototype.opacity = function (value) { - this.addEffect(new ex.Effects.Opacity(value)); + Actor.prototype.scaleBy = function (sizeX, sizeY, duration) { + this.actionQueue.add(new ex.Internal.Actions.ScaleBy(this, sizeX, sizeY, duration)); + return this; }; /** - * Applies the grayscale effect to a sprite, removing color information. + * This method will cause an actor to blink (become visible and not + * visible). Optionally, you may specify the number of blinks. Specify the amount of time + * the actor should be visible per blink, and the amount of time not visible. + * This method is part of the actor 'Action' fluent API allowing action chaining. + * @param timeVisible The amount of time to stay visible per blink in milliseconds + * @param timeNotVisible The amount of time to stay not visible per blink in milliseconds + * @param numBlinks The number of times to blink + * @obsolete Use [[ActionContext.blink|Actor.actions.blink]] */ - Animation.prototype.grayscale = function () { - this.addEffect(new ex.Effects.Grayscale()); + Actor.prototype.blink = function (timeVisible, timeNotVisible, numBlinks) { + if (numBlinks === void 0) { numBlinks = 1; } + this.actionQueue.add(new ex.Internal.Actions.Blink(this, timeVisible, timeNotVisible, numBlinks)); + return this; }; /** - * Applies the invert effect to a sprite, inverting the pixel colors. + * This method will cause an actor's opacity to change from its current value + * to the provided value by a specified `duration` (in milliseconds). This method is + * part of the actor 'Action' fluent API allowing action chaining. + * @param opacity The ending opacity + * @param duration The time it should take to fade the actor (in milliseconds) + * @obsolete Use [[ActionContext.fade|Actor.actions.fade]] */ - Animation.prototype.invert = function () { - this.addEffect(new ex.Effects.Invert()); + Actor.prototype.fade = function (opacity, duration) { + this.actionQueue.add(new ex.Internal.Actions.Fade(this, opacity, duration)); + return this; }; /** - * Applies the fill effect to a sprite, changing the color channels of all non-transparent pixels to match a given color + * This method will delay the next action from executing for the specified + * `duration` (in milliseconds). This method is part of the actor + * 'Action' fluent API allowing action chaining. + * @param duration The amount of time to delay the next action in the queue from executing in milliseconds + * @obsolete Use [[ActionContext.delay|Actor.actions.delay]] */ - Animation.prototype.fill = function (color) { - this.addEffect(new ex.Effects.Fill(color)); + Actor.prototype.delay = function (duration) { + this.actionQueue.add(new ex.Internal.Actions.Delay(this, duration)); + return this; }; /** - * Applies the colorize effect to a sprite, changing the color channels of all pixesl to be the average of the original color and the - * provided color. + * This method will add an action to the queue that will remove the actor from the + * scene once it has completed its previous actions. Any actions on the + * action queue after this action will not be executed. + * @obsolete Use [[ActionContext.die|Actor.actions.die]] */ - Animation.prototype.colorize = function (color) { - this.addEffect(new ex.Effects.Colorize(color)); + Actor.prototype.die = function () { + this.actionQueue.add(new ex.Internal.Actions.Die(this)); + return this; }; /** - * Applies the lighten effect to a sprite, changes the lightness of the color according to hsl + * This method allows you to call an arbitrary method as the next action in the + * action queue. This is useful if you want to execute code in after a specific + * action, i.e An actor arrives at a destination after traversing a path + * @obsolete Use [[ActionContext.callMethod|Actor.actions.callMethod]] */ - Animation.prototype.lighten = function (factor) { - if (factor === void 0) { factor = 0.1; } - this.addEffect(new ex.Effects.Lighten(factor)); + Actor.prototype.callMethod = function (method) { + this.actionQueue.add(new ex.Internal.Actions.CallMethod(this, method)); + return this; }; /** - * Applies the darken effect to a sprite, changes the darkness of the color according to hsl + * This method will cause the actor to repeat all of the previously + * called actions a certain number of times. If the number of repeats + * is not specified it will repeat forever. This method is part of + * the actor 'Action' fluent API allowing action chaining + * @param times The number of times to repeat all the previous actions in the action queue. If nothing is specified the actions will + * repeat forever + * @obsolete Use [[ActionContext.repeat|Actor.actions.repeat]] */ - Animation.prototype.darken = function (factor) { - if (factor === void 0) { factor = 0.1; } - this.addEffect(new ex.Effects.Darken(factor)); + Actor.prototype.repeat = function (times) { + if (!times) { + this.repeatForever(); + return this; + } + this.actionQueue.add(new ex.Internal.Actions.Repeat(this, times, this.actionQueue.getActions())); + return this; }; /** - * Applies the saturate effect to a sprite, saturates the color acccording to hsl + * This method will cause the actor to repeat all of the previously + * called actions forever. This method is part of the actor 'Action' + * fluent API allowing action chaining. + * @obsolete Use [[ActionContext.repeatForever|Actor.actions.repeatForever]] */ - Animation.prototype.saturate = function (factor) { - if (factor === void 0) { factor = 0.1; } - this.addEffect(new ex.Effects.Saturate(factor)); + Actor.prototype.repeatForever = function () { + this.actionQueue.add(new ex.Internal.Actions.RepeatForever(this, this.actionQueue.getActions())); + return this; }; /** - * Applies the desaturate effect to a sprite, desaturates the color acccording to hsl + * This method will cause the actor to follow another at a specified distance + * @param actor The actor to follow + * @param followDistance The distance to maintain when following, if not specified the actor will follow at the current distance. + * @obsolete Use [[ActionContext.follow|Actor.actions.follow]] */ - Animation.prototype.desaturate = function (factor) { - if (factor === void 0) { factor = 0.1; } - this.addEffect(new ex.Effects.Desaturate(factor)); + Actor.prototype.follow = function (actor, followDistance) { + if (typeof followDistance === 'undefined') { + this.actionQueue.add(new ex.Internal.Actions.Follow(this, actor)); + } + else { + this.actionQueue.add(new ex.Internal.Actions.Follow(this, actor, followDistance)); + } + return this; }; /** - * Add a [[ISpriteEffect]] manually + * This method will cause the actor to move towards another Actor until they + * collide ("meet") at a specified speed. + * @param actor The actor to meet + * @param speed The speed in pixels per second to move, if not specified it will match the speed of the other actor + * @obsolete Use [[ActionContext.meet|Actor.actions.meet]] */ - Animation.prototype.addEffect = function (effect) { - for (var i in this.sprites) { - this.sprites[i].addEffect(effect); + Actor.prototype.meet = function (actor, speed) { + if (typeof speed === 'undefined') { + this.actionQueue.add(new ex.Internal.Actions.Meet(this, actor)); } - }; - Animation.prototype.removeEffect = function (param) { - for (var i in this.sprites) { - this.sprites[i].removeEffect(param); + else { + this.actionQueue.add(new ex.Internal.Actions.Meet(this, actor, speed)); } + return this; }; /** - * Clear all sprite effects + * Returns a promise that resolves when the current action queue up to now + * is finished. + * @obsolete Use [[ActionContext.asPromise|Actor.actions.asPromise]] */ - Animation.prototype.clearEffects = function () { - for (var i in this.sprites) { - this.sprites[i].clearEffects(); - } + Actor.prototype.asPromise = function () { + var complete = new ex.Promise(); + this.callMethod(function () { + complete.resolve(); + }); + return complete; }; - Animation.prototype._setAnchor = function (point) { - //if (!this.anchor.equals(point)) { - for (var i in this.sprites) { - this.sprites[i].anchor.setTo(point.x, point.y); + Actor.prototype._getCalculatedAnchor = function () { + return new ex.Point(this.getWidth() * this.anchor.x, this.getHeight() * this.anchor.y); + }; + /** + * Called by the Engine, updates the state of the actor + * @param engine The reference to the current game engine + * @param delta The time elapsed since the last update in milliseconds + */ + Actor.prototype.update = function (engine, delta) { + if (!this._isInitialized) { + this.onInitialize(engine); + this.eventDispatcher.emit('initialize', new ex.InitializeEvent(engine)); + this._isInitialized = true; } - //} + this.emit('preupdate', new ex.PreUpdateEvent(engine, delta, this)); + var eventDispatcher = this.eventDispatcher; + // Update action queue + this.actionQueue.update(delta); + // Update color only opacity + if (this.color) { + this.color.a = this.opacity; + } + // Update actor pipeline (movement, collision detection, event propagation, offscreen culling) + for (var i = 0; i < this.traits.length; i++) { + this.traits[i].update(this, engine, delta); + } + eventDispatcher.emit('update', new ex.UpdateEvent(delta)); + this.emit('postupdate', new ex.PostUpdateEvent(engine, delta, this)); }; - Animation.prototype._setRotation = function (radians) { - //if (this.rotation !== radians) { - for (var i in this.sprites) { - this.sprites[i].rotation = radians; + /** + * Called by the Engine, draws the actor to the screen + * @param ctx The rendering context + * @param delta The time since the last draw in milliseconds + */ + Actor.prototype.draw = function (ctx, delta) { + var anchorPoint = this._getCalculatedAnchor(); + ctx.save(); + ctx.translate(this.x, this.y); + ctx.scale(this.scale.x, this.scale.y); + ctx.rotate(this.rotation); + this.emit('predraw', new ex.PreDrawEvent(ctx, delta, this)); + // calculate changing opacity + if (this.previousOpacity !== this.opacity) { + for (var drawing in this.frames) { + this.frames[drawing].addEffect(new ex.Effects.Opacity(this.opacity)); + } + this.previousOpacity = this.opacity; } - //} + if (this.currentDrawing) { + var xDiff = 0; + var yDiff = 0; + if (this.centerDrawingX) { + xDiff = (this.currentDrawing.naturalWidth * this.currentDrawing.scale.x - this.getWidth()) / 2 - + this.currentDrawing.naturalWidth * this.currentDrawing.scale.x * this.currentDrawing.anchor.x; + } + if (this.centerDrawingY) { + yDiff = (this.currentDrawing.naturalHeight * this.currentDrawing.scale.y - this.getHeight()) / 2 - + this.currentDrawing.naturalHeight * this.currentDrawing.scale.y * this.currentDrawing.anchor.y; + } + this.currentDrawing.draw(ctx, -anchorPoint.x - xDiff, -anchorPoint.y - yDiff); + } + else { + if (this.color) { + ctx.fillStyle = this.color.toString(); + ctx.fillRect(-anchorPoint.x, -anchorPoint.y, this._width, this._height); + } + } + // Draw child actors + for (var i = 0; i < this.children.length; i++) { + if (this.children[i].visible) { + this.children[i].draw(ctx, delta); + } + } + this.emit('postdraw', new ex.PostDrawEvent(ctx, delta, this)); + ctx.restore(); }; - Animation.prototype._setScale = function (scale) { - //if (!this.scale.equals(scale)) { - for (var i in this.sprites) { - this.sprites[i].scale = scale; + /** + * Called by the Engine, draws the actors debugging to the screen + * @param ctx The rendering context + */ + Actor.prototype.debugDraw = function (ctx) { + this.emit('predebugdraw', new ex.PreDebugDrawEvent(ctx, this)); + // Draw actor bounding box + var bb = this.getBounds(); + bb.debugDraw(ctx); + // Draw actor Id + ctx.fillText('id: ' + this.id, bb.left + 3, bb.top + 10); + // Draw actor anchor point + ctx.fillStyle = ex.Color.Yellow.toString(); + ctx.beginPath(); + ctx.arc(this.getWorldX(), this.getWorldY(), 3, 0, Math.PI * 2); + ctx.closePath(); + ctx.fill(); + // Culling Box debug draw + for (var j = 0; j < this.traits.length; j++) { + if (this.traits[j] instanceof ex.Traits.OffscreenCulling) { + this.traits[j].cullingBox.debugDraw(ctx); + } + } + // Unit Circle debug draw + ctx.strokeStyle = ex.Color.Yellow.toString(); + ctx.beginPath(); + var radius = Math.min(this.getWidth(), this.getHeight()); + ctx.arc(this.getWorldX(), this.getWorldY(), radius, 0, Math.PI * 2); + ctx.closePath(); + ctx.stroke(); + var ticks = { '0 Pi': 0, + 'Pi/2': Math.PI / 2, + 'Pi': Math.PI, + '3/2 Pi': 3 * Math.PI / 2 }; + var oldFont = ctx.font; + for (var tick in ticks) { + ctx.fillStyle = ex.Color.Yellow.toString(); + ctx.font = '14px'; + ctx.textAlign = 'center'; + ctx.fillText(tick, this.getWorldX() + Math.cos(ticks[tick]) * (radius + 10), this.getWorldY() + Math.sin(ticks[tick]) * (radius + 10)); + } + ctx.font = oldFont; + // Draw child actors + ctx.save(); + ctx.translate(this.x, this.y); + ctx.rotate(this.rotation); + // Draw child actors + for (var i = 0; i < this.children.length; i++) { + this.children[i].debugDraw(ctx); } - //} + ctx.restore(); + this.emit('postdebugdraw', new ex.PostDebugDrawEvent(ctx, this)); }; /** - * Resets the animation to first frame. + * Indicates the next id to be set */ - Animation.prototype.reset = function () { - this.currentFrame = 0; - }; + Actor.maxId = 0; + return Actor; + })(ex.Class); + ex.Actor = Actor; + /** + * An enum that describes the types of collisions actors can participate in + */ + (function (CollisionType) { /** - * Indicates whether the animation is complete, animations that loop are never complete. + * Actors with the `PreventCollision` setting do not participate in any + * collisions and do not raise collision events. */ - Animation.prototype.isDone = function () { - return (!this.loop && this.currentFrame >= this.sprites.length); - }; + CollisionType[CollisionType["PreventCollision"] = 0] = "PreventCollision"; /** - * Not meant to be called by game developers. Ticks the animation forward internally and - * calculates whether to change to the frame. - * @internal + * Actors with the `Passive` setting only raise collision events, but are not + * influenced or moved by other actors and do not influence or move other actors. */ - Animation.prototype.tick = function () { - var time = Date.now(); - if ((time - this._oldTime) > this.speed) { - this.currentFrame = (this.loop ? (this.currentFrame + 1) % this.sprites.length : this.currentFrame + 1); - this._oldTime = time; - } - }; - Animation.prototype._updateValues = function () { - this._setAnchor(this.anchor); - this._setRotation(this.rotation); - this._setScale(this.scale); - }; + CollisionType[CollisionType["Passive"] = 1] = "Passive"; /** - * Skips ahead a specified number of frames in the animation - * @param frames Frames to skip ahead + * Actors with the `Active` setting raise collision events and participate + * in collisions with other actors and will be push or moved by actors sharing + * the `Active` or `Fixed` setting. */ - Animation.prototype.skip = function (frames) { - this.currentFrame = (this.currentFrame + frames) % this.sprites.length; - }; - Animation.prototype.draw = function (ctx, x, y) { - this.tick(); - this._updateValues(); - var currSprite; - if (this.currentFrame < this.sprites.length) { - currSprite = this.sprites[this.currentFrame]; - if (this.flipVertical) { - currSprite.flipVertical = this.flipVertical; - } - if (this.flipHorizontal) { - currSprite.flipHorizontal = this.flipHorizontal; - } - currSprite.draw(ctx, x, y); - } - if (this.freezeFrame !== -1 && this.currentFrame >= this.sprites.length) { - currSprite = this.sprites[ex.Util.clamp(this.freezeFrame, 0, this.sprites.length - 1)]; - currSprite.draw(ctx, x, y); - } - // add the calculated width - if (currSprite) { - this.width = currSprite.width; - this.height = currSprite.height; - } - }; + CollisionType[CollisionType["Active"] = 2] = "Active"; /** - * Plays an animation at an arbitrary location in the game. - * @param x The x position in the game to play - * @param y The y position in the game to play + * Actors with the `Elastic` setting will behave the same as `Active`, except that they will + * "bounce" in the opposite direction given their velocity dx/dy. This is a naive implementation meant for + * prototyping, for a more robust elastic collision listen to the "collision" event and perform your custom logic. + * @obsolete This behavior will be handled by a future physics system */ - Animation.prototype.play = function (x, y) { - this.reset(); - this._engine.playAnimation(this, x, y); - }; - return Animation; - })(); - ex.Animation = Animation; -})(ex || (ex = {})); -/// -/// -/// -var ex; -(function (ex) { - var Internal; - (function (Internal) { - var FallbackAudio = (function () { - function FallbackAudio(path, volume) { - this._log = ex.Logger.getInstance(); - this.onload = function () { return; }; - this.onprogress = function () { return; }; - this.onerror = function () { return; }; - if (window.AudioContext) { - this._log.debug('Using new Web Audio Api for ' + path); - this._soundImpl = new WebAudio(path, volume); - } - else { - this._log.debug('Falling back to Audio Element for ' + path); - this._soundImpl = new AudioTag(path, volume); - } - } - FallbackAudio.prototype.setVolume = function (volume) { - this._soundImpl.setVolume(volume); - }; - FallbackAudio.prototype.setLoop = function (loop) { - this._soundImpl.setLoop(loop); - }; - FallbackAudio.prototype.load = function () { - this._soundImpl.onload = this.onload; - this._soundImpl.onprogress = this.onprogress; - this._soundImpl.onerror = this.onerror; - this._soundImpl.load(); - }; - FallbackAudio.prototype.isPlaying = function () { - return this._soundImpl.isPlaying(); - }; - FallbackAudio.prototype.play = function () { - return this._soundImpl.play(); - }; - FallbackAudio.prototype.pause = function () { - this._soundImpl.pause(); - }; - FallbackAudio.prototype.stop = function () { - this._soundImpl.stop(); - }; - return FallbackAudio; - })(); - Internal.FallbackAudio = FallbackAudio; - var AudioTag = (function () { - function AudioTag(path, volume) { - var _this = this; - this.path = path; - this._audioElements = new Array(5); - this._loadedAudio = null; - this._isLoaded = false; - this._index = 0; - this._log = ex.Logger.getInstance(); - this._isPlaying = false; - this._currentOffset = 0; - this.onload = function () { return; }; - this.onprogress = function () { return; }; - this.onerror = function () { return; }; - for (var i = 0; i < this._audioElements.length; i++) { - (function (i) { - _this._audioElements[i] = new Audio(); - })(i); - } - if (volume) { - this.setVolume(ex.Util.clamp(volume, 0, 1.0)); - } - else { - this.setVolume(1.0); - } - } - AudioTag.prototype.isPlaying = function () { - return this._isPlaying; - }; - AudioTag.prototype._audioLoaded = function () { - this._isLoaded = true; - }; - AudioTag.prototype.setVolume = function (volume) { - var i = 0, len = this._audioElements.length; - for (i; i < len; i++) { - this._audioElements[i].volume = volume; - } - }; - AudioTag.prototype.setLoop = function (loop) { - var i = 0, len = this._audioElements.length; - for (i; i < len; i++) { - this._audioElements[i].loop = loop; - } - }; - AudioTag.prototype.getLoop = function () { - this._audioElements.some(function (a) { return a.loop; }); - }; - AudioTag.prototype.load = function () { - var _this = this; - var request = new XMLHttpRequest(); - request.open('GET', this.path, true); - request.responseType = 'blob'; - request.onprogress = this.onprogress; - request.onerror = this.onerror; - request.onload = function (e) { - if (request.status !== 200) { - _this._log.error('Failed to load audio resource ', _this.path, ' server responded with error code', request.status); - _this.onerror(request.response); - _this._isLoaded = false; - return; - } - _this._loadedAudio = URL.createObjectURL(request.response); - _this._audioElements.forEach(function (a) { - a.src = _this._loadedAudio; - }); - _this.onload(e); - }; - request.send(); - }; - AudioTag.prototype.play = function () { - var _this = this; - this._audioElements[this._index].load(); - //this.audioElements[this.index].currentTime = this._currentOffset; - this._audioElements[this._index].play(); - this._currentOffset = 0; - var done = new ex.Promise(); - this._isPlaying = true; - if (!this.getLoop()) { - this._audioElements[this._index].addEventListener('ended', function () { - _this._isPlaying = false; - done.resolve(true); - }); - } - this._index = (this._index + 1) % this._audioElements.length; - return done; - }; - AudioTag.prototype.pause = function () { - this._index = (this._index - 1 + this._audioElements.length) % this._audioElements.length; - this._currentOffset = this._audioElements[this._index].currentTime; - this._audioElements.forEach(function (a) { - a.pause(); - }); - this._isPlaying = false; - }; - AudioTag.prototype.stop = function () { - this._audioElements.forEach(function (a) { - a.pause(); - //a.currentTime = 0; - }); - this._isPlaying = false; - }; - return AudioTag; - })(); - Internal.AudioTag = AudioTag; - if (window.AudioContext) { - var audioContext = new window.AudioContext(); + CollisionType[CollisionType["Elastic"] = 3] = "Elastic"; + /** + * Actors with the `Fixed` setting raise collision events and participate in + * collisions with other actors. Actors with the `Fixed` setting will not be + * pushed or moved by other actors sharing the `Fixed`. Think of Fixed + * actors as "immovable/onstoppable" objects. If two `Fixed` actors meet they will + * not be pushed or moved by each other, they will not interact except to throw + * collision events. + */ + CollisionType[CollisionType["Fixed"] = 4] = "Fixed"; + })(ex.CollisionType || (ex.CollisionType = {})); + var CollisionType = ex.CollisionType; +})(ex || (ex = {})); +var ex; +(function (ex) { + /** + * Logging level that Excalibur will tag + */ + (function (LogLevel) { + LogLevel[LogLevel["Debug"] = 0] = "Debug"; + LogLevel[LogLevel["Info"] = 1] = "Info"; + LogLevel[LogLevel["Warn"] = 2] = "Warn"; + LogLevel[LogLevel["Error"] = 3] = "Error"; + LogLevel[LogLevel["Fatal"] = 4] = "Fatal"; + })(ex.LogLevel || (ex.LogLevel = {})); + var LogLevel = ex.LogLevel; + /** + * Static singleton that represents the logging facility for Excalibur. + * Excalibur comes built-in with a [[ConsoleAppender]] and [[ScreenAppender]]. + * Derive from [[IAppender]] to create your own logging appenders. + * + * ## Example: Logging + * + * ```js + * // set default log level (default: Info) + * ex.Logger.getInstance().defaultLevel = ex.LogLevel.Warn; + * + * // this will not be shown because it is below Warn + * ex.Logger.getInstance().info("This will be logged as Info"); + * // this will show because it is Warn + * ex.Logger.getInstance().warn("This will be logged as Warn"); + * // this will show because it is above Warn + * ex.Logger.getInstance().error("This will be logged as Error"); + * // this will show because it is above Warn + * ex.Logger.getInstance().fatal("This will be logged as Fatal"); + * ``` + */ + var Logger = (function () { + function Logger() { + this._appenders = []; + /** + * Gets or sets the default logging level. Excalibur will only log + * messages if equal to or above this level. Default: [[LogLevel.Info]] + */ + this.defaultLevel = LogLevel.Info; + if (Logger._instance) { + throw new Error('Logger is a singleton'); + } + Logger._instance = this; + // Default console appender + Logger._instance.addAppender(new ConsoleAppender()); + return Logger._instance; } - var WebAudio = (function () { - function WebAudio(soundPath, volume) { - this._context = audioContext; - this._volume = this._context.createGain(); - this._buffer = null; - this._sound = null; - this._path = ''; - this._isLoaded = false; - this._loop = false; - this._isPlaying = false; - this._isPaused = false; - this._currentOffset = 0; - this._logger = ex.Logger.getInstance(); - this.onload = function () { return; }; - this.onprogress = function () { return; }; - this.onerror = function () { return; }; - this._path = soundPath; - if (volume) { - this._volume.gain.value = ex.Util.clamp(volume, 0, 1.0); - } - else { - this._volume.gain.value = 1.0; // max volume - } + /** + * Gets the current static instance of Logger + */ + Logger.getInstance = function () { + if (Logger._instance == null) { + Logger._instance = new Logger(); } - WebAudio.prototype.setVolume = function (volume) { - this._volume.gain.value = volume; - }; - WebAudio.prototype.load = function () { - var _this = this; - var request = new XMLHttpRequest(); - request.open('GET', this._path); - request.responseType = 'arraybuffer'; - request.onprogress = this.onprogress; - request.onerror = this.onerror; - request.onload = function () { - if (request.status !== 200) { - _this._logger.error('Failed to load audio resource ', _this._path, ' server responded with error code', request.status); - _this.onerror(request.response); - _this._isLoaded = false; - return; - } - _this._context.decodeAudioData(request.response, function (buffer) { - _this._buffer = buffer; - _this._isLoaded = true; - _this.onload(_this); - }, function (e) { - _this._logger.error('Unable to decode ' + _this._path + - ' this browser may not fully support this format, or the file may be corrupt, ' + - 'if this is an mp3 try removing id3 tags and album art from the file.'); - _this._isLoaded = false; - _this.onload(_this); - }); - }; - try { - request.send(); - } - catch (e) { - console.error('Error loading sound! If this is a cross origin error, you must host your sound with your html and javascript.'); + return Logger._instance; + }; + /** + * Adds a new [[IAppender]] to the list of appenders to write to + */ + Logger.prototype.addAppender = function (appender) { + this._appenders.push(appender); + }; + /** + * Clears all appenders from the logger + */ + Logger.prototype.clearAppenders = function () { + this._appenders.length = 0; + }; + /** + * Logs a message at a given LogLevel + * @param level The LogLevel`to log the message at + * @param args An array of arguments to write to an appender + */ + Logger.prototype._log = function (level, args) { + if (level == null) { + level = this.defaultLevel; + } + var i = 0, len = this._appenders.length; + for (i; i < len; i++) { + if (level >= this.defaultLevel) { + this._appenders[i].log(level, args); } - }; - WebAudio.prototype.setLoop = function (loop) { - this._loop = loop; - }; - WebAudio.prototype.isPlaying = function () { - return this._isPlaying; - }; - WebAudio.prototype.play = function () { - var _this = this; - if (this._isLoaded) { - this._sound = this._context.createBufferSource(); - this._sound.buffer = this._buffer; - this._sound.loop = this._loop; - this._sound.connect(this._volume); - this._volume.connect(this._context.destination); - this._sound.start(0, this._currentOffset % this._buffer.duration); - this._currentOffset = 0; - var done; - if (!this._isPaused || !this._playPromise) { - done = new ex.Promise(); - } - else { - done = this._playPromise; - } - this._isPaused = false; - this._isPlaying = true; - if (!this._loop) { - this._sound.onended = (function () { - _this._isPlaying = false; - if (!_this._isPaused) { - done.resolve(true); - } - }).bind(this); - } - this._playPromise = done; - return done; + } + }; + /** + * Writes a log message at the [[LogLevel.Debug]] level + * @param args Accepts any number of arguments + */ + Logger.prototype.debug = function () { + var args = []; + for (var _i = 0; _i < arguments.length; _i++) { + args[_i - 0] = arguments[_i]; + } + this._log(LogLevel.Debug, args); + }; + /** + * Writes a log message at the [[LogLevel.Info]] level + * @param args Accepts any number of arguments + */ + Logger.prototype.info = function () { + var args = []; + for (var _i = 0; _i < arguments.length; _i++) { + args[_i - 0] = arguments[_i]; + } + this._log(LogLevel.Info, args); + }; + /** + * Writes a log message at the [[LogLevel.Warn]] level + * @param args Accepts any number of arguments + */ + Logger.prototype.warn = function () { + var args = []; + for (var _i = 0; _i < arguments.length; _i++) { + args[_i - 0] = arguments[_i]; + } + this._log(LogLevel.Warn, args); + }; + /** + * Writes a log message at the [[LogLevel.Error]] level + * @param args Accepts any number of arguments + */ + Logger.prototype.error = function () { + var args = []; + for (var _i = 0; _i < arguments.length; _i++) { + args[_i - 0] = arguments[_i]; + } + this._log(LogLevel.Error, args); + }; + /** + * Writes a log message at the [[LogLevel.Fatal]] level + * @param args Accepts any number of arguments + */ + Logger.prototype.fatal = function () { + var args = []; + for (var _i = 0; _i < arguments.length; _i++) { + args[_i - 0] = arguments[_i]; + } + this._log(LogLevel.Fatal, args); + }; + Logger._instance = null; + return Logger; + })(); + ex.Logger = Logger; + /** + * Console appender for browsers (i.e. `console.log`) + */ + var ConsoleAppender = (function () { + function ConsoleAppender() { + } + /** + * Logs a message at the given [[LogLevel]] + * @param level Level to log at + * @param args Arguments to log + */ + ConsoleAppender.prototype.log = function (level, args) { + // Check for console support + if (!console && !console.log && console.warn && console.error) { + // todo maybe do something better than nothing + return; + } + // Create a new console args array + var consoleArgs = []; + consoleArgs.unshift.apply(consoleArgs, args); + consoleArgs.unshift('[' + LogLevel[level] + '] : '); + if (level < LogLevel.Warn) { + // Call .log for Debug/Info + if (console.log.apply) { + // this is required on some older browsers that don't support apply on console.log :( + console.log.apply(console, consoleArgs); } else { - return ex.Promise.wrap(true); + console.log(consoleArgs.join(' ')); } - }; - WebAudio.prototype.pause = function () { - if (this._isPlaying) { - try { - window.clearTimeout(this._playingTimer); - this._sound.stop(0); - this._currentOffset = this._context.currentTime; - this._isPlaying = false; - this._isPaused = true; - } - catch (e) { - this._logger.warn('The sound clip', this._path, 'has already been paused!'); - } + } + else if (level < LogLevel.Error) { + // Call .warn for Warn + if (console.warn.apply) { + console.warn.apply(console, consoleArgs); } - }; - WebAudio.prototype.stop = function () { - if (this._sound) { - try { - window.clearTimeout(this._playingTimer); - this._currentOffset = 0; - this._sound.stop(0); - this._isPlaying = false; - this._isPaused = false; - } - catch (e) { - this._logger.warn('The sound clip', this._path, 'has already been stopped!'); - } + else { + console.warn(consoleArgs.join(' ')); } - }; - return WebAudio; - })(); - Internal.WebAudio = WebAudio; - })(Internal = ex.Internal || (ex.Internal = {})); + } + else { + // Call .error for Error/Fatal + if (console.error.apply) { + console.error.apply(console, consoleArgs); + } + else { + console.error(consoleArgs.join(' ')); + } + } + }; + return ConsoleAppender; + })(); + ex.ConsoleAppender = ConsoleAppender; + /** + * On-screen (canvas) appender + */ + var ScreenAppender = (function () { + /** + * @param width Width of the screen appender in pixels + * @param height Height of the screen appender in pixels + */ + function ScreenAppender(width, height) { + // @todo Clean this up + this._messages = []; + this._canvas = document.createElement('canvas'); + this._canvas.width = width || window.innerWidth; + this._canvas.height = height || window.innerHeight; + this._canvas.style.position = 'absolute'; + this._ctx = this._canvas.getContext('2d'); + document.body.appendChild(this._canvas); + } + /** + * Logs a message at the given [[LogLevel]] + * @param level Level to log at + * @param args Arguments to log + */ + ScreenAppender.prototype.log = function (level, args) { + var message = args.join(','); + this._ctx.clearRect(0, 0, this._canvas.width, this._canvas.height); + this._messages.unshift('[' + LogLevel[level] + '] : ' + message); + var pos = 10; + var opacity = 1.0; + for (var i = 0; i < this._messages.length; i++) { + this._ctx.fillStyle = 'rgba(255,255,255,' + opacity.toFixed(2) + ')'; + this._ctx.fillText(this._messages[i], 200, pos); + pos += 10; + opacity = opacity > 0 ? opacity - .05 : 0; + } + }; + return ScreenAppender; + })(); + ex.ScreenAppender = ScreenAppender; +})(ex || (ex = {})); +/// +/// +/// +var ex; +(function (ex) { + /** + * Base event type in Excalibur that all other event types derive from. Not all event types are thrown on all Excalibur game objects, + * some events are unique to a type, others are not. + * + * Excalibur events follow the convention that the name of the thrown event for listening will be the same as the Event object in all + * lower case with the 'Event' suffix removed. + * + * For example: + * - PreDrawEvent event object and "predraw" as the event name + * + * ```typescript + * + * actor.on('predraw', (evtObj: PreDrawEvent) => { + * // do some pre drawing + * }) + * + * ``` + * + */ + var GameEvent = (function () { + function GameEvent() { + } + return GameEvent; + })(); + ex.GameEvent = GameEvent; + /** + * The 'predraw' event is emitted on actors, scenes, and engine before drawing starts. Actors' predraw happens inside their graphics + * transform so that all drawing takes place with the actor as the origin. + * + */ + var PreDrawEvent = (function (_super) { + __extends(PreDrawEvent, _super); + function PreDrawEvent(ctx, delta, target) { + _super.call(this); + this.ctx = ctx; + this.delta = delta; + this.target = target; + } + return PreDrawEvent; + })(GameEvent); + ex.PreDrawEvent = PreDrawEvent; + /** + * The 'postdraw' event is emitted on actors, scenes, and engine after drawing finishes. Actors' postdraw happens inside their graphics + * transform so that all drawing takes place with the actor as the origin. + * + */ + var PostDrawEvent = (function (_super) { + __extends(PostDrawEvent, _super); + function PostDrawEvent(ctx, delta, target) { + _super.call(this); + this.ctx = ctx; + this.delta = delta; + this.target = target; + } + return PostDrawEvent; + })(GameEvent); + ex.PostDrawEvent = PostDrawEvent; + /** + * The 'predebugdraw' event is emitted on actors, scenes, and engine before debug drawing starts. + */ + var PreDebugDrawEvent = (function (_super) { + __extends(PreDebugDrawEvent, _super); + function PreDebugDrawEvent(ctx, target) { + _super.call(this); + this.ctx = ctx; + this.target = target; + } + return PreDebugDrawEvent; + })(GameEvent); + ex.PreDebugDrawEvent = PreDebugDrawEvent; + /** + * The 'postdebugdraw' event is emitted on actors, scenes, and engine after debug drawing starts. + */ + var PostDebugDrawEvent = (function (_super) { + __extends(PostDebugDrawEvent, _super); + function PostDebugDrawEvent(ctx, target) { + _super.call(this); + this.ctx = ctx; + this.target = target; + } + return PostDebugDrawEvent; + })(GameEvent); + ex.PostDebugDrawEvent = PostDebugDrawEvent; + /** + * The 'preupdate' event is emitted on actors, scenes, and engine before the update starts. + */ + var PreUpdateEvent = (function (_super) { + __extends(PreUpdateEvent, _super); + function PreUpdateEvent(engine, delta, target) { + _super.call(this); + this.engine = engine; + this.delta = delta; + this.target = target; + } + return PreUpdateEvent; + })(GameEvent); + ex.PreUpdateEvent = PreUpdateEvent; + /** + * The 'postupdate' event is emitted on actors, scenes, and engine after the update ends. This is equivalent to the obsolete 'update' + * event. + */ + var PostUpdateEvent = (function (_super) { + __extends(PostUpdateEvent, _super); + function PostUpdateEvent(engine, delta, target) { + _super.call(this); + this.engine = engine; + this.delta = delta; + this.target = target; + } + return PostUpdateEvent; + })(GameEvent); + ex.PostUpdateEvent = PostUpdateEvent; + /** + * Event received when a gamepad is connected to Excalibur. [[Input.Gamepads|engine.input.gamepads]] receives this event. + */ + var GamepadConnectEvent = (function (_super) { + __extends(GamepadConnectEvent, _super); + function GamepadConnectEvent(index, gamepad) { + _super.call(this); + this.index = index; + this.gamepad = gamepad; + } + return GamepadConnectEvent; + })(GameEvent); + ex.GamepadConnectEvent = GamepadConnectEvent; + /** + * Event received when a gamepad is disconnected from Excalibur. [[Input.Gamepads|engine.input.gamepads]] receives this event. + */ + var GamepadDisconnectEvent = (function (_super) { + __extends(GamepadDisconnectEvent, _super); + function GamepadDisconnectEvent(index) { + _super.call(this); + this.index = index; + } + return GamepadDisconnectEvent; + })(GameEvent); + ex.GamepadDisconnectEvent = GamepadDisconnectEvent; + /** + * Gamepad button event. See [[Gamepads]] for information on responding to controller input. [[Gamepad]] instances receive this event; + */ + var GamepadButtonEvent = (function (_super) { + __extends(GamepadButtonEvent, _super); + /** + * @param button The Gamepad button + * @param value A numeric value between 0 and 1 + */ + function GamepadButtonEvent(button, value) { + _super.call(this); + this.button = button; + this.value = value; + } + return GamepadButtonEvent; + })(ex.GameEvent); + ex.GamepadButtonEvent = GamepadButtonEvent; + /** + * Gamepad axis event. See [[Gamepads]] for information on responding to controller input. [[Gamepad]] instances receive this event; + */ + var GamepadAxisEvent = (function (_super) { + __extends(GamepadAxisEvent, _super); + /** + * @param axis The Gamepad axis + * @param value A numeric value between -1 and 1 + */ + function GamepadAxisEvent(axis, value) { + _super.call(this); + this.axis = axis; + this.value = value; + } + return GamepadAxisEvent; + })(ex.GameEvent); + ex.GamepadAxisEvent = GamepadAxisEvent; + /** + * Subscribe event thrown when handlers for events other than subscribe are added. Meta event that is received by + * [[EventDispatcher|event dispatchers]]. + */ + var SubscribeEvent = (function (_super) { + __extends(SubscribeEvent, _super); + function SubscribeEvent(topic, handler) { + _super.call(this); + this.topic = topic; + this.handler = handler; + } + return SubscribeEvent; + })(GameEvent); + ex.SubscribeEvent = SubscribeEvent; + /** + * Unsubscribe event thrown when handlers for events other than unsubscribe are removed. Meta event that is received by + * [[EventDispatcher|event dispatchers]]. + */ + var UnsubscribeEvent = (function (_super) { + __extends(UnsubscribeEvent, _super); + function UnsubscribeEvent(topic, handler) { + _super.call(this); + this.topic = topic; + this.handler = handler; + } + return UnsubscribeEvent; + })(GameEvent); + ex.UnsubscribeEvent = UnsubscribeEvent; + /** + * Event received by the [[Engine]] when the browser window is visible on a screen. + */ + var VisibleEvent = (function (_super) { + __extends(VisibleEvent, _super); + function VisibleEvent() { + _super.call(this); + } + return VisibleEvent; + })(GameEvent); + ex.VisibleEvent = VisibleEvent; + /** + * Event received by the [[Engine]] when the browser window is hidden from all screens. + */ + var HiddenEvent = (function (_super) { + __extends(HiddenEvent, _super); + function HiddenEvent() { + _super.call(this); + } + return HiddenEvent; + })(GameEvent); + ex.HiddenEvent = HiddenEvent; + /** + * Event thrown on an [[Actor|actor]] when a collision has occured + */ + var CollisionEvent = (function (_super) { + __extends(CollisionEvent, _super); + /** + * @param actor The actor the event was thrown on + * @param other The actor that was collided with + * @param side The side that was collided with + */ + function CollisionEvent(actor, other, side, intersection) { + _super.call(this); + this.actor = actor; + this.other = other; + this.side = side; + this.intersection = intersection; + } + return CollisionEvent; + })(GameEvent); + ex.CollisionEvent = CollisionEvent; + /** + * Event thrown on a game object on Excalibur update, this is equivalent to postupdate. + * @obsolete Please use [[PostUpdateEvent|postupdate]], or [[PreUpdateEvent|preupdate]]. + */ + var UpdateEvent = (function (_super) { + __extends(UpdateEvent, _super); + /** + * @param delta The number of milliseconds since the last update + */ + function UpdateEvent(delta) { + _super.call(this); + this.delta = delta; + } + return UpdateEvent; + })(GameEvent); + ex.UpdateEvent = UpdateEvent; + /** + * Event thrown on an [[Actor]] only once before the first update call + */ + var InitializeEvent = (function (_super) { + __extends(InitializeEvent, _super); + /** + * @param engine The reference to the current engine + */ + function InitializeEvent(engine) { + _super.call(this); + this.engine = engine; + } + return InitializeEvent; + })(GameEvent); + ex.InitializeEvent = InitializeEvent; + /** + * Event thrown on a [[Scene]] on activation + */ + var ActivateEvent = (function (_super) { + __extends(ActivateEvent, _super); + /** + * @param oldScene The reference to the old scene + */ + function ActivateEvent(oldScene) { + _super.call(this); + this.oldScene = oldScene; + } + return ActivateEvent; + })(GameEvent); + ex.ActivateEvent = ActivateEvent; + /** + * Event thrown on a [[Scene]] on deactivation + */ + var DeactivateEvent = (function (_super) { + __extends(DeactivateEvent, _super); + /** + * @param newScene The reference to the new scene + */ + function DeactivateEvent(newScene) { + _super.call(this); + this.newScene = newScene; + } + return DeactivateEvent; + })(GameEvent); + ex.DeactivateEvent = DeactivateEvent; + /** + * Event thrown on an [[Actor]] when it completely leaves the screen. + */ + var ExitViewPortEvent = (function (_super) { + __extends(ExitViewPortEvent, _super); + function ExitViewPortEvent() { + _super.call(this); + } + return ExitViewPortEvent; + })(GameEvent); + ex.ExitViewPortEvent = ExitViewPortEvent; + /** + * Event thrown on an [[Actor]] when it completely leaves the screen. + */ + var EnterViewPortEvent = (function (_super) { + __extends(EnterViewPortEvent, _super); + function EnterViewPortEvent() { + _super.call(this); + } + return EnterViewPortEvent; + })(GameEvent); + ex.EnterViewPortEvent = EnterViewPortEvent; })(ex || (ex = {})); -/// -// Promises/A+ Spec http://promises-aplus.github.io/promises-spec/ +/// var ex; (function (ex) { /** - * Valid states for a promise to be in - */ - (function (PromiseState) { - PromiseState[PromiseState["Resolved"] = 0] = "Resolved"; - PromiseState[PromiseState["Rejected"] = 1] = "Rejected"; - PromiseState[PromiseState["Pending"] = 2] = "Pending"; - })(ex.PromiseState || (ex.PromiseState = {})); - var PromiseState = ex.PromiseState; - /** - * Promises/A+ spec implementation of promises + * Excalibur's internal event dispatcher implementation. + * Callbacks are fired immediately after an event is published. + * Typically you will use [[Class.eventDispatcher]] since most classes in + * Excalibur inherit from [[Class]]. You will rarely create an `EventDispatcher` + * yourself. * - * Promises are used to do asynchronous work and they are useful for - * creating a chain of actions. In Excalibur they are used for loading, - * sounds, animation, actions, and more. + * When working with events, be sure to keep in mind the order of subscriptions + * and try not to create a situation that requires specific things to happen in + * order. Events are best used for input events, tying together disparate objects, + * or for UI updates. * - * ## A Promise Chain + * ## Example: Actor events * - * Promises can be chained together and can be useful for creating a queue - * of functions to be called when something is done. + * Actors implement an EventDispatcher ([[Actor.eventDispatcher]]) so they can + * send and receive events. For example, they can enable Pointer events (mouse/touch) + * and you can respond to them by subscribing to the event names. * - * The first [[Promise]] you will encounter is probably [[Engine.start]] - * which resolves when the game has finished loading. + * You can also emit any other kind of event for your game just by using a custom + * `string` value and implementing a class that inherits from [[GameEvent]]. * * ```js - * var game = new ex.Engine(); + * var player = new ex.Actor(...); * - * // perform start-up logic once game is ready - * game.start().then(function () { + * // Enable pointer events for this actor + * player.enableCapturePointer = true; * - * // start-up & initialization logic + * // subscribe to pointerdown event + * player.on("pointerdown", function (evt: ex.Input.PointerEvent) { + * console.log("Player was clicked!"); + * }); + * + * // turn off subscription + * player.off("pointerdown"); * + * // subscribe to custom event + * player.on("death", function (evt) { + * console.log("Player died:", evt); * }); + * + * // trigger custom event + * player.emit("death", new DeathEvent()); + * * ``` * - * ## Handling errors + * ## Example: Pub/Sub with Excalibur * - * You can optionally pass an error handler to [[Promise.then]] which will handle - * any errors that occur during Promise execution. + * You can also create an EventDispatcher for any arbitrary object, for example + * a global game event aggregator (shown below as `vent`). Anything in your game can subscribe to + * it, if the event aggregator is in the global scope. + * + * *Warning:* This can easily get out of hand. Avoid this usage, it just serves as + * an example. * * ```js - * var game = new ex.Engine(); + * // create a publisher on an empty object + * var vent = new ex.EventDispatcher({}); * - * game.start().then( - * // success handler - * function () { - * }, + * // handler for an event + * var subscription = function (event) { + * console.log(event); + * } * - * // error handler - * function (err) { - * } - * ); - * ``` + * // add a subscription + * vent.subscribe("someevent", subscription); * - * Any errors that go unhandled will be bubbled up to the browser. + * // publish an event somewhere in the game + * vent.emit("someevent", new ex.GameEvent()); + * ``` */ - var Promise = (function () { - function Promise() { - this._state = PromiseState.Pending; - this._successCallbacks = []; - this._rejectCallback = function () { return; }; - this._logger = ex.Logger.getInstance(); - } - /** - * Wrap a value in a resolved promise - * @param value An optional value to wrap in a resolved promise - */ - Promise.wrap = function (value) { - var promise = (new Promise()).resolve(value); - return promise; - }; + var EventDispatcher = (function () { /** - * Returns a new promise that resolves when all the promises passed to it resolve, or rejects - * when at least 1 promise rejects. + * @param target The object that will be the recipient of events from this event dispatcher */ - Promise.join = function () { - var promises = []; - for (var _i = 0; _i < arguments.length; _i++) { - promises[_i - 0] = arguments[_i]; - } - var joinedPromise = new Promise(); - if (!promises || !promises.length) { - return joinedPromise.resolve(); - } - var total = promises.length; - var successes = 0; - var rejects = 0; - var errors = []; - promises.forEach(function (p) { - p.then(function () { - successes += 1; - if (successes === total) { - joinedPromise.resolve(); - } - else if (successes + rejects + errors.length === total) { - joinedPromise.reject(errors); - } - }, function () { - rejects += 1; - if (successes + rejects + errors.length === total) { - joinedPromise.reject(errors); - } - }).error(function (e) { - errors.push(e); - if ((errors.length + successes + rejects) === total) { - joinedPromise.reject(errors); - } - }); - }); - return joinedPromise; - }; + function EventDispatcher(target) { + this._handlers = {}; + this._wiredEventDispatchers = []; + this._log = ex.Logger.getInstance(); + this._target = target; + } /** - * Chain success and reject callbacks after the promise is resovled - * @param successCallback Call on resolution of promise - * @param rejectCallback Call on rejection of promise + * Publish an event for target + * @param eventName The name of the event to publish + * @param event Optionally pass an event data object to the handler + * + * @obsolete Use [[emit]] instead. */ - Promise.prototype.then = function (successCallback, rejectCallback) { - if (successCallback) { - this._successCallbacks.push(successCallback); - // If the promise is already resovled call immediately - if (this.state() === PromiseState.Resolved) { - try { - successCallback.call(this, this._value); - } - catch (e) { - this._handleError(e); - } - } + EventDispatcher.prototype.publish = function (eventName, event) { + if (!eventName) { + // key not mapped + return; } - if (rejectCallback) { - this._rejectCallback = rejectCallback; - // If the promise is already rejected call immediately - if (this.state() === PromiseState.Rejected) { - try { - rejectCallback.call(this, this._value); - } - catch (e) { - this._handleError(e); - } + eventName = eventName.toLowerCase(); + var target = this._target; + if (!event) { + event = new ex.GameEvent(); + } + event.target = target; + var i, len; + if (this._handlers[eventName]) { + i = 0; + len = this._handlers[eventName].length; + for (i; i < len; i++) { + this._handlers[eventName][i].call(target, event); } } - return this; + i = 0; + len = this._wiredEventDispatchers.length; + for (i; i < len; i++) { + this._wiredEventDispatchers[i].emit(eventName, event); + } }; /** - * Add an error callback to the promise - * @param errorCallback Call if there was an error in a callback + * Alias for [[publish]], publishes an event for target + * @param eventName The name of the event to publish + * @param event Optionally pass an event data object to the handler */ - Promise.prototype.error = function (errorCallback) { - if (errorCallback) { - this._errorCallback = errorCallback; - } - return this; + EventDispatcher.prototype.emit = function (eventName, event) { + this.publish(eventName, event); }; /** - * Resolve the promise and pass an option value to the success callbacks - * @param value Value to pass to the success callbacks + * Subscribe an event handler to a particular event name, multiple handlers per event name are allowed. + * @param eventName The name of the event to subscribe to + * @param handler The handler callback to fire on this event */ - Promise.prototype.resolve = function (value) { - var _this = this; - if (this._state === PromiseState.Pending) { - this._value = value; - try { - this._state = PromiseState.Resolved; - this._successCallbacks.forEach(function (cb) { - cb.call(_this, _this._value); - }); - } - catch (e) { - this._handleError(e); - } + EventDispatcher.prototype.subscribe = function (eventName, handler) { + eventName = eventName.toLowerCase(); + if (!this._handlers[eventName]) { + this._handlers[eventName] = []; } - else { - throw new Error('Cannot resolve a promise that is not in a pending state!'); + this._handlers[eventName].push(handler); + // meta event handlers + if (eventName !== 'unsubscribe' && eventName !== 'subscribe') { + this.emit('subscribe', new ex.SubscribeEvent(eventName, handler)); } - return this; }; /** - * Reject the promise and pass an option value to the reject callbacks - * @param value Value to pass to the reject callbacks + * Unsubscribe an event handler(s) from an event. If a specific handler + * is specified for an event, only that handler will be unsubscribed. + * Otherwise all handlers will be unsubscribed for that event. + * + * @param eventName The name of the event to unsubscribe + * @param handler Optionally the specific handler to unsubscribe + * */ - Promise.prototype.reject = function (value) { - if (this._state === PromiseState.Pending) { - this._value = value; - try { - this._state = PromiseState.Rejected; - this._rejectCallback.call(this, this._value); + EventDispatcher.prototype.unsubscribe = function (eventName, handler) { + eventName = eventName.toLowerCase(); + var eventHandlers = this._handlers[eventName]; + if (eventHandlers) { + // if no explicit handler is give with the event name clear all handlers + if (!handler) { + this._handlers[eventName].length = 0; } - catch (e) { - this._handleError(e); + else { + var index = eventHandlers.indexOf(handler); + this._handlers[eventName].splice(index, 1); } } - else { - throw new Error('Cannot reject a promise that is not in a pending state!'); + // meta event handlers + if (eventName !== 'unsubscribe' && eventName !== 'subscribe') { + this.emit('unsubscribe', new ex.UnsubscribeEvent(eventName, handler)); } - return this; }; /** - * Inpect the current state of a promise + * Wires this event dispatcher to also recieve events from another */ - Promise.prototype.state = function () { - return this._state; + EventDispatcher.prototype.wire = function (eventDispatcher) { + eventDispatcher._wiredEventDispatchers.push(this); }; - Promise.prototype._handleError = function (e) { - if (this._errorCallback) { - this._errorCallback.call(this, e); - } - else { - // rethrow error - throw e; + /** + * Unwires this event dispatcher from another + */ + EventDispatcher.prototype.unwire = function (eventDispatcher) { + var index = eventDispatcher._wiredEventDispatchers.indexOf(this); + if (index > -1) { + eventDispatcher._wiredEventDispatchers.splice(index, 1); } }; - return Promise; + return EventDispatcher; })(); - ex.Promise = Promise; + ex.EventDispatcher = EventDispatcher; })(ex || (ex = {})); -/// var ex; (function (ex) { /** - * Generic Resources - * - * The [[Resource]] type allows games built in Excalibur to load generic resources. - * For any type of remote resource it is recommended to use [[Resource]] for preloading. - * - * [[Resource]] is an [[ILoadable]] so it can be passed to a [[Loader]] to pre-load before - * a level or game. - * - * Example usages: JSON, compressed files, blobs. + * Provides standard colors (e.g. [[Color.Black]]) + * but you can also create custom colors using RGB, HSL, or Hex. Also provides + * useful color operations like [[Color.lighten]], [[Color.darken]], and more. * - * ## Pre-loading generic resources + * ## Creating colors * * ```js - * var resLevel1 = new ex.Resource("/assets/levels/1.json", "application/json"); - * var loader = new ex.Loader(resLevel1); + * // RGBA + * new ex.Color(r, g, b, a); + * ex.Color.fromRGB(r, g, b, a); * - * // attach a handler to process once loaded - * resLevel1.processDownload = function (data) { + * // HSLA + * ex.Color.fromHSL(h, s, l, a); * - * // process JSON - * var json = JSON.parse(data); + * // Hex, alpha optional + * ex.Color.fromHex("#000000"); + * ex.Color.fromHex("#000000FF"); + * ``` * - * // create a new level (inherits Scene) with the JSON configuration - * var level = new Level(json); + * ## Working with colors * - * // add a new scene - * game.add(level.name, level); - * } + * Since Javascript does not support structs, if you change a color "constant" like [[Color.Black]] + * it will change it across the entire game. You can safely use the color operations + * like [[Color.lighten]] and [[Color.darken]] because they `clone` the color to + * return a new color. However, be aware that this can use up memory if used excessively. * - * game.start(loader); - * ``` + * Just be aware that if you directly alter properties (i.e. [[Color.r]], etc.) , this will change it + * for all the code that uses that instance of Color. */ - var Resource = (function () { + var Color = (function () { /** - * @param path Path to the remote resource - * @param responseType The Content-Type to expect (e.g. `application/json`) - * @param bustCache Whether or not to cache-bust requests + * Creates a new instance of Color from an r, g, b, a + * + * @param r The red component of color (0-255) + * @param g The green component of color (0-255) + * @param b The blue component of color (0-255) + * @param a The alpha component of color (0-1.0) */ - function Resource(path, responseType, bustCache) { - if (bustCache === void 0) { bustCache = true; } - this.path = path; - this.responseType = responseType; - this.bustCache = bustCache; - this.data = null; - this.logger = ex.Logger.getInstance(); - this.onprogress = function () { return; }; - this.oncomplete = function () { return; }; - this.onerror = function () { return; }; + function Color(r, g, b, a) { + this.r = r; + this.g = g; + this.b = b; + this.a = (a != null ? a : 1); } /** - * Returns true if the Resource is completely loaded and is ready - * to be drawn. + * Creates a new instance of Color from an r, g, b, a + * + * @param r The red component of color (0-255) + * @param g The green component of color (0-255) + * @param b The blue component of color (0-255) + * @param a The alpha component of color (0-1.0) */ - Resource.prototype.isLoaded = function () { - return !!this.data; - }; - Resource.prototype.wireEngine = function (engine) { - this._engine = engine; + Color.fromRGB = function (r, g, b, a) { + return new Color(r, g, b, a); }; - Resource.prototype._cacheBust = function (uri) { - var query = /\?\w*=\w*/; - if (query.test(uri)) { - uri += ('&__=' + Date.now()); + /** + * Creates a new inscance of Color from a hex string + * + * @param hex CSS color string of the form #ffffff, the alpha component is optional + */ + Color.fromHex = function (hex) { + var hexRegEx = /^#?([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})?$/i; + var match = null; + if (match = hex.match(hexRegEx)) { + var r = parseInt(match[1], 16); + var g = parseInt(match[2], 16); + var b = parseInt(match[3], 16); + var a = 1; + if (match[4]) { + a = parseInt(match[4], 16) / 255; + } + return new Color(r, g, b, a); } else { - uri += ('?__=' + Date.now()); + throw new Error('Invalid hex string: ' + hex); } - return uri; - }; - Resource.prototype._start = function (e) { - this.logger.debug('Started loading resource ' + this.path); }; /** - * Begin loading the resource and returns a promise to be resolved on completion - */ - Resource.prototype.load = function () { - var _this = this; - var complete = new ex.Promise(); - var request = new XMLHttpRequest(); - request.open('GET', this.bustCache ? this._cacheBust(this.path) : this.path, true); - request.responseType = this.responseType; - request.onloadstart = function (e) { _this._start(e); }; - request.onprogress = this.onprogress; - request.onerror = this.onerror; - request.onload = function (e) { - if (request.status !== 200) { - _this.logger.error('Failed to load resource ', _this.path, ' server responded with error code', request.status); - _this.onerror(request.response); - complete.resolve(request.response); - return; - } - _this.data = _this.processDownload(request.response); - _this.oncomplete(); - _this.logger.debug('Completed loading resource', _this.path); - complete.resolve(_this.data); - }; - request.send(); - return complete; + * Creats a new instance of Color from hsla values + * + * @param h Hue is represented [0-1] + * @param s Saturation is represented [0-1] + * @param l Luminance is represented [0-1] + * @param a Alpha is represented [0-1] + */ + Color.fromHSL = function (h, s, l, a) { + if (a === void 0) { a = 1.0; } + var temp = new HSLColor(h, s, l, a); + return temp.toRGBA(); }; /** - * Returns the loaded data once the resource is loaded + * Lightens the current color by a specified amount + * + * @param factor The amount to lighten by [0-1] */ - Resource.prototype.getData = function () { - return this.data; + Color.prototype.lighten = function (factor) { + if (factor === void 0) { factor = 0.1; } + var temp = HSLColor.fromRGBA(this.r, this.g, this.b, this.a); + temp.l += (temp.l * factor); + return temp.toRGBA(); }; /** - * This method is meant to be overriden to handle any additional - * processing. Such as decoding downloaded audio bits. + * Darkens the current color by a specified amount + * + * @param factor The amount to darken by [0-1] */ - Resource.prototype.processDownload = function (data) { - // Handle any additional loading after the xhr has completed. - return URL.createObjectURL(data); + Color.prototype.darken = function (factor) { + if (factor === void 0) { factor = 0.1; } + var temp = HSLColor.fromRGBA(this.r, this.g, this.b, this.a); + temp.l -= (temp.l * factor); + return temp.toRGBA(); }; - return Resource; - })(); - ex.Resource = Resource; -})(ex || (ex = {})); -/// -/// -/// -/// -/// -var ex; -(function (ex) { - /** - * Textures - * - * The [[Texture]] object allows games built in Excalibur to load image resources. - * [[Texture]] is an [[ILoadable]] which means it can be passed to a [[Loader]] - * to pre-load before starting a level or game. - * - * Textures are the raw image so to add a drawing to a game, you must create - * a [[Sprite]]. You can use [[Texture.asSprite]] to quickly generate a Sprite - * instance. - * - * ## Pre-loading textures - * - * Pass the [[Texture]] to a [[Loader]] to pre-load the asset. Once a [[Texture]] - * is loaded, you can generate a [[Sprite]] with it. - * - * ```js - * var txPlayer = new ex.Texture("/assets/tx/player.png"); - * - * var loader = new ex.Loader(txPlayer); - * - * game.start(loader).then(function () { - * - * var player = new ex.Actor(); - * - * player.addDrawing(txPlayer); - * - * game.add(player); - * }); - * ``` - */ - var Texture = (function (_super) { - __extends(Texture, _super); /** - * @param path Path to the image resource - * @param bustCache Optionally load texture with cache busting + * Saturates the current color by a specified amount + * + * @param factor The amount to saturate by [0-1] */ - function Texture(path, bustCache) { - if (bustCache === void 0) { bustCache = true; } - _super.call(this, path, 'blob', bustCache); - this.path = path; - this.bustCache = bustCache; - /** - * A [[Promise]] that resolves when the Texture is loaded. - */ - this.loaded = new ex.Promise(); - this._isLoaded = false; - this._sprite = null; - this._sprite = new ex.Sprite(this, 0, 0, 0, 0); - } + Color.prototype.saturate = function (factor) { + if (factor === void 0) { factor = 0.1; } + var temp = HSLColor.fromRGBA(this.r, this.g, this.b, this.a); + temp.s += (temp.s * factor); + return temp.toRGBA(); + }; /** - * Returns true if the Texture is completely loaded and is ready - * to be drawn. + * Desaturates the current color by a specified amount + * + * @param factor The amount to desaturate by [0-1] */ - Texture.prototype.isLoaded = function () { - return this._isLoaded; + Color.prototype.desaturate = function (factor) { + if (factor === void 0) { factor = 0.1; } + var temp = HSLColor.fromRGBA(this.r, this.g, this.b, this.a); + temp.s -= (temp.s * factor); + return temp.toRGBA(); }; /** - * Begins loading the texture and returns a promise to be resolved on completion + * Multiplies a color by another, results in a darker color + * + * @param color The other color */ - Texture.prototype.load = function () { - var _this = this; - var complete = new ex.Promise(); - var loaded = _super.prototype.load.call(this); - loaded.then(function () { - _this.image = new Image(); - _this.image.addEventListener('load', function () { - _this._isLoaded = true; - _this.width = _this._sprite.swidth = _this._sprite.naturalWidth = _this._sprite.width = _this.image.naturalWidth; - _this.height = _this._sprite.sheight = _this._sprite.naturalHeight = _this._sprite.height = _this.image.naturalHeight; - _this.loaded.resolve(_this.image); - complete.resolve(_this.image); - }); - _this.image.src = _super.prototype.getData.call(_this); - }, function () { - complete.reject('Error loading texture.'); - }); - return complete; + Color.prototype.mulitiply = function (color) { + var newR = ((color.r / 255 * this.r / 255) * 255); + var newG = ((color.g / 255 * this.g / 255) * 255); + var newB = ((color.b / 255 * this.b / 255) * 255); + var newA = (color.a * this.a); + return new Color(newR, newG, newB, newA); }; - Texture.prototype.asSprite = function () { - return this._sprite; + /** + * Screens a color by another, results in a lighter color + * + * @param color The other color + */ + Color.prototype.screen = function (color) { + var color1 = color.invert(); + var color2 = color.invert(); + return color1.mulitiply(color2).invert(); }; - return Texture; - })(ex.Resource); - ex.Texture = Texture; - /** - * Sounds - * - * The [[Sound]] object allows games built in Excalibur to load audio - * components, from soundtracks to sound effects. [[Sound]] is an [[ILoadable]] - * which means it can be passed to a [[Loader]] to pre-load before a game or level. - * - * ## Pre-loading sounds - * - * Pass the [[Sound]] to a [[Loader]] to pre-load the asset. Once a [[Sound]] - * is loaded, you can [[Sound.play|play]] it. - * - * ```js - * var sndPlayerDeath = new ex.Sound("/assets/snd/player-death.mp3", "/assets/snd/player-wav.mp3"); - * - * var loader = new ex.Loader(sndPlayerDeath); - * - * game.start(loader).then(function () { - * - * sndPlayerDeath.play(); - * }); - * ``` - */ - var Sound = (function () { /** - * @param paths A list of audio sources (clip.wav, clip.mp3, clip.ogg) for this audio clip. This is done for browser compatibility. + * Inverts the current color */ - function Sound() { - var paths = []; - for (var _i = 0; _i < arguments.length; _i++) { - paths[_i - 0] = arguments[_i]; - } - this._logger = ex.Logger.getInstance(); - this.onprogress = function () { return; }; - this.oncomplete = function () { return; }; - this.onerror = function () { return; }; - this.onload = function () { return; }; - this._isLoaded = false; - this._selectedFile = ''; - this._wasPlayingOnHidden = false; - /* Chrome : MP3, WAV, Ogg - * Firefox : WAV, Ogg, - * IE : MP3, WAV coming soon - * Safari MP3, WAV, Ogg - */ - this._selectedFile = ''; - for (var i = 0; i < paths.length; i++) { - if (Sound.canPlayFile(paths[i])) { - this._selectedFile = paths[i]; - break; - } - } - if (!this._selectedFile) { - this._logger.warn('This browser does not support any of the audio files specified:', paths.join(', ')); - this._logger.warn('Attempting to use', paths[0]); - this._selectedFile = paths[0]; // select the first specified - } - this.sound = new ex.Internal.FallbackAudio(this._selectedFile, 1.0); - } + Color.prototype.invert = function () { + return new Color(255 - this.r, 255 - this.g, 255 - this.b, 1.0 - this.a); + }; /** - * Whether or not the browser can play this file as HTML5 Audio + * Averages the current color with another + * + * @param color The other color */ - Sound.canPlayFile = function (file) { - try { - var a = new Audio(); - var filetype = /.*\.([A-Za-z0-9]+)$/; - var type = file.match(filetype)[1]; - if (a.canPlayType('audio/' + type)) { - return true; - } - { - return false; - } - } - catch (e) { - ex.Logger.getInstance().warn('Cannot determine audio support, assuming no support for the Audio Tag', e); - return false; - } + Color.prototype.average = function (color) { + var newR = (color.r + this.r) / 2; + var newG = (color.g + this.g) / 2; + var newB = (color.b + this.b) / 2; + var newA = (color.a + this.a) / 2; + return new Color(newR, newG, newB, newA); }; - Sound.prototype.wireEngine = function (engine) { - var _this = this; - if (engine) { - this._engine = engine; - this._engine.on('hidden', function () { - if (engine.pauseAudioWhenHidden && _this.isPlaying()) { - _this._wasPlayingOnHidden = true; - _this.pause(); - } - }); - this._engine.on('visible', function () { - if (engine.pauseAudioWhenHidden && _this._wasPlayingOnHidden) { - _this.play(); - _this._wasPlayingOnHidden = false; - } - }); + /** + * Returns a CSS string representation of a color. + */ + Color.prototype.toString = function () { + var result = String(this.r.toFixed(0)) + ', ' + String(this.g.toFixed(0)) + ', ' + String(this.b.toFixed(0)); + if (this.a !== undefined || this.a !== null) { + return 'rgba(' + result + ', ' + String(this.a) + ')'; } + return 'rgb(' + result + ')'; }; /** - * Sets the volume of the sound clip - * @param volume A volume value between 0-1.0 + * Returns a CSS string representation of a color. */ - Sound.prototype.setVolume = function (volume) { - if (this.sound) { - this.sound.setVolume(volume); - } + Color.prototype.fillStyle = function () { + return this.toString(); }; /** - * Indicates whether the clip should loop when complete - * @param loop Set the looping flag + * Returns a clone of the current color. */ - Sound.prototype.setLoop = function (loop) { - if (this.sound) { - this.sound.setLoop(loop); - } + Color.prototype.clone = function () { + return new Color(this.r, this.g, this.b, this.a); }; /** - * Whether or not the sound is playing right now + * Black (#000000) */ - Sound.prototype.isPlaying = function () { - if (this.sound) { - return this.sound.isPlaying(); - } - }; + Color.Black = Color.fromHex('#000000'); /** - * Play the sound, returns a promise that resolves when the sound is done playing + * White (#FFFFFF) */ - Sound.prototype.play = function () { - if (this.sound) { - return this.sound.play(); - } - }; + Color.White = Color.fromHex('#FFFFFF'); /** - * Stop the sound, and do not rewind + * Gray (#808080) */ - Sound.prototype.pause = function () { - if (this.sound) { - this.sound.pause(); - } - }; + Color.Gray = Color.fromHex('#808080'); /** - * Stop the sound and rewind + * Light gray (#D3D3D3) */ - Sound.prototype.stop = function () { - if (this.sound) { - this.sound.stop(); - } - }; + Color.LightGray = Color.fromHex('#D3D3D3'); /** - * Returns true if the sound is loaded + * Dark gray (#A9A9A9) */ - Sound.prototype.isLoaded = function () { - return this._isLoaded; - }; + Color.DarkGray = Color.fromHex('#A9A9A9'); /** - * Begins loading the sound and returns a promise to be resolved on completion + * Yellow (#FFFF00) */ - Sound.prototype.load = function () { - var _this = this; - var complete = new ex.Promise(); - this._logger.debug('Started loading sound', this._selectedFile); - this.sound.onprogress = this.onprogress; - this.sound.onload = function () { - _this.oncomplete(); - _this._isLoaded = true; - _this._logger.debug('Completed loading sound', _this._selectedFile); - complete.resolve(_this.sound); - }; - this.sound.onerror = function (e) { - _this.onerror(e); - complete.resolve(e); - }; - this.sound.load(); - return complete; - }; - return Sound; + Color.Yellow = Color.fromHex('#FFFF00'); + /** + * Orange (#FFA500) + */ + Color.Orange = Color.fromHex('#FFA500'); + /** + * Red (#FF0000) + */ + Color.Red = Color.fromHex('#FF0000'); + /** + * Vermillion (#FF5B31) + */ + Color.Vermillion = Color.fromHex('#FF5B31'); + /** + * Rose (#FF007F) + */ + Color.Rose = Color.fromHex('#FF007F'); + /** + * Magenta (#FF00FF) + */ + Color.Magenta = Color.fromHex('#FF00FF'); + /** + * Violet (#7F00FF) + */ + Color.Violet = Color.fromHex('#7F00FF'); + /** + * Blue (#0000FF) + */ + Color.Blue = Color.fromHex('#0000FF'); + /** + * Azure (#007FFF) + */ + Color.Azure = Color.fromHex('#007FFF'); + /** + * Cyan (#00FFFF) + */ + Color.Cyan = Color.fromHex('#00FFFF'); + /** + * Viridian (#59978F) + */ + Color.Viridian = Color.fromHex('#59978F'); + /** + * Green (#00FF00) + */ + Color.Green = Color.fromHex('#00FF00'); + /** + * Chartreuse (#7FFF00) + */ + Color.Chartreuse = Color.fromHex('#7FFF00'); + /** + * Transparent (#FFFFFF00) + */ + Color.Transparent = Color.fromHex('#FFFFFF00'); + return Color; })(); - ex.Sound = Sound; + ex.Color = Color; /** - * Pre-loading assets + * Internal HSL Color representation * - * The loader provides a mechanism to preload multiple resources at - * one time. The loader must be passed to the engine in order to - * trigger the loading progress bar. + * http://en.wikipedia.org/wiki/HSL_and_HSV + * http://axonflux.com/handy-rgb-to-hsl-and-rgb-to-hsv-color-model-c + */ + var HSLColor = (function () { + function HSLColor(h, s, l, a) { + this.h = h; + this.s = s; + this.l = l; + this.a = a; + } + HSLColor.fromRGBA = function (r, g, b, a) { + r /= 255; + g /= 255; + b /= 255; + var max = Math.max(r, g, b), min = Math.min(r, g, b); + var h, s, l = (max + min) / 2; + if (max === min) { + h = s = 0; // achromatic + } + else { + var d = max - min; + s = l > 0.5 ? d / (2 - max - min) : d / (max + min); + switch (max) { + case r: + h = (g - b) / d + (g < b ? 6 : 0); + break; + case g: + h = (b - r) / d + 2; + break; + case b: + h = (r - g) / d + 4; + break; + } + h /= 6; + } + return new HSLColor(h, s, l, a); + }; + HSLColor.prototype.toRGBA = function () { + var r, g, b; + if (this.s === 0) { + r = g = b = this.l; // achromatic + } + else { + function hue2rgb(p, q, t) { + if (t < 0) { + t += 1; + } + if (t > 1) { + t -= 1; + } + if (t < 1 / 6) { + return p + (q - p) * 6 * t; + } + if (t < 1 / 2) { + return q; + } + if (t < 2 / 3) { + return p + (q - p) * (2 / 3 - t) * 6; + } + return p; + } + var q = this.l < 0.5 ? this.l * (1 + this.s) : this.l + this.s - this.l * this.s; + var p = 2 * this.l - q; + r = hue2rgb(p, q, this.h + 1 / 3); + g = hue2rgb(p, q, this.h); + b = hue2rgb(p, q, this.h - 1 / 3); + } + return new Color(r * 255, g * 255, b * 255, this.a); + }; + return HSLColor; + })(); +})(ex || (ex = {})); +/// +var ex; +(function (ex) { + /** + * Helper [[Actor]] primitive for drawing UI's, optimized for UI drawing. Does + * not participate in collisions. Drawn on top of all other actors. + */ + var UIActor = (function (_super) { + __extends(UIActor, _super); + /** + * @param x The starting x coordinate of the actor + * @param y The starting y coordinate of the actor + * @param width The starting width of the actor + * @param height The starting height of the actor + */ + function UIActor(x, y, width, height) { + _super.call(this, x, y, width, height); + this.traits = []; + this.traits.push(new ex.Traits.Movement()); + this.traits.push(new ex.Traits.CapturePointer()); + this.anchor.setTo(0, 0); + this.collisionType = ex.CollisionType.PreventCollision; + this.enableCapturePointer = true; + } + UIActor.prototype.onInitialize = function (engine) { + this._engine = engine; + }; + UIActor.prototype.contains = function (x, y, useWorld) { + if (useWorld === void 0) { useWorld = true; } + if (useWorld) { + return _super.prototype.contains.call(this, x, y); + } + var coords = this._engine.worldToScreenCoordinates(new ex.Point(x, y)); + return _super.prototype.contains.call(this, coords.x, coords.y); + }; + return UIActor; + })(ex.Actor); + ex.UIActor = UIActor; +})(ex || (ex = {})); +/// +/// +var ex; +(function (ex) { + /** + * Triggers * - * The [[Loader]] itself implements [[ILoadable]] so you can load loaders. + * Triggers are a method of firing arbitrary code on collision. These are useful + * as 'buttons', 'switches', or to trigger effects in a game. By default triggers + * are invisible, and can only be seen when [[Engine.isDebug]] is set to `true`. * - * ## Example: Pre-loading resources for a game + * ## Creating a trigger * * ```js - * // create a loader - * var loader = new ex.Loader(); + * var game = new ex.Game(); * - * // create a resource dictionary (best practice is to keep a separate file) - * var resources = { - * TextureGround: new ex.Texture("/images/textures/ground.png"), - * SoundDeath: new ex.Sound("/sound/death.wav", "/sound/death.mp3") - * }; + * // create a handler + * function onTrigger() { * - * // loop through dictionary and add to loader - * for (var loadable in resources) { - * if (resources.hasOwnProperty(loadable)) { - * loader.addResource(loadable); - * } + * // `this` will be the Trigger instance + * ex.Logger.getInstance().info("Trigger was triggered!", this); * } * - * // start game - * game.start(loader).then(function () { - * console.log("Game started!"); - * }); + * // set a trigger at (100, 100) that is 40x40px + * var trigger = new ex.Trigger(100, 100, 40, 40, onTrigger, 1); + * + * // create an actor across from the trigger + * var actor = new ex.Actor(100, 0, 40, 40, ex.Color.Red); + * + * // tell the actor to move towards the trigger over 3 seconds + * actor.moveTo(100, 200, 3000); + * + * game.add(trigger); + * game.add(actor); + * + * game.start(); * ``` */ - var Loader = (function () { + var Trigger = (function (_super) { + __extends(Trigger, _super); /** - * @param loadables Optionally provide the list of resources you want to load at constructor time + * @param x The x position of the trigger + * @param y The y position of the trigger + * @param width The width of the trigger + * @param height The height of the trigger + * @param action Callback to fire when trigger is activated, `this` will be bound to the Trigger instance + * @param repeats The number of times that this trigger should fire, by default it is 1, if -1 is supplied it will fire indefinitely */ - function Loader(loadables) { - this._resourceList = []; - this._index = 0; - this._resourceCount = 0; - this._numLoaded = 0; - this._progressCounts = {}; - this._totalCounts = {}; - this.onprogress = function () { return; }; - this.oncomplete = function () { return; }; - this.onerror = function () { return; }; - if (loadables) { - this.addResources(loadables); - } + function Trigger(x, y, width, height, action, repeats) { + _super.call(this, x, y, width, height); + this._action = function () { return; }; + this.repeats = 1; + this.target = null; + this.repeats = repeats || this.repeats; + this._action = action || this._action; + this.collisionType = ex.CollisionType.PreventCollision; + this.eventDispatcher = new ex.EventDispatcher(this); + this.actionQueue = new ex.Internal.Actions.ActionQueue(this); } - Loader.prototype.wireEngine = function (engine) { - this._engine = engine; - }; - /** - * Add a resource to the loader to load - * @param loadable Resource to add - */ - Loader.prototype.addResource = function (loadable) { - var key = this._index++; - this._resourceList.push(loadable); - this._progressCounts[key] = 0; - this._totalCounts[key] = 1; - this._resourceCount++; - }; - /** - * Add a list of resources to the loader to load - * @param loadables The list of resources to load - */ - Loader.prototype.addResources = function (loadables) { - var i = 0, len = loadables.length; - for (i; i < len; i++) { - this.addResource(loadables[i]); - } - }; - Loader.prototype._sumCounts = function (obj) { - var sum = 0; - var prev = 0; - for (var i in obj) { - sum += obj[i] | 0; - } - return sum; - }; - /** - * Returns true if the loader has completely loaded all resources - */ - Loader.prototype.isLoaded = function () { - return this._numLoaded === this._resourceCount; - }; - /** - * Begin loading all of the supplied resources, returning a promise - * that resolves when loading of all is complete - */ - Loader.prototype.load = function () { - var _this = this; - var complete = new ex.Promise(); - var me = this; - if (this._resourceList.length === 0) { - me.oncomplete.call(me); - return complete; - } - var progressArray = new Array(this._resourceList.length); - var progressChunks = this._resourceList.length; - this._resourceList.forEach(function (r, i) { - if (_this._engine) { - r.wireEngine(_this._engine); - } - r.onprogress = function (e) { - var total = e.total; - var loaded = e.loaded; - progressArray[i] = { loaded: ((loaded / total) * (100 / progressChunks)), total: 100 }; - var progressResult = progressArray.reduce(function (accum, next) { - return { loaded: (accum.loaded + next.loaded), total: 100 }; - }, { loaded: 0, total: 100 }); - me.onprogress.call(me, progressResult); - }; - r.oncomplete = r.onerror = function () { - me._numLoaded++; - if (me._numLoaded === me._resourceCount) { - me.onprogress.call(me, { loaded: 100, total: 100 }); - me.oncomplete.call(me); - complete.resolve(); - } - }; - }); - function loadNext(list, index) { - if (!list[index]) { - return; + Trigger.prototype.update = function (engine, delta) { + // Update action queue + this.actionQueue.update(delta); + // Update placements based on linear algebra + this.x += this.dx * delta / 1000; + this.y += this.dy * delta / 1000; + this.rotation += this.rx * delta / 1000; + this.scale.x += this.sx * delta / 1000; + this.scale.y += this.sy * delta / 1000; + // check for trigger collisions + if (this.target) { + if (this.collides(this.target)) { + this._dispatchAction(); } - list[index].load().then(function () { - loadNext(list, index + 1); - }); } - loadNext(this._resourceList, 0); - return complete; - }; - return Loader; - })(); - ex.Loader = Loader; -})(ex || (ex = {})); -/// -var ex; -(function (ex) { - var Detector = (function () { - function Detector() { - this.failedTests = []; - // critical browser features required for ex to run - this._criticalTests = { - // Test canvas/2d context support - canvasSupport: function () { - var elem = document.createElement('canvas'); - return !!(elem.getContext && elem.getContext('2d')); - }, - // Test array buffer support ex uses for downloading binary data - arrayBufferSupport: function () { - var xhr = new XMLHttpRequest(); - xhr.open('GET', '/'); - try { - xhr.responseType = 'arraybuffer'; - } - catch (e) { - return false; + else { + for (var i = 0; i < engine.currentScene.children.length; i++) { + var other = engine.currentScene.children[i]; + if (other !== this && + other.collisionType !== ex.CollisionType.PreventCollision && + this.collides(other)) { + this._dispatchAction(); } - return xhr.responseType === 'arraybuffer'; - }, - // Test data urls ex uses for sprites - dataUrlSupport: function () { - var canvas = document.createElement('canvas'); - return canvas.toDataURL('image/png').indexOf('data:image/png') === 0; - }, - // Test object url support for loading - objectUrlSupport: function () { - return 'URL' in window && 'revokeObjectURL' in URL && 'createObjectURL' in URL; - }, - // RGBA support for colors - rgbaSupport: function () { - var style = document.createElement('a').style; - style.cssText = 'background-color:rgba(150,255,150,.5)'; - return ('' + style.backgroundColor).indexOf('rgba') > -1; - } - }; - // warnings excalibur performance will be degraded - this._warningTest = { - webAudioSupport: function () { - return !!(window.AudioContext || - window.webkitAudioContext || - window.mozAudioContext || - window.msAudioContext || - window.oAudioContext); - }, - webglSupport: function () { - var elem = document.createElement('canvas'); - return !!(elem.getContext && elem.getContext('webgl')); - } - }; - } - Detector.prototype.test = function () { - // Critical test will for ex not to run - var failedCritical = false; - for (var test in this._criticalTests) { - if (!this._criticalTests[test]()) { - this.failedTests.push(test); - ex.Logger.getInstance().error('Critical browser feature missing, Excalibur requires:', test); - failedCritical = true; - } - } - if (failedCritical) { - return false; - } - // Warning tests do not for ex to return false to compatibility - for (var warning in this._warningTest) { - if (!this._warningTest[warning]()) { - ex.Logger.getInstance().warn('Warning browser feature missing, Excalibur will have reduced performance:', warning); } } - return true; + // remove trigger if its done, -1 repeat forever + if (this.repeats === 0) { + this.kill(); + } }; - return Detector; - })(); - ex.Detector = Detector; + Trigger.prototype._dispatchAction = function () { + this._action.call(this); + this.repeats--; + }; + Trigger.prototype.draw = function (ctx, delta) { + // does not draw + return; + }; + Trigger.prototype.debugDraw = function (ctx) { + _super.prototype.debugDraw.call(this, ctx); + // Meant to draw debug information about actors + ctx.save(); + ctx.translate(this.x, this.y); + var bb = this.getBounds(); + bb.left = bb.left - this.getWorldX(); + bb.right = bb.right - this.getWorldX(); + bb.top = bb.top - this.getWorldY(); + bb.bottom = bb.bottom - this.getWorldY(); + // Currently collision primitives cannot rotate + // ctx.rotate(this.rotation); + ctx.fillStyle = ex.Color.Violet.toString(); + ctx.strokeStyle = ex.Color.Violet.toString(); + ctx.fillText('Trigger', 10, 10); + bb.debugDraw(ctx); + ctx.restore(); + }; + return Trigger; + })(ex.Actor); + ex.Trigger = Trigger; })(ex || (ex = {})); -/// -/// -/// +/// +/// +/// +/// var ex; (function (ex) { /** - * Excalibur's built in templating class, it is a loadable that will load - * and html fragment from a url. Excalibur templating is very basic only - * allowing bindings of the type `data-text="this.obj.someprop"`, - * `data-style="color:this.obj.color.toString()"`. Bindings allow all valid - * Javascript expressions. + * An enum that represents the types of emitter nozzles */ - var Template = (function () { - /** - * @param path Location of the html template - */ - function Template(path) { - this.path = path; - this._isLoaded = false; - this.logger = ex.Logger.getInstance(); - this.onprogress = function () { return; }; - this.oncomplete = function () { return; }; - this.onerror = function () { return; }; - this._innerElement = document.createElement('div'); - this._innerElement.className = 'excalibur-template'; - } - Template.prototype.wireEngine = function (engine) { - this._engine = engine; - }; - /** - * Returns the full html template string once loaded. - */ - Template.prototype.getTemplateString = function () { - if (!this._isLoaded) { - return ''; - } - return this._htmlString; - }; - Template.prototype._compile = function () { - this._innerElement.innerHTML = this._htmlString; - this._styleElements = this._innerElement.querySelectorAll('[data-style]'); - this._textElements = this._innerElement.querySelectorAll('[data-text]'); - }; - Template.prototype._evaluateExpresion = function (expression, ctx) { - var func = new Function('return ' + expression + ';'); - var val = func.call(ctx); - return val; - }; - /** - * Applies any ctx object you wish and evaluates the template. - * Overload this method to include your favorite template library. - * You may return either an HTML string or a Dom node. - * @param ctx Any object you wish to apply to the template - */ - Template.prototype.apply = function (ctx) { - var _this = this; - /* tslint:disable:no-string-literal */ - for (var j = 0; j < this._styleElements.length; j++) { - (function () { - // poor man's json parse for things that aren't exactly json :( - // Extract style expressions - var styles = {}; - _this._styleElements[j].dataset['style'].split(';').forEach(function (s) { - if (s) { - var vals = s.split(':'); - styles[vals[0].trim()] = vals[1].trim(); - } - }); - // Evaluate parsed style expressions - for (var style in styles) { - (function () { - var expression = styles[style]; - _this._styleElements[j].style[style] = _this._evaluateExpresion(expression, ctx); - })(); - } - })(); - } - for (var i = 0; i < this._textElements.length; i++) { - (function () { - // Evaluate text expressions - var expression = _this._textElements[i].dataset['text']; - _this._textElements[i].innerText = _this._evaluateExpresion(expression, ctx); - })(); - } - // If the template HTML has a root element return that, otherwise use constructed root - if (this._innerElement.children.length === 1) { - this._innerElement = this._innerElement.firstChild; - } - /* tslint:enable:no-string-literal */ - return this._innerElement; - }; + (function (EmitterType) { /** - * Begins loading the template. Returns a promise that resolves with the template string when loaded. + * Constant for the circular emitter type */ - Template.prototype.load = function () { - var _this = this; - var complete = new ex.Promise(); - var request = new XMLHttpRequest(); - request.open('GET', this.path, true); - request.responseType = 'text'; - request.onprogress = this.onprogress; - request.onerror = this.onerror; - request.onload = function (e) { - if (request.status !== 200) { - _this.logger.error('Failed to load html template resource ', _this.path, ' server responded with error code', request.status); - _this.onerror(request.response); - _this._isLoaded = false; - complete.resolve('error'); - return; - } - _this._htmlString = request.response; - _this.oncomplete(); - _this.logger.debug('Completed loading template', _this.path); - _this._compile(); - _this._isLoaded = true; - complete.resolve(_this._htmlString); - }; - if (request.overrideMimeType) { - request.overrideMimeType('text/plain; charset=x-user-defined'); - } - request.send(); - return complete; - }; + EmitterType[EmitterType["Circle"] = 0] = "Circle"; /** - * Indicates whether the template has been loaded + * Constant for the rectangular emitter type */ - Template.prototype.isLoaded = function () { - return this._isLoaded; - }; - return Template; - })(); - ex.Template = Template; + EmitterType[EmitterType["Rectangle"] = 1] = "Rectangle"; + })(ex.EmitterType || (ex.EmitterType = {})); + var EmitterType = ex.EmitterType; /** - * Excalibur's binding library that allows you to bind an html - * template to the dom given a certain context. Excalibur bindings are only updated - * when the update() method is called + * Particle is used in a [[ParticleEmitter]] */ - var Binding = (function () { - /** - * @param parentElementId The id of the element in the dom to attach the template binding - * @param template The template you wish to bind - * @param ctx The context of the binding, which can be any object - */ - function Binding(parentElementId, template, ctx) { - this.parent = document.getElementById(parentElementId); - this.template = template; - this._ctx = ctx; - this.update(); + var Particle = (function () { + function Particle(emitter, life, opacity, beginColor, endColor, position, velocity, acceleration, startSize, endSize) { + this.position = new ex.Vector(0, 0); + this.velocity = new ex.Vector(0, 0); + this.acceleration = new ex.Vector(0, 0); + this.particleRotationalVelocity = 0; + this.currentRotation = 0; + this.focus = null; + this.focusAccel = 0; + this.opacity = 1; + this.beginColor = ex.Color.White.clone(); + this.endColor = ex.Color.White.clone(); + // Life is counted in ms + this.life = 300; + this.fadeFlag = false; + // Color transitions + this._rRate = 1; + this._gRate = 1; + this._bRate = 1; + this._aRate = 0; + this._currentColor = ex.Color.White.clone(); + this.emitter = null; + this.particleSize = 5; + this.particleSprite = null; + this.sizeRate = 0; + this.elapsedMultiplier = 0; + this.emitter = emitter; + this.life = life || this.life; + this.opacity = opacity || this.opacity; + this.endColor = endColor || this.endColor.clone(); + this.beginColor = beginColor || this.beginColor.clone(); + this._currentColor = this.beginColor.clone(); + this.position = position || this.position; + this.velocity = velocity || this.velocity; + this.acceleration = acceleration || this.acceleration; + this._rRate = (this.endColor.r - this.beginColor.r) / this.life; + this._gRate = (this.endColor.g - this.beginColor.g) / this.life; + this._bRate = (this.endColor.b - this.beginColor.b) / this.life; + this._aRate = this.opacity / this.life; + this.startSize = startSize || 0; + this.endSize = endSize || 0; + if ((this.endSize > 0) && (this.startSize > 0)) { + this.sizeRate = (this.endSize - this.startSize) / this.life; + this.particleSize = this.startSize; + } } - /** - * Listen to any arbitrary object's events to update this binding - * @param obj Any object that supports addEventListener - * @param events A list of events to listen for - * @param handler A optional handler to fire on any event - */ - Binding.prototype.listen = function (obj, events, handler) { - var _this = this; - // todo - if (!handler) { - handler = function () { - _this.update(); - }; + Particle.prototype.kill = function () { + this.emitter.removeParticle(this); + }; + Particle.prototype.update = function (delta) { + this.life = this.life - delta; + this.elapsedMultiplier = this.elapsedMultiplier + delta; + if (this.life < 0) { + this.kill(); + } + if (this.fadeFlag) { + this.opacity = ex.Util.clamp(this._aRate * this.life, 0.0001, 1); } - if (obj.addEventListener) { - events.forEach(function (e) { - obj.addEventListener(e, handler); - }); + if ((this.startSize > 0) && (this.endSize > 0)) { + this.particleSize = ex.Util.clamp(this.sizeRate * delta + this.particleSize, Math.min(this.startSize, this.endSize), Math.max(this.startSize, this.endSize)); } - }; - /** - * Update this template binding with the latest values from - * the ctx reference passed to the constructor - */ - Binding.prototype.update = function () { - var html = this._applyTemplate(this.template, this._ctx); - if (html instanceof String) { - this.parent.innerHTML = html; + this._currentColor.r = ex.Util.clamp(this._currentColor.r + this._rRate * delta, 0, 255); + this._currentColor.g = ex.Util.clamp(this._currentColor.g + this._gRate * delta, 0, 255); + this._currentColor.b = ex.Util.clamp(this._currentColor.b + this._bRate * delta, 0, 255); + this._currentColor.a = ex.Util.clamp(this.opacity, 0.0001, 1); + if (this.focus) { + var accel = this.focus.minus(this.position).normalize().scale(this.focusAccel).scale(delta / 1000); + this.velocity = this.velocity.add(accel); } - if (html instanceof Node) { - if (this.parent.lastChild !== html) { - this.parent.appendChild(html); - } + else { + this.velocity = this.velocity.add(this.acceleration.scale(delta / 1000)); + } + this.position = this.position.add(this.velocity.scale(delta / 1000)); + if (this.particleRotationalVelocity) { + this.currentRotation = (this.currentRotation + this.particleRotationalVelocity * delta / 1000) % (2 * Math.PI); } }; - Binding.prototype._applyTemplate = function (template, ctx) { - if (template.isLoaded()) { - return template.apply(ctx); + Particle.prototype.draw = function (ctx) { + if (this.particleSprite) { + this.particleSprite.rotation = this.currentRotation; + this.particleSprite.scale.setTo(this.particleSize, this.particleSize); + this.particleSprite.draw(ctx, this.position.x, this.position.y); + return; } + this._currentColor.a = ex.Util.clamp(this.opacity, 0.0001, 1); + ctx.fillStyle = this._currentColor.toString(); + ctx.beginPath(); + ctx.arc(this.position.x, this.position.y, this.particleSize, 0, Math.PI * 2); + ctx.fill(); + ctx.closePath(); }; - return Binding; + return Particle; })(); - ex.Binding = Binding; -})(ex || (ex = {})); -/// -var ex; -(function (ex) { - /** - * Enum representing the different horizontal text alignments - */ - (function (TextAlign) { - /** - * The text is left-aligned. - */ - TextAlign[TextAlign["Left"] = 0] = "Left"; - /** - * The text is right-aligned. - */ - TextAlign[TextAlign["Right"] = 1] = "Right"; - /** - * The text is centered. - */ - TextAlign[TextAlign["Center"] = 2] = "Center"; - /** - * The text is aligned at the normal start of the line (left-aligned for left-to-right locales, - * right-aligned for right-to-left locales). - */ - TextAlign[TextAlign["Start"] = 3] = "Start"; - /** - * The text is aligned at the normal end of the line (right-aligned for left-to-right locales, - * left-aligned for right-to-left locales). - */ - TextAlign[TextAlign["End"] = 4] = "End"; - })(ex.TextAlign || (ex.TextAlign = {})); - var TextAlign = ex.TextAlign; - /** - * Enum representing the different baseline text alignments - */ - (function (BaseAlign) { - /** - * The text baseline is the top of the em square. - */ - BaseAlign[BaseAlign["Top"] = 0] = "Top"; - /** - * The text baseline is the hanging baseline. Currently unsupported; this will act like - * alphabetic. - */ - BaseAlign[BaseAlign["Hanging"] = 1] = "Hanging"; - /** - * The text baseline is the middle of the em square. - */ - BaseAlign[BaseAlign["Middle"] = 2] = "Middle"; - /** - * The text baseline is the normal alphabetic baseline. - */ - BaseAlign[BaseAlign["Alphabetic"] = 3] = "Alphabetic"; - /** - * The text baseline is the ideographic baseline; this is the bottom of - * the body of the characters, if the main body of characters protrudes - * beneath the alphabetic baseline. Currently unsupported; this will - * act like alphabetic. - */ - BaseAlign[BaseAlign["Ideographic"] = 4] = "Ideographic"; - /** - * The text baseline is the bottom of the bounding box. This differs - * from the ideographic baseline in that the ideographic baseline - * doesn't consider descenders. - */ - BaseAlign[BaseAlign["Bottom"] = 5] = "Bottom"; - })(ex.BaseAlign || (ex.BaseAlign = {})); - var BaseAlign = ex.BaseAlign; + ex.Particle = Particle; /** - * Labels - * - * Labels are the way to draw small amounts of text to the screen. They are - * actors and inherit all of the benifits and capabilities. + * Particle Emitters * - * ## Creating a Label + * Using a particle emitter is a great way to create interesting effects + * in your game, like smoke, fire, water, explosions, etc. `ParticleEmitter` + * extend [[Actor]] allowing you to use all of the features that come with. * - * You can pass in arguments to the [[Label.constructor]] or simply set the - * properties you need after creating an instance of the [[Label]]. + * The easiest way to create a `ParticleEmitter` is to use the + * [Particle Tester](http://excaliburjs.com/particle-tester/) to generate code for emitters. * - * Since labels are [[Actor|Actors]], they need to be added to a [[Scene]] - * to be drawn and updated on-screen. + * ## Example: Adding an emitter * * ```js - * var game = new ex.Engine(); - * - * // constructor - * var label = new ex.Label("Hello World", 50, 50, "10px Arial"); - * - * // properties - * var label = new ex.Label(); - * label.x = 50; - * label.y = 50; - * label.font = "10px Arial"; - * label.text = "Foo"; - * label.color = ex.Color.White; - * label.textAlign = ex.TextAlign.Center; - * - * // add to current scene - * game.add(label); - * - * // start game - * game.start(); - * ``` - * - * ## Web Fonts - * - * The HTML5 Canvas API draws text using CSS syntax. Because of this, web fonts - * are fully supported. To draw a web font, follow the same procedure you use - * for CSS. Then simply pass in the font string to the [[Label]] constructor - * or set [[Label.font]]. - * - * **index.html** - * - * ```html - * - * - * - * - * - * - * - * - * - * - * - * ``` + * var actor = new ex.Actor(...); + * var emitter = new ex.ParticleEmitter(...); * - * **game.js** + * emitter.emitterType = ex.EmitterType.Circle; // Shape of emitter nozzle + * emitter.radius = 5; + * emitter.minVel = 100; + * emitter.maxVel = 200; + * emitter.minAngle = 0; + * emitter.maxAngle = Math.PI * 2; + * emitter.emitRate = 300; // 300 particles/second + * emitter.opacity = 0.5; + * emitter.fadeFlag = true; // fade particles overtime + * emitter.particleLife = 1000; // in milliseconds = 1 sec + * emitter.maxSize = 10; // in pixels + * emitter.minSize = 1; + * emitter.particleColor = ex.Color.Rose; * - * ```js - * var game = new ex.Engine(); + * // set emitter settings + * emitter.isEmitting = true; // should the emitter be emitting * - * var label = new ex.Label(); - * label.font = "12px Foobar, Arial, Sans-Serif"; - * label.text = "Hello World"; + * // add the emitter as a child actor, it will draw on top of the parent actor + * // and move with the parent + * actor.add(emitter); * - * game.add(label); - * game.start(); + * // or, alternatively, add it to the current scene + * engine.add(emitter); * ``` - * - * ## Performance Implications - * - * It is recommended to use a [[SpriteFont]] for labels as the raw Canvas - * API for drawing text is slow (`fillText`). Too many labels that - * do not use sprite fonts will visibly affect the frame rate of your game. - * - * Alternatively, you can always use HTML and CSS to draw UI elements, but - * currently Excalibur does not provide a way to easily interact with the - * DOM. Still, this will not affect canvas performance and is a way to - * lighten your game, if needed. */ - var Label = (function (_super) { - __extends(Label, _super); + var ParticleEmitter = (function (_super) { + __extends(ParticleEmitter, _super); /** - * @param text The text of the label - * @param x The x position of the label - * @param y The y position of the label - * @param font Use any valid CSS font string for the label's font. Web fonts are supported. Default is `10px sans-serif`. - * @param spriteFont Use an Excalibur sprite font for the label's font, if a SpriteFont is provided it will take precendence - * over a css font. + * @param x The x position of the emitter + * @param y The y position of the emitter + * @param width The width of the emitter + * @param height The height of the emitter */ - function Label(text, x, y, font, spriteFont) { - _super.call(this, x, y); + function ParticleEmitter(x, y, width, height) { + _super.call(this, x, y, width, height, ex.Color.White); + this._particlesToEmit = 0; + this.numParticles = 0; + /** + * Gets or sets the isEmitting flag + */ + this.isEmitting = true; + /** + * Gets or sets the backing particle collection + */ + this.particles = null; + /** + * Gets or sets the backing deadParticle collection + */ + this.deadParticles = null; + /** + * Gets or sets the minimum partical velocity + */ + this.minVel = 0; + /** + * Gets or sets the maximum partical velocity + */ + this.maxVel = 0; + /** + * Gets or sets the acceleration vector for all particles + */ + this.acceleration = new ex.Vector(0, 0); + /** + * Gets or sets the minimum angle in radians + */ + this.minAngle = 0; + /** + * Gets or sets the maximum angle in radians + */ + this.maxAngle = 0; /** - * The font size in pixels, default is 10px + * Gets or sets the emission rate for particles (particles/sec) */ - this.fontSize = 10; + this.emitRate = 1; //particles/sec /** - * Gets or sets the horizontal text alignment property for the label. + * Gets or sets the life of each particle in milliseconds */ - this.textAlign = TextAlign.Left; + this.particleLife = 2000; /** - * Gets or sets the baseline alignment property for the label. + * Gets or sets the opacity of each particle from 0 to 1.0 */ - this.baseAlign = BaseAlign.Bottom; + this.opacity = 1; /** - * Gets or sets the letter spacing on a Label. Only supported with Sprite Fonts. + * Gets or sets the fade flag which causes particles to gradually fade out over the course of their life. */ - this.letterSpacing = 0; //px + this.fadeFlag = false; /** - * Whether or not the [[SpriteFont]] will be case-sensitive when matching characters. + * Gets or sets the optional focus where all particles should accelerate towards */ - this.caseInsensitive = true; - this._textShadowOn = false; - this._shadowOffsetX = 0; - this._shadowOffsetY = 0; - this._shadowColor = ex.Color.Black.clone(); - this._shadowColorDirty = false; - this._textSprites = {}; - this._shadowSprites = {}; - this._color = ex.Color.Black.clone(); - this.text = text || ''; - this.color = ex.Color.Black.clone(); - this.spriteFont = spriteFont; + this.focus = null; + /** + * Gets or sets the acceleration for focusing particles if a focus has been specified + */ + this.focusAccel = 1; + /* + * Gets or sets the optional starting size for the particles + */ + this.startSize = null; + /* + * Gets or sets the optional ending size for the particles + */ + this.endSize = null; + /** + * Gets or sets the minimum size of all particles + */ + this.minSize = 5; + /** + * Gets or sets the maximum size of all particles + */ + this.maxSize = 5; + /** + * Gets or sets the beginning color of all particles + */ + this.beginColor = ex.Color.White; + /** + * Gets or sets the ending color of all particles + */ + this.endColor = ex.Color.White; + /** + * Gets or sets the sprite that a particle should use + * @warning Performance intensive + */ + this.particleSprite = null; + /** + * Gets or sets the emitter type for the particle emitter + */ + this.emitterType = EmitterType.Rectangle; + /** + * Gets or sets the emitter radius, only takes effect when the [[emitterType]] is [[EmitterType.Circle]] + */ + this.radius = 0; + /** + * Gets or sets the particle rotational speed velocity + */ + this.particleRotationalVelocity = 0; + /** + * Indicates whether particles should start with a random rotation + */ + this.randomRotation = false; this.collisionType = ex.CollisionType.PreventCollision; - this.font = font || '10px sans-serif'; // coallesce to default canvas font - if (spriteFont) { + this.particles = new ex.Util.Collection(); + this.deadParticles = new ex.Util.Collection(); + // Remove offscreen culling from particle emitters + for (var trait in this.traits) { + if (this.traits[trait] instanceof ex.Traits.OffscreenCulling) { + this.traits.splice(trait, 1); + } } } - /** - * Returns the width of the text in the label (in pixels); - * @param ctx Rending context to measure the string with - */ - Label.prototype.getTextWidth = function (ctx) { - var oldFont = ctx.font; - ctx.font = this.font; - var width = ctx.measureText(this.text).width; - ctx.font = oldFont; - return width; - }; - // TypeScript doesn't support string enums :( - Label.prototype._lookupTextAlign = function (textAlign) { - switch (textAlign) { - case TextAlign.Left: - return 'left'; - case TextAlign.Right: - return 'right'; - case TextAlign.Center: - return 'center'; - case TextAlign.End: - return 'end'; - case TextAlign.Start: - return 'start'; - default: - return 'start'; - } - }; - Label.prototype._lookupBaseAlign = function (baseAlign) { - switch (baseAlign) { - case BaseAlign.Alphabetic: - return 'alphabetic'; - case BaseAlign.Bottom: - return 'bottom'; - case BaseAlign.Hanging: - return 'hangin'; - case BaseAlign.Ideographic: - return 'ideographic'; - case BaseAlign.Middle: - return 'middle'; - case BaseAlign.Top: - return 'top'; - default: - return 'alphabetic'; - } - }; - /** - * Sets the text shadow for sprite fonts - * @param offsetX The x offset in pixels to place the shadow - * @param offsetY The y offset in pixles to place the shadow - * @param shadowColor The color of the text shadow - */ - Label.prototype.setTextShadow = function (offsetX, offsetY, shadowColor) { - this.spriteFont.setTextShadow(offsetX, offsetY, shadowColor); - }; - /** - * Toggles text shadows on or off, only applies when using sprite fonts - */ - Label.prototype.useTextShadow = function (on) { - this.spriteFont.useTextShadow(on); + ParticleEmitter.prototype.removeParticle = function (particle) { + this.deadParticles.push(particle); }; /** - * Clears the current text shadow + * Causes the emitter to emit particles + * @param particleCount Number of particles to emit right now */ - Label.prototype.clearTextShadow = function () { - this._textShadowOn = false; - this._shadowOffsetX = 0; - this._shadowOffsetY = 0; - this._shadowColor = ex.Color.Black.clone(); + ParticleEmitter.prototype.emitParticles = function (particleCount) { + for (var i = 0; i < particleCount; i++) { + this.particles.push(this._createParticle()); + } }; - Label.prototype.update = function (engine, delta) { - _super.prototype.update.call(this, engine, delta); - /* - if (this.spriteFont && (this._color !== this.color || this.previousOpacity !== this.opacity)) { - for (var character in this._textSprites) { - this._textSprites[character].clearEffects(); - this._textSprites[character].fill(this.color.clone()); - this._textSprites[character].opacity(this.opacity); - - } - this._color = this.color; - this.previousOpacity = this.opacity; - } - - if (this.spriteFont && this._textShadowOn && this._shadowColorDirty && this._shadowColor) { - for (var characterShadow in this._shadowSprites) { - this._shadowSprites[characterShadow].clearEffects(); - this._shadowSprites[characterShadow].addEffect(new Effects.Fill(this._shadowColor.clone())); - } - this._shadowColorDirty = false; - }*/ + ParticleEmitter.prototype.clearParticles = function () { + this.particles.clear(); }; - Label.prototype.draw = function (ctx, delta) { - ctx.save(); - ctx.translate(this.x, this.y); - ctx.scale(this.scale.x, this.scale.y); - ctx.rotate(this.rotation); - if (this._textShadowOn) { - ctx.save(); - ctx.translate(this._shadowOffsetX, this._shadowOffsetY); - this._fontDraw(ctx, delta, this._shadowSprites); - ctx.restore(); + // Creates a new particle given the contraints of the emitter + ParticleEmitter.prototype._createParticle = function () { + // todo implement emitter contraints; + var ranX = 0; + var ranY = 0; + var angle = ex.Util.randomInRange(this.minAngle, this.maxAngle); + var vel = ex.Util.randomInRange(this.minVel, this.maxVel); + var size = this.startSize || ex.Util.randomInRange(this.minSize, this.maxSize); + var dx = vel * Math.cos(angle); + var dy = vel * Math.sin(angle); + if (this.emitterType === EmitterType.Rectangle) { + ranX = ex.Util.randomInRange(this.x, this.x + this.getWidth()); + ranY = ex.Util.randomInRange(this.y, this.y + this.getHeight()); } - this._fontDraw(ctx, delta, this._textSprites); - _super.prototype.draw.call(this, ctx, delta); - ctx.restore(); - }; - Label.prototype._fontDraw = function (ctx, delta, sprites) { - if (this.spriteFont) { - this.spriteFont.draw(ctx, this.text, 0, 0, { - color: this.color.clone(), - baseAlign: this.baseAlign, - textAlign: this.textAlign, - fontSize: this.fontSize, - letterSpacing: this.letterSpacing, - opacity: this.opacity - }); + else if (this.emitterType === EmitterType.Circle) { + var radius = ex.Util.randomInRange(0, this.radius); + ranX = radius * Math.cos(angle) + this.x; + ranY = radius * Math.sin(angle) + this.y; } - else { - var oldAlign = ctx.textAlign; - var oldTextBaseline = ctx.textBaseline; - ctx.textAlign = this._lookupTextAlign(this.textAlign); - ctx.textBaseline = this._lookupBaseAlign(this.baseAlign); - if (this.color) { - this.color.a = this.opacity; - } - ctx.fillStyle = this.color.toString(); - ctx.font = this.fontSize + " " + this.font; - if (this.maxWidth) { - ctx.fillText(this.text, 0, 0, this.maxWidth); - } - else { - ctx.fillText(this.text, 0, 0); + var p = new Particle(this, this.particleLife, this.opacity, this.beginColor, this.endColor, new ex.Vector(ranX, ranY), new ex.Vector(dx, dy), this.acceleration, this.startSize, this.endSize); + p.fadeFlag = this.fadeFlag; + p.particleSize = size; + if (this.particleSprite) { + p.particleSprite = this.particleSprite; + } + p.particleRotationalVelocity = this.particleRotationalVelocity; + if (this.randomRotation) { + p.currentRotation = ex.Util.randomInRange(0, Math.PI * 2); + } + if (this.focus) { + p.focus = this.focus.add(new ex.Vector(this.x, this.y)); + p.focusAccel = this.focusAccel; + } + return p; + }; + ParticleEmitter.prototype.update = function (engine, delta) { + var _this = this; + _super.prototype.update.call(this, engine, delta); + if (this.isEmitting) { + this._particlesToEmit += this.emitRate * (delta / 1000); + //var numParticles = Math.ceil(this.emitRate * delta / 1000); + if (this._particlesToEmit > 1.0) { + this.emitParticles(Math.floor(this._particlesToEmit)); + this._particlesToEmit = this._particlesToEmit - Math.floor(this._particlesToEmit); } - ctx.textAlign = oldAlign; - ctx.textBaseline = oldTextBaseline; } + this.particles.forEach(function (p) { return p.update(delta); }); + this.deadParticles.forEach(function (p) { return _this.particles.removeElement(p); }); + this.deadParticles.clear(); }; - Label.prototype.debugDraw = function (ctx) { + ParticleEmitter.prototype.draw = function (ctx, delta) { + // todo is there a more efficient to draw + // possibly use a webgl offscreen canvas and shaders to do particles? + this.particles.forEach(function (p) { return p.draw(ctx); }); + }; + ParticleEmitter.prototype.debugDraw = function (ctx) { _super.prototype.debugDraw.call(this, ctx); + ctx.fillStyle = ex.Color.Black.toString(); + ctx.fillText('Particles: ' + this.particles.count(), this.x, this.y + 20); + if (this.focus) { + ctx.fillRect(this.focus.x + this.x, this.focus.y + this.y, 3, 3); + ex.Util.drawLine(ctx, 'yellow', this.focus.x + this.x, this.focus.y + this.y, _super.prototype.getCenter.call(this).x, _super.prototype.getCenter.call(this).y); + ctx.fillText('Focus', this.focus.x + this.x, this.focus.y + this.y); + } }; - return Label; + return ParticleEmitter; })(ex.Actor); - ex.Label = Label; + ex.ParticleEmitter = ParticleEmitter; })(ex || (ex = {})); -/// var ex; (function (ex) { - var Input; - (function (Input) { - /** - * The type of pointer for a [[PointerEvent]]. - */ - (function (PointerType) { - PointerType[PointerType["Touch"] = 0] = "Touch"; - PointerType[PointerType["Mouse"] = 1] = "Mouse"; - PointerType[PointerType["Pen"] = 2] = "Pen"; - PointerType[PointerType["Unknown"] = 3] = "Unknown"; - })(Input.PointerType || (Input.PointerType = {})); - var PointerType = Input.PointerType; - /** - * The mouse button being pressed. - */ - (function (PointerButton) { - PointerButton[PointerButton["Left"] = 0] = "Left"; - PointerButton[PointerButton["Middle"] = 1] = "Middle"; - PointerButton[PointerButton["Right"] = 2] = "Right"; - PointerButton[PointerButton["Unknown"] = 3] = "Unknown"; - })(Input.PointerButton || (Input.PointerButton = {})); - var PointerButton = Input.PointerButton; - /** - * Determines the scope of handling mouse/touch events. See [[Pointers]] for more information. - */ - (function (PointerScope) { - /** - * Handle events on the `canvas` element only. Events originating outside the - * `canvas` will not be handled. - */ - PointerScope[PointerScope["Canvas"] = 0] = "Canvas"; - /** - * Handles events on the entire document. All events will be handled by Excalibur. - */ - PointerScope[PointerScope["Document"] = 1] = "Document"; - })(Input.PointerScope || (Input.PointerScope = {})); - var PointerScope = Input.PointerScope; - /** - * Pointer events - * - * Represents a mouse, touch, or stylus event. See [[Pointers]] for more information on - * handling pointer input. - * - * For mouse-based events, you can inspect [[PointerEvent.button]] to see what button was pressed. - */ - var PointerEvent = (function (_super) { - __extends(PointerEvent, _super); - /** - * @param x The `x` coordinate of the event (in world coordinates) - * @param y The `y` coordinate of the event (in world coordinates) - * @param index The index of the pointer (zero-based) - * @param pointerType The type of pointer - * @param button The button pressed (if [[PointerType.Mouse]]) - * @param ev The raw DOM event being handled - */ - function PointerEvent(x, y, index, pointerType, button, ev) { - _super.call(this); - this.x = x; - this.y = y; - this.index = index; - this.pointerType = pointerType; - this.button = button; - this.ev = ev; - } - return PointerEvent; - })(ex.GameEvent); - Input.PointerEvent = PointerEvent; - ; - /** - * Mouse and Touch (Pointers) - * - * Handles pointer events (mouse, touch, stylus, etc.) and normalizes to - * [W3C Pointer Events](http://www.w3.org/TR/pointerevents/). - * - * There is always at least one [[Pointer]] available ([[Pointers.primary]]) and - * you can request multiple pointers to support multi-touch scenarios. - * - * Since [[Pointers.primary]] normalizes both mouse and touch events, your game - * automatically supports touch for the primary pointer by default. When - * you handle the events, you can customize what your game does based on the type - * of pointer, if applicable. - * - * Excalibur handles mouse/touch events and normalizes them to a [[PointerEvent]] - * that your game can subscribe to and handle (`engine.input.pointers`). - * - * ## Events - * - * You can subscribe to pointer events through `engine.input.pointers`. A [[PointerEvent]] object is - * passed to your handler which offers information about the pointer input being received. - * - * - `down` - When a pointer is pressed down (any mouse button or finger press) - * - `up` - When a pointer is lifted - * - `move` - When a pointer moves (be wary of performance issues when subscribing to this) - * - `cancel` - When a pointer event is canceled for some reason - * - * ```js - * engine.input.pointers.primary.on("down", function (evt) { }); - * engine.input.pointers.primary.on("up", function (evt) { }); - * engine.input.pointers.primary.on("move", function (evt) { }); - * engine.input.pointers.primary.on("cancel", function (evt) { }); - * ``` - * - * ## Pointer scope (window vs. canvas) - * - * You have the option to handle *all* pointer events in the browser by setting - * [[IEngineOptions.pointerScope]] to [[PointerScope.Document]]. If this is enabled, - * Excalibur will handle every pointer event in the browser. This is useful for handling - * complex input and having control over every interaction. - * - * You can also use [[PointerScope.Canvas]] to only scope event handling to the game - * canvas. This is useful if you don't care about events that occur outside. - * - * One real-world example is dragging and gestures. Sometimes a player will drag their - * finger outside your game and then into it, expecting it to work. If [[PointerScope]] - * is set to [[PointerScope.Canvas|Canvas]] this will not work. If it is set to - * [[PointerScope.Document|Document]], it will. - * - * ## Responding to input - * - * The primary pointer can be a mouse, stylus, or 1 finger touch event. You - * can inspect what it is from the [[PointerEvent]] handled. - * - * ```js - * engine.input.pointers.primary.on("down", function (pe) { - * if (pe.pointerType === ex.Input.PointerType.Mouse) { - * ex.Logger.getInstance().info("Mouse event:", pe); - * } else if (pe.pointerType === ex.Input.PointerType.Touch) { - * ex.Logger.getInstance().info("Touch event:", pe); - * } - * }); - * ``` - * - * ## Multiple Pointers (Multi-Touch) - * - * When there is more than one pointer detected on the screen, - * this is considered multi-touch. For example, pressing one finger, - * then another, will create two pointers. If you lift a finger, - * the first one remains and the second one disappears. - * - * You can handle multi-touch by subscribing to however many pointers - * you would like to support. If a pointer doesn't yet exist, it will - * be created. You do not need to check if a pointer exists. If it does - * exist, it will propogate events, otherwise it will remain idle. - * - * Excalibur does not impose a limit to the amount of pointers you can - * subscribe to, so by all means, support all 10 fingers. - * - * *Note:* There is no way to identify touches after they happen; you can only - * know that there are *n* touches on the screen at once. - * - * ```js - * function paint(color) { - * - * // create a handler for the event - * return function (pe) { - * if (pe.pointerType === ex.Input.PointerType.Touch) { - * engine.canvas.fillStyle = color; - * engine.canvas.fillRect(pe.x, pe.y, 5, 5); - * } - * } - * } - * - * engine.input.pointers.at(0).on("move", paint("blue")); // 1st finger - * engine.input.pointers.at(1).on("move", paint("red")); // 2nd finger - * engine.input.pointers.at(2).on("move", paint("green")); // 3rd finger - * ``` - * - * ## Actor pointer events - * - * By default, [[Actor|Actors]] do not participate in pointer events. In other - * words, when you "click" an Actor, it will not throw an event **for that Actor**, - * only a generic pointer event for the game. This is to keep performance - * high and allow actors to "opt-in" to handling pointer events. - * - * To opt-in, set [[Actor.enableCapturePointer]] to `true` and the [[Actor]] will - * start publishing `pointerup` and `pointerdown` events. `pointermove` events - * will not be published by default due to performance implications. If you want - * an actor to receive move events, set [[ICapturePointerConfig.captureMoveEvents]] to - * `true`. - * - * Actor pointer events will be prefixed with `pointer`. - * - * ```js - * var player = new ex.Actor(); - * - * // enable propogating pointer events - * player.enableCapturePointer = true; - * - * // enable move events, warning: performance intensive! - * player.capturePointer.captureMoveEvents = true; + /** + * Animations + * + * Animations allow you to display a series of images one after another, + * creating the illusion of change. Generally these images will come from a [[SpriteSheet]] source. + * + * ## Creating an animation + * + * Create a [[Texture]] that contains the frames of your animation. Once the texture + * is [[Loader|loaded]], you can then generate an [[Animation]] by creating a [[SpriteSheet]] + * and using [[SpriteSheet.getAnimationForAll]]. + * + * ```js + * var game = new ex.Engine(); + * var txAnimPlayerIdle = new ex.Texture("/assets/tx/anim-player-idle.png"); + * + * // load assets + * var loader = new ex.Loader(txAnimPlayerIdle); + * + * // start game + * game.start(loader).then(function () { + * var player = new ex.Actor(); + * + * // create sprite sheet with 5 columns, 1 row, 80x80 frames + * var playerIdleSheet = new ex.SpriteSheet(txAnimPlayerIdle, 5, 1, 80, 80); + * + * // create animation (125ms frame speed) + * var playerIdleAnimation = playerIdleSheet.getAnimationForAll(game, 125); + * + * // add drawing to player as "idle" + * player.addDrawing("idle", playerIdleAnimation); + * + * // add player to game + * game.add(player); + * }); + * ``` + * + * ## Sprite effects + * + * You can add [[SpriteEffect|sprite effects]] to an animation through methods + * like [[Animation.invert]] or [[Animation.lighten]]. Keep in mind, since this + * manipulates the raw pixel values of a [[Sprite]], it can have a performance impact. + */ + var Animation = (function () { + /** + * Typically you will use a [[SpriteSheet]] to generate an [[Animation]]. * - * // subscribe to input - * player.on("pointerup", function (ev) { - * player.logger.info("Player selected!", ev); - * }); - * ``` + * @param engine Reference to the current game engine + * @param images An array of sprites to create the frames for the animation + * @param speed The number in milliseconds to display each frame in the animation + * @param loop Indicates whether the animation should loop after it is completed */ - var Pointers = (function (_super) { - __extends(Pointers, _super); - function Pointers(engine) { - _super.call(this); - this._pointerDown = []; - this._pointerUp = []; - this._pointerMove = []; - this._pointerCancel = []; - this._pointers = []; - this._activePointers = []; - this._engine = engine; - this._pointers.push(new Pointer()); - this._activePointers = [-1]; - this.primary = this._pointers[0]; - } + function Animation(engine, images, speed, loop) { /** - * Initializes pointer event listeners + * Current frame index being shown */ - Pointers.prototype.init = function (scope) { - if (scope === void 0) { scope = PointerScope.Document; } - var target = document; - if (scope === PointerScope.Document) { - target = document; - } - else { - target = this._engine.canvas; - } - // Touch Events - target.addEventListener('touchstart', this._handleTouchEvent('down', this._pointerDown)); - target.addEventListener('touchend', this._handleTouchEvent('up', this._pointerUp)); - target.addEventListener('touchmove', this._handleTouchEvent('move', this._pointerMove)); - target.addEventListener('touchcancel', this._handleTouchEvent('cancel', this._pointerCancel)); - // W3C Pointer Events - // Current: IE11, IE10 - if (window.PointerEvent) { - // IE11 - this._engine.canvas.style.touchAction = 'none'; - target.addEventListener('pointerdown', this._handlePointerEvent('down', this._pointerDown)); - target.addEventListener('pointerup', this._handlePointerEvent('up', this._pointerUp)); - target.addEventListener('pointermove', this._handlePointerEvent('move', this._pointerMove)); - target.addEventListener('pointercancel', this._handlePointerEvent('cancel', this._pointerMove)); - } - else if (window.MSPointerEvent) { - // IE10 - this._engine.canvas.style.msTouchAction = 'none'; - target.addEventListener('MSPointerDown', this._handlePointerEvent('down', this._pointerDown)); - target.addEventListener('MSPointerUp', this._handlePointerEvent('up', this._pointerUp)); - target.addEventListener('MSPointerMove', this._handlePointerEvent('move', this._pointerMove)); - target.addEventListener('MSPointerCancel', this._handlePointerEvent('cancel', this._pointerMove)); - } - else { - // Mouse Events - target.addEventListener('mousedown', this._handleMouseEvent('down', this._pointerDown)); - target.addEventListener('mouseup', this._handleMouseEvent('up', this._pointerUp)); - target.addEventListener('mousemove', this._handleMouseEvent('move', this._pointerMove)); - } - }; - Pointers.prototype.update = function (delta) { - this._pointerUp.length = 0; - this._pointerDown.length = 0; - this._pointerMove.length = 0; - this._pointerCancel.length = 0; - }; + this.currentFrame = 0; + this._oldTime = Date.now(); + this.anchor = new ex.Point(0.0, 0.0); + this.rotation = 0.0; + this.scale = new ex.Point(1, 1); /** - * Safely gets a Pointer at a specific index and initializes one if it doesn't yet exist - * @param index The pointer index to retrieve + * Indicates whether the animation should loop after it is completed */ - Pointers.prototype.at = function (index) { - if (index >= this._pointers.length) { - // Ensure there is a pointer to retrieve - for (var i = this._pointers.length - 1, max = index; i < max; i++) { - this._pointers.push(new Pointer()); - this._activePointers.push(-1); - } - } - return this._pointers[index]; - }; + this.loop = false; /** - * Get number of pointers being watched + * Indicates the frame index the animation should freeze on for a non-looping + * animation. By default it is the last frame. */ - Pointers.prototype.count = function () { - return this._pointers.length; - }; + this.freezeFrame = -1; /** - * Propogates events to actor if necessary + * Flip each frame vertically. Sets [[Sprite.flipVertical]]. */ - Pointers.prototype.propogate = function (actor) { - var isUIActor = actor instanceof ex.UIActor; - var i = 0, len = this._pointerUp.length; - for (i; i < len; i++) { - if (actor.contains(this._pointerUp[i].x, this._pointerUp[i].y, !isUIActor)) { - actor.eventDispatcher.emit('pointerup', this._pointerUp[i]); - } - } - i = 0; - len = this._pointerDown.length; - for (i; i < len; i++) { - if (actor.contains(this._pointerDown[i].x, this._pointerDown[i].y, !isUIActor)) { - actor.eventDispatcher.emit('pointerdown', this._pointerDown[i]); - } - } - if (actor.capturePointer.captureMoveEvents) { - i = 0; - len = this._pointerMove.length; - for (i; i < len; i++) { - if (actor.contains(this._pointerMove[i].x, this._pointerMove[i].y, !isUIActor)) { - actor.eventDispatcher.emit('pointermove', this._pointerMove[i]); - } - } - } - i = 0; - len = this._pointerCancel.length; - for (i; i < len; i++) { - if (actor.contains(this._pointerCancel[i].x, this._pointerCancel[i].y, !isUIActor)) { - actor.eventDispatcher.emit('pointercancel', this._pointerCancel[i]); - } - } - }; - Pointers.prototype._handleMouseEvent = function (eventName, eventArr) { - var _this = this; - return function (e) { - e.preventDefault(); - var x = e.pageX - ex.Util.getPosition(_this._engine.canvas).x; - var y = e.pageY - ex.Util.getPosition(_this._engine.canvas).y; - var transformedPoint = _this._engine.screenToWorldCoordinates(new ex.Point(x, y)); - var pe = new PointerEvent(transformedPoint.x, transformedPoint.y, 0, PointerType.Mouse, e.button, e); - eventArr.push(pe); - _this.at(0).eventDispatcher.emit(eventName, pe); - }; - }; - Pointers.prototype._handleTouchEvent = function (eventName, eventArr) { - var _this = this; - return function (e) { - e.preventDefault(); - for (var i = 0, len = e.changedTouches.length; i < len; i++) { - var index = _this._pointers.length > 1 ? _this._getPointerIndex(e.changedTouches[i].identifier) : 0; - if (index === -1) { - continue; - } - var x = e.changedTouches[i].pageX - ex.Util.getPosition(_this._engine.canvas).x; - var y = e.changedTouches[i].pageY - ex.Util.getPosition(_this._engine.canvas).y; - var transformedPoint = _this._engine.screenToWorldCoordinates(new ex.Point(x, y)); - var pe = new PointerEvent(transformedPoint.x, transformedPoint.y, index, PointerType.Touch, PointerButton.Unknown, e); - eventArr.push(pe); - _this.at(index).eventDispatcher.emit(eventName, pe); - // only with multi-pointer - if (_this._pointers.length > 1) { - if (eventName === 'up') { - // remove pointer ID from pool when pointer is lifted - _this._activePointers[index] = -1; - } - else if (eventName === 'down') { - // set pointer ID to given index - _this._activePointers[index] = e.changedTouches[i].identifier; - } - } - } - }; - }; - Pointers.prototype._handlePointerEvent = function (eventName, eventArr) { - var _this = this; - return function (e) { - e.preventDefault(); - // get the index for this pointer ID if multi-pointer is asked for - var index = _this._pointers.length > 1 ? _this._getPointerIndex(e.pointerId) : 0; - if (index === -1) { - return; - } - var x = e.pageX - ex.Util.getPosition(_this._engine.canvas).x; - var y = e.pageY - ex.Util.getPosition(_this._engine.canvas).y; - var transformedPoint = _this._engine.screenToWorldCoordinates(new ex.Point(x, y)); - var pe = new PointerEvent(transformedPoint.x, transformedPoint.y, index, _this._stringToPointerType(e.pointerType), e.button, e); - eventArr.push(pe); - _this.at(index).eventDispatcher.emit(eventName, pe); - // only with multi-pointer - if (_this._pointers.length > 1) { - if (eventName === 'up') { - // remove pointer ID from pool when pointer is lifted - _this._activePointers[index] = -1; - } - else if (eventName === 'down') { - // set pointer ID to given index - _this._activePointers[index] = e.pointerId; - } - } - }; - }; + this.flipVertical = false; /** - * Gets the index of the pointer specified for the given pointer ID or finds the next empty pointer slot available. - * This is required because IE10/11 uses incrementing pointer IDs so we need to store a mapping of ID => idx + * Flip each frame horizontally. Sets [[Sprite.flipHorizontal]]. */ - Pointers.prototype._getPointerIndex = function (pointerId) { - var idx; - if ((idx = this._activePointers.indexOf(pointerId)) > -1) { - return idx; - } - for (var i = 0; i < this._activePointers.length; i++) { - if (this._activePointers[i] === -1) { - return i; - } - } - // ignore pointer because game isn't watching - return -1; - }; - Pointers.prototype._stringToPointerType = function (s) { - switch (s) { - case 'touch': - return PointerType.Touch; - case 'mouse': - return PointerType.Mouse; - case 'pen': - return PointerType.Pen; - default: - return PointerType.Unknown; - } - }; - return Pointers; - })(ex.Class); - Input.Pointers = Pointers; + this.flipHorizontal = false; + this.width = 0; + this.height = 0; + this.naturalWidth = 0; + this.naturalHeight = 0; + this.sprites = images; + this.speed = speed; + this._engine = engine; + if (loop != null) { + this.loop = loop; + } + if (images && images[0]) { + this.height = images[0] ? images[0].height : 0; + this.width = images[0] ? images[0].width : 0; + this.naturalWidth = images[0] ? images[0].naturalWidth : 0; + this.naturalHeight = images[0] ? images[0].naturalHeight : 0; + this.freezeFrame = images.length - 1; + } + } /** - * Captures and dispatches PointerEvents + * Applies the opacity effect to a sprite, setting the alpha of all pixels to a given value */ - var Pointer = (function (_super) { - __extends(Pointer, _super); - function Pointer() { - _super.apply(this, arguments); + Animation.prototype.opacity = function (value) { + this.addEffect(new ex.Effects.Opacity(value)); + }; + /** + * Applies the grayscale effect to a sprite, removing color information. + */ + Animation.prototype.grayscale = function () { + this.addEffect(new ex.Effects.Grayscale()); + }; + /** + * Applies the invert effect to a sprite, inverting the pixel colors. + */ + Animation.prototype.invert = function () { + this.addEffect(new ex.Effects.Invert()); + }; + /** + * Applies the fill effect to a sprite, changing the color channels of all non-transparent pixels to match a given color + */ + Animation.prototype.fill = function (color) { + this.addEffect(new ex.Effects.Fill(color)); + }; + /** + * Applies the colorize effect to a sprite, changing the color channels of all pixesl to be the average of the original color and the + * provided color. + */ + Animation.prototype.colorize = function (color) { + this.addEffect(new ex.Effects.Colorize(color)); + }; + /** + * Applies the lighten effect to a sprite, changes the lightness of the color according to hsl + */ + Animation.prototype.lighten = function (factor) { + if (factor === void 0) { factor = 0.1; } + this.addEffect(new ex.Effects.Lighten(factor)); + }; + /** + * Applies the darken effect to a sprite, changes the darkness of the color according to hsl + */ + Animation.prototype.darken = function (factor) { + if (factor === void 0) { factor = 0.1; } + this.addEffect(new ex.Effects.Darken(factor)); + }; + /** + * Applies the saturate effect to a sprite, saturates the color acccording to hsl + */ + Animation.prototype.saturate = function (factor) { + if (factor === void 0) { factor = 0.1; } + this.addEffect(new ex.Effects.Saturate(factor)); + }; + /** + * Applies the desaturate effect to a sprite, desaturates the color acccording to hsl + */ + Animation.prototype.desaturate = function (factor) { + if (factor === void 0) { factor = 0.1; } + this.addEffect(new ex.Effects.Desaturate(factor)); + }; + /** + * Add a [[ISpriteEffect]] manually + */ + Animation.prototype.addEffect = function (effect) { + for (var i in this.sprites) { + this.sprites[i].addEffect(effect); } - return Pointer; - })(ex.Class); - Input.Pointer = Pointer; - })(Input = ex.Input || (ex.Input = {})); -})(ex || (ex = {})); -var ex; -(function (ex) { - var Input; - (function (Input) { + }; + Animation.prototype.removeEffect = function (param) { + for (var i in this.sprites) { + this.sprites[i].removeEffect(param); + } + }; /** - * Enum representing input key codes + * Clear all sprite effects */ - (function (Keys) { - Keys[Keys["Num1"] = 97] = "Num1"; - Keys[Keys["Num2"] = 98] = "Num2"; - Keys[Keys["Num3"] = 99] = "Num3"; - Keys[Keys["Num4"] = 100] = "Num4"; - Keys[Keys["Num5"] = 101] = "Num5"; - Keys[Keys["Num6"] = 102] = "Num6"; - Keys[Keys["Num7"] = 103] = "Num7"; - Keys[Keys["Num8"] = 104] = "Num8"; - Keys[Keys["Num9"] = 105] = "Num9"; - Keys[Keys["Num0"] = 96] = "Num0"; - Keys[Keys["Numlock"] = 144] = "Numlock"; - Keys[Keys["Semicolon"] = 186] = "Semicolon"; - Keys[Keys["A"] = 65] = "A"; - Keys[Keys["B"] = 66] = "B"; - Keys[Keys["C"] = 67] = "C"; - Keys[Keys["D"] = 68] = "D"; - Keys[Keys["E"] = 69] = "E"; - Keys[Keys["F"] = 70] = "F"; - Keys[Keys["G"] = 71] = "G"; - Keys[Keys["H"] = 72] = "H"; - Keys[Keys["I"] = 73] = "I"; - Keys[Keys["J"] = 74] = "J"; - Keys[Keys["K"] = 75] = "K"; - Keys[Keys["L"] = 76] = "L"; - Keys[Keys["M"] = 77] = "M"; - Keys[Keys["N"] = 78] = "N"; - Keys[Keys["O"] = 79] = "O"; - Keys[Keys["P"] = 80] = "P"; - Keys[Keys["Q"] = 81] = "Q"; - Keys[Keys["R"] = 82] = "R"; - Keys[Keys["S"] = 83] = "S"; - Keys[Keys["T"] = 84] = "T"; - Keys[Keys["U"] = 85] = "U"; - Keys[Keys["V"] = 86] = "V"; - Keys[Keys["W"] = 87] = "W"; - Keys[Keys["X"] = 88] = "X"; - Keys[Keys["Y"] = 89] = "Y"; - Keys[Keys["Z"] = 90] = "Z"; - Keys[Keys["Shift"] = 16] = "Shift"; - Keys[Keys["Alt"] = 18] = "Alt"; - Keys[Keys["Up"] = 38] = "Up"; - Keys[Keys["Down"] = 40] = "Down"; - Keys[Keys["Left"] = 37] = "Left"; - Keys[Keys["Right"] = 39] = "Right"; - Keys[Keys["Space"] = 32] = "Space"; - Keys[Keys["Esc"] = 27] = "Esc"; - })(Input.Keys || (Input.Keys = {})); - var Keys = Input.Keys; - ; + Animation.prototype.clearEffects = function () { + for (var i in this.sprites) { + this.sprites[i].clearEffects(); + } + }; + Animation.prototype._setAnchor = function (point) { + //if (!this.anchor.equals(point)) { + for (var i in this.sprites) { + this.sprites[i].anchor.setTo(point.x, point.y); + } + //} + }; + Animation.prototype._setRotation = function (radians) { + //if (this.rotation !== radians) { + for (var i in this.sprites) { + this.sprites[i].rotation = radians; + } + //} + }; + Animation.prototype._setScale = function (scale) { + //if (!this.scale.equals(scale)) { + for (var i in this.sprites) { + this.sprites[i].scale = scale; + } + //} + }; /** - * Event thrown on a game object for a key event + * Resets the animation to first frame. */ - var KeyEvent = (function (_super) { - __extends(KeyEvent, _super); - /** - * @param key The key responsible for throwing the event - */ - function KeyEvent(key) { - _super.call(this); - this.key = key; + Animation.prototype.reset = function () { + this.currentFrame = 0; + }; + /** + * Indicates whether the animation is complete, animations that loop are never complete. + */ + Animation.prototype.isDone = function () { + return (!this.loop && this.currentFrame >= this.sprites.length); + }; + /** + * Not meant to be called by game developers. Ticks the animation forward internally and + * calculates whether to change to the frame. + * @internal + */ + Animation.prototype.tick = function () { + var time = Date.now(); + if ((time - this._oldTime) > this.speed) { + this.currentFrame = (this.loop ? (this.currentFrame + 1) % this.sprites.length : this.currentFrame + 1); + this._oldTime = time; } - return KeyEvent; - })(ex.GameEvent); - Input.KeyEvent = KeyEvent; + }; + Animation.prototype._updateValues = function () { + this._setAnchor(this.anchor); + this._setRotation(this.rotation); + this._setScale(this.scale); + }; /** - * Keyboard input - * - * Working with the keyboard is easy in Excalibur. You can inspect - * whether a button is [[Keyboard.isKeyDown|down]], [[Keyboard.isKeyUp|up]], or - * [[Keyboard.isKeyPressed|pressed]]. Common keys are held in the [[Input.Keys]] - * enumeration but you can pass any character code to the methods. - * - * Excalibur subscribes to the browser events and keeps track of - * what keys are currently down, up, or pressed. A key can be pressed - * for multiple frames, but a key cannot be down or up for more than one - * update frame. - * - * ## Inspecting the keyboard - * - * You can inspect [[Engine.input]] to see what the state of the keyboard - * is during an update. - * - * ```ts - * class Player extends ex.Actor { - * public update(engine, delta) { - * - * if (engine.input.keyboard.isKeyPressed(ex.Input.Keys.W) || - * engine.input.keyboard.isKeyPressed(ex.Input.Keys.Up)) { - * - * player._moveForward(); - * } - * - * } - * } - * ``` + * Skips ahead a specified number of frames in the animation + * @param frames Frames to skip ahead + */ + Animation.prototype.skip = function (frames) { + this.currentFrame = (this.currentFrame + frames) % this.sprites.length; + }; + Animation.prototype.draw = function (ctx, x, y) { + this.tick(); + this._updateValues(); + var currSprite; + if (this.currentFrame < this.sprites.length) { + currSprite = this.sprites[this.currentFrame]; + if (this.flipVertical) { + currSprite.flipVertical = this.flipVertical; + } + if (this.flipHorizontal) { + currSprite.flipHorizontal = this.flipHorizontal; + } + currSprite.draw(ctx, x, y); + } + if (this.freezeFrame !== -1 && this.currentFrame >= this.sprites.length) { + currSprite = this.sprites[ex.Util.clamp(this.freezeFrame, 0, this.sprites.length - 1)]; + currSprite.draw(ctx, x, y); + } + // add the calculated width + if (currSprite) { + this.width = currSprite.width; + this.height = currSprite.height; + } + }; + /** + * Plays an animation at an arbitrary location in the game. + * @param x The x position in the game to play + * @param y The y position in the game to play */ - var Keyboard = (function (_super) { - __extends(Keyboard, _super); - function Keyboard(engine) { - _super.call(this); - this._keys = []; - this._keysUp = []; - this._keysDown = []; - this._engine = engine; + Animation.prototype.play = function (x, y) { + this.reset(); + this._engine.playAnimation(this, x, y); + }; + return Animation; + })(); + ex.Animation = Animation; +})(ex || (ex = {})); +/// +/// +/// +var ex; +(function (ex) { + var Internal; + (function (Internal) { + var FallbackAudio = (function () { + function FallbackAudio(path, volume) { + this._log = ex.Logger.getInstance(); + this.onload = function () { return; }; + this.onprogress = function () { return; }; + this.onerror = function () { return; }; + if (window.AudioContext) { + this._log.debug('Using new Web Audio Api for ' + path); + this._soundImpl = new WebAudio(path, volume); + } + else { + this._log.debug('Falling back to Audio Element for ' + path); + this._soundImpl = new AudioTag(path, volume); + } } - /** - * Initialize Keyboard event listeners - */ - Keyboard.prototype.init = function () { - var _this = this; - window.addEventListener('blur', function (ev) { - _this._keys.length = 0; // empties array efficiently - }); - // key up is on window because canvas cannot have focus - window.addEventListener('keyup', function (ev) { - var key = _this._keys.indexOf(ev.keyCode); - _this._keys.splice(key, 1); - _this._keysUp.push(ev.keyCode); - var keyEvent = new KeyEvent(ev.keyCode); - // alias the old api, we may want to deprecate this in the future - _this.eventDispatcher.emit('up', keyEvent); - _this.eventDispatcher.emit('release', keyEvent); - }); - // key down is on window because canvas cannot have focus - window.addEventListener('keydown', function (ev) { - if (_this._keys.indexOf(ev.keyCode) === -1) { - _this._keys.push(ev.keyCode); - _this._keysDown.push(ev.keyCode); - var keyEvent = new KeyEvent(ev.keyCode); - _this.eventDispatcher.emit('down', keyEvent); - _this.eventDispatcher.emit('press', keyEvent); - } - }); + FallbackAudio.prototype.setVolume = function (volume) { + this._soundImpl.setVolume(volume); }; - Keyboard.prototype.update = function (delta) { - // Reset keysDown and keysUp after update is complete - this._keysDown.length = 0; - this._keysUp.length = 0; - // Emit synthetic "hold" event - for (var i = 0; i < this._keys.length; i++) { - this.eventDispatcher.emit('hold', new KeyEvent(this._keys[i])); - } + FallbackAudio.prototype.setLoop = function (loop) { + this._soundImpl.setLoop(loop); }; - /** - * Gets list of keys being pressed down - */ - Keyboard.prototype.getKeys = function () { - return this._keys; + FallbackAudio.prototype.load = function () { + this._soundImpl.onload = this.onload; + this._soundImpl.onprogress = this.onprogress; + this._soundImpl.onerror = this.onerror; + this._soundImpl.load(); }; - /** - * Tests if a certain key was just pressed this frame. This is cleared at the end of the update frame. - * @param key Test wether a key was just pressed - */ - Keyboard.prototype.wasPressed = function (key) { - return this._keysDown.indexOf(key) > -1; + FallbackAudio.prototype.isPlaying = function () { + return this._soundImpl.isPlaying(); }; - /** - * Tests if a certain key is held down. This is persisted between frames. - * @param key Test wether a key is held down - */ - Keyboard.prototype.isHeld = function (key) { - return this._keys.indexOf(key) > -1; + FallbackAudio.prototype.play = function () { + return this._soundImpl.play(); }; - /** - * Tests if a certain key was just released this frame. This is cleared at the end of the update frame. - * @param key Test wether a key was just released - */ - Keyboard.prototype.wasReleased = function (key) { - return this._keysUp.indexOf(key) > -1; + FallbackAudio.prototype.pause = function () { + this._soundImpl.pause(); }; - return Keyboard; - })(ex.Class); - Input.Keyboard = Keyboard; - })(Input = ex.Input || (ex.Input = {})); -})(ex || (ex = {})); -var ex; -(function (ex) { - var Input; - (function (Input) { - /** - * Controller Support (Gamepads) - * - * Excalibur leverages the HTML5 Gamepad API [where it is supported](http://caniuse.com/#feat=gamepad) - * to provide controller support for your games. - * - * You can query any [[Gamepad|Gamepads]] that are connected or listen to events ("button" and "axis"). - * - * You must opt-in to controller support ([[Gamepads.enabled]]) because it is a polling-based - * API, so we have to check it each update frame. - * - * Any number of gamepads are supported using the [[Gamepads.at]] method. If a [[Gamepad]] is - * not connected, it will simply not throw events. - * - * ## Responding to button input - * - * [[Buttons|Gamepad buttons]] typically have values between 0 and 1, however depending on - * the sensitivity of the controller, even if a button is idle it could have a - * very tiny value. For this reason, you can pass in a threshold to several - * methods to customize how sensitive you want to be in detecting button presses. - * - * You can inspect any connected [[Gamepad]] using [[Gamepad.isButtonPressed]], [[Gamepad.getButton]], - * or you can subscribe to the `button` event published on the [[Gamepad]] which passes - * a [[GamepadButtonEvent]] to your handler. - * - * ```js - * // enable gamepad support - * engine.input.gamepads.enabled = true; - * - * // query gamepad on update - * engine.on("update", function (ev) { - * - * // access any gamepad by index - * if (engine.input.gamepads.at(0).isButtonPressed(ex.Input.Buttons.Face1)) { - * ex.Logger.getInstance().info("Controller A button pressed"); - * } - * - * // query individual button - * if (engine.input.gamepads.at(0).getButton(ex.Input.Buttons.DpadLeft) > 0.2) { - * ex.Logger.getInstance().info("Controller D-pad left value is > 0.2") - * } - * }); - * - * // subscribe to button events - * engine.input.gamepads.at(0).on("button", function (ev) { - * ex.Logger.getInstance().info(ev.button, ev.value); - * }); - * ``` - * - * ## Responding to axis input - * - * [[Axes|Gamepad axes]] typically have values between -1 and 1, but even idle - * sticks can still propogate very small values depending on the quality and age - * of a controller. For this reason, you can set [[Gamepads.MinAxisMoveThreshold]] - * to set the (absolute) threshold after which Excalibur will start publishing `axis` events. - * By default it is set to a value that normally will not throw events if a stick is idle. - * - * You can query axes via [[Gamepad.getAxes]] or by subscribing to the `axis` event on [[Gamepad]] - * which passes a [[GamepadAxisEvent]] to your handler. - * - * ```js - * // enable gamepad support - * engine.input.gamepads.enabled = true; - * - * // query gamepad on update - * engine.on("update", function (ev) { - * - * // access any gamepad by index - * var axisValue; - * if ((axisValue = engine.input.gamepads.at(0).getAxes(ex.Input.Axes.LeftStickX)) > 0.5) { - * ex.Logger.getInstance().info("Move right", axisValue); - * } - * }); - * - * // subscribe to axis events - * engine.input.gamepads.at(0).on("axis", function (ev) { - * ex.Logger.getInstance().info(ev.axis, ev.value); - * }); - * ``` - */ - var Gamepads = (function (_super) { - __extends(Gamepads, _super); - function Gamepads(engine) { - _super.call(this); - /** - * Whether or not to poll for Gamepad input (default: `false`) - */ - this.enabled = false; - /** - * Whether or not Gamepad API is supported - */ - this.supported = !!navigator.getGamepads; - this._gamePadTimeStamps = [0, 0, 0, 0]; - this._oldPads = []; - this._pads = []; - this._initSuccess = false; - this._navigator = navigator; - this._minimumConfiguration = null; - this._engine = engine; - } - Gamepads.prototype.init = function () { - if (!this.supported) { - return; - } - if (this._initSuccess) { - return; - } - // In Chrome, this will return 4 undefined items until a button is pressed - // In FF, this will not return any items until a button is pressed - this._oldPads = this._clonePads(this._navigator.getGamepads()); - if (this._oldPads.length && this._oldPads[0]) { - this._initSuccess = true; + FallbackAudio.prototype.stop = function () { + this._soundImpl.stop(); + }; + return FallbackAudio; + })(); + Internal.FallbackAudio = FallbackAudio; + var AudioTag = (function () { + function AudioTag(path, volume) { + var _this = this; + this.path = path; + this._audioElements = new Array(5); + this._loadedAudio = null; + this._isLoaded = false; + this._index = 0; + this._log = ex.Logger.getInstance(); + this._isPlaying = false; + this._currentOffset = 0; + this.onload = function () { return; }; + this.onprogress = function () { return; }; + this.onerror = function () { return; }; + for (var i = 0; i < this._audioElements.length; i++) { + (function (i) { + _this._audioElements[i] = new Audio(); + })(i); } + if (volume) { + this.setVolume(ex.Util.clamp(volume, 0, 1.0)); + } + else { + this.setVolume(1.0); + } + } + AudioTag.prototype.isPlaying = function () { + return this._isPlaying; }; - /** - * Sets the minimum gamepad configuration, for example {axis: 4, buttons: 4} means - * this game requires at minimum 4 axis inputs and 4 buttons, this is not restrictive - * all other controllers with more axis or buttons are valid as well. If no minimum - * configuration is set all pads are valid. - */ - Gamepads.prototype.setMinimumGamepadConfiguration = function (config) { - this._enableAndUpdate(); // if config is used, implicitely enable - this._minimumConfiguration = config; + AudioTag.prototype._audioLoaded = function () { + this._isLoaded = true; }; - /** - * When implicitely enabled, set the enabled flag and run an update so information is updated - */ - Gamepads.prototype._enableAndUpdate = function () { - if (!this.enabled) { - this.enabled = true; - this.update(100); + AudioTag.prototype.setVolume = function (volume) { + var i = 0, len = this._audioElements.length; + for (i; i < len; i++) { + this._audioElements[i].volume = volume; } }; - /** - * Checks a navigator gamepad against the minimum configuration if present. - */ - Gamepads.prototype._isGamepadValid = function (pad) { - if (!this._minimumConfiguration) { - return true; - } - ; - if (!pad) { - return false; + AudioTag.prototype.setLoop = function (loop) { + var i = 0, len = this._audioElements.length; + for (i; i < len; i++) { + this._audioElements[i].loop = loop; } - ; - var axesLength = pad.axes.filter(function (value, index, array) { - return (typeof value !== undefined); - }).length; - var buttonLength = pad.buttons.filter(function (value, index, array) { - return (typeof value !== undefined); - }).length; - return axesLength >= this._minimumConfiguration.axis && - buttonLength >= this._minimumConfiguration.buttons && - pad.connected; - }; - Gamepads.prototype.on = function (eventName, handler) { - this._enableAndUpdate(); // implicitly enable - _super.prototype.on.call(this, eventName, handler); }; - Gamepads.prototype.off = function (eventName, handler) { - this._enableAndUpdate(); // implicitly enable - _super.prototype.off.call(this, eventName, handler); + AudioTag.prototype.getLoop = function () { + this._audioElements.some(function (a) { return a.loop; }); }; - /** - * Updates Gamepad state and publishes Gamepad events - */ - Gamepads.prototype.update = function (delta) { - if (!this.enabled || !this.supported) { - return; - } - this.init(); - var gamepads = this._navigator.getGamepads(); - for (var i = 0; i < gamepads.length; i++) { - if (!gamepads[i]) { - // If was connected, but now isn't emit the disconnect event - if (this.at(i).connected) { - this.eventDispatcher.emit('disconnect', new GamepadDisconnectEvent(i)); - } - // Reset connection status - this.at(i).connected = false; - continue; - } - else { - if (!this.at(i).connected && this._isGamepadValid(gamepads[i])) { - this.eventDispatcher.emit('connect', new GamepadConnectEvent(i, this.at(i))); - } - // Set connection status - this.at(i).connected = true; - } - ; - // Only supported in Chrome - if (gamepads[i].timestamp && gamepads[i].timestamp === this._gamePadTimeStamps[i]) { - continue; - } - this._gamePadTimeStamps[i] = gamepads[i].timestamp; - // Add reference to navigator gamepad - this.at(i).navigatorGamepad = gamepads[i]; - // Buttons - var b, a, value, buttonIndex, axesIndex; - for (b in Buttons) { - if (typeof Buttons[b] !== 'number') { - continue; - } - buttonIndex = Buttons[b]; - if (gamepads[i].buttons[buttonIndex]) { - value = gamepads[i].buttons[buttonIndex].value; - if (value !== this._oldPads[i].getButton(buttonIndex)) { - if (gamepads[i].buttons[buttonIndex].pressed) { - this.at(i).updateButton(buttonIndex, value); - this.at(i).eventDispatcher.publish('button', new GamepadButtonEvent(buttonIndex, value)); - } - else { - this.at(i).updateButton(buttonIndex, 0); - } - } - } - } - // Axes - for (a in Axes) { - if (typeof Axes[a] !== 'number') { - continue; - } - axesIndex = Axes[a]; - value = gamepads[i].axes[axesIndex]; - if (value !== this._oldPads[i].getAxes(axesIndex)) { - this.at(i).updateAxes(axesIndex, value); - this.at(i).eventDispatcher.emit('axis', new GamepadAxisEvent(axesIndex, value)); - } + AudioTag.prototype.load = function () { + var _this = this; + var request = new XMLHttpRequest(); + request.open('GET', this.path, true); + request.responseType = 'blob'; + request.onprogress = this.onprogress; + request.onerror = this.onerror; + request.onload = function (e) { + if (request.status !== 200) { + _this._log.error('Failed to load audio resource ', _this.path, ' server responded with error code', request.status); + _this.onerror(request.response); + _this._isLoaded = false; + return; } - this._oldPads[i] = this._clonePad(gamepads[i]); - } + _this._loadedAudio = URL.createObjectURL(request.response); + _this._audioElements.forEach(function (a) { + a.src = _this._loadedAudio; + }); + _this.onload(e); + }; + request.send(); }; - /** - * Safely retrieves a Gamepad at a specific index and creates one if it doesn't yet exist - */ - Gamepads.prototype.at = function (index) { - this._enableAndUpdate(); // implicitly enable gamepads when at() is called - if (index >= this._pads.length) { - // Ensure there is a pad to retrieve - for (var i = this._pads.length - 1, max = index; i < max; i++) { - this._pads.push(new Gamepad()); - this._oldPads.push(new Gamepad()); - } + AudioTag.prototype.play = function () { + var _this = this; + this._audioElements[this._index].load(); + //this.audioElements[this.index].currentTime = this._currentOffset; + this._audioElements[this._index].play(); + this._currentOffset = 0; + var done = new ex.Promise(); + this._isPlaying = true; + if (!this.getLoop()) { + this._audioElements[this._index].addEventListener('ended', function () { + _this._isPlaying = false; + done.resolve(true); + }); } - return this._pads[index]; + this._index = (this._index + 1) % this._audioElements.length; + return done; }; - /** - * Returns a list of all valid gamepads that meet the minimum configuration requirment. - */ - Gamepads.prototype.getValidGamepads = function () { - this._enableAndUpdate(); - var result = []; - for (var i = 0; i < this._pads.length; i++) { - if (this._isGamepadValid(this.at(i).navigatorGamepad) && this.at(i).connected) { - result.push(this.at(i)); - } - } - return result; + AudioTag.prototype.pause = function () { + this._index = (this._index - 1 + this._audioElements.length) % this._audioElements.length; + this._currentOffset = this._audioElements[this._index].currentTime; + this._audioElements.forEach(function (a) { + a.pause(); + }); + this._isPlaying = false; }; - /** - * Gets the number of connected gamepads - */ - Gamepads.prototype.count = function () { - return this._pads.filter(function (p) { return p.connected; }).length; + AudioTag.prototype.stop = function () { + this._audioElements.forEach(function (a) { + a.pause(); + //a.currentTime = 0; + }); + this._isPlaying = false; }; - Gamepads.prototype._clonePads = function (pads) { - var arr = []; - for (var i = 0, len = pads.length; i < len; i++) { - arr.push(this._clonePad(pads[i])); + return AudioTag; + })(); + Internal.AudioTag = AudioTag; + if (window.AudioContext) { + var audioContext = new window.AudioContext(); + } + var WebAudio = (function () { + function WebAudio(soundPath, volume) { + this._context = audioContext; + this._volume = this._context.createGain(); + this._buffer = null; + this._sound = null; + this._path = ''; + this._isLoaded = false; + this._loop = false; + this._isPlaying = false; + this._isPaused = false; + this._currentOffset = 0; + this._logger = ex.Logger.getInstance(); + this.onload = function () { return; }; + this.onprogress = function () { return; }; + this.onerror = function () { return; }; + this._path = soundPath; + if (volume) { + this._volume.gain.value = ex.Util.clamp(volume, 0, 1.0); } - return arr; - }; - /** - * Fastest way to clone a known object is to do it yourself - */ - Gamepads.prototype._clonePad = function (pad) { - var i, len; - var clonedPad = new Gamepad(); - if (!pad) { - return clonedPad; + else { + this._volume.gain.value = 1.0; // max volume } - for (i = 0, len = pad.buttons.length; i < len; i++) { - if (pad.buttons[i]) { - clonedPad.updateButton(i, pad.buttons[i].value); + } + WebAudio.prototype.setVolume = function (volume) { + this._volume.gain.value = volume; + }; + WebAudio.prototype.load = function () { + var _this = this; + var request = new XMLHttpRequest(); + request.open('GET', this._path); + request.responseType = 'arraybuffer'; + request.onprogress = this.onprogress; + request.onerror = this.onerror; + request.onload = function () { + if (request.status !== 200) { + _this._logger.error('Failed to load audio resource ', _this._path, ' server responded with error code', request.status); + _this.onerror(request.response); + _this._isLoaded = false; + return; } + _this._context.decodeAudioData(request.response, function (buffer) { + _this._buffer = buffer; + _this._isLoaded = true; + _this.onload(_this); + }, function (e) { + _this._logger.error('Unable to decode ' + _this._path + + ' this browser may not fully support this format, or the file may be corrupt, ' + + 'if this is an mp3 try removing id3 tags and album art from the file.'); + _this._isLoaded = false; + _this.onload(_this); + }); + }; + try { + request.send(); } - for (i = 0, len = pad.axes.length; i < len; i++) { - clonedPad.updateAxes(i, pad.axes[i]); + catch (e) { + console.error('Error loading sound! If this is a cross origin error, you must host your sound with your html and javascript.'); } - return clonedPad; }; - /** - * The minimum value an axis has to move before considering it a change - */ - Gamepads.MinAxisMoveThreshold = 0.05; - return Gamepads; - })(ex.Class); - Input.Gamepads = Gamepads; - /** - * Gamepad holds state information for a connected controller. See [[Gamepads]] - * for more information on handling controller input. - */ - var Gamepad = (function (_super) { - __extends(Gamepad, _super); - function Gamepad() { - _super.call(this); - this.connected = false; - this._buttons = new Array(16); - this._axes = new Array(4); - var i; - for (i = 0; i < this._buttons.length; i++) { - this._buttons[i] = 0; - } - for (i = 0; i < this._axes.length; i++) { - this._axes[i] = 0; - } - } - /** - * Whether or not the given button is pressed - * @param button The button to query - * @param threshold The threshold over which the button is considered to be pressed - */ - Gamepad.prototype.isButtonPressed = function (button, threshold) { - if (threshold === void 0) { threshold = 1; } - return this._buttons[button] >= threshold; + WebAudio.prototype.setLoop = function (loop) { + this._loop = loop; }; - /** - * Gets the given button value between 0 and 1 - */ - Gamepad.prototype.getButton = function (button) { - return this._buttons[button]; + WebAudio.prototype.isPlaying = function () { + return this._isPlaying; }; - /** - * Gets the given axis value between -1 and 1. Values below - * [[MinAxisMoveThreshold]] are considered 0. - */ - Gamepad.prototype.getAxes = function (axes) { - var value = this._axes[axes]; - if (Math.abs(value) < Gamepads.MinAxisMoveThreshold) { - return 0; + WebAudio.prototype.play = function () { + var _this = this; + if (this._isLoaded) { + this._sound = this._context.createBufferSource(); + this._sound.buffer = this._buffer; + this._sound.loop = this._loop; + this._sound.connect(this._volume); + this._volume.connect(this._context.destination); + this._sound.start(0, this._currentOffset % this._buffer.duration); + this._currentOffset = 0; + var done; + if (!this._isPaused || !this._playPromise) { + done = new ex.Promise(); + } + else { + done = this._playPromise; + } + this._isPaused = false; + this._isPlaying = true; + if (!this._loop) { + this._sound.onended = (function () { + _this._isPlaying = false; + if (!_this._isPaused) { + done.resolve(true); + } + }).bind(this); + } + this._playPromise = done; + return done; } else { - return value; + return ex.Promise.wrap(true); } }; - Gamepad.prototype.updateButton = function (buttonIndex, value) { - this._buttons[buttonIndex] = value; + WebAudio.prototype.pause = function () { + if (this._isPlaying) { + try { + window.clearTimeout(this._playingTimer); + this._sound.stop(0); + this._currentOffset = this._context.currentTime; + this._isPlaying = false; + this._isPaused = true; + } + catch (e) { + this._logger.warn('The sound clip', this._path, 'has already been paused!'); + } + } }; - Gamepad.prototype.updateAxes = function (axesIndex, value) { - this._axes[axesIndex] = value; + WebAudio.prototype.stop = function () { + if (this._sound) { + try { + window.clearTimeout(this._playingTimer); + this._currentOffset = 0; + this._sound.stop(0); + this._isPlaying = false; + this._isPaused = false; + } + catch (e) { + this._logger.warn('The sound clip', this._path, 'has already been stopped!'); + } + } }; - return Gamepad; - })(ex.Class); - Input.Gamepad = Gamepad; - /** - * Gamepad Buttons enumeration - */ - (function (Buttons) { - /** - * Face 1 button (e.g. A) - */ - Buttons[Buttons["Face1"] = 0] = "Face1"; - /** - * Face 2 button (e.g. B) - */ - Buttons[Buttons["Face2"] = 1] = "Face2"; - /** - * Face 3 button (e.g. X) - */ - Buttons[Buttons["Face3"] = 2] = "Face3"; - /** - * Face 4 button (e.g. Y) - */ - Buttons[Buttons["Face4"] = 3] = "Face4"; - /** - * Left bumper button - */ - Buttons[Buttons["LeftBumper"] = 4] = "LeftBumper"; - /** - * Right bumper button - */ - Buttons[Buttons["RightBumper"] = 5] = "RightBumper"; - /** - * Left trigger button - */ - Buttons[Buttons["LeftTrigger"] = 6] = "LeftTrigger"; - /** - * Right trigger button - */ - Buttons[Buttons["RightTrigger"] = 7] = "RightTrigger"; - /** - * Select button - */ - Buttons[Buttons["Select"] = 8] = "Select"; - /** - * Start button - */ - Buttons[Buttons["Start"] = 9] = "Start"; - /** - * Left analog stick press (e.g. L3) - */ - Buttons[Buttons["LeftStick"] = 10] = "LeftStick"; - /** - * Right analog stick press (e.g. R3) - */ - Buttons[Buttons["RightStick"] = 11] = "RightStick"; - /** - * D-pad up - */ - Buttons[Buttons["DpadUp"] = 12] = "DpadUp"; - /** - * D-pad down - */ - Buttons[Buttons["DpadDown"] = 13] = "DpadDown"; - /** - * D-pad left - */ - Buttons[Buttons["DpadLeft"] = 14] = "DpadLeft"; - /** - * D-pad right - */ - Buttons[Buttons["DpadRight"] = 15] = "DpadRight"; - })(Input.Buttons || (Input.Buttons = {})); - var Buttons = Input.Buttons; + return WebAudio; + })(); + Internal.WebAudio = WebAudio; + })(Internal = ex.Internal || (ex.Internal = {})); +})(ex || (ex = {})); +/// +// Promises/A+ Spec http://promises-aplus.github.io/promises-spec/ +var ex; +(function (ex) { + /** + * Valid states for a promise to be in + */ + (function (PromiseState) { + PromiseState[PromiseState["Resolved"] = 0] = "Resolved"; + PromiseState[PromiseState["Rejected"] = 1] = "Rejected"; + PromiseState[PromiseState["Pending"] = 2] = "Pending"; + })(ex.PromiseState || (ex.PromiseState = {})); + var PromiseState = ex.PromiseState; + /** + * Promises/A+ spec implementation of promises + * + * Promises are used to do asynchronous work and they are useful for + * creating a chain of actions. In Excalibur they are used for loading, + * sounds, animation, actions, and more. + * + * ## A Promise Chain + * + * Promises can be chained together and can be useful for creating a queue + * of functions to be called when something is done. + * + * The first [[Promise]] you will encounter is probably [[Engine.start]] + * which resolves when the game has finished loading. + * + * ```js + * var game = new ex.Engine(); + * + * // perform start-up logic once game is ready + * game.start().then(function () { + * + * // start-up & initialization logic + * + * }); + * ``` + * + * ## Handling errors + * + * You can optionally pass an error handler to [[Promise.then]] which will handle + * any errors that occur during Promise execution. + * + * ```js + * var game = new ex.Engine(); + * + * game.start().then( + * // success handler + * function () { + * }, + * + * // error handler + * function (err) { + * } + * ); + * ``` + * + * Any errors that go unhandled will be bubbled up to the browser. + */ + var Promise = (function () { + function Promise() { + this._state = PromiseState.Pending; + this._successCallbacks = []; + this._rejectCallback = function () { return; }; + this._logger = ex.Logger.getInstance(); + } /** - * Gamepad Axes enumeration + * Wrap a value in a resolved promise + * @param value An optional value to wrap in a resolved promise */ - (function (Axes) { - /** - * Left analogue stick X direction - */ - Axes[Axes["LeftStickX"] = 0] = "LeftStickX"; - /** - * Left analogue stick Y direction - */ - Axes[Axes["LeftStickY"] = 1] = "LeftStickY"; - /** - * Right analogue stick X direction - */ - Axes[Axes["RightStickX"] = 2] = "RightStickX"; - /** - * Right analogue stick Y direction - */ - Axes[Axes["RightStickY"] = 3] = "RightStickY"; - })(Input.Axes || (Input.Axes = {})); - var Axes = Input.Axes; + Promise.wrap = function (value) { + var promise = (new Promise()).resolve(value); + return promise; + }; /** - * Event recieved when a gamepad is connected to excalibur + * Returns a new promise that resolves when all the promises passed to it resolve, or rejects + * when at least 1 promise rejects. */ - var GamepadConnectEvent = (function (_super) { - __extends(GamepadConnectEvent, _super); - function GamepadConnectEvent(index, gamepad) { - _super.call(this); - this.index = index; - this.gamepad = gamepad; + Promise.join = function () { + var promises = []; + for (var _i = 0; _i < arguments.length; _i++) { + promises[_i - 0] = arguments[_i]; } - return GamepadConnectEvent; - })(ex.GameEvent); - Input.GamepadConnectEvent = GamepadConnectEvent; + var joinedPromise = new Promise(); + if (!promises || !promises.length) { + return joinedPromise.resolve(); + } + var total = promises.length; + var successes = 0; + var rejects = 0; + var errors = []; + promises.forEach(function (p) { + p.then(function () { + successes += 1; + if (successes === total) { + joinedPromise.resolve(); + } + else if (successes + rejects + errors.length === total) { + joinedPromise.reject(errors); + } + }, function () { + rejects += 1; + if (successes + rejects + errors.length === total) { + joinedPromise.reject(errors); + } + }).error(function (e) { + errors.push(e); + if ((errors.length + successes + rejects) === total) { + joinedPromise.reject(errors); + } + }); + }); + return joinedPromise; + }; /** - * Event recieved when a gamepad is disconnected from excalibur + * Chain success and reject callbacks after the promise is resovled + * @param successCallback Call on resolution of promise + * @param rejectCallback Call on rejection of promise */ - var GamepadDisconnectEvent = (function (_super) { - __extends(GamepadDisconnectEvent, _super); - function GamepadDisconnectEvent(index) { - _super.call(this); - this.index = index; + Promise.prototype.then = function (successCallback, rejectCallback) { + if (successCallback) { + this._successCallbacks.push(successCallback); + // If the promise is already resovled call immediately + if (this.state() === PromiseState.Resolved) { + try { + successCallback.call(this, this._value); + } + catch (e) { + this._handleError(e); + } + } } - return GamepadDisconnectEvent; - })(ex.GameEvent); - Input.GamepadDisconnectEvent = GamepadDisconnectEvent; + if (rejectCallback) { + this._rejectCallback = rejectCallback; + // If the promise is already rejected call immediately + if (this.state() === PromiseState.Rejected) { + try { + rejectCallback.call(this, this._value); + } + catch (e) { + this._handleError(e); + } + } + } + return this; + }; /** - * Gamepad button event. See [[Gamepads]] for information on responding to controller input. + * Add an error callback to the promise + * @param errorCallback Call if there was an error in a callback */ - var GamepadButtonEvent = (function (_super) { - __extends(GamepadButtonEvent, _super); - /** - * @param button The Gamepad button - * @param value A numeric value between 0 and 1 - */ - function GamepadButtonEvent(button, value) { - _super.call(this); - this.button = button; - this.value = value; + Promise.prototype.error = function (errorCallback) { + if (errorCallback) { + this._errorCallback = errorCallback; } - return GamepadButtonEvent; - })(ex.GameEvent); - Input.GamepadButtonEvent = GamepadButtonEvent; + return this; + }; /** - * Gamepad axis event. See [[Gamepads]] for information on responding to controller input. + * Resolve the promise and pass an option value to the success callbacks + * @param value Value to pass to the success callbacks */ - var GamepadAxisEvent = (function (_super) { - __extends(GamepadAxisEvent, _super); - /** - * @param axis The Gamepad axis - * @param value A numeric value between -1 and 1 - */ - function GamepadAxisEvent(axis, value) { - _super.call(this); - this.axis = axis; - this.value = value; - } - return GamepadAxisEvent; - })(ex.GameEvent); - Input.GamepadAxisEvent = GamepadAxisEvent; - })(Input = ex.Input || (ex.Input = {})); -})(ex || (ex = {})); -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/** - * # Welcome to the Excalibur API - * - * This documentation is automatically generated from the Excalibur - * source code on [GitHub](http://github.com/excaliburjs/Excalibur). - * - * If you're just starting out, we recommend reading the tutorials and guides - * on [Excaliburjs.com](http://excaliburjs.com/docs). If you have questions, - * feel free to get help on the [Excalibur.js mailing list](https://groups.google.com/forum/#!forum/excaliburjs). - * - * If you're looking for a specific method or property, you can search the documentation - * using the search icon at the top or just start typing. - * - * ## Where to Start - * - * These are the core concepts of Excalibur that you should be - * familiar with. - * - * - [[Engine|Intro to the Engine]] - * - [[EventDispatcher|Eventing]] - * - [[Scene|Working with Scenes]] - * - [[BaseCamera|Working with Cameras]] - * - [[Actor|Working with Actors]] - * - [[Label|Labels]] - * - [[Trigger|Triggers]] - * - [[UIActor|UI Actors (HUD)]] - * - [[ActionContext|Action API]] - * - [[Group|Groups]] - * - * ## Working with Resources - * - * Excalibur provides easy ways of loading assets, from images to JSON files. - * - * - [[Loader|Working with the Loader]] - * - [[Texture|Loading Textures]] - * - [[Sound|Loading Sounds]] - * - [[Resource|Loading Generic Resources]] - * - * ## Working with Input - * - * Excalibur comes built-in with support for mouse, keyboard, touch, and controllers. - * - * - [[Pointers|Mouse and Touch]] - * - [[Keyboard]] - * - [[Gamepads|Controller Support]] - * - * ## Working with Media - * - * Add sounds, images, and animations to your game. - * - * - [[Sprite|Working with Sprites]] - * - [[Sound|Working with Sounds]] - * - [[SpriteSheet|Working with SpriteSheets]] - * - [[Animation|Working with Animations]] - * - * ## Effects and Particles - * - * Every game needs an explosion or two. Add sprite effects such as lighten, - * darken, and colorize. - * - * - [[Effects|Sprite Effects]] - * - [[ParticleEmitter|Particle Emitters]] - * - * ## Math - * - * These classes provide the basics for math & algebra operations. - * - * - [[Point]] - * - [[Vector]] - * - [[Ray]] - * - [[Line]] - * - [[Projection]] - * - * ## Utilities - * - * - [[Util|Utility Functions]] - * - [[Promise|Promises and Async]] - * - [[Logger|Logging]] - * - [[Color|Colors]] - * - [[Timer|Timers]] - */ + Promise.prototype.resolve = function (value) { + var _this = this; + if (this._state === PromiseState.Pending) { + this._value = value; + try { + this._state = PromiseState.Resolved; + this._successCallbacks.forEach(function (cb) { + cb.call(_this, _this._value); + }); + } + catch (e) { + this._handleError(e); + } + } + else { + throw new Error('Cannot resolve a promise that is not in a pending state!'); + } + return this; + }; + /** + * Reject the promise and pass an option value to the reject callbacks + * @param value Value to pass to the reject callbacks + */ + Promise.prototype.reject = function (value) { + if (this._state === PromiseState.Pending) { + this._value = value; + try { + this._state = PromiseState.Rejected; + this._rejectCallback.call(this, this._value); + } + catch (e) { + this._handleError(e); + } + } + else { + throw new Error('Cannot reject a promise that is not in a pending state!'); + } + return this; + }; + /** + * Inpect the current state of a promise + */ + Promise.prototype.state = function () { + return this._state; + }; + Promise.prototype._handleError = function (e) { + if (this._errorCallback) { + this._errorCallback.call(this, e); + } + else { + // rethrow error + throw e; + } + }; + return Promise; + })(); + ex.Promise = Promise; +})(ex || (ex = {})); +/// var ex; (function (ex) { /** - * The Excalibur Engine - * - * The [[Engine]] is the main driver for a game. It is responsible for - * starting/stopping the game, maintaining state, transmitting events, - * loading resources, and managing the scene. + * Generic Resources * - * Excalibur uses the HTML5 Canvas API for drawing your game to the screen. - * The canvas is available to all `draw` functions for raw manipulation, - * but Excalibur is meant to simplify or completely remove the need to use - * the canvas directly. + * The [[Resource]] type allows games built in Excalibur to load generic resources. + * For any type of remote resource it is recommended to use [[Resource]] for preloading. * - * ## Creating a Game + * [[Resource]] is an [[ILoadable]] so it can be passed to a [[Loader]] to pre-load before + * a level or game. * - * To create a new game, create a new instance of [[Engine]] and pass in - * the configuration ([[IEngineOptions]]). Excalibur only supports a single - * instance of a game at a time, so it is safe to use globally. + * Example usages: JSON, compressed files, blobs. * - * You can then call [[start]] which starts the game and optionally accepts - * a [[Loader]] which you can use to pre-load assets. + * ## Pre-loading generic resources * * ```js - * var game = new ex.Engine({ width: 800, height: 600 }); + * var resLevel1 = new ex.Resource("/assets/levels/1.json", "application/json"); + * var loader = new ex.Loader(resLevel1); * - * // call game.start, which is a Promise - * game.start().then(function () { - * // ready, set, go! - * }); - * ``` + * // attach a handler to process once loaded + * resLevel1.processDownload = function (data) { * - * ## The Main Loop + * // process JSON + * var json = JSON.parse(data); * - * The Excalibur engine uses a simple main loop. The engine updates and renders - * the "scene graph" which is the [[Scene|scenes]] and the tree of [[Actor|actors]] within that - * scene. Only one [[Scene]] can be active at once, the engine does not update/draw any other - * scene, which means any actors will not be updated/drawn if they are part of a deactivated scene. + * // create a new level (inherits Scene) with the JSON configuration + * var level = new Level(json); * - * **Scene Graph** + * // add a new scene + * game.add(level.name, level); + * } * + * game.start(loader); * ``` - * Engine - * |_ Scene 1 (activated) - * |_ Actor 1 - * |_ Child Actor 1 - * |_ Actor 2 - * |_ Scene 2 (deactiveated) - * |_ Scene 3 (deactiveated) - * ``` - * - * The engine splits the game into two primary responsibilities: updating and drawing. This is - * to keep your game smart about splitting duties so that you aren't drawing when doing - * logic or performing logic as you draw. - * - * ### Update Loop - * - * The first operation run is the [[Engine.update|update]] loop. [[Actor]] and [[Scene]] both implement - * an overridable/extendable `update` method. Use it to perform any logic-based operations - * in your game for a particular class. - * - * ### Draw Loop - * - * The next step is the [[Engine.draw|draw]] loop. A [[Scene]] loops through its child [[Actor|actors]] and - * draws each one. You can override the `draw` method on an actor to customize its drawing. - * You should **not** perform any logic in a draw call, it should only relate to drawing. - * - * ## Working with Scenes - * - * The engine automatically creates a "root" [[Scene]]. You can use this for whatever you want. - * You can manipulate scenes using [[Engine.add|add]], [[Engine.remove|remove]], - * and [[Engine.goToScene|goToScene]]. You can overwrite or remove the `root` scene if - * you want. There always has to be at least one scene and only **one** scene can be - * active at any one time. - * - * Learn more about the [[Scene|scene lifecycle]]. - * - * ### Adding a scene - * - * ```js - * var game = new ex.Engine(); - * - * // create a new level - * var level1 = new ex.Scene(); - * - * // add level 1 to the game - * game.add("level1", level1); + */ + var Resource = (function () { + /** + * @param path Path to the remote resource + * @param responseType The Content-Type to expect (e.g. `application/json`) + * @param bustCache Whether or not to cache-bust requests + */ + function Resource(path, responseType, bustCache) { + if (bustCache === void 0) { bustCache = true; } + this.path = path; + this.responseType = responseType; + this.bustCache = bustCache; + this.data = null; + this.logger = ex.Logger.getInstance(); + this.onprogress = function () { return; }; + this.oncomplete = function () { return; }; + this.onerror = function () { return; }; + } + /** + * Returns true if the Resource is completely loaded and is ready + * to be drawn. + */ + Resource.prototype.isLoaded = function () { + return !!this.data; + }; + Resource.prototype.wireEngine = function (engine) { + this._engine = engine; + }; + Resource.prototype._cacheBust = function (uri) { + var query = /\?\w*=\w*/; + if (query.test(uri)) { + uri += ('&__=' + Date.now()); + } + else { + uri += ('?__=' + Date.now()); + } + return uri; + }; + Resource.prototype._start = function (e) { + this.logger.debug('Started loading resource ' + this.path); + }; + /** + * Begin loading the resource and returns a promise to be resolved on completion + */ + Resource.prototype.load = function () { + var _this = this; + var complete = new ex.Promise(); + var request = new XMLHttpRequest(); + request.open('GET', this.bustCache ? this._cacheBust(this.path) : this.path, true); + request.responseType = this.responseType; + request.onloadstart = function (e) { _this._start(e); }; + request.onprogress = this.onprogress; + request.onerror = this.onerror; + request.onload = function (e) { + if (request.status !== 200) { + _this.logger.error('Failed to load resource ', _this.path, ' server responded with error code', request.status); + _this.onerror(request.response); + complete.resolve(request.response); + return; + } + _this.data = _this.processDownload(request.response); + _this.oncomplete(); + _this.logger.debug('Completed loading resource', _this.path); + complete.resolve(_this.data); + }; + request.send(); + return complete; + }; + /** + * Returns the loaded data once the resource is loaded + */ + Resource.prototype.getData = function () { + return this.data; + }; + /** + * This method is meant to be overriden to handle any additional + * processing. Such as decoding downloaded audio bits. + */ + Resource.prototype.processDownload = function (data) { + // Handle any additional loading after the xhr has completed. + return URL.createObjectURL(data); + }; + return Resource; + })(); + ex.Resource = Resource; +})(ex || (ex = {})); +/// +/// +/// +/// +/// +var ex; +(function (ex) { + /** + * Textures * - * // in response to user input, go to level 1 - * game.goToScene("level1"); + * The [[Texture]] object allows games built in Excalibur to load image resources. + * [[Texture]] is an [[ILoadable]] which means it can be passed to a [[Loader]] + * to pre-load before starting a level or game. * - * // go back to main menu - * game.goToScene("root"); - * ``` + * Textures are the raw image so to add a drawing to a game, you must create + * a [[Sprite]]. You can use [[Texture.asSprite]] to quickly generate a Sprite + * instance. * - * ### Accessing the current scene + * ## Pre-loading textures * - * To add actors and other entities to the current [[Scene]], you can use [[Engine.add|add]]. Alternatively, - * you can use [[Engine.currentScene]] to directly access the current scene. + * Pass the [[Texture]] to a [[Loader]] to pre-load the asset. Once a [[Texture]] + * is loaded, you can generate a [[Sprite]] with it. * - * ## Managing the Viewport + * ```js + * var txPlayer = new ex.Texture("/assets/tx/player.png"); * - * Excalibur supports multiple [[DisplayMode|display modes]] for a game. Pass in a `displayMode` - * option when creating a game to customize the viewport. + * var loader = new ex.Loader(txPlayer); * - * ## Extending the Engine + * game.start(loader).then(function () { * - * For complex games, any entity that inherits [[Class]] can be extended to override built-in - * functionality. This is recommended for [[Actor|actors]] and [[Scene|scenes]], especially. + * var player = new ex.Actor(); * - * You can customize the options or provide more for your game by extending [[Engine]]. + * player.addDrawing(txPlayer); * - * **TypeScript** + * game.add(player); + * }); + * ``` + */ + var Texture = (function (_super) { + __extends(Texture, _super); + /** + * @param path Path to the image resource + * @param bustCache Optionally load texture with cache busting + */ + function Texture(path, bustCache) { + if (bustCache === void 0) { bustCache = true; } + _super.call(this, path, 'blob', bustCache); + this.path = path; + this.bustCache = bustCache; + /** + * A [[Promise]] that resolves when the Texture is loaded. + */ + this.loaded = new ex.Promise(); + this._isLoaded = false; + this._sprite = null; + this._sprite = new ex.Sprite(this, 0, 0, 0, 0); + } + /** + * Returns true if the Texture is completely loaded and is ready + * to be drawn. + */ + Texture.prototype.isLoaded = function () { + return this._isLoaded; + }; + /** + * Begins loading the texture and returns a promise to be resolved on completion + */ + Texture.prototype.load = function () { + var _this = this; + var complete = new ex.Promise(); + var loaded = _super.prototype.load.call(this); + loaded.then(function () { + _this.image = new Image(); + _this.image.addEventListener('load', function () { + _this._isLoaded = true; + _this.width = _this._sprite.swidth = _this._sprite.naturalWidth = _this._sprite.width = _this.image.naturalWidth; + _this.height = _this._sprite.sheight = _this._sprite.naturalHeight = _this._sprite.height = _this.image.naturalHeight; + _this.loaded.resolve(_this.image); + complete.resolve(_this.image); + }); + _this.image.src = _super.prototype.getData.call(_this); + }, function () { + complete.reject('Error loading texture.'); + }); + return complete; + }; + Texture.prototype.asSprite = function () { + return this._sprite; + }; + return Texture; + })(ex.Resource); + ex.Texture = Texture; + /** + * Sounds * - * ```ts - * class Game extends ex.Engine { + * The [[Sound]] object allows games built in Excalibur to load audio + * components, from soundtracks to sound effects. [[Sound]] is an [[ILoadable]] + * which means it can be passed to a [[Loader]] to pre-load before a game or level. * - * constructor() { - * super({ width: 800, height: 600, displayMode: DisplayMode.FullScreen }); - * } + * ## Pre-loading sounds * - * public start() { - * // add custom scenes - * this.add("mainmenu", new MainMenu()); + * Pass the [[Sound]] to a [[Loader]] to pre-load the asset. Once a [[Sound]] + * is loaded, you can [[Sound.play|play]] it. * - * return super.start(myLoader).then(() => { + * ```js + * // define multiple sources (such as mp3/wav/ogg) as a browser fallback + * var sndPlayerDeath = new ex.Sound("/assets/snd/player-death.mp3", "/assets/snd/player-death.wav"); * - * this.goToScene("mainmenu"); + * var loader = new ex.Loader(sndPlayerDeath); * - * // custom start-up - * }); - * } - * } + * game.start(loader).then(function () { * - * var game = new Game(); - * game.start(); + * sndPlayerDeath.play(); + * }); * ``` + */ + var Sound = (function () { + /** + * @param paths A list of audio sources (clip.wav, clip.mp3, clip.ogg) for this audio clip. This is done for browser compatibility. + */ + function Sound() { + var paths = []; + for (var _i = 0; _i < arguments.length; _i++) { + paths[_i - 0] = arguments[_i]; + } + this._logger = ex.Logger.getInstance(); + this.onprogress = function () { return; }; + this.oncomplete = function () { return; }; + this.onerror = function () { return; }; + this.onload = function () { return; }; + this._isLoaded = false; + this._selectedFile = ''; + this._wasPlayingOnHidden = false; + /* Chrome : MP3, WAV, Ogg + * Firefox : WAV, Ogg, + * IE : MP3, WAV coming soon + * Safari MP3, WAV, Ogg + */ + this._selectedFile = ''; + for (var i = 0; i < paths.length; i++) { + if (Sound.canPlayFile(paths[i])) { + this._selectedFile = paths[i]; + break; + } + } + if (!this._selectedFile) { + this._logger.warn('This browser does not support any of the audio files specified:', paths.join(', ')); + this._logger.warn('Attempting to use', paths[0]); + this._selectedFile = paths[0]; // select the first specified + } + this.sound = new ex.Internal.FallbackAudio(this._selectedFile, 1.0); + } + /** + * Whether or not the browser can play this file as HTML5 Audio + */ + Sound.canPlayFile = function (file) { + try { + var a = new Audio(); + var filetype = /.*\.([A-Za-z0-9]+)$/; + var type = file.match(filetype)[1]; + if (a.canPlayType('audio/' + type)) { + return true; + } + { + return false; + } + } + catch (e) { + ex.Logger.getInstance().warn('Cannot determine audio support, assuming no support for the Audio Tag', e); + return false; + } + }; + Sound.prototype.wireEngine = function (engine) { + var _this = this; + if (engine) { + this._engine = engine; + this._engine.on('hidden', function () { + if (engine.pauseAudioWhenHidden && _this.isPlaying()) { + _this._wasPlayingOnHidden = true; + _this.pause(); + } + }); + this._engine.on('visible', function () { + if (engine.pauseAudioWhenHidden && _this._wasPlayingOnHidden) { + _this.play(); + _this._wasPlayingOnHidden = false; + } + }); + } + }; + /** + * Sets the volume of the sound clip + * @param volume A volume value between 0-1.0 + */ + Sound.prototype.setVolume = function (volume) { + if (this.sound) { + this.sound.setVolume(volume); + } + }; + /** + * Indicates whether the clip should loop when complete + * @param loop Set the looping flag + */ + Sound.prototype.setLoop = function (loop) { + if (this.sound) { + this.sound.setLoop(loop); + } + }; + /** + * Whether or not the sound is playing right now + */ + Sound.prototype.isPlaying = function () { + if (this.sound) { + return this.sound.isPlaying(); + } + }; + /** + * Play the sound, returns a promise that resolves when the sound is done playing + */ + Sound.prototype.play = function () { + if (this.sound) { + return this.sound.play(); + } + }; + /** + * Stop the sound, and do not rewind + */ + Sound.prototype.pause = function () { + if (this.sound) { + this.sound.pause(); + } + }; + /** + * Stop the sound and rewind + */ + Sound.prototype.stop = function () { + if (this.sound) { + this.sound.stop(); + } + }; + /** + * Returns true if the sound is loaded + */ + Sound.prototype.isLoaded = function () { + return this._isLoaded; + }; + /** + * Begins loading the sound and returns a promise to be resolved on completion + */ + Sound.prototype.load = function () { + var _this = this; + var complete = new ex.Promise(); + this._logger.debug('Started loading sound', this._selectedFile); + this.sound.onprogress = this.onprogress; + this.sound.onload = function () { + _this.oncomplete(); + _this._isLoaded = true; + _this._logger.debug('Completed loading sound', _this._selectedFile); + complete.resolve(_this.sound); + }; + this.sound.onerror = function (e) { + _this.onerror(e); + complete.resolve(e); + }; + this.sound.load(); + return complete; + }; + return Sound; + })(); + ex.Sound = Sound; + /** + * Pre-loading assets * - * **Javascript** - * - * ```js - * var Game = ex.Engine.extend({ + * The loader provides a mechanism to preload multiple resources at + * one time. The loader must be passed to the engine in order to + * trigger the loading progress bar. * - * constructor: function () { - * Engine.call(this, { width: 800, height: 600, displayMode: DisplayMode.FullScreen }); - * } + * The [[Loader]] itself implements [[ILoadable]] so you can load loaders. * - * start: function() { - * // add custom scenes - * this.add("mainmenu", new MainMenu()); + * ## Example: Pre-loading resources for a game * - * var _this = this; - * return Engine.prototype.start.call(this, myLoader).then(function() { + * ```js + * // create a loader + * var loader = new ex.Loader(); * - * _this.goToScene("mainmenu"); + * // create a resource dictionary (best practice is to keep a separate file) + * var resources = { + * TextureGround: new ex.Texture("/images/textures/ground.png"), + * SoundDeath: new ex.Sound("/sound/death.wav", "/sound/death.mp3") + * }; * - * // custom start-up - * }); + * // loop through dictionary and add to loader + * for (var loadable in resources) { + * if (resources.hasOwnProperty(loadable)) { + * loader.addResource(loadable); * } - * }); + * } * - * var game = new Game(); - * game.start(); + * // start game + * game.start(loader).then(function () { + * console.log("Game started!"); + * }); * ``` */ - var Engine = (function (_super) { - __extends(Engine, _super); + var Loader = (function () { /** - * @internal + * @param loadables Optionally provide the list of resources you want to load at constructor time */ - function Engine(args) { - _super.call(this); - /** - * Gets or sets the [[CollisionStrategy]] for Excalibur actors - */ - this.collisionStrategy = ex.CollisionStrategy.DynamicAABBTree; - this._hasStarted = false; - /** - * Current FPS - */ - this.fps = 0; - /** - * Gets or sets the list of post processors to apply at the end of drawing a frame (such as [[ColorBlindCorrector]]) - */ - this.postProcessors = []; - /** - * Contains all the scenes currently registered with Excalibur - */ - this.scenes = {}; - this._animations = []; - /** - * Indicates whether the engine is set to fullscreen or not - */ - this.isFullscreen = false; - /** - * Indicates the current [[DisplayMode]] of the engine. - */ - this.displayMode = DisplayMode.FullScreen; - /** - * Indicates whether audio should be paused when the game is no longer visible. - */ - this.pauseAudioWhenHidden = true; - /** - * Indicates whether the engine should draw with debug information - */ - this.isDebug = false; - this.debugColor = new ex.Color(255, 255, 255); - /** - * Sets the background color for the engine. - */ - this.backgroundColor = new ex.Color(0, 0, 100); - /** - * The action to take when a fatal exception is thrown - */ - this.onFatalException = function (e) { ex.Logger.getInstance().fatal(e); }; - this._isSmoothingEnabled = true; - this._isLoading = false; - this._progress = 0; - this._total = 1; - var width; - var height; - var canvasElementId; - var displayMode; - var options = null; - if (typeof arguments[0] === 'number') { - width = arguments[0]; - height = arguments[1]; - canvasElementId = arguments[2]; - displayMode = arguments[3]; + function Loader(loadables) { + this._resourceList = []; + this._index = 0; + this._resourceCount = 0; + this._numLoaded = 0; + this._progressCounts = {}; + this._totalCounts = {}; + this.onprogress = function () { return; }; + this.oncomplete = function () { return; }; + this.onerror = function () { return; }; + if (loadables) { + this.addResources(loadables); } - else { - options = arguments[0] || { width: 0, height: 0, canvasElementId: '', displayMode: DisplayMode.FullScreen }; - width = options.width; - height = options.height; - canvasElementId = options.canvasElementId; - displayMode = options.displayMode; + } + Loader.prototype.wireEngine = function (engine) { + this._engine = engine; + }; + /** + * Add a resource to the loader to load + * @param loadable Resource to add + */ + Loader.prototype.addResource = function (loadable) { + var key = this._index++; + this._resourceList.push(loadable); + this._progressCounts[key] = 0; + this._totalCounts[key] = 1; + this._resourceCount++; + }; + /** + * Add a list of resources to the loader to load + * @param loadables The list of resources to load + */ + Loader.prototype.addResources = function (loadables) { + var i = 0, len = loadables.length; + for (i; i < len; i++) { + this.addResource(loadables[i]); } - // Check compatibility - var detector = new ex.Detector(); - if (!(this._compatible = detector.test())) { - var message = document.createElement('div'); - message.innerText = 'Sorry, your browser does not support all the features needed for Excalibur'; - document.body.appendChild(message); - detector.failedTests.forEach(function (test) { - var testMessage = document.createElement('div'); - testMessage.innerText = 'Browser feature missing ' + test; - document.body.appendChild(testMessage); + }; + Loader.prototype._sumCounts = function (obj) { + var sum = 0; + var prev = 0; + for (var i in obj) { + sum += obj[i] | 0; + } + return sum; + }; + /** + * Returns true if the loader has completely loaded all resources + */ + Loader.prototype.isLoaded = function () { + return this._numLoaded === this._resourceCount; + }; + /** + * Begin loading all of the supplied resources, returning a promise + * that resolves when loading of all is complete + */ + Loader.prototype.load = function () { + var _this = this; + var complete = new ex.Promise(); + var me = this; + if (this._resourceList.length === 0) { + me.oncomplete.call(me); + return complete; + } + var progressArray = new Array(this._resourceList.length); + var progressChunks = this._resourceList.length; + this._resourceList.forEach(function (r, i) { + if (_this._engine) { + r.wireEngine(_this._engine); + } + r.onprogress = function (e) { + var total = e.total; + var loaded = e.loaded; + progressArray[i] = { loaded: ((loaded / total) * (100 / progressChunks)), total: 100 }; + var progressResult = progressArray.reduce(function (accum, next) { + return { loaded: (accum.loaded + next.loaded), total: 100 }; + }, { loaded: 0, total: 100 }); + me.onprogress.call(me, progressResult); + }; + r.oncomplete = r.onerror = function () { + me._numLoaded++; + if (me._numLoaded === me._resourceCount) { + me.onprogress.call(me, { loaded: 100, total: 100 }); + me.oncomplete.call(me); + complete.resolve(); + } + }; + }); + function loadNext(list, index) { + if (!list[index]) { + return; + } + list[index].load().then(function () { + loadNext(list, index + 1); }); - if (canvasElementId) { - var canvas = document.getElementById(canvasElementId); - if (canvas) { - canvas.parentElement.removeChild(canvas); + } + loadNext(this._resourceList, 0); + return complete; + }; + return Loader; + })(); + ex.Loader = Loader; +})(ex || (ex = {})); +/// +var ex; +(function (ex) { + var Detector = (function () { + function Detector() { + this.failedTests = []; + // critical browser features required for ex to run + this._criticalTests = { + // Test canvas/2d context support + canvasSupport: function () { + var elem = document.createElement('canvas'); + return !!(elem.getContext && elem.getContext('2d')); + }, + // Test array buffer support ex uses for downloading binary data + arrayBufferSupport: function () { + var xhr = new XMLHttpRequest(); + xhr.open('GET', '/'); + try { + xhr.responseType = 'arraybuffer'; + } + catch (e) { + return false; } + return xhr.responseType === 'arraybuffer'; + }, + // Test data urls ex uses for sprites + dataUrlSupport: function () { + var canvas = document.createElement('canvas'); + return canvas.toDataURL('image/png').indexOf('data:image/png') === 0; + }, + // Test object url support for loading + objectUrlSupport: function () { + return 'URL' in window && 'revokeObjectURL' in URL && 'createObjectURL' in URL; + }, + // RGBA support for colors + rgbaSupport: function () { + var style = document.createElement('a').style; + style.cssText = 'background-color:rgba(150,255,150,.5)'; + return ('' + style.backgroundColor).indexOf('rgba') > -1; + } + }; + // warnings excalibur performance will be degraded + this._warningTest = { + webAudioSupport: function () { + return !!(window.AudioContext || + window.webkitAudioContext || + window.mozAudioContext || + window.msAudioContext || + window.oAudioContext); + }, + webglSupport: function () { + var elem = document.createElement('canvas'); + return !!(elem.getContext && elem.getContext('webgl')); + } + }; + } + Detector.prototype.test = function () { + // Critical test will for ex not to run + var failedCritical = false; + for (var test in this._criticalTests) { + if (!this._criticalTests[test]()) { + this.failedTests.push(test); + ex.Logger.getInstance().error('Critical browser feature missing, Excalibur requires:', test); + failedCritical = true; } - return; - } - this._logger = ex.Logger.getInstance(); - this._logger.info('Powered by Excalibur.js visit", "http://excaliburjs.com", "for more information.'); - this._logger.debug('Building engine...'); - this.canvasElementId = canvasElementId; - if (canvasElementId) { - this._logger.debug('Using Canvas element specified: ' + canvasElementId); - this.canvas = document.getElementById(canvasElementId); } - else { - this._logger.debug('Using generated canvas element'); - this.canvas = document.createElement('canvas'); + if (failedCritical) { + return false; } - if (width && height) { - if (displayMode === undefined) { - this.displayMode = DisplayMode.Fixed; + // Warning tests do not for ex to return false to compatibility + for (var warning in this._warningTest) { + if (!this._warningTest[warning]()) { + ex.Logger.getInstance().warn('Warning browser feature missing, Excalibur will have reduced performance:', warning); } - this._logger.debug('Engine viewport is size ' + width + ' x ' + height); - this.width = width; - this.canvas.width = width; - this.height = height; - this.canvas.height = height; - } - else if (!displayMode) { - this._logger.debug('Engine viewport is fullscreen'); - this.displayMode = DisplayMode.FullScreen; } - this._loader = new ex.Loader(); - this._initialize(options); - this.rootScene = this.currentScene = new ex.Scene(this); - this.addScene('root', this.rootScene); - this.goToScene('root'); - } - /** - * Plays a sprite animation on the screen at the specified `x` and `y` - * (in game coordinates, not screen pixels). These animations play - * independent of actors, and will be cleaned up internally as soon - * as they are complete. Note animations that loop will never be - * cleaned up. - * - * @param animation Animation to play - * @param x x game coordinate to play the animation - * @param y y game coordinate to play the animation - */ - Engine.prototype.playAnimation = function (animation, x, y) { - this._animations.push(new AnimationNode(animation, x, y)); - }; - /** - * Adds an actor to the [[currentScene]] of the game. This is synonymous - * to calling `engine.currentScene.addChild(actor)`. - * - * Actors can only be drawn if they are a member of a scene, and only - * the [[currentScene]] may be drawn or updated. - * - * @param actor The actor to add to the [[currentScene]] - * - * @obsolete Use [[add]] instead. - */ - Engine.prototype.addChild = function (actor) { - this.currentScene.addChild(actor); - }; - /** - * Removes an actor from the [[currentScene]] of the game. This is synonymous - * to calling `engine.currentScene.removeChild(actor)`. - * Actors that are removed from a scene will no longer be drawn or updated. - * - * @param actor The actor to remove from the [[currentScene]]. - */ - Engine.prototype.removeChild = function (actor) { - this.currentScene.removeChild(actor); - }; - /** - * Adds a [[TileMap]] to the [[currentScene]], once this is done the TileMap - * will be drawn and updated. - */ - Engine.prototype.addTileMap = function (tileMap) { - this.currentScene.addTileMap(tileMap); + return true; }; + return Detector; + })(); + ex.Detector = Detector; +})(ex || (ex = {})); +/// +/// +/// +var ex; +(function (ex) { + /** + * Excalibur's built in templating class, it is a loadable that will load + * and html fragment from a url. Excalibur templating is very basic only + * allowing bindings of the type `data-text="this.obj.someprop"`, + * `data-style="color:this.obj.color.toString()"`. Bindings allow all valid + * Javascript expressions. + */ + var Template = (function () { /** - * Removes a [[TileMap]] from the [[currentScene]], it will no longer be drawn or updated. + * @param path Location of the html template */ - Engine.prototype.removeTileMap = function (tileMap) { - this.currentScene.removeTileMap(tileMap); + function Template(path) { + this.path = path; + this._isLoaded = false; + this.logger = ex.Logger.getInstance(); + this.onprogress = function () { return; }; + this.oncomplete = function () { return; }; + this.onerror = function () { return; }; + this._innerElement = document.createElement('div'); + this._innerElement.className = 'excalibur-template'; + } + Template.prototype.wireEngine = function (engine) { + this._engine = engine; }; /** - * Adds a [[Timer]] to the [[currentScene]]. - * @param timer The timer to add to the [[currentScene]]. + * Returns the full html template string once loaded. */ - Engine.prototype.addTimer = function (timer) { - return this.currentScene.addTimer(timer); + Template.prototype.getTemplateString = function () { + if (!this._isLoaded) { + return ''; + } + return this._htmlString; }; - /** - * Removes a [[Timer]] from the [[currentScene]]. - * @param timer The timer to remove to the [[currentScene]]. - */ - Engine.prototype.removeTimer = function (timer) { - return this.currentScene.removeTimer(timer); + Template.prototype._compile = function () { + this._innerElement.innerHTML = this._htmlString; + this._styleElements = this._innerElement.querySelectorAll('[data-style]'); + this._textElements = this._innerElement.querySelectorAll('[data-text]'); }; - /** - * Adds a [[Scene]] to the engine, think of scenes in Excalibur as you - * would levels or menus. - * - * @param key The name of the scene, must be unique - * @param scene The scene to add to the engine - */ - Engine.prototype.addScene = function (key, scene) { - if (this.scenes[key]) { - this._logger.warn('Scene', key, 'already exists overwriting'); - } - this.scenes[key] = scene; - scene.engine = this; + Template.prototype._evaluateExpresion = function (expression, ctx) { + var func = new Function('return ' + expression + ';'); + var val = func.call(ctx); + return val; }; /** - * @internal + * Applies any ctx object you wish and evaluates the template. + * Overload this method to include your favorite template library. + * You may return either an HTML string or a Dom node. + * @param ctx Any object you wish to apply to the template */ - Engine.prototype.removeScene = function (entity) { - if (entity instanceof ex.Scene) { - // remove scene - for (var key in this.scenes) { - if (this.scenes.hasOwnProperty(key)) { - if (this.scenes[key] === entity) { - delete this.scenes[key]; + Template.prototype.apply = function (ctx) { + var _this = this; + /* tslint:disable:no-string-literal */ + for (var j = 0; j < this._styleElements.length; j++) { + (function () { + // poor man's json parse for things that aren't exactly json :( + // Extract style expressions + var styles = {}; + _this._styleElements[j].dataset['style'].split(';').forEach(function (s) { + if (s) { + var vals = s.split(':'); + styles[vals[0].trim()] = vals[1].trim(); } + }); + // Evaluate parsed style expressions + for (var style in styles) { + (function () { + var expression = styles[style]; + _this._styleElements[j].style[style] = _this._evaluateExpresion(expression, ctx); + })(); } - } - } - if (typeof entity === 'string') { - // remove scene - delete this.scenes[entity]; - } - }; - Engine.prototype.add = function (entity) { - if (entity instanceof ex.UIActor) { - this.currentScene.addUIActor(entity); - return; - } - if (entity instanceof ex.Actor) { - this.addChild(entity); - } - if (entity instanceof ex.Timer) { - this.addTimer(entity); - } - if (entity instanceof ex.TileMap) { - this.addTileMap(entity); - } - if (arguments.length === 2) { - this.addScene(arguments[0], arguments[1]); - } - }; - Engine.prototype.remove = function (entity) { - if (entity instanceof ex.UIActor) { - this.currentScene.removeUIActor(entity); - return; - } - if (entity instanceof ex.Actor) { - this.removeChild(entity); - } - if (entity instanceof ex.Timer) { - this.removeTimer(entity); - } - if (entity instanceof ex.TileMap) { - this.removeTileMap(entity); + })(); } - if (entity instanceof ex.Scene) { - this.removeScene(entity); + for (var i = 0; i < this._textElements.length; i++) { + (function () { + // Evaluate text expressions + var expression = _this._textElements[i].dataset['text']; + _this._textElements[i].innerText = _this._evaluateExpresion(expression, ctx); + })(); } - if (typeof entity === 'string') { - this.removeScene(entity); + // If the template HTML has a root element return that, otherwise use constructed root + if (this._innerElement.children.length === 1) { + this._innerElement = this._innerElement.firstChild; } + /* tslint:enable:no-string-literal */ + return this._innerElement; }; /** - * Changes the currently updating and drawing scene to a different, - * named scene. Calls the [[Scene]] lifecycle events. - * @param key The key of the scene to trasition to. + * Begins loading the template. Returns a promise that resolves with the template string when loaded. */ - Engine.prototype.goToScene = function (key) { - if (this.scenes[key]) { - var oldScene = this.currentScene; - var newScene = this.scenes[key]; - this._logger.debug('Going to scene:', key); - // only deactivate when initialized - if (this.currentScene.isInitialized) { - this.currentScene.onDeactivate.call(this.currentScene); - this.currentScene.eventDispatcher.emit('deactivate', new ex.DeactivateEvent(newScene)); - } - // set current scene to new one - this.currentScene = newScene; - if (!this.currentScene.isInitialized) { - this.currentScene.onInitialize.call(this.currentScene, this); - this.currentScene.eventDispatcher.emit('initialize', new ex.InitializeEvent(this)); - this.currentScene.isInitialized = true; + Template.prototype.load = function () { + var _this = this; + var complete = new ex.Promise(); + var request = new XMLHttpRequest(); + request.open('GET', this.path, true); + request.responseType = 'text'; + request.onprogress = this.onprogress; + request.onerror = this.onerror; + request.onload = function (e) { + if (request.status !== 200) { + _this.logger.error('Failed to load html template resource ', _this.path, ' server responded with error code', request.status); + _this.onerror(request.response); + _this._isLoaded = false; + complete.resolve('error'); + return; } - this.currentScene.onActivate.call(this.currentScene); - this.currentScene.eventDispatcher.emit('activate', new ex.ActivateEvent(oldScene)); - } - else { - this._logger.error('Scene', key, 'does not exist!'); + _this._htmlString = request.response; + _this.oncomplete(); + _this.logger.debug('Completed loading template', _this.path); + _this._compile(); + _this._isLoaded = true; + complete.resolve(_this._htmlString); + }; + if (request.overrideMimeType) { + request.overrideMimeType('text/plain; charset=x-user-defined'); } + request.send(); + return complete; }; /** - * Returns the width of the engine's drawing surface in pixels. + * Indicates whether the template has been loaded */ - Engine.prototype.getWidth = function () { - if (this.currentScene && this.currentScene.camera) { - return this.width / this.currentScene.camera.getZoom(); - } - return this.width; + Template.prototype.isLoaded = function () { + return this._isLoaded; }; + return Template; + })(); + ex.Template = Template; + /** + * Excalibur's binding library that allows you to bind an html + * template to the dom given a certain context. Excalibur bindings are only updated + * when the update() method is called + */ + var Binding = (function () { /** - * Returns the height of the engine's drawing surface in pixels. + * @param parentElementId The id of the element in the dom to attach the template binding + * @param template The template you wish to bind + * @param ctx The context of the binding, which can be any object */ - Engine.prototype.getHeight = function () { - if (this.currentScene && this.currentScene.camera) { - return this.height / this.currentScene.camera.getZoom(); - } - return this.height; - }; + function Binding(parentElementId, template, ctx) { + this.parent = document.getElementById(parentElementId); + this.template = template; + this._ctx = ctx; + this.update(); + } /** - * Transforms the current x, y from screen coordinates to world coordinates - * @param point Screen coordinate to convert + * Listen to any arbitrary object's events to update this binding + * @param obj Any object that supports addEventListener + * @param events A list of events to listen for + * @param handler A optional handler to fire on any event */ - Engine.prototype.screenToWorldCoordinates = function (point) { - var newX = point.x; - var newY = point.y; - // transform back to world space - newX = (newX / this.canvas.clientWidth) * this.getWidth(); - newY = (newY / this.canvas.clientHeight) * this.getHeight(); - // transform based on zoom - newX = newX - this.getWidth() / 2; - newY = newY - this.getHeight() / 2; - // shift by focus - if (this.currentScene && this.currentScene.camera) { - var focus = this.currentScene.camera.getFocus(); - newX += focus.x; - newY += focus.y; + Binding.prototype.listen = function (obj, events, handler) { + var _this = this; + // todo + if (!handler) { + handler = function () { + _this.update(); + }; } - return new ex.Point(Math.floor(newX), Math.floor(newY)); - }; - /** - * Transforms a world coordinate, to a screen coordinate - * @param point World coordinate to convert - */ - Engine.prototype.worldToScreenCoordinates = function (point) { - var screenX = point.x; - var screenY = point.y; - // shift by focus - if (this.currentScene && this.currentScene.camera) { - var focus = this.currentScene.camera.getFocus(); - screenX -= focus.x; - screenY -= focus.y; + if (obj.addEventListener) { + events.forEach(function (e) { + obj.addEventListener(e, handler); + }); } - // transfrom back on zoom - screenX = screenX + this.getWidth() / 2; - screenY = screenY + this.getHeight() / 2; - // transform back to screen space - screenX = (screenX * this.canvas.clientWidth) / this.getWidth(); - screenY = (screenY * this.canvas.clientHeight) / this.getHeight(); - return new ex.Point(Math.floor(screenX), Math.floor(screenY)); }; /** - * Sets the internal canvas height based on the selected display mode. + * Update this template binding with the latest values from + * the ctx reference passed to the constructor */ - Engine.prototype._setHeightByDisplayMode = function (parent) { - if (this.displayMode === DisplayMode.Container) { - this.width = this.canvas.width = parent.clientWidth; - this.height = this.canvas.height = parent.clientHeight; + Binding.prototype.update = function () { + var html = this._applyTemplate(this.template, this._ctx); + if (html instanceof String) { + this.parent.innerHTML = html; } - if (this.displayMode === DisplayMode.FullScreen) { - document.body.style.margin = '0px'; - document.body.style.overflow = 'hidden'; - this.width = this.canvas.width = parent.innerWidth; - this.height = this.canvas.height = parent.innerHeight; + if (html instanceof Node) { + if (this.parent.lastChild !== html) { + this.parent.appendChild(html); + } } }; - /** - * Initializes the internal canvas, rendering context, displaymode, and native event listeners - */ - Engine.prototype._initialize = function (options) { - var _this = this; - if (this.displayMode === DisplayMode.FullScreen || this.displayMode === DisplayMode.Container) { - var parent = (this.displayMode === DisplayMode.Container ? - (this.canvas.parentElement || document.body) : window); - this._setHeightByDisplayMode(parent); - window.addEventListener('resize', function (ev) { - _this._logger.debug('View port resized'); - _this._setHeightByDisplayMode(parent); - _this._logger.info('parent.clientHeight ' + parent.clientHeight); - _this.setAntialiasing(_this._isSmoothingEnabled); - }); - } - // initialize inputs - this.input = { - keyboard: new ex.Input.Keyboard(this), - pointers: new ex.Input.Pointers(this), - gamepads: new ex.Input.Gamepads(this) - }; - this.input.keyboard.init(); - this.input.pointers.init(options ? options.pointerScope : ex.Input.PointerScope.Document); - this.input.gamepads.init(); - // Issue #385 make use of the visibility api - // https://developer.mozilla.org/en-US/docs/Web/Guide/User_experience/Using_the_Page_Visibility_API - document.addEventListener('visibilitychange', function () { - if (document.hidden || document.msHidden) { - _this.eventDispatcher.emit('hidden', new ex.HiddenEvent()); - _this._logger.debug('Window hidden'); - } - else { - _this.eventDispatcher.emit('visible', new ex.VisibleEvent()); - _this._logger.debug('Window visible'); - } - }); - /* - // DEPRECATED in favor of visibility api - window.addEventListener('blur', () => { - this.eventDispatcher.publish(EventType[EventType.Blur], new BlurEvent()); - }); - - window.addEventListener('focus', () => { - this.eventDispatcher.publish(EventType[EventType.Focus], new FocusEvent()); - });*/ - this.ctx = this.canvas.getContext('2d'); - if (!this.canvasElementId) { - document.body.appendChild(this.canvas); + Binding.prototype._applyTemplate = function (template, ctx) { + if (template.isLoaded()) { + return template.apply(ctx); } }; + return Binding; + })(); + ex.Binding = Binding; +})(ex || (ex = {})); +/// +var ex; +(function (ex) { + /** + * Enum representing the different font size units + * https://developer.mozilla.org/en-US/docs/Web/CSS/font-size + */ + (function (FontUnit) { + /** + * Em is a scalable unit, 1 em is equal to the current font size of the current element, parent elements can effect em values + */ + FontUnit[FontUnit["Em"] = 0] = "Em"; + /** + * Rem is similar to the Em, it is a scalable unit. 1 rem is eqaul to the font size of the root element + */ + FontUnit[FontUnit["Rem"] = 1] = "Rem"; + /** + * Pixel is a unit of length in screen pixels + */ + FontUnit[FontUnit["Px"] = 2] = "Px"; + /** + * Point is a physical unit length (1/72 of an inch) + */ + FontUnit[FontUnit["Pt"] = 3] = "Pt"; + /** + * Percent is a scalable unit similar to Em, the only difference is the Em units scale faster when Text-Size stuff + */ + FontUnit[FontUnit["Percent"] = 4] = "Percent"; + })(ex.FontUnit || (ex.FontUnit = {})); + var FontUnit = ex.FontUnit; + /** + * Enum representing the different horizontal text alignments + */ + (function (TextAlign) { + /** + * The text is left-aligned. + */ + TextAlign[TextAlign["Left"] = 0] = "Left"; + /** + * The text is right-aligned. + */ + TextAlign[TextAlign["Right"] = 1] = "Right"; + /** + * The text is centered. + */ + TextAlign[TextAlign["Center"] = 2] = "Center"; /** - * If supported by the browser, this will set the antialiasing flag on the - * canvas. Set this to `false` if you want a 'jagged' pixel art look to your - * image resources. - * @param isSmooth Set smoothing to true or false + * The text is aligned at the normal start of the line (left-aligned for left-to-right locales, + * right-aligned for right-to-left locales). */ - Engine.prototype.setAntialiasing = function (isSmooth) { - this._isSmoothingEnabled = isSmooth; - this.ctx.imageSmoothingEnabled = isSmooth; - this.ctx.webkitImageSmoothingEnabled = isSmooth; - this.ctx.mozImageSmoothingEnabled = isSmooth; - this.ctx.msImageSmoothingEnabled = isSmooth; - }; + TextAlign[TextAlign["Start"] = 3] = "Start"; /** - * Return the current smoothing status of the canvas + * The text is aligned at the normal end of the line (right-aligned for left-to-right locales, + * left-aligned for right-to-left locales). */ - Engine.prototype.getAntialiasing = function () { - return this.ctx.imageSmoothingEnabled || - this.ctx.webkitImageSmoothingEnabled || - this.ctx.mozImageSmoothingEnabled || - this.ctx.msImageSmoothingEnabled; - }; + TextAlign[TextAlign["End"] = 4] = "End"; + })(ex.TextAlign || (ex.TextAlign = {})); + var TextAlign = ex.TextAlign; + /** + * Enum representing the different baseline text alignments + */ + (function (BaseAlign) { /** - * Updates the entire state of the game - * @param delta Number of milliseconds elapsed since the last update. + * The text baseline is the top of the em square. */ - Engine.prototype._update = function (delta) { - if (this._isLoading) { - // suspend updates untill loading is finished - return; - } - // process engine level events - this.currentScene.update(this, delta); - // update animations - this._animations = this._animations.filter(function (a) { - return !a.animation.isDone(); - }); - // Update input listeners - this.input.keyboard.update(delta); - this.input.pointers.update(delta); - this.input.gamepads.update(delta); - // Publish update event - this.eventDispatcher.emit(ex.EventType[ex.EventType.Update], new ex.UpdateEvent(delta)); - }; + BaseAlign[BaseAlign["Top"] = 0] = "Top"; /** - * Draws the entire game - * @param draw Number of milliseconds elapsed since the last draw. + * The text baseline is the hanging baseline. Currently unsupported; this will act like + * alphabetic. */ - Engine.prototype._draw = function (delta) { - var ctx = this.ctx; - if (this._isLoading) { - ctx.fillStyle = 'black'; - ctx.fillRect(0, 0, this.width, this.height); - this._drawLoadingBar(ctx, this._progress, this._total); - // Drawing nothing else while loading - return; - } - ctx.clearRect(0, 0, this.width, this.height); - ctx.fillStyle = this.backgroundColor.toString(); - ctx.fillRect(0, 0, this.width, this.height); - this.currentScene.draw(this.ctx, delta); - // todo needs to be a better way of doing this - var a = 0, len = this._animations.length; - for (a; a < len; a++) { - this._animations[a].animation.draw(ctx, this._animations[a].x, this._animations[a].y); - } - this.fps = 1.0 / (delta / 1000); - // Draw debug information - if (this.isDebug) { - this.ctx.font = 'Consolas'; - this.ctx.fillStyle = this.debugColor.toString(); - var keys = this.input.keyboard.getKeys(); - for (var j = 0; j < keys.length; j++) { - this.ctx.fillText(keys[j].toString() + ' : ' + (ex.Input.Keys[keys[j]] ? ex.Input.Keys[keys[j]] : 'Not Mapped'), 100, 10 * j + 10); - } - this.ctx.fillText('FPS:' + this.fps.toFixed(2).toString(), 10, 10); - } - // Post processing - for (var i = 0; i < this.postProcessors.length; i++) { - this.postProcessors[i].process(this.ctx.getImageData(0, 0, this.width, this.height), this.ctx); - } - //ctx.drawImage(currentImage, 0, 0, this.width, this.height); - }; + BaseAlign[BaseAlign["Hanging"] = 1] = "Hanging"; /** - * Starts the internal game loop for Excalibur after loading - * any provided assets. - * @param loader Optional resources to load before starting the main loop. Some [[ILoadable]] such as a [[Loader]] collection, - * [[Sound]], or [[Texture]]. + * The text baseline is the middle of the em square. */ - Engine.prototype.start = function (loader) { - if (!this._compatible) { - var promise = new ex.Promise(); - return promise.reject('Excalibur is incompatible with your browser'); - } - var loadingComplete; - if (loader) { - loader.wireEngine(this); - loadingComplete = this.load(loader); - } - else { - loadingComplete = ex.Promise.wrap(); - } - if (!this._hasStarted) { - this._hasStarted = true; - this._logger.debug('Starting game...'); - // Mainloop - var lastTime = Date.now(); - var game = this; - (function mainloop() { - if (!game._hasStarted) { - return; - } - try { - game._requestId = window.requestAnimationFrame(mainloop); - // Get the time to calculate time-elapsed - var now = Date.now(); - var elapsed = Math.floor(now - lastTime) || 1; - // Resolves issue #138 if the game has been paused, or blurred for - // more than a 200 milliseconds, reset elapsed time to 1. This improves reliability - // and provides more expected behavior when the engine comes back - // into focus - if (elapsed > 200) { - elapsed = 1; - } - game._update(elapsed); - game._draw(elapsed); - lastTime = now; - } - catch (e) { - window.cancelAnimationFrame(game._requestId); - game.stop(); - game.onFatalException(e); - } - })(); - this._logger.debug('Game started'); - } - else { + BaseAlign[BaseAlign["Middle"] = 2] = "Middle"; + /** + * The text baseline is the normal alphabetic baseline. + */ + BaseAlign[BaseAlign["Alphabetic"] = 3] = "Alphabetic"; + /** + * The text baseline is the ideographic baseline; this is the bottom of + * the body of the characters, if the main body of characters protrudes + * beneath the alphabetic baseline. Currently unsupported; this will + * act like alphabetic. + */ + BaseAlign[BaseAlign["Ideographic"] = 4] = "Ideographic"; + /** + * The text baseline is the bottom of the bounding box. This differs + * from the ideographic baseline in that the ideographic baseline + * doesn't consider descenders. + */ + BaseAlign[BaseAlign["Bottom"] = 5] = "Bottom"; + })(ex.BaseAlign || (ex.BaseAlign = {})); + var BaseAlign = ex.BaseAlign; + /** + * Labels + * + * Labels are the way to draw small amounts of text to the screen. They are + * actors and inherit all of the benifits and capabilities. + * + * ## Creating a Label + * + * You can pass in arguments to the [[Label.constructor]] or simply set the + * properties you need after creating an instance of the [[Label]]. + * + * Since labels are [[Actor|Actors]], they need to be added to a [[Scene]] + * to be drawn and updated on-screen. + * + * ```js + * var game = new ex.Engine(); + * + * // constructor + * var label = new ex.Label("Hello World", 50, 50, "10px Arial"); + * + * // properties + * var label = new ex.Label(); + * label.x = 50; + * label.y = 50; + * label.font = "10px Arial"; + * label.text = "Foo"; + * label.color = ex.Color.White; + * label.textAlign = ex.TextAlign.Center; + * + * // add to current scene + * game.add(label); + * + * // start game + * game.start(); + * ``` + * + * ## Web Fonts + * + * The HTML5 Canvas API draws text using CSS syntax. Because of this, web fonts + * are fully supported. To draw a web font, follow the same procedure you use + * for CSS. Then simply pass in the font string to the [[Label]] constructor + * or set [[Label.font]]. + * + * **index.html** + * + * ```html + * + * + * + * + * + * + * + * + * + * + * + * ``` + * + * **game.js** + * + * ```js + * var game = new ex.Engine(); + * + * var label = new ex.Label(); + * label.font = "12px Foobar, Arial, Sans-Serif"; + * label.text = "Hello World"; + * + * game.add(label); + * game.start(); + * ``` + * + * ## Performance Implications + * + * It is recommended to use a [[SpriteFont]] for labels as the raw Canvas + * API for drawing text is slow (`fillText`). Too many labels that + * do not use sprite fonts will visibly affect the frame rate of your game. + * + * Alternatively, you can always use HTML and CSS to draw UI elements, but + * currently Excalibur does not provide a way to easily interact with the + * DOM. Still, this will not affect canvas performance and is a way to + * lighten your game, if needed. + */ + var Label = (function (_super) { + __extends(Label, _super); + /** + * @param text The text of the label + * @param x The x position of the label + * @param y The y position of the label + * @param font Use any valid CSS font string for the label's font. Web fonts are supported. Default is `10px sans-serif`. + * @param spriteFont Use an Excalibur sprite font for the label's font, if a SpriteFont is provided it will take precendence + * over a css font. + */ + function Label(text, x, y, fontFamily, spriteFont) { + _super.call(this, x, y); + /** + * The font size in the selected units, default is 10 (default units is pixel) + */ + this.fontSize = 10; + /** + * The css units for a font size such as px, pt, em (SpriteFont only support px), by default is 'px'; + */ + this.fontUnit = FontUnit.Px; + /** + * Gets or sets the horizontal text alignment property for the label. + */ + this.textAlign = TextAlign.Left; + /** + * Gets or sets the baseline alignment property for the label. + */ + this.baseAlign = BaseAlign.Bottom; + /** + * Gets or sets the letter spacing on a Label. Only supported with Sprite Fonts. + */ + this.letterSpacing = 0; //px + /** + * Whether or not the [[SpriteFont]] will be case-sensitive when matching characters. + */ + this.caseInsensitive = true; + this._textShadowOn = false; + this._shadowOffsetX = 0; + this._shadowOffsetY = 0; + this._shadowColor = ex.Color.Black.clone(); + this._shadowColorDirty = false; + this._textSprites = {}; + this._shadowSprites = {}; + this._color = ex.Color.Black.clone(); + this.text = text || ''; + this.color = ex.Color.Black.clone(); + this.spriteFont = spriteFont; + this.collisionType = ex.CollisionType.PreventCollision; + this.fontFamily = fontFamily || '10px sans-serif'; // coallesce to default canvas font + if (spriteFont) { } - return loadingComplete; - }; + } /** - * Stops Excalibur's main loop, useful for pausing the game. + * Returns the width of the text in the label (in pixels); + * @param ctx Rending context to measure the string with */ - Engine.prototype.stop = function () { - if (this._hasStarted) { - this._hasStarted = false; - this._logger.debug('Game stopped'); + Label.prototype.getTextWidth = function (ctx) { + var oldFont = ctx.font; + ctx.font = this.fontFamily; + var width = ctx.measureText(this.text).width; + ctx.font = oldFont; + return width; + }; + // TypeScript doesn't support string enums :( + Label.prototype._lookupFontUnit = function (fontUnit) { + switch (fontUnit) { + case FontUnit.Em: + return 'em'; + case FontUnit.Rem: + return 'rem'; + case FontUnit.Pt: + return 'pt'; + case FontUnit.Px: + return 'px'; + case FontUnit.Percent: + return '%'; + default: + return 'px'; } }; - /** - * Takes a screen shot of the current viewport and returns it as an - * HTML Image Element. - */ - Engine.prototype.screenshot = function () { - var result = new Image(); - var raw = this.canvas.toDataURL('image/png'); - result.src = raw; - return result; + Label.prototype._lookupTextAlign = function (textAlign) { + switch (textAlign) { + case TextAlign.Left: + return 'left'; + case TextAlign.Right: + return 'right'; + case TextAlign.Center: + return 'center'; + case TextAlign.End: + return 'end'; + case TextAlign.Start: + return 'start'; + default: + return 'start'; + } }; - /** - * Draws the Excalibur loading bar - * @param ctx The canvas rendering context - * @param loaded Number of bytes loaded - * @param total Total number of bytes to load - */ - Engine.prototype._drawLoadingBar = function (ctx, loaded, total) { - if (this._loadingDraw) { - this._loadingDraw(ctx, loaded, total); - return; + Label.prototype._lookupBaseAlign = function (baseAlign) { + switch (baseAlign) { + case BaseAlign.Alphabetic: + return 'alphabetic'; + case BaseAlign.Bottom: + return 'bottom'; + case BaseAlign.Hanging: + return 'hangin'; + case BaseAlign.Ideographic: + return 'ideographic'; + case BaseAlign.Middle: + return 'middle'; + case BaseAlign.Top: + return 'top'; + default: + return 'alphabetic'; } - var y = this.canvas.height / 2; - var width = this.canvas.width / 3; - var x = width; - // loading image - var image = new Image(); - /* tslint:disable:max-line-length */ - // 64 bit string encoding of the excalibur logo - image.src = 'data:image/png;base64,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'; - /* tslint:enable:max-line-length */ - var imageHeight = width * 3 / 8; - var oldAntialias = this.getAntialiasing(); - this.setAntialiasing(true); - ctx.drawImage(image, 0, 0, 800, 300, x, y - imageHeight - 20, width, imageHeight); - // loading box - ctx.strokeStyle = 'white'; - ctx.lineWidth = 2; - ctx.strokeRect(x, y, width, 20); - var progress = width * (loaded / total); - ctx.fillStyle = 'white'; - var margin = 5; - var progressWidth = progress - margin * 2; - var height = 20 - margin * 2; - ctx.fillRect(x + margin, y + margin, progressWidth > 0 ? progressWidth : 0, height); - this.setAntialiasing(oldAntialias); }; /** - * Sets the loading screen draw function if you want to customize the draw - * @param fcn Callback to draw the loading screen which is passed a rendering context, the number of bytes loaded, and the total - * number of bytes to load. + * Sets the text shadow for sprite fonts + * @param offsetX The x offset in pixels to place the shadow + * @param offsetY The y offset in pixles to place the shadow + * @param shadowColor The color of the text shadow */ - Engine.prototype.setLoadingDrawFunction = function (fcn) { - this._loadingDraw = fcn; + Label.prototype.setTextShadow = function (offsetX, offsetY, shadowColor) { + this.spriteFont.setTextShadow(offsetX, offsetY, shadowColor); }; /** - * Another option available to you to load resources into the game. - * Immediately after calling this the game will pause and the loading screen - * will appear. - * @param loader Some [[ILoadable]] such as a [[Loader]] collection, [[Sound]], or [[Texture]]. + * Toggles text shadows on or off, only applies when using sprite fonts */ - Engine.prototype.load = function (loader) { - var _this = this; - var complete = new ex.Promise(); - this._isLoading = true; - loader.onprogress = function (e) { - _this._progress = e.loaded; - _this._total = e.total; - _this._logger.debug('Loading ' + (100 * _this._progress / _this._total).toFixed(0)); - }; - loader.oncomplete = function () { - setTimeout(function () { - _this._isLoading = false; - complete.resolve(); - }, 500); - }; - loader.load(); - return complete; + Label.prototype.useTextShadow = function (on) { + this.spriteFont.useTextShadow(on); }; - return Engine; - })(ex.Class); - ex.Engine = Engine; - /** - * Enum representing the different display modes available to Excalibur - */ - (function (DisplayMode) { - /** - * Show the game as full screen - */ - DisplayMode[DisplayMode["FullScreen"] = 0] = "FullScreen"; /** - * Scale the game to the parent DOM container - */ - DisplayMode[DisplayMode["Container"] = 1] = "Container"; - /** - * Show the game as a fixed size + * Clears the current text shadow */ - DisplayMode[DisplayMode["Fixed"] = 2] = "Fixed"; - })(ex.DisplayMode || (ex.DisplayMode = {})); - var DisplayMode = ex.DisplayMode; - /** - * @internal - */ - var AnimationNode = (function () { - function AnimationNode(animation, x, y) { - this.animation = animation; - this.x = x; - this.y = y; - } - return AnimationNode; - })(); + Label.prototype.clearTextShadow = function () { + this._textShadowOn = false; + this._shadowOffsetX = 0; + this._shadowOffsetY = 0; + this._shadowColor = ex.Color.Black.clone(); + }; + Label.prototype.update = function (engine, delta) { + _super.prototype.update.call(this, engine, delta); + /* + if (this.spriteFont && (this._color !== this.color || this.previousOpacity !== this.opacity)) { + for (var character in this._textSprites) { + this._textSprites[character].clearEffects(); + this._textSprites[character].fill(this.color.clone()); + this._textSprites[character].opacity(this.opacity); + + } + this._color = this.color; + this.previousOpacity = this.opacity; + } + + if (this.spriteFont && this._textShadowOn && this._shadowColorDirty && this._shadowColor) { + for (var characterShadow in this._shadowSprites) { + this._shadowSprites[characterShadow].clearEffects(); + this._shadowSprites[characterShadow].addEffect(new Effects.Fill(this._shadowColor.clone())); + } + this._shadowColorDirty = false; + }*/ + }; + Label.prototype.draw = function (ctx, delta) { + ctx.save(); + ctx.translate(this.x, this.y); + ctx.scale(this.scale.x, this.scale.y); + ctx.rotate(this.rotation); + if (this._textShadowOn) { + ctx.save(); + ctx.translate(this._shadowOffsetX, this._shadowOffsetY); + this._fontDraw(ctx, delta, this._shadowSprites); + ctx.restore(); + } + this._fontDraw(ctx, delta, this._textSprites); + _super.prototype.draw.call(this, ctx, delta); + ctx.restore(); + }; + Label.prototype._fontDraw = function (ctx, delta, sprites) { + if (this.spriteFont) { + this.spriteFont.draw(ctx, this.text, 0, 0, { + color: this.color.clone(), + baseAlign: this.baseAlign, + textAlign: this.textAlign, + fontSize: this.fontSize, + letterSpacing: this.letterSpacing, + opacity: this.opacity + }); + } + else { + var oldAlign = ctx.textAlign; + var oldTextBaseline = ctx.textBaseline; + ctx.textAlign = this._lookupTextAlign(this.textAlign); + ctx.textBaseline = this._lookupBaseAlign(this.baseAlign); + if (this.color) { + this.color.a = this.opacity; + } + ctx.fillStyle = this.color.toString(); + ctx.font = "" + this.fontSize + this._lookupFontUnit(this.fontUnit) + " " + this.fontFamily; + if (this.maxWidth) { + ctx.fillText(this.text, 0, 0, this.maxWidth); + } + else { + ctx.fillText(this.text, 0, 0); + } + ctx.textAlign = oldAlign; + ctx.textBaseline = oldTextBaseline; + } + }; + Label.prototype.debugDraw = function (ctx) { + _super.prototype.debugDraw.call(this, ctx); + }; + return Label; + })(ex.Actor); + ex.Label = Label; })(ex || (ex = {})); +/// var ex; (function (ex) { - /** - * An enum that describes the strategies that rotation actions can use - */ - (function (RotationType) { + var Input; + (function (Input) { /** - * Rotation via `ShortestPath` will use the smallest angle - * between the starting and ending points. This strategy is the default behavior. + * The type of pointer for a [[PointerEvent]]. */ - RotationType[RotationType["ShortestPath"] = 0] = "ShortestPath"; + (function (PointerType) { + PointerType[PointerType["Touch"] = 0] = "Touch"; + PointerType[PointerType["Mouse"] = 1] = "Mouse"; + PointerType[PointerType["Pen"] = 2] = "Pen"; + PointerType[PointerType["Unknown"] = 3] = "Unknown"; + })(Input.PointerType || (Input.PointerType = {})); + var PointerType = Input.PointerType; /** - * Rotation via `LongestPath` will use the largest angle - * between the starting and ending points. + * The mouse button being pressed. */ - RotationType[RotationType["LongestPath"] = 1] = "LongestPath"; + (function (PointerButton) { + PointerButton[PointerButton["Left"] = 0] = "Left"; + PointerButton[PointerButton["Middle"] = 1] = "Middle"; + PointerButton[PointerButton["Right"] = 2] = "Right"; + PointerButton[PointerButton["Unknown"] = 3] = "Unknown"; + })(Input.PointerButton || (Input.PointerButton = {})); + var PointerButton = Input.PointerButton; /** - * Rotation via `Clockwise` will travel in a clockwise direction, - * regardless of the starting and ending points. + * Determines the scope of handling mouse/touch events. See [[Pointers]] for more information. */ - RotationType[RotationType["Clockwise"] = 2] = "Clockwise"; + (function (PointerScope) { + /** + * Handle events on the `canvas` element only. Events originating outside the + * `canvas` will not be handled. + */ + PointerScope[PointerScope["Canvas"] = 0] = "Canvas"; + /** + * Handles events on the entire document. All events will be handled by Excalibur. + */ + PointerScope[PointerScope["Document"] = 1] = "Document"; + })(Input.PointerScope || (Input.PointerScope = {})); + var PointerScope = Input.PointerScope; /** - * Rotation via `CounterClockwise` will travel in a counterclockwise direction, - * regardless of the starting and ending points. + * Pointer events + * + * Represents a mouse, touch, or stylus event. See [[Pointers]] for more information on + * handling pointer input. + * + * For mouse-based events, you can inspect [[PointerEvent.button]] to see what button was pressed. */ - RotationType[RotationType["CounterClockwise"] = 3] = "CounterClockwise"; - })(ex.RotationType || (ex.RotationType = {})); - var RotationType = ex.RotationType; -})(ex || (ex = {})); -/// -/// -/// -/// -/** - * See [[ActionContext|Action API]] for more information about Actions. - */ -var ex; -(function (ex) { - var Internal; - (function (Internal) { - var Actions; - (function (Actions) { - var EaseTo = (function () { - function EaseTo(actor, x, y, duration, easingFcn) { - this.actor = actor; - this.easingFcn = easingFcn; - this._currentLerpTime = 0; - this._lerpDuration = 1 * 1000; // 5 seconds - this._lerpStart = new ex.Point(0, 0); - this._lerpEnd = new ex.Point(0, 0); - this._initialized = false; - this._stopped = false; - this._distance = 0; - this._lerpDuration = duration; - this._lerpEnd = new ex.Point(x, y); + var PointerEvent = (function (_super) { + __extends(PointerEvent, _super); + /** + * @param x The `x` coordinate of the event (in world coordinates) + * @param y The `y` coordinate of the event (in world coordinates) + * @param index The index of the pointer (zero-based) + * @param pointerType The type of pointer + * @param button The button pressed (if [[PointerType.Mouse]]) + * @param ev The raw DOM event being handled + */ + function PointerEvent(x, y, index, pointerType, button, ev) { + _super.call(this); + this.x = x; + this.y = y; + this.index = index; + this.pointerType = pointerType; + this.button = button; + this.ev = ev; + } + return PointerEvent; + })(ex.GameEvent); + Input.PointerEvent = PointerEvent; + ; + /** + * Mouse and Touch (Pointers) + * + * Handles pointer events (mouse, touch, stylus, etc.) and normalizes to + * [W3C Pointer Events](http://www.w3.org/TR/pointerevents/). + * + * There is always at least one [[Pointer]] available ([[Pointers.primary]]) and + * you can request multiple pointers to support multi-touch scenarios. + * + * Since [[Pointers.primary]] normalizes both mouse and touch events, your game + * automatically supports touch for the primary pointer by default. When + * you handle the events, you can customize what your game does based on the type + * of pointer, if applicable. + * + * Excalibur handles mouse/touch events and normalizes them to a [[PointerEvent]] + * that your game can subscribe to and handle (`engine.input.pointers`). + * + * ## Events + * + * You can subscribe to pointer events through `engine.input.pointers.on`. A [[PointerEvent]] object is + * passed to your handler which offers information about the pointer input being received. + * + * - `down` - When a pointer is pressed down (any mouse button or finger press) + * - `up` - When a pointer is lifted + * - `move` - When a pointer moves (be wary of performance issues when subscribing to this) + * - `cancel` - When a pointer event is canceled for some reason + * + * ```js + * engine.input.pointers.primary.on("down", function (evt) { }); + * engine.input.pointers.primary.on("up", function (evt) { }); + * engine.input.pointers.primary.on("move", function (evt) { }); + * engine.input.pointers.primary.on("cancel", function (evt) { }); + * ``` + * + * ## Pointer scope (window vs. canvas) + * + * You have the option to handle *all* pointer events in the browser by setting + * [[IEngineOptions.pointerScope]] to [[PointerScope.Document]]. If this is enabled, + * Excalibur will handle every pointer event in the browser. This is useful for handling + * complex input and having control over every interaction. + * + * You can also use [[PointerScope.Canvas]] to only scope event handling to the game + * canvas. This is useful if you don't care about events that occur outside the game. + * + * One real-world example is dragging and gestures. Sometimes a player will drag their + * finger outside your game and then into it, expecting it to work. If [[PointerScope]] + * is set to [[PointerScope.Canvas|Canvas]] this will not work. If it is set to + * [[PointerScope.Document|Document]], it will. + * + * ## Responding to input + * + * The primary pointer can be a mouse, stylus, or single finger touch event. You + * can inspect what type of pointer it is from the [[PointerEvent]] handled. + * + * ```js + * engine.input.pointers.primary.on("down", function (pe) { + * if (pe.pointerType === ex.Input.PointerType.Mouse) { + * ex.Logger.getInstance().info("Mouse event:", pe); + * } else if (pe.pointerType === ex.Input.PointerType.Touch) { + * ex.Logger.getInstance().info("Touch event:", pe); + * } + * }); + * ``` + * + * ## Multiple Pointers (Multi-Touch) + * + * When there is more than one pointer detected on the screen, + * this is considered multi-touch. For example, pressing one finger, + * then another, will create two pointers. If you lift a finger, + * the first one remains and the second one disappears. + * + * You can handle multi-touch by subscribing to however many pointers + * you would like to support. If a pointer doesn't yet exist, it will + * be created. You do not need to check if a pointer exists. If it does + * exist, it will propogate events, otherwise it will remain idle. + * + * Excalibur does not impose a limit to the amount of pointers you can + * subscribe to, so by all means, support all 10 fingers. + * + * *Note:* There is no way to identify touches after they happen; you can only + * know that there are *n* touches on the screen at once. + * + * ```js + * function paint(color) { + * + * // create a handler for the event + * return function (pe) { + * if (pe.pointerType === ex.Input.PointerType.Touch) { + * engine.canvas.fillStyle = color; + * engine.canvas.fillRect(pe.x, pe.y, 5, 5); + * } + * } + * } + * + * engine.input.pointers.at(0).on("move", paint("blue")); // 1st finger + * engine.input.pointers.at(1).on("move", paint("red")); // 2nd finger + * engine.input.pointers.at(2).on("move", paint("green")); // 3rd finger + * ``` + * + * ## Actor pointer events + * + * By default, [[Actor|Actors]] do not participate in pointer events. In other + * words, when you "click" an Actor, it will not throw an event **for that Actor**, + * only a generic pointer event for the game. This is to keep performance + * high and allow actors to "opt-in" to handling pointer events. Actors will automatically + * opt-in if a pointer related event handler is set on them `actor.on("pointerdown", () => {})` for example. + * + * To opt-in manually, set [[Actor.enableCapturePointer]] to `true` and the [[Actor]] will + * start publishing `pointerup` and `pointerdown` events. `pointermove` events + * will not be published by default due to performance implications. If you want + * an actor to receive move events, set [[ICapturePointerConfig.captureMoveEvents]] to + * `true`. + * + * Actor pointer events will be prefixed with `pointer`. + * + * ```js + * var player = new ex.Actor(); + * + * // enable propogating pointer events + * player.enableCapturePointer = true; + * + * // enable move events, warning: performance intensive! + * player.capturePointer.captureMoveEvents = true; + * + * // subscribe to input + * player.on("pointerup", function (ev) { + * player.logger.info("Player selected!", ev); + * }); + * ``` + */ + var Pointers = (function (_super) { + __extends(Pointers, _super); + function Pointers(engine) { + _super.call(this); + this._pointerDown = []; + this._pointerUp = []; + this._pointerMove = []; + this._pointerCancel = []; + this._pointers = []; + this._activePointers = []; + this._engine = engine; + this._pointers.push(new Pointer()); + this._activePointers = [-1]; + this.primary = this._pointers[0]; + } + /** + * Initializes pointer event listeners + */ + Pointers.prototype.init = function (scope) { + if (scope === void 0) { scope = PointerScope.Document; } + var target = document; + if (scope === PointerScope.Document) { + target = document; } - EaseTo.prototype._initialize = function () { - this._lerpStart = new ex.Point(this.actor.x, this.actor.y); - this._currentLerpTime = 0; - this._distance = this._lerpStart.toVector().distance(this._lerpEnd.toVector()); - }; - EaseTo.prototype.update = function (delta) { - if (!this._initialized) { - this._initialize(); - this._initialized = true; - } - var newX = this.actor.x; - var newY = this.actor.y; - if (this._currentLerpTime < this._lerpDuration) { - if (this._lerpEnd.x < this._lerpStart.x) { - newX = this._lerpStart.x - (this.easingFcn(this._currentLerpTime, this._lerpEnd.x, this._lerpStart.x, this._lerpDuration) - this._lerpEnd.x); - } - else { - newX = this.easingFcn(this._currentLerpTime, this._lerpStart.x, this._lerpEnd.x, this._lerpDuration); - } - if (this._lerpEnd.y < this._lerpStart.y) { - newY = this._lerpStart.y - (this.easingFcn(this._currentLerpTime, this._lerpEnd.y, this._lerpStart.y, this._lerpDuration) - this._lerpEnd.y); - } - else { - newY = this.easingFcn(this._currentLerpTime, this._lerpStart.y, this._lerpEnd.y, this._lerpDuration); - } - this.actor.x = newX; - this.actor.y = newY; - this._currentLerpTime += delta; - } - else { - this.actor.x = this._lerpEnd.x; - this.actor.y = this._lerpEnd.y; - } - }; - EaseTo.prototype.isComplete = function (actor) { - return this._stopped || (new ex.Vector(actor.x, actor.y)).distance(this._lerpStart.toVector()) >= this._distance; - }; - EaseTo.prototype.reset = function () { - this._initialized = false; - }; - EaseTo.prototype.stop = function () { - this._stopped = true; - }; - return EaseTo; - })(); - Actions.EaseTo = EaseTo; - var MoveTo = (function () { - function MoveTo(actor, destx, desty, speed) { - this._started = false; - this._stopped = false; - this._actor = actor; - this._end = new ex.Vector(destx, desty); - this._speed = speed; + else { + target = this._engine.canvas; } - MoveTo.prototype.update = function (delta) { - if (!this._started) { - this._started = true; - this._start = new ex.Vector(this._actor.x, this._actor.y); - this._distance = this._start.distance(this._end); - this._dir = this._end.minus(this._start).normalize(); - } - var m = this._dir.scale(this._speed); - this._actor.dx = m.x; - this._actor.dy = m.y; - if (this.isComplete(this._actor)) { - this._actor.x = this._end.x; - this._actor.y = this._end.y; - this._actor.dy = 0; - this._actor.dx = 0; - } - }; - MoveTo.prototype.isComplete = function (actor) { - return this._stopped || (new ex.Vector(actor.x, actor.y)).distance(this._start) >= this._distance; - }; - MoveTo.prototype.stop = function () { - this._actor.dy = 0; - this._actor.dx = 0; - this._stopped = true; - }; - MoveTo.prototype.reset = function () { - this._started = false; - }; - return MoveTo; - })(); - Actions.MoveTo = MoveTo; - var MoveBy = (function () { - function MoveBy(actor, destx, desty, time) { - this._started = false; - this._stopped = false; - this._actor = actor; - this._end = new ex.Vector(destx, desty); - if (time <= 0) { - ex.Logger.getInstance().error('Attempted to moveBy time less than or equal to zero : ' + time); - throw new Error('Cannot move in time <= 0'); - } - this._time = time; + // Touch Events + target.addEventListener('touchstart', this._handleTouchEvent('down', this._pointerDown)); + target.addEventListener('touchend', this._handleTouchEvent('up', this._pointerUp)); + target.addEventListener('touchmove', this._handleTouchEvent('move', this._pointerMove)); + target.addEventListener('touchcancel', this._handleTouchEvent('cancel', this._pointerCancel)); + // W3C Pointer Events + // Current: IE11, IE10 + if (window.PointerEvent) { + // IE11 + this._engine.canvas.style.touchAction = 'none'; + target.addEventListener('pointerdown', this._handlePointerEvent('down', this._pointerDown)); + target.addEventListener('pointerup', this._handlePointerEvent('up', this._pointerUp)); + target.addEventListener('pointermove', this._handlePointerEvent('move', this._pointerMove)); + target.addEventListener('pointercancel', this._handlePointerEvent('cancel', this._pointerMove)); } - MoveBy.prototype.update = function (delta) { - if (!this._started) { - this._started = true; - this._start = new ex.Vector(this._actor.x, this._actor.y); - this._distance = this._start.distance(this._end); - this._dir = this._end.minus(this._start).normalize(); - this._speed = this._distance / (this._time / 1000); - } - var m = this._dir.scale(this._speed); - this._actor.dx = m.x; - this._actor.dy = m.y; - if (this.isComplete(this._actor)) { - this._actor.x = this._end.x; - this._actor.y = this._end.y; - this._actor.dy = 0; - this._actor.dx = 0; - } - }; - MoveBy.prototype.isComplete = function (actor) { - return this._stopped || (new ex.Vector(actor.x, actor.y)).distance(this._start) >= this._distance; - }; - MoveBy.prototype.stop = function () { - this._actor.dy = 0; - this._actor.dx = 0; - this._stopped = true; - }; - MoveBy.prototype.reset = function () { - this._started = false; - }; - return MoveBy; - })(); - Actions.MoveBy = MoveBy; - var Follow = (function () { - function Follow(actor, actorToFollow, followDistance) { - this._started = false; - this._stopped = false; - this._actor = actor; - this._actorToFollow = actorToFollow; - this._current = new ex.Vector(this._actor.x, this._actor.y); - this._end = new ex.Vector(actorToFollow.x, actorToFollow.y); - this._maximumDistance = (followDistance !== undefined) ? followDistance : this._current.distance(this._end); - this._speed = 0; + else if (window.MSPointerEvent) { + // IE10 + this._engine.canvas.style.msTouchAction = 'none'; + target.addEventListener('MSPointerDown', this._handlePointerEvent('down', this._pointerDown)); + target.addEventListener('MSPointerUp', this._handlePointerEvent('up', this._pointerUp)); + target.addEventListener('MSPointerMove', this._handlePointerEvent('move', this._pointerMove)); + target.addEventListener('MSPointerCancel', this._handlePointerEvent('cancel', this._pointerMove)); } - Follow.prototype.update = function (delta) { - if (!this._started) { - this._started = true; - this._distanceBetween = this._current.distance(this._end); - this._dir = this._end.minus(this._current).normalize(); - } - var actorToFollowSpeed = Math.sqrt(Math.pow(this._actorToFollow.dx, 2) + Math.pow(this._actorToFollow.dy, 2)); - if (actorToFollowSpeed !== 0) { - this._speed = actorToFollowSpeed; + else { + // Mouse Events + target.addEventListener('mousedown', this._handleMouseEvent('down', this._pointerDown)); + target.addEventListener('mouseup', this._handleMouseEvent('up', this._pointerUp)); + target.addEventListener('mousemove', this._handleMouseEvent('move', this._pointerMove)); + } + }; + Pointers.prototype.update = function (delta) { + this._pointerUp.length = 0; + this._pointerDown.length = 0; + this._pointerMove.length = 0; + this._pointerCancel.length = 0; + }; + /** + * Safely gets a Pointer at a specific index and initializes one if it doesn't yet exist + * @param index The pointer index to retrieve + */ + Pointers.prototype.at = function (index) { + if (index >= this._pointers.length) { + // Ensure there is a pointer to retrieve + for (var i = this._pointers.length - 1, max = index; i < max; i++) { + this._pointers.push(new Pointer()); + this._activePointers.push(-1); } - this._current.x = this._actor.x; - this._current.y = this._actor.y; - this._end.x = this._actorToFollow.x; - this._end.y = this._actorToFollow.y; - this._distanceBetween = this._current.distance(this._end); - this._dir = this._end.minus(this._current).normalize(); - if (this._distanceBetween >= this._maximumDistance) { - var m = this._dir.scale(this._speed); - this._actor.dx = m.x; - this._actor.dy = m.y; + } + return this._pointers[index]; + }; + /** + * Get number of pointers being watched + */ + Pointers.prototype.count = function () { + return this._pointers.length; + }; + /** + * Propogates events to actor if necessary + */ + Pointers.prototype.propogate = function (actor) { + var isUIActor = actor instanceof ex.UIActor; + var i = 0, len = this._pointerUp.length; + for (i; i < len; i++) { + if (actor.contains(this._pointerUp[i].x, this._pointerUp[i].y, !isUIActor)) { + actor.eventDispatcher.emit('pointerup', this._pointerUp[i]); } - else { - this._actor.dx = 0; - this._actor.dy = 0; + } + i = 0; + len = this._pointerDown.length; + for (i; i < len; i++) { + if (actor.contains(this._pointerDown[i].x, this._pointerDown[i].y, !isUIActor)) { + actor.eventDispatcher.emit('pointerdown', this._pointerDown[i]); } - if (this.isComplete(this._actor)) { - // TODO this should never occur - this._actor.x = this._end.x; - this._actor.y = this._end.y; - this._actor.dy = 0; - this._actor.dx = 0; + } + if (actor.capturePointer.captureMoveEvents) { + i = 0; + len = this._pointerMove.length; + for (i; i < len; i++) { + if (actor.contains(this._pointerMove[i].x, this._pointerMove[i].y, !isUIActor)) { + actor.eventDispatcher.emit('pointermove', this._pointerMove[i]); + } } + } + i = 0; + len = this._pointerCancel.length; + for (i; i < len; i++) { + if (actor.contains(this._pointerCancel[i].x, this._pointerCancel[i].y, !isUIActor)) { + actor.eventDispatcher.emit('pointercancel', this._pointerCancel[i]); + } + } + }; + Pointers.prototype._handleMouseEvent = function (eventName, eventArr) { + var _this = this; + return function (e) { + e.preventDefault(); + var x = e.pageX - ex.Util.getPosition(_this._engine.canvas).x; + var y = e.pageY - ex.Util.getPosition(_this._engine.canvas).y; + var transformedPoint = _this._engine.screenToWorldCoordinates(new ex.Point(x, y)); + var pe = new PointerEvent(transformedPoint.x, transformedPoint.y, 0, PointerType.Mouse, e.button, e); + eventArr.push(pe); + _this.at(0).eventDispatcher.emit(eventName, pe); }; - Follow.prototype.stop = function () { - this._actor.dy = 0; - this._actor.dx = 0; - this._stopped = true; - }; - Follow.prototype.isComplete = function (actor) { - // the actor following should never stop unless specified to do so - return this._stopped; - }; - Follow.prototype.reset = function () { - this._started = false; + }; + Pointers.prototype._handleTouchEvent = function (eventName, eventArr) { + var _this = this; + return function (e) { + e.preventDefault(); + for (var i = 0, len = e.changedTouches.length; i < len; i++) { + var index = _this._pointers.length > 1 ? _this._getPointerIndex(e.changedTouches[i].identifier) : 0; + if (index === -1) { + continue; + } + var x = e.changedTouches[i].pageX - ex.Util.getPosition(_this._engine.canvas).x; + var y = e.changedTouches[i].pageY - ex.Util.getPosition(_this._engine.canvas).y; + var transformedPoint = _this._engine.screenToWorldCoordinates(new ex.Point(x, y)); + var pe = new PointerEvent(transformedPoint.x, transformedPoint.y, index, PointerType.Touch, PointerButton.Unknown, e); + eventArr.push(pe); + _this.at(index).eventDispatcher.emit(eventName, pe); + // only with multi-pointer + if (_this._pointers.length > 1) { + if (eventName === 'up') { + // remove pointer ID from pool when pointer is lifted + _this._activePointers[index] = -1; + } + else if (eventName === 'down') { + // set pointer ID to given index + _this._activePointers[index] = e.changedTouches[i].identifier; + } + } + } }; - return Follow; - })(); - Actions.Follow = Follow; - var Meet = (function () { - function Meet(actor, actorToMeet, speed) { - this._started = false; - this._stopped = false; - this._speedWasSpecified = false; - this._actor = actor; - this._actorToMeet = actorToMeet; - this._current = new ex.Vector(this._actor.x, this._actor.y); - this._end = new ex.Vector(actorToMeet.x, actorToMeet.y); - this._speed = speed || 0; - if (speed !== undefined) { - this._speedWasSpecified = true; + }; + Pointers.prototype._handlePointerEvent = function (eventName, eventArr) { + var _this = this; + return function (e) { + e.preventDefault(); + // get the index for this pointer ID if multi-pointer is asked for + var index = _this._pointers.length > 1 ? _this._getPointerIndex(e.pointerId) : 0; + if (index === -1) { + return; } - } - Meet.prototype.update = function (delta) { - if (!this._started) { - this._started = true; - this._distanceBetween = this._current.distance(this._end); - this._dir = this._end.minus(this._current).normalize(); + var x = e.pageX - ex.Util.getPosition(_this._engine.canvas).x; + var y = e.pageY - ex.Util.getPosition(_this._engine.canvas).y; + var transformedPoint = _this._engine.screenToWorldCoordinates(new ex.Point(x, y)); + var pe = new PointerEvent(transformedPoint.x, transformedPoint.y, index, _this._stringToPointerType(e.pointerType), e.button, e); + eventArr.push(pe); + _this.at(index).eventDispatcher.emit(eventName, pe); + // only with multi-pointer + if (_this._pointers.length > 1) { + if (eventName === 'up') { + // remove pointer ID from pool when pointer is lifted + _this._activePointers[index] = -1; + } + else if (eventName === 'down') { + // set pointer ID to given index + _this._activePointers[index] = e.pointerId; + } } - var actorToMeetSpeed = Math.sqrt(Math.pow(this._actorToMeet.dx, 2) + Math.pow(this._actorToMeet.dy, 2)); - if ((actorToMeetSpeed !== 0) && (!this._speedWasSpecified)) { - this._speed = actorToMeetSpeed; + }; + }; + /** + * Gets the index of the pointer specified for the given pointer ID or finds the next empty pointer slot available. + * This is required because IE10/11 uses incrementing pointer IDs so we need to store a mapping of ID => idx + */ + Pointers.prototype._getPointerIndex = function (pointerId) { + var idx; + if ((idx = this._activePointers.indexOf(pointerId)) > -1) { + return idx; + } + for (var i = 0; i < this._activePointers.length; i++) { + if (this._activePointers[i] === -1) { + return i; } - this._current.x = this._actor.x; - this._current.y = this._actor.y; - this._end.x = this._actorToMeet.x; - this._end.y = this._actorToMeet.y; - this._distanceBetween = this._current.distance(this._end); - this._dir = this._end.minus(this._current).normalize(); - var m = this._dir.scale(this._speed); - this._actor.dx = m.x; - this._actor.dy = m.y; - if (this.isComplete(this._actor)) { - this._actor.x = this._end.x; - this._actor.y = this._end.y; - this._actor.dy = 0; - this._actor.dx = 0; + } + // ignore pointer because game isn't watching + return -1; + }; + Pointers.prototype._stringToPointerType = function (s) { + switch (s) { + case 'touch': + return PointerType.Touch; + case 'mouse': + return PointerType.Mouse; + case 'pen': + return PointerType.Pen; + default: + return PointerType.Unknown; + } + }; + return Pointers; + })(ex.Class); + Input.Pointers = Pointers; + /** + * Captures and dispatches PointerEvents + */ + var Pointer = (function (_super) { + __extends(Pointer, _super); + function Pointer() { + _super.apply(this, arguments); + } + return Pointer; + })(ex.Class); + Input.Pointer = Pointer; + })(Input = ex.Input || (ex.Input = {})); +})(ex || (ex = {})); +var ex; +(function (ex) { + var Input; + (function (Input) { + /** + * Enum representing input key codes + */ + (function (Keys) { + Keys[Keys["Num1"] = 97] = "Num1"; + Keys[Keys["Num2"] = 98] = "Num2"; + Keys[Keys["Num3"] = 99] = "Num3"; + Keys[Keys["Num4"] = 100] = "Num4"; + Keys[Keys["Num5"] = 101] = "Num5"; + Keys[Keys["Num6"] = 102] = "Num6"; + Keys[Keys["Num7"] = 103] = "Num7"; + Keys[Keys["Num8"] = 104] = "Num8"; + Keys[Keys["Num9"] = 105] = "Num9"; + Keys[Keys["Num0"] = 96] = "Num0"; + Keys[Keys["Numlock"] = 144] = "Numlock"; + Keys[Keys["Semicolon"] = 186] = "Semicolon"; + Keys[Keys["A"] = 65] = "A"; + Keys[Keys["B"] = 66] = "B"; + Keys[Keys["C"] = 67] = "C"; + Keys[Keys["D"] = 68] = "D"; + Keys[Keys["E"] = 69] = "E"; + Keys[Keys["F"] = 70] = "F"; + Keys[Keys["G"] = 71] = "G"; + Keys[Keys["H"] = 72] = "H"; + Keys[Keys["I"] = 73] = "I"; + Keys[Keys["J"] = 74] = "J"; + Keys[Keys["K"] = 75] = "K"; + Keys[Keys["L"] = 76] = "L"; + Keys[Keys["M"] = 77] = "M"; + Keys[Keys["N"] = 78] = "N"; + Keys[Keys["O"] = 79] = "O"; + Keys[Keys["P"] = 80] = "P"; + Keys[Keys["Q"] = 81] = "Q"; + Keys[Keys["R"] = 82] = "R"; + Keys[Keys["S"] = 83] = "S"; + Keys[Keys["T"] = 84] = "T"; + Keys[Keys["U"] = 85] = "U"; + Keys[Keys["V"] = 86] = "V"; + Keys[Keys["W"] = 87] = "W"; + Keys[Keys["X"] = 88] = "X"; + Keys[Keys["Y"] = 89] = "Y"; + Keys[Keys["Z"] = 90] = "Z"; + Keys[Keys["Shift"] = 16] = "Shift"; + Keys[Keys["Alt"] = 18] = "Alt"; + Keys[Keys["Up"] = 38] = "Up"; + Keys[Keys["Down"] = 40] = "Down"; + Keys[Keys["Left"] = 37] = "Left"; + Keys[Keys["Right"] = 39] = "Right"; + Keys[Keys["Space"] = 32] = "Space"; + Keys[Keys["Esc"] = 27] = "Esc"; + })(Input.Keys || (Input.Keys = {})); + var Keys = Input.Keys; + ; + /** + * Event thrown on a game object for a key event + */ + var KeyEvent = (function (_super) { + __extends(KeyEvent, _super); + /** + * @param key The key responsible for throwing the event + */ + function KeyEvent(key) { + _super.call(this); + this.key = key; + } + return KeyEvent; + })(ex.GameEvent); + Input.KeyEvent = KeyEvent; + /** + * Keyboard input + * + * Working with the keyboard is easy in Excalibur. You can inspect + * whether a button was just [[Keyboard.wasPressed|pressed]] or [[Keyboard.wasReleased|released]] this frame, or + * if the key is currently being [[Keyboard.isHeld|held]] down. Common keys are held in the [[Input.Keys]] + * enumeration but you can pass any character code to the methods. + * + * Excalibur subscribes to the browser events and keeps track of + * what keys are currently held, released, or pressed. A key can be held + * for multiple frames, but a key cannot be pressed or released for more than one subsequent + * update frame. + * + * ## Inspecting the keyboard + * + * You can inspect [[Engine.input]] to see what the state of the keyboard + * is during an update. + * + * It is recommended that keyboard actions that directly effect actors be handled like so to improve code quality: + * ```ts + * class Player extends ex.Actor { + * public update(engine, delta) { + * + * if (engine.input.keyboard.isHeld(ex.Input.Keys.W) || + * engine.input.keyboard.isHeld(ex.Input.Keys.Up)) { + * + * player._moveForward(); + * } + * + * if (engine.input.keyboard.wasPressed(ex.Input.Keys.Right)) { + * player._fire(); + * } + * } + * } + * ``` + * ## Events + * You can subscribe to keyboard events through `engine.input.keyboard.on`. A [[KeyEvent]] object is + * passed to your handler which offers information about the key that was part of the event. + * + * - `press` - When a key was just pressed this frame + * - `release` - When a key was just released this frame + * - `hold` - Whenever a key is in the down position + * + * ```ts + * engine.input.pointers.primary.on("press", (evt: KeyEvent) => {...}); + * engine.input.pointers.primary.on("release", (evt: KeyEvent) => {...}); + * engine.input.pointers.primary.on("hold", (evt: KeyEvent) => {...}); + * ``` + */ + var Keyboard = (function (_super) { + __extends(Keyboard, _super); + function Keyboard(engine) { + _super.call(this); + this._keys = []; + this._keysUp = []; + this._keysDown = []; + this._engine = engine; + } + /** + * Initialize Keyboard event listeners + */ + Keyboard.prototype.init = function () { + var _this = this; + window.addEventListener('blur', function (ev) { + _this._keys.length = 0; // empties array efficiently + }); + // key up is on window because canvas cannot have focus + window.addEventListener('keyup', function (ev) { + var key = _this._keys.indexOf(ev.keyCode); + _this._keys.splice(key, 1); + _this._keysUp.push(ev.keyCode); + var keyEvent = new KeyEvent(ev.keyCode); + // alias the old api, we may want to deprecate this in the future + _this.eventDispatcher.emit('up', keyEvent); + _this.eventDispatcher.emit('release', keyEvent); + }); + // key down is on window because canvas cannot have focus + window.addEventListener('keydown', function (ev) { + if (_this._keys.indexOf(ev.keyCode) === -1) { + _this._keys.push(ev.keyCode); + _this._keysDown.push(ev.keyCode); + var keyEvent = new KeyEvent(ev.keyCode); + _this.eventDispatcher.emit('down', keyEvent); + _this.eventDispatcher.emit('press', keyEvent); } - }; - Meet.prototype.isComplete = function (actor) { - return this._stopped || (this._distanceBetween <= 1); - }; - Meet.prototype.stop = function () { - this._actor.dy = 0; - this._actor.dx = 0; - this._stopped = true; - }; - Meet.prototype.reset = function () { - this._started = false; - }; - return Meet; - })(); - Actions.Meet = Meet; - var RotateTo = (function () { - function RotateTo(actor, angleRadians, speed, rotationType) { - this._started = false; - this._stopped = false; - this._actor = actor; - this._end = angleRadians; - this._speed = speed; - this._rotationType = rotationType || ex.RotationType.ShortestPath; + }); + }; + Keyboard.prototype.update = function (delta) { + // Reset keysDown and keysUp after update is complete + this._keysDown.length = 0; + this._keysUp.length = 0; + // Emit synthetic "hold" event + for (var i = 0; i < this._keys.length; i++) { + this.eventDispatcher.emit('hold', new KeyEvent(this._keys[i])); } - RotateTo.prototype.update = function (delta) { - if (!this._started) { - this._started = true; - this._start = this._actor.rotation; - var distance1 = Math.abs(this._end - this._start); - var distance2 = ex.Util.TwoPI - distance1; - if (distance1 > distance2) { - this._shortDistance = distance2; - this._longDistance = distance1; - } - else { - this._shortDistance = distance1; - this._longDistance = distance2; - } - this._shortestPathIsPositive = (this._start - this._end + ex.Util.TwoPI) % ex.Util.TwoPI >= Math.PI; - switch (this._rotationType) { - case ex.RotationType.ShortestPath: - this._distance = this._shortDistance; - if (this._shortestPathIsPositive) { - this._direction = 1; - } - else { - this._direction = -1; - } - break; - case ex.RotationType.LongestPath: - this._distance = this._longDistance; - if (this._shortestPathIsPositive) { - this._direction = -1; - } - else { - this._direction = 1; - } - break; - case ex.RotationType.Clockwise: - this._direction = 1; - if (this._shortestPathIsPositive) { - this._distance = this._shortDistance; - } - else { - this._distance = this._longDistance; - } - break; - case ex.RotationType.CounterClockwise: - this._direction = -1; - if (!this._shortestPathIsPositive) { - this._distance = this._shortDistance; - } - else { - this._distance = this._longDistance; - } - break; - } - } - this._actor.rx = this._direction * this._speed; - if (this.isComplete(this._actor)) { - this._actor.rotation = this._end; - this._actor.rx = 0; - this._stopped = true; - } - }; - RotateTo.prototype.isComplete = function (actor) { - var distanceTravelled = Math.abs(this._actor.rotation - this._start); - return this._stopped || (distanceTravelled >= Math.abs(this._distance)); - }; - RotateTo.prototype.stop = function () { - this._actor.rx = 0; - this._stopped = true; - }; - RotateTo.prototype.reset = function () { - this._started = false; - }; - return RotateTo; - })(); - Actions.RotateTo = RotateTo; - var RotateBy = (function () { - function RotateBy(actor, angleRadians, time, rotationType) { - this._started = false; - this._stopped = false; - this._actor = actor; - this._end = angleRadians; - this._time = time; - this._rotationType = rotationType || ex.RotationType.ShortestPath; + }; + /** + * Gets list of keys being pressed down + */ + Keyboard.prototype.getKeys = function () { + return this._keys; + }; + /** + * Tests if a certain key was just pressed this frame. This is cleared at the end of the update frame. + * @param key Test wether a key was just pressed + */ + Keyboard.prototype.wasPressed = function (key) { + return this._keysDown.indexOf(key) > -1; + }; + /** + * Tests if a certain key is held down. This is persisted between frames. + * @param key Test wether a key is held down + */ + Keyboard.prototype.isHeld = function (key) { + return this._keys.indexOf(key) > -1; + }; + /** + * Tests if a certain key was just released this frame. This is cleared at the end of the update frame. + * @param key Test wether a key was just released + */ + Keyboard.prototype.wasReleased = function (key) { + return this._keysUp.indexOf(key) > -1; + }; + return Keyboard; + })(ex.Class); + Input.Keyboard = Keyboard; + })(Input = ex.Input || (ex.Input = {})); +})(ex || (ex = {})); +var ex; +(function (ex) { + var Input; + (function (Input) { + /** + * Controller Support (Gamepads) + * + * Excalibur leverages the HTML5 Gamepad API [where it is supported](http://caniuse.com/#feat=gamepad) + * to provide controller support for your games. + * + * You can query any [[Gamepad|Gamepads]] that are connected or listen to events ("button" and "axis"). + * + * You must opt-in to controller support ([[Gamepads.enabled]]) because it is a polling-based + * API, so we have to check it each update frame. If an gamepad related event handler is set, you will + * automatically opt-in to controller polling. + * + * HTML5 Gamepad API only supports a maximum of 4 gamepads. You can access them using the [[Gamepads.at]] method. If a [[Gamepad]] is + * not connected, it will simply not throw events. + * + * ## Gamepad Filtering + * + * Different browsers/devices are sometimes loose about the devices they consider Gamepads, you can set minimum device requirements with + * `engine.inpute.gamepads.setMinimumGamepadConfiguration` so that undesired devices are not reported to you (Touchpads, Mice, Web + * Cameras, etc.). + * ```js + * // ensures that only gamepads with at least 4 axis and 8 buttons are reported for events + * engine.input.gamepads.setMinimumGamepadConfiguration({ + * axis: 4, + * buttons: 8 + * }); + * ``` + * + * ## Events + * + * You can subscribe to gamepad connect and disconnect events through `engine.input.gamepads.on`. + * A [[GamepadConnectEvent]] or [[GamepadDisconnectEvent]] will be passed to you. + * + * - `connect` - When a gamepad connects it will fire this event and pass a [[GamepadConnectEvent]] with a reference to the gamepad. + * - `disconnect` - When a gamepad disconnects it will fire this event and pass a [[GamepadDisconnectEvent]] + * + * Once you have a reference to a gamepad you may listen to changes on that gamepad with `.on`. A [[GamepadButtonEvent]] or + * [[GamepadAxisEvent]] will be passed to you. + * - `button` - Whenever a button is pressed on the game + * - `axis` - Whenever an axis + * + * ```ts + * + * engine.input.gamepads.on('connect', (ce: ex.Input.GamepadConnectEvent) => { + * var newPlayer = CreateNewPlayer(); // pseudo-code for new player logic on gamepad connection + * console.log("Gamepad connected", ce); + * ce.gamepad.on('button', (be: ex.GamepadButtonEvent) => { + * if(be.button === ex.Input.Buttons.Face1) { + * newPlayer.jump(); + * } + * }); + * + * ce.gamepad.on('axis', (ae: ex.GamepadAxisEvent) => { + * if(ae.axis === ex.Input.Axis.LeftStickX && ae.value > .5){ + * newPlayer.moveRight(); + * } + * }) + * + * }); + * + * + * ``` + * + * ## Responding to button input + * + * [[Buttons|Gamepad buttons]] typically have values between 0 and 1, however depending on + * the sensitivity of the controller, even if a button is idle it could have a + * very tiny value. For this reason, you can pass in a threshold to several + * methods to customize how sensitive you want to be in detecting button presses. + * + * You can inspect any connected [[Gamepad]] using [[Gamepad.isButtonPressed]], [[Gamepad.getButton]], + * or you can subscribe to the `button` event published on the [[Gamepad]] which passes + * a [[GamepadButtonEvent]] to your handler. + * + * ```js + * // enable gamepad support + * engine.input.gamepads.enabled = true; + * + * // query gamepad on update + * engine.on("update", function (ev) { + * + * // access any gamepad by index + * if (engine.input.gamepads.at(0).isButtonPressed(ex.Input.Buttons.Face1)) { + * ex.Logger.getInstance().info("Controller A button pressed"); + * } + * + * // query individual button + * if (engine.input.gamepads.at(0).getButton(ex.Input.Buttons.DpadLeft) > 0.2) { + * ex.Logger.getInstance().info("Controller D-pad left value is > 0.2") + * } + * }); + * + * // subscribe to button events + * engine.input.gamepads.at(0).on("button", function (ev) { + * ex.Logger.getInstance().info(ev.button, ev.value); + * }); + * ``` + * + * ## Responding to axis input + * + * [[Axes|Gamepad axes]] typically have values between -1 and 1, but even idle + * sticks can still propogate very small values depending on the quality and age + * of a controller. For this reason, you can set [[Gamepads.MinAxisMoveThreshold]] + * to set the (absolute) threshold after which Excalibur will start publishing `axis` events. + * By default it is set to a value that normally will not throw events if a stick is idle. + * + * You can query axes via [[Gamepad.getAxes]] or by subscribing to the `axis` event on [[Gamepad]] + * which passes a [[GamepadAxisEvent]] to your handler. + * + * ```js + * // enable gamepad support + * engine.input.gamepads.enabled = true; + * + * // query gamepad on update + * engine.on("update", function (ev) { + * + * // access any gamepad by index + * var axisValue; + * if ((axisValue = engine.input.gamepads.at(0).getAxes(ex.Input.Axes.LeftStickX)) > 0.5) { + * ex.Logger.getInstance().info("Move right", axisValue); + * } + * }); + * + * // subscribe to axis events + * engine.input.gamepads.at(0).on("axis", function (ev) { + * ex.Logger.getInstance().info(ev.axis, ev.value); + * }); + * ``` + */ + var Gamepads = (function (_super) { + __extends(Gamepads, _super); + function Gamepads(engine) { + _super.call(this); + /** + * Whether or not to poll for Gamepad input (default: `false`) + */ + this.enabled = false; + /** + * Whether or not Gamepad API is supported + */ + this.supported = !!navigator.getGamepads; + this._gamePadTimeStamps = [0, 0, 0, 0]; + this._oldPads = []; + this._pads = []; + this._initSuccess = false; + this._navigator = navigator; + this._minimumConfiguration = null; + this._engine = engine; + } + Gamepads.prototype.init = function () { + if (!this.supported) { + return; } - RotateBy.prototype.update = function (delta) { - if (!this._started) { - this._started = true; - this._start = this._actor.rotation; - var distance1 = Math.abs(this._end - this._start); - var distance2 = ex.Util.TwoPI - distance1; - if (distance1 > distance2) { - this._shortDistance = distance2; - this._longDistance = distance1; - } - else { - this._shortDistance = distance1; - this._longDistance = distance2; - } - this._shortestPathIsPositive = (this._start - this._end + ex.Util.TwoPI) % ex.Util.TwoPI >= Math.PI; - switch (this._rotationType) { - case ex.RotationType.ShortestPath: - this._distance = this._shortDistance; - if (this._shortestPathIsPositive) { - this._direction = 1; - } - else { - this._direction = -1; - } - break; - case ex.RotationType.LongestPath: - this._distance = this._longDistance; - if (this._shortestPathIsPositive) { - this._direction = -1; - } - else { - this._direction = 1; - } - break; - case ex.RotationType.Clockwise: - this._direction = 1; - if (this._shortDistance >= 0) { - this._distance = this._shortDistance; - } - else { - this._distance = this._longDistance; - } - break; - case ex.RotationType.CounterClockwise: - this._direction = -1; - if (this._shortDistance <= 0) { - this._distance = this._shortDistance; - } - else { - this._distance = this._longDistance; - } - break; - } - this._speed = Math.abs(this._distance / this._time * 1000); - } - this._actor.rx = this._direction * this._speed; - if (this.isComplete(this._actor)) { - this._actor.rotation = this._end; - this._actor.rx = 0; - this._stopped = true; - } - }; - RotateBy.prototype.isComplete = function (actor) { - var distanceTravelled = Math.abs(this._actor.rotation - this._start); - return this._stopped || (distanceTravelled >= Math.abs(this._distance)); - }; - RotateBy.prototype.stop = function () { - this._actor.rx = 0; - this._stopped = true; - }; - RotateBy.prototype.reset = function () { - this._started = false; - }; - return RotateBy; - })(); - Actions.RotateBy = RotateBy; - var ScaleTo = (function () { - function ScaleTo(actor, scaleX, scaleY, speedX, speedY) { - this._started = false; - this._stopped = false; - this._actor = actor; - this._endX = scaleX; - this._endY = scaleY; - this._speedX = speedX; - this._speedY = speedY; + if (this._initSuccess) { + return; } - ScaleTo.prototype.update = function (delta) { - if (!this._started) { - this._started = true; - this._startX = this._actor.scale.x; - this._startY = this._actor.scale.y; - this._distanceX = Math.abs(this._endX - this._startX); - this._distanceY = Math.abs(this._endY - this._startY); - } - if (!(Math.abs(this._actor.scale.x - this._startX) >= this._distanceX)) { - var directionX = this._endY < this._startY ? -1 : 1; - this._actor.sx = this._speedX * directionX; - } - else { - this._actor.sx = 0; - } - if (!(Math.abs(this._actor.scale.y - this._startY) >= this._distanceY)) { - var directionY = this._endY < this._startY ? -1 : 1; - this._actor.sy = this._speedY * directionY; - } - else { - this._actor.sy = 0; - } - if (this.isComplete(this._actor)) { - this._actor.scale.x = this._endX; - this._actor.scale.y = this._endY; - this._actor.sx = 0; - this._actor.sy = 0; - } - }; - ScaleTo.prototype.isComplete = function (actor) { - return this._stopped || ((Math.abs(this._actor.scale.y - this._startX) >= this._distanceX) && - (Math.abs(this._actor.scale.y - this._startY) >= this._distanceY)); - }; - ScaleTo.prototype.stop = function () { - this._actor.sx = 0; - this._actor.sy = 0; - this._stopped = true; - }; - ScaleTo.prototype.reset = function () { - this._started = false; - }; - return ScaleTo; - })(); - Actions.ScaleTo = ScaleTo; - var ScaleBy = (function () { - function ScaleBy(actor, scaleX, scaleY, time) { - this._started = false; - this._stopped = false; - this._actor = actor; - this._endX = scaleX; - this._endY = scaleY; - this._time = time; - this._speedX = (this._endX - this._actor.scale.x) / time * 1000; - this._speedY = (this._endY - this._actor.scale.y) / time * 1000; + // In Chrome, this will return 4 undefined items until a button is pressed + // In FF, this will not return any items until a button is pressed + this._oldPads = this._clonePads(this._navigator.getGamepads()); + if (this._oldPads.length && this._oldPads[0]) { + this._initSuccess = true; } - ScaleBy.prototype.update = function (delta) { - if (!this._started) { - this._started = true; - this._startX = this._actor.scale.x; - this._startY = this._actor.scale.y; - this._distanceX = Math.abs(this._endX - this._startX); - this._distanceY = Math.abs(this._endY - this._startY); - } - var directionX = this._endX < this._startX ? -1 : 1; - var directionY = this._endY < this._startY ? -1 : 1; - this._actor.sx = this._speedX * directionX; - this._actor.sy = this._speedY * directionY; - if (this.isComplete(this._actor)) { - this._actor.scale.x = this._endX; - this._actor.scale.y = this._endY; - this._actor.sx = 0; - this._actor.sy = 0; - } - }; - ScaleBy.prototype.isComplete = function (actor) { - return this._stopped || ((Math.abs(this._actor.scale.x - this._startX) >= this._distanceX) && - (Math.abs(this._actor.scale.y - this._startY) >= this._distanceY)); - }; - ScaleBy.prototype.stop = function () { - this._actor.sx = 0; - this._actor.sy = 0; - this._stopped = true; - }; - ScaleBy.prototype.reset = function () { - this._started = false; - }; - return ScaleBy; - })(); - Actions.ScaleBy = ScaleBy; - var Delay = (function () { - function Delay(actor, delay) { - this._elapsedTime = 0; - this._started = false; - this._stopped = false; - this._actor = actor; - this._delay = delay; + }; + /** + * Sets the minimum gamepad configuration, for example {axis: 4, buttons: 4} means + * this game requires at minimum 4 axis inputs and 4 buttons, this is not restrictive + * all other controllers with more axis or buttons are valid as well. If no minimum + * configuration is set all pads are valid. + */ + Gamepads.prototype.setMinimumGamepadConfiguration = function (config) { + this._enableAndUpdate(); // if config is used, implicitely enable + this._minimumConfiguration = config; + }; + /** + * When implicitely enabled, set the enabled flag and run an update so information is updated + */ + Gamepads.prototype._enableAndUpdate = function () { + if (!this.enabled) { + this.enabled = true; + this.update(100); } - Delay.prototype.update = function (delta) { - if (!this._started) { - this._started = true; - } - this.x = this._actor.x; - this.y = this._actor.y; - this._elapsedTime += delta; - }; - Delay.prototype.isComplete = function (actor) { - return this._stopped || (this._elapsedTime >= this._delay); - }; - Delay.prototype.stop = function () { - this._stopped = true; - }; - Delay.prototype.reset = function () { - this._elapsedTime = 0; - this._started = false; - }; - return Delay; - })(); - Actions.Delay = Delay; - var Blink = (function () { - function Blink(actor, timeVisible, timeNotVisible, numBlinks) { - if (numBlinks === void 0) { numBlinks = 1; } - this._timeVisible = 0; - this._timeNotVisible = 0; - this._elapsedTime = 0; - this._totalTime = 0; - this._stopped = false; - this._started = false; - this._actor = actor; - this._timeVisible = timeVisible; - this._timeNotVisible = timeNotVisible; - this._duration = (timeVisible + timeNotVisible) * numBlinks; + }; + /** + * Checks a navigator gamepad against the minimum configuration if present. + */ + Gamepads.prototype._isGamepadValid = function (pad) { + if (!this._minimumConfiguration) { + return true; } - Blink.prototype.update = function (delta) { - if (!this._started) { - this._started = true; - } - this._elapsedTime += delta; - this._totalTime += delta; - if (this._actor.visible && this._elapsedTime >= this._timeVisible) { - this._actor.visible = false; - this._elapsedTime = 0; - } - if (!this._actor.visible && this._elapsedTime >= this._timeNotVisible) { - this._actor.visible = true; - this._elapsedTime = 0; - } - if (this.isComplete(this._actor)) { - this._actor.visible = true; - } - }; - Blink.prototype.isComplete = function (actor) { - return this._stopped || (this._totalTime >= this._duration); - }; - Blink.prototype.stop = function () { - this._actor.visible = true; - this._stopped = true; - }; - Blink.prototype.reset = function () { - this._started = false; - this._elapsedTime = 0; - this._totalTime = 0; - }; - return Blink; - })(); - Actions.Blink = Blink; - var Fade = (function () { - function Fade(actor, endOpacity, speed) { - this._multiplyer = 1; - this._started = false; - this._stopped = false; - this._actor = actor; - this._endOpacity = endOpacity; - this._speed = speed; - if (endOpacity < actor.opacity) { - this._multiplyer = -1; - } + ; + if (!pad) { + return false; } - Fade.prototype.update = function (delta) { - if (!this._started) { - this._started = true; + ; + var axesLength = pad.axes.filter(function (value, index, array) { + return (typeof value !== undefined); + }).length; + var buttonLength = pad.buttons.filter(function (value, index, array) { + return (typeof value !== undefined); + }).length; + return axesLength >= this._minimumConfiguration.axis && + buttonLength >= this._minimumConfiguration.buttons && + pad.connected; + }; + Gamepads.prototype.on = function (eventName, handler) { + this._enableAndUpdate(); // implicitly enable + _super.prototype.on.call(this, eventName, handler); + }; + Gamepads.prototype.off = function (eventName, handler) { + this._enableAndUpdate(); // implicitly enable + _super.prototype.off.call(this, eventName, handler); + }; + /** + * Updates Gamepad state and publishes Gamepad events + */ + Gamepads.prototype.update = function (delta) { + if (!this.enabled || !this.supported) { + return; + } + this.init(); + var gamepads = this._navigator.getGamepads(); + for (var i = 0; i < gamepads.length; i++) { + if (!gamepads[i]) { + // If was connected, but now isn't emit the disconnect event + if (this.at(i).connected) { + this.eventDispatcher.emit('disconnect', new ex.GamepadDisconnectEvent(i)); + } + // Reset connection status + this.at(i).connected = false; + continue; } - if (this._speed > 0) { - this._actor.opacity += this._multiplyer * (Math.abs(this._actor.opacity - this._endOpacity) * delta) / this._speed; + else { + if (!this.at(i).connected && this._isGamepadValid(gamepads[i])) { + this.eventDispatcher.emit('connect', new ex.GamepadConnectEvent(i, this.at(i))); + } + // Set connection status + this.at(i).connected = true; } - this._speed -= delta; - ex.Logger.getInstance().debug('actor opacity: ' + this._actor.opacity); - if (this.isComplete(this._actor)) { - this._actor.opacity = this._endOpacity; + ; + // Only supported in Chrome + if (gamepads[i].timestamp && gamepads[i].timestamp === this._gamePadTimeStamps[i]) { + continue; } - }; - Fade.prototype.isComplete = function (actor) { - return this._stopped || (Math.abs(this._actor.opacity - this._endOpacity) < 0.05); - }; - Fade.prototype.stop = function () { - this._stopped = true; - }; - Fade.prototype.reset = function () { - this._started = false; - }; - return Fade; - })(); - Actions.Fade = Fade; - var Die = (function () { - function Die(actor) { - this._started = false; - this._stopped = false; - this._actor = actor; - } - Die.prototype.update = function (delta) { - this._actor.actionQueue.clearActions(); - this._actor.kill(); - this._stopped = true; - }; - Die.prototype.isComplete = function () { - return this._stopped; - }; - Die.prototype.stop = function () { return; }; - Die.prototype.reset = function () { return; }; - return Die; - })(); - Actions.Die = Die; - var CallMethod = (function () { - function CallMethod(actor, method) { - this._method = null; - this._actor = null; - this._hasBeenCalled = false; - this._actor = actor; - this._method = method; - } - CallMethod.prototype.update = function (delta) { - this._method.call(this._actor); - this._hasBeenCalled = true; - }; - CallMethod.prototype.isComplete = function (actor) { - return this._hasBeenCalled; - }; - CallMethod.prototype.reset = function () { - this._hasBeenCalled = false; - }; - CallMethod.prototype.stop = function () { - this._hasBeenCalled = true; - }; - return CallMethod; - })(); - Actions.CallMethod = CallMethod; - var Repeat = (function () { - function Repeat(actor, repeat, actions) { - this._stopped = false; - this._actor = actor; - this._actionQueue = new ActionQueue(actor); - this._repeat = repeat; - this._originalRepeat = repeat; - var i = 0, len = actions.length; - for (i; i < len; i++) { - actions[i].reset(); - this._actionQueue.add(actions[i]); + this._gamePadTimeStamps[i] = gamepads[i].timestamp; + // Add reference to navigator gamepad + this.at(i).navigatorGamepad = gamepads[i]; + // Buttons + var b, a, value, buttonIndex, axesIndex; + for (b in Buttons) { + if (typeof Buttons[b] !== 'number') { + continue; + } + buttonIndex = Buttons[b]; + if (gamepads[i].buttons[buttonIndex]) { + value = gamepads[i].buttons[buttonIndex].value; + if (value !== this._oldPads[i].getButton(buttonIndex)) { + if (gamepads[i].buttons[buttonIndex].pressed) { + this.at(i).updateButton(buttonIndex, value); + this.at(i).eventDispatcher.publish('button', new ex.GamepadButtonEvent(buttonIndex, value)); + } + else { + this.at(i).updateButton(buttonIndex, 0); + } + } + } + } + // Axes + for (a in Axes) { + if (typeof Axes[a] !== 'number') { + continue; + } + axesIndex = Axes[a]; + value = gamepads[i].axes[axesIndex]; + if (value !== this._oldPads[i].getAxes(axesIndex)) { + this.at(i).updateAxes(axesIndex, value); + this.at(i).eventDispatcher.emit('axis', new ex.GamepadAxisEvent(axesIndex, value)); + } } - ; + this._oldPads[i] = this._clonePad(gamepads[i]); } - Repeat.prototype.update = function (delta) { - this.x = this._actor.x; - this.y = this._actor.y; - if (!this._actionQueue.hasNext()) { - this._actionQueue.reset(); - this._repeat--; - } - this._actionQueue.update(delta); - }; - Repeat.prototype.isComplete = function () { - return this._stopped || (this._repeat <= 0); - }; - Repeat.prototype.stop = function () { - this._stopped = true; - }; - Repeat.prototype.reset = function () { - this._repeat = this._originalRepeat; - }; - return Repeat; - })(); - Actions.Repeat = Repeat; - var RepeatForever = (function () { - function RepeatForever(actor, actions) { - this._stopped = false; - this._actor = actor; - this._actionQueue = new ActionQueue(actor); - var i = 0, len = actions.length; - for (i; i < len; i++) { - actions[i].reset(); - this._actionQueue.add(actions[i]); + }; + /** + * Safely retrieves a Gamepad at a specific index and creates one if it doesn't yet exist + */ + Gamepads.prototype.at = function (index) { + this._enableAndUpdate(); // implicitly enable gamepads when at() is called + if (index >= this._pads.length) { + // Ensure there is a pad to retrieve + for (var i = this._pads.length - 1, max = index; i < max; i++) { + this._pads.push(new Gamepad()); + this._oldPads.push(new Gamepad()); } - ; } - RepeatForever.prototype.update = function (delta) { - this.x = this._actor.x; - this.y = this._actor.y; - if (this._stopped) { - return; + return this._pads[index]; + }; + /** + * Returns a list of all valid gamepads that meet the minimum configuration requirment. + */ + Gamepads.prototype.getValidGamepads = function () { + this._enableAndUpdate(); + var result = []; + for (var i = 0; i < this._pads.length; i++) { + if (this._isGamepadValid(this.at(i).navigatorGamepad) && this.at(i).connected) { + result.push(this.at(i)); } - if (!this._actionQueue.hasNext()) { - this._actionQueue.reset(); + } + return result; + }; + /** + * Gets the number of connected gamepads + */ + Gamepads.prototype.count = function () { + return this._pads.filter(function (p) { return p.connected; }).length; + }; + Gamepads.prototype._clonePads = function (pads) { + var arr = []; + for (var i = 0, len = pads.length; i < len; i++) { + arr.push(this._clonePad(pads[i])); + } + return arr; + }; + /** + * Fastest way to clone a known object is to do it yourself + */ + Gamepads.prototype._clonePad = function (pad) { + var i, len; + var clonedPad = new Gamepad(); + if (!pad) { + return clonedPad; + } + for (i = 0, len = pad.buttons.length; i < len; i++) { + if (pad.buttons[i]) { + clonedPad.updateButton(i, pad.buttons[i].value); } - this._actionQueue.update(delta); - }; - RepeatForever.prototype.isComplete = function () { - return this._stopped; - }; - RepeatForever.prototype.stop = function () { - this._stopped = true; - this._actionQueue.clearActions(); - }; - RepeatForever.prototype.reset = function () { return; }; - return RepeatForever; - })(); - Actions.RepeatForever = RepeatForever; + } + for (i = 0, len = pad.axes.length; i < len; i++) { + clonedPad.updateAxes(i, pad.axes[i]); + } + return clonedPad; + }; + /** + * The minimum value an axis has to move before considering it a change + */ + Gamepads.MinAxisMoveThreshold = 0.05; + return Gamepads; + })(ex.Class); + Input.Gamepads = Gamepads; + /** + * Gamepad holds state information for a connected controller. See [[Gamepads]] + * for more information on handling controller input. + */ + var Gamepad = (function (_super) { + __extends(Gamepad, _super); + function Gamepad() { + _super.call(this); + this.connected = false; + this._buttons = new Array(16); + this._axes = new Array(4); + var i; + for (i = 0; i < this._buttons.length; i++) { + this._buttons[i] = 0; + } + for (i = 0; i < this._axes.length; i++) { + this._axes[i] = 0; + } + } + /** + * Whether or not the given button is pressed + * @param button The button to query + * @param threshold The threshold over which the button is considered to be pressed + */ + Gamepad.prototype.isButtonPressed = function (button, threshold) { + if (threshold === void 0) { threshold = 1; } + return this._buttons[button] >= threshold; + }; + /** + * Gets the given button value between 0 and 1 + */ + Gamepad.prototype.getButton = function (button) { + return this._buttons[button]; + }; + /** + * Gets the given axis value between -1 and 1. Values below + * [[MinAxisMoveThreshold]] are considered 0. + */ + Gamepad.prototype.getAxes = function (axes) { + var value = this._axes[axes]; + if (Math.abs(value) < Gamepads.MinAxisMoveThreshold) { + return 0; + } + else { + return value; + } + }; + Gamepad.prototype.updateButton = function (buttonIndex, value) { + this._buttons[buttonIndex] = value; + }; + Gamepad.prototype.updateAxes = function (axesIndex, value) { + this._axes[axesIndex] = value; + }; + return Gamepad; + })(ex.Class); + Input.Gamepad = Gamepad; + /** + * Gamepad Buttons enumeration + */ + (function (Buttons) { + /** + * Face 1 button (e.g. A) + */ + Buttons[Buttons["Face1"] = 0] = "Face1"; + /** + * Face 2 button (e.g. B) + */ + Buttons[Buttons["Face2"] = 1] = "Face2"; + /** + * Face 3 button (e.g. X) + */ + Buttons[Buttons["Face3"] = 2] = "Face3"; + /** + * Face 4 button (e.g. Y) + */ + Buttons[Buttons["Face4"] = 3] = "Face4"; + /** + * Left bumper button + */ + Buttons[Buttons["LeftBumper"] = 4] = "LeftBumper"; + /** + * Right bumper button + */ + Buttons[Buttons["RightBumper"] = 5] = "RightBumper"; + /** + * Left trigger button + */ + Buttons[Buttons["LeftTrigger"] = 6] = "LeftTrigger"; + /** + * Right trigger button + */ + Buttons[Buttons["RightTrigger"] = 7] = "RightTrigger"; + /** + * Select button + */ + Buttons[Buttons["Select"] = 8] = "Select"; + /** + * Start button + */ + Buttons[Buttons["Start"] = 9] = "Start"; + /** + * Left analog stick press (e.g. L3) + */ + Buttons[Buttons["LeftStick"] = 10] = "LeftStick"; + /** + * Right analog stick press (e.g. R3) + */ + Buttons[Buttons["RightStick"] = 11] = "RightStick"; + /** + * D-pad up + */ + Buttons[Buttons["DpadUp"] = 12] = "DpadUp"; + /** + * D-pad down + */ + Buttons[Buttons["DpadDown"] = 13] = "DpadDown"; + /** + * D-pad left + */ + Buttons[Buttons["DpadLeft"] = 14] = "DpadLeft"; + /** + * D-pad right + */ + Buttons[Buttons["DpadRight"] = 15] = "DpadRight"; + })(Input.Buttons || (Input.Buttons = {})); + var Buttons = Input.Buttons; + /** + * Gamepad Axes enumeration + */ + (function (Axes) { + /** + * Left analogue stick X direction + */ + Axes[Axes["LeftStickX"] = 0] = "LeftStickX"; + /** + * Left analogue stick Y direction + */ + Axes[Axes["LeftStickY"] = 1] = "LeftStickY"; + /** + * Right analogue stick X direction + */ + Axes[Axes["RightStickX"] = 2] = "RightStickX"; + /** + * Right analogue stick Y direction + */ + Axes[Axes["RightStickY"] = 3] = "RightStickY"; + })(Input.Axes || (Input.Axes = {})); + var Axes = Input.Axes; + })(Input = ex.Input || (ex.Input = {})); +})(ex || (ex = {})); +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/** + * # Welcome to the Excalibur API + * + * This documentation is automatically generated from the Excalibur + * source code on [GitHub](http://github.com/excaliburjs/Excalibur). + * + * If you're just starting out, we recommend reading the tutorials and guides + * on [Excaliburjs.com](http://excaliburjs.com/docs). If you have questions, + * feel free to get help on the [Excalibur.js mailing list](https://groups.google.com/forum/#!forum/excaliburjs). + * + * If you're looking for a specific method or property, you can search the documentation + * using the search icon at the top or just start typing. + * + * ## Where to Start + * + * These are the core concepts of Excalibur that you should become + * familiar with. + * + * - [[Engine|Intro to the Engine]] + * - [[EventDispatcher|Eventing]] + * - [[Scene|Working with Scenes]] + * - [[BaseCamera|Working with Cameras]] + * - [[Actor|Working with Actors]] + * - [[Label|Labels]] + * - [[Trigger|Triggers]] + * - [[UIActor|UI Actors (HUD)]] + * - [[ActionContext|Action API]] + * - [[Group|Groups]] + * + * ## Working with Resources + * + * Excalibur provides easy ways of loading assets, from images to JSON files. + * + * - [[Loader|Working with the Loader]] + * - [[Texture|Loading Textures]] + * - [[Sound|Loading Sounds]] + * - [[Resource|Loading Generic Resources]] + * + * ## Working with Input + * + * Excalibur comes built-in with support for mouse, keyboard, touch, and controllers. + * + * - [[Pointers|Mouse and Touch]] + * - [[Keyboard]] + * - [[Gamepads|Controller Support]] + * + * ## Working with Media + * + * Add sounds, images, and animations to your game. + * + * - [[Sprite|Working with Sprites]] + * - [[Sound|Working with Sounds]] + * - [[SpriteSheet|Working with SpriteSheets]] + * - [[Animation|Working with Animations]] + * - [[TileMap|Working with TileMaps]] + * + * ## Effects and Particles + * + * Every game needs an explosion or two. Add sprite effects such as lighten, + * darken, and colorize. + * + * - [[Effects|Sprite Effects]] + * - [[ParticleEmitter|Particle Emitters]] + * - [[IPostProcessor|Post Processors]] + * + * ## Math + * + * These classes provide the basics for math & algebra operations. + * + * - [[Point]] + * - [[Vector]] + * - [[Ray]] + * - [[Line]] + * - [[Projection]] + * + * ## Utilities + * + * - [[Util|Utility Functions]] + * - [[Promise|Promises and Async]] + * - [[Logger|Logging]] + * - [[Color|Colors]] + * - [[Timer|Timers]] + */ +var ex; +(function (ex) { + /** + * The Excalibur Engine + * + * The [[Engine]] is the main driver for a game. It is responsible for + * starting/stopping the game, maintaining state, transmitting events, + * loading resources, and managing the scene. + * + * Excalibur uses the HTML5 Canvas API for drawing your game to the screen. + * The canvas is available to all `draw` functions for raw manipulation, + * but Excalibur is meant to simplify or completely remove the need to use + * the canvas directly. + * + * ## Creating a Game + * + * To create a new game, create a new instance of [[Engine]] and pass in + * the configuration ([[IEngineOptions]]). Excalibur only supports a single + * instance of a game at a time, so it is safe to use globally. + * + * You can then call [[start]] which starts the game and optionally accepts + * a [[Loader]] which you can use to pre-load assets. + * + * ```js + * var game = new ex.Engine({ width: 800, height: 600 }); + * + * // call game.start, which is a Promise + * game.start().then(function () { + * // ready, set, go! + * }); + * ``` + * + * ## The Main Loop + * + * The Excalibur engine uses a simple main loop. The engine updates and renders + * the "scene graph" which is the [[Scene|scenes]] and the tree of [[Actor|actors]] within that + * scene. Only one [[Scene]] can be active at a time. The engine does not update/draw any other + * scene, which means any actors will not be updated/drawn if they are part of a deactivated scene. + * + * ![Engine Lifecycle](/assets/images/docs/EngineLifeCycle.png) + * + * **Scene Graph** + * + * ``` + * Engine + * |_ Scene 1 (activated) + * |_ Actor 1 + * |_ Child Actor 1 + * |_ Actor 2 + * |_ Scene 2 (deactiveated) + * |_ Scene 3 (deactiveated) + * ``` + * + * The engine splits the game into two primary responsibilities: updating and drawing. This is + * to keep your game smart about splitting duties so that you aren't drawing when doing + * logic or performing logic as you draw. + * + * ### Update Loop + * + * The first operation run is the [[Engine._update|update]] loop. [[Actor]] and [[Scene]] both implement + * an overridable/extendable `update` method. Use it to perform any logic-based operations + * in your game for a particular class. + * + * ### Draw Loop + * + * The next step is the [[Engine._draw|draw]] loop. A [[Scene]] loops through its child [[Actor|actors]] and + * draws each one. You can override the `draw` method on an actor to customize its drawing. + * You should **not** perform any logic in a draw call, it should only relate to drawing. + * + * ## Working with Scenes + * + * The engine automatically creates a "root" [[Scene]]. You can use this for whatever you want. + * You can manipulate scenes using [[Engine.add|add]], [[Engine.remove|remove]], + * and [[Engine.goToScene|goToScene]]. You can overwrite or remove the `root` scene if + * you want. There always has to be at least one scene and only **one** scene can be + * active at any one time. + * + * Learn more about the [[Scene|scene lifecycle]]. + * + * ### Adding a scene + * + * ```js + * var game = new ex.Engine(); + * + * // create a new level + * var level1 = new ex.Scene(); + * + * // add level 1 to the game + * game.add("level1", level1); + * + * // in response to user input, go to level 1 + * game.goToScene("level1"); + * + * // go back to main menu + * game.goToScene("root"); + * ``` + * + * ### Accessing the current scene + * + * To add actors and other entities to the current [[Scene]], you can use [[Engine.add|add]]. Alternatively, + * you can use [[Engine.currentScene]] to directly access the current scene. + * + * ## Managing the Viewport + * + * Excalibur supports multiple [[DisplayMode|display modes]] for a game. Pass in a `displayMode` + * option when creating a game to customize the viewport. + * + * ## Extending the Engine + * + * For complex games, any entity that inherits [[Class]] can be extended to override built-in + * functionality. This is recommended for [[Actor|actors]] and [[Scene|scenes]], especially. + * + * You can customize the options or provide more for your game by extending [[Engine]]. + * + * **TypeScript** + * + * ```ts + * class Game extends ex.Engine { + * + * constructor() { + * super({ width: 800, height: 600, displayMode: DisplayMode.FullScreen }); + * } + * + * public start() { + * // add custom scenes + * this.add("mainmenu", new MainMenu()); + * + * return super.start(myLoader).then(() => { + * + * this.goToScene("mainmenu"); + * + * // custom start-up + * }); + * } + * } + * + * var game = new Game(); + * game.start(); + * ``` + * + * **Javascript** + * + * ```js + * var Game = ex.Engine.extend({ + * + * constructor: function () { + * Engine.call(this, { width: 800, height: 600, displayMode: DisplayMode.FullScreen }); + * } + * + * start: function() { + * // add custom scenes + * this.add("mainmenu", new MainMenu()); + * + * var _this = this; + * return Engine.prototype.start.call(this, myLoader).then(function() { + * + * _this.goToScene("mainmenu"); + * + * // custom start-up + * }); + * } + * }); + * + * var game = new Game(); + * game.start(); + * ``` + */ + var Engine = (function (_super) { + __extends(Engine, _super); + /** + * @internal + */ + function Engine(args) { + _super.call(this); /** - * Action Queues - * - * Action queues are part of the [[ActionContext|Action API]] and - * store the list of actions to be executed for an [[Actor]]. - * - * Actors implement [[Action.actionQueue]] which can be manipulated by - * advanced users to adjust the actions currently being executed in the - * queue. + * Gets or sets the [[CollisionStrategy]] for Excalibur actors */ - var ActionQueue = (function () { - function ActionQueue(actor) { - this._actions = []; - this._completedActions = []; - this._actor = actor; - } - ActionQueue.prototype.add = function (action) { - this._actions.push(action); - }; - ActionQueue.prototype.remove = function (action) { - var index = this._actions.indexOf(action); - this._actions.splice(index, 1); - }; - ActionQueue.prototype.clearActions = function () { - this._actions.length = 0; - this._completedActions.length = 0; - if (this._currentAction) { - this._currentAction.stop(); - } - }; - ActionQueue.prototype.getActions = function () { - return this._actions.concat(this._completedActions); - }; - ActionQueue.prototype.hasNext = function () { - return this._actions.length > 0; - }; - ActionQueue.prototype.reset = function () { - this._actions = this.getActions(); - var i = 0, len = this._actions.length; - for (i; i < len; i++) { - this._actions[i].reset(); + this.collisionStrategy = ex.CollisionStrategy.DynamicAABBTree; + this._hasStarted = false; + /** + * Current FPS + */ + this.fps = 0; + /** + * Gets or sets the list of post processors to apply at the end of drawing a frame (such as [[ColorBlindCorrector]]) + */ + this.postProcessors = []; + /** + * Contains all the scenes currently registered with Excalibur + */ + this.scenes = {}; + this._animations = []; + /** + * Indicates whether the engine is set to fullscreen or not + */ + this.isFullscreen = false; + /** + * Indicates the current [[DisplayMode]] of the engine. + */ + this.displayMode = DisplayMode.FullScreen; + /** + * Indicates whether audio should be paused when the game is no longer visible. + */ + this.pauseAudioWhenHidden = true; + /** + * Indicates whether the engine should draw with debug information + */ + this.isDebug = false; + this.debugColor = new ex.Color(255, 255, 255); + /** + * Sets the background color for the engine. + */ + this.backgroundColor = new ex.Color(0, 0, 100); + /** + * The action to take when a fatal exception is thrown + */ + this.onFatalException = function (e) { ex.Logger.getInstance().fatal(e); }; + this._isSmoothingEnabled = true; + this._isLoading = false; + this._progress = 0; + this._total = 1; + var width; + var height; + var canvasElementId; + var displayMode; + var options = null; + if (typeof arguments[0] === 'number') { + width = arguments[0]; + height = arguments[1]; + canvasElementId = arguments[2]; + displayMode = arguments[3]; + } + else { + options = arguments[0] || { width: 0, height: 0, canvasElementId: '', displayMode: DisplayMode.FullScreen }; + width = options.width; + height = options.height; + canvasElementId = options.canvasElementId; + displayMode = options.displayMode; + } + // Check compatibility + var detector = new ex.Detector(); + if (!(this._compatible = detector.test())) { + var message = document.createElement('div'); + message.innerText = 'Sorry, your browser does not support all the features needed for Excalibur'; + document.body.appendChild(message); + detector.failedTests.forEach(function (test) { + var testMessage = document.createElement('div'); + testMessage.innerText = 'Browser feature missing ' + test; + document.body.appendChild(testMessage); + }); + if (canvasElementId) { + var canvas = document.getElementById(canvasElementId); + if (canvas) { + canvas.parentElement.removeChild(canvas); } - this._completedActions = []; - }; - ActionQueue.prototype.update = function (delta) { - if (this._actions.length > 0) { - this._currentAction = this._actions[0]; - this._currentAction.update(delta); - if (this._currentAction.isComplete(this._actor)) { - this._completedActions.push(this._actions.shift()); + } + return; + } + this._logger = ex.Logger.getInstance(); + this._logger.info('Powered by Excalibur.js visit", "http://excaliburjs.com", "for more information.'); + this._logger.debug('Building engine...'); + this.canvasElementId = canvasElementId; + if (canvasElementId) { + this._logger.debug('Using Canvas element specified: ' + canvasElementId); + this.canvas = document.getElementById(canvasElementId); + } + else { + this._logger.debug('Using generated canvas element'); + this.canvas = document.createElement('canvas'); + } + if (width && height) { + if (displayMode === undefined) { + this.displayMode = DisplayMode.Fixed; + } + this._logger.debug('Engine viewport is size ' + width + ' x ' + height); + this.width = width; + this.canvas.width = width; + this.height = height; + this.canvas.height = height; + } + else if (!displayMode) { + this._logger.debug('Engine viewport is fullscreen'); + this.displayMode = DisplayMode.FullScreen; + } + this._loader = new ex.Loader(); + this._initialize(options); + this.rootScene = this.currentScene = new ex.Scene(this); + this.addScene('root', this.rootScene); + this.goToScene('root'); + } + /** + * Plays a sprite animation on the screen at the specified `x` and `y` + * (in game coordinates, not screen pixels). These animations play + * independent of actors, and will be cleaned up internally as soon + * as they are complete. Note animations that loop will never be + * cleaned up. + * + * @param animation Animation to play + * @param x x game coordinate to play the animation + * @param y y game coordinate to play the animation + */ + Engine.prototype.playAnimation = function (animation, x, y) { + this._animations.push(new AnimationNode(animation, x, y)); + }; + /** + * Adds an actor to the [[currentScene]] of the game. This is synonymous + * to calling `engine.currentScene.addChild(actor)`. + * + * Actors can only be drawn if they are a member of a scene, and only + * the [[currentScene]] may be drawn or updated. + * + * @param actor The actor to add to the [[currentScene]] + * + * @obsolete Use [[add]] instead. + */ + Engine.prototype.addChild = function (actor) { + this.currentScene.addChild(actor); + }; + /** + * Removes an actor from the [[currentScene]] of the game. This is synonymous + * to calling `engine.currentScene.removeChild(actor)`. + * Actors that are removed from a scene will no longer be drawn or updated. + * + * @param actor The actor to remove from the [[currentScene]]. + */ + Engine.prototype.removeChild = function (actor) { + this.currentScene.removeChild(actor); + }; + /** + * Adds a [[TileMap]] to the [[currentScene]], once this is done the TileMap + * will be drawn and updated. + */ + Engine.prototype.addTileMap = function (tileMap) { + this.currentScene.addTileMap(tileMap); + }; + /** + * Removes a [[TileMap]] from the [[currentScene]], it will no longer be drawn or updated. + */ + Engine.prototype.removeTileMap = function (tileMap) { + this.currentScene.removeTileMap(tileMap); + }; + /** + * Adds a [[Timer]] to the [[currentScene]]. + * @param timer The timer to add to the [[currentScene]]. + */ + Engine.prototype.addTimer = function (timer) { + return this.currentScene.addTimer(timer); + }; + /** + * Removes a [[Timer]] from the [[currentScene]]. + * @param timer The timer to remove to the [[currentScene]]. + */ + Engine.prototype.removeTimer = function (timer) { + return this.currentScene.removeTimer(timer); + }; + /** + * Adds a [[Scene]] to the engine, think of scenes in Excalibur as you + * would levels or menus. + * + * @param key The name of the scene, must be unique + * @param scene The scene to add to the engine + */ + Engine.prototype.addScene = function (key, scene) { + if (this.scenes[key]) { + this._logger.warn('Scene', key, 'already exists overwriting'); + } + this.scenes[key] = scene; + scene.engine = this; + }; + /** + * @internal + */ + Engine.prototype.removeScene = function (entity) { + if (entity instanceof ex.Scene) { + // remove scene + for (var key in this.scenes) { + if (this.scenes.hasOwnProperty(key)) { + if (this.scenes[key] === entity) { + delete this.scenes[key]; } } - }; - return ActionQueue; - })(); - Actions.ActionQueue = ActionQueue; - })(Actions = Internal.Actions || (Internal.Actions = {})); - })(Internal = ex.Internal || (ex.Internal = {})); -})(ex || (ex = {})); -/// -/// -/// -var ex; -(function (ex) { - /** - * Creates a closed polygon drawing given a list of [[Point]]s. - * - * @warning Use sparingly as Polygons are performance intensive - */ - var Polygon = (function () { + } + } + if (typeof entity === 'string') { + // remove scene + delete this.scenes[entity]; + } + }; + Engine.prototype.add = function (entity) { + if (entity instanceof ex.UIActor) { + this.currentScene.addUIActor(entity); + return; + } + if (entity instanceof ex.Actor) { + this.addChild(entity); + } + if (entity instanceof ex.Timer) { + this.addTimer(entity); + } + if (entity instanceof ex.TileMap) { + this.addTileMap(entity); + } + if (arguments.length === 2) { + this.addScene(arguments[0], arguments[1]); + } + }; + Engine.prototype.remove = function (entity) { + if (entity instanceof ex.UIActor) { + this.currentScene.removeUIActor(entity); + return; + } + if (entity instanceof ex.Actor) { + this.removeChild(entity); + } + if (entity instanceof ex.Timer) { + this.removeTimer(entity); + } + if (entity instanceof ex.TileMap) { + this.removeTileMap(entity); + } + if (entity instanceof ex.Scene) { + this.removeScene(entity); + } + if (typeof entity === 'string') { + this.removeScene(entity); + } + }; /** - * @param points The points to use to build the polygon in order + * Changes the currently updating and drawing scene to a different, + * named scene. Calls the [[Scene]] lifecycle events. + * @param key The key of the scene to trasition to. */ - function Polygon(points) { - /** - * The width of the lines of the polygon - */ - this.lineWidth = 5; - /** - * Indicates whether the polygon is filled or not. - */ - this.filled = false; - this._points = []; - this.anchor = new ex.Point(0, 0); - this.rotation = 0; - this.scale = new ex.Point(1, 1); - this._points = points; - var minX = this._points.reduce(function (prev, curr) { - return Math.min(prev, curr.x); - }, 0); - var maxX = this._points.reduce(function (prev, curr) { - return Math.max(prev, curr.x); - }, 0); - this.width = maxX - minX; - var minY = this._points.reduce(function (prev, curr) { - return Math.min(prev, curr.y); - }, 0); - var maxY = this._points.reduce(function (prev, curr) { - return Math.max(prev, curr.y); - }, 0); - this.height = maxY - minY; - this.naturalHeight = this.height; - this.naturalWidth = this.width; - } + Engine.prototype.goToScene = function (key) { + if (this.scenes[key]) { + var oldScene = this.currentScene; + var newScene = this.scenes[key]; + this._logger.debug('Going to scene:', key); + // only deactivate when initialized + if (this.currentScene.isInitialized) { + this.currentScene.onDeactivate.call(this.currentScene); + this.currentScene.eventDispatcher.emit('deactivate', new ex.DeactivateEvent(newScene)); + } + // set current scene to new one + this.currentScene = newScene; + if (!this.currentScene.isInitialized) { + this.currentScene.onInitialize.call(this.currentScene, this); + this.currentScene.eventDispatcher.emit('initialize', new ex.InitializeEvent(this)); + this.currentScene.isInitialized = true; + } + this.currentScene.onActivate.call(this.currentScene); + this.currentScene.eventDispatcher.emit('activate', new ex.ActivateEvent(oldScene)); + } + else { + this._logger.error('Scene', key, 'does not exist!'); + } + }; + /** + * Returns the width of the engine's drawing surface in pixels. + */ + Engine.prototype.getWidth = function () { + if (this.currentScene && this.currentScene.camera) { + return this.width / this.currentScene.camera.getZoom(); + } + return this.width; + }; + /** + * Returns the height of the engine's drawing surface in pixels. + */ + Engine.prototype.getHeight = function () { + if (this.currentScene && this.currentScene.camera) { + return this.height / this.currentScene.camera.getZoom(); + } + return this.height; + }; + /** + * Transforms the current x, y from screen coordinates to world coordinates + * @param point Screen coordinate to convert + */ + Engine.prototype.screenToWorldCoordinates = function (point) { + var newX = point.x; + var newY = point.y; + // transform back to world space + newX = (newX / this.canvas.clientWidth) * this.getWidth(); + newY = (newY / this.canvas.clientHeight) * this.getHeight(); + // transform based on zoom + newX = newX - this.getWidth() / 2; + newY = newY - this.getHeight() / 2; + // shift by focus + if (this.currentScene && this.currentScene.camera) { + var focus = this.currentScene.camera.getFocus(); + newX += focus.x; + newY += focus.y; + } + return new ex.Point(Math.floor(newX), Math.floor(newY)); + }; + /** + * Transforms a world coordinate, to a screen coordinate + * @param point World coordinate to convert + */ + Engine.prototype.worldToScreenCoordinates = function (point) { + var screenX = point.x; + var screenY = point.y; + // shift by focus + if (this.currentScene && this.currentScene.camera) { + var focus = this.currentScene.camera.getFocus(); + screenX -= focus.x; + screenY -= focus.y; + } + // transfrom back on zoom + screenX = screenX + this.getWidth() / 2; + screenY = screenY + this.getHeight() / 2; + // transform back to screen space + screenX = (screenX * this.canvas.clientWidth) / this.getWidth(); + screenY = (screenY * this.canvas.clientHeight) / this.getHeight(); + return new ex.Point(Math.floor(screenX), Math.floor(screenY)); + }; + /** + * Sets the internal canvas height based on the selected display mode. + */ + Engine.prototype._setHeightByDisplayMode = function (parent) { + if (this.displayMode === DisplayMode.Container) { + this.width = this.canvas.width = parent.clientWidth; + this.height = this.canvas.height = parent.clientHeight; + } + if (this.displayMode === DisplayMode.FullScreen) { + document.body.style.margin = '0px'; + document.body.style.overflow = 'hidden'; + this.width = this.canvas.width = parent.innerWidth; + this.height = this.canvas.height = parent.innerHeight; + } + }; + /** + * Initializes the internal canvas, rendering context, displaymode, and native event listeners + */ + Engine.prototype._initialize = function (options) { + var _this = this; + if (this.displayMode === DisplayMode.FullScreen || this.displayMode === DisplayMode.Container) { + var parent = (this.displayMode === DisplayMode.Container ? + (this.canvas.parentElement || document.body) : window); + this._setHeightByDisplayMode(parent); + window.addEventListener('resize', function (ev) { + _this._logger.debug('View port resized'); + _this._setHeightByDisplayMode(parent); + _this._logger.info('parent.clientHeight ' + parent.clientHeight); + _this.setAntialiasing(_this._isSmoothingEnabled); + }); + } + // initialize inputs + this.input = { + keyboard: new ex.Input.Keyboard(this), + pointers: new ex.Input.Pointers(this), + gamepads: new ex.Input.Gamepads(this) + }; + this.input.keyboard.init(); + this.input.pointers.init(options ? options.pointerScope : ex.Input.PointerScope.Document); + this.input.gamepads.init(); + // Issue #385 make use of the visibility api + // https://developer.mozilla.org/en-US/docs/Web/Guide/User_experience/Using_the_Page_Visibility_API + document.addEventListener('visibilitychange', function () { + if (document.hidden || document.msHidden) { + _this.eventDispatcher.emit('hidden', new ex.HiddenEvent()); + _this._logger.debug('Window hidden'); + } + else { + _this.eventDispatcher.emit('visible', new ex.VisibleEvent()); + _this._logger.debug('Window visible'); + } + }); + /* + // DEPRECATED in favor of visibility api + window.addEventListener('blur', () => { + this.eventDispatcher.publish(EventType[EventType.Blur], new BlurEvent()); + }); + + window.addEventListener('focus', () => { + this.eventDispatcher.publish(EventType[EventType.Focus], new FocusEvent()); + });*/ + this.ctx = this.canvas.getContext('2d'); + if (!this.canvasElementId) { + document.body.appendChild(this.canvas); + } + }; + /** + * If supported by the browser, this will set the antialiasing flag on the + * canvas. Set this to `false` if you want a 'jagged' pixel art look to your + * image resources. + * @param isSmooth Set smoothing to true or false + */ + Engine.prototype.setAntialiasing = function (isSmooth) { + this._isSmoothingEnabled = isSmooth; + this.ctx.imageSmoothingEnabled = isSmooth; + this.ctx.webkitImageSmoothingEnabled = isSmooth; + this.ctx.mozImageSmoothingEnabled = isSmooth; + this.ctx.msImageSmoothingEnabled = isSmooth; + }; /** - * @notimplemented Effects are not supported on `Polygon` + * Return the current smoothing status of the canvas */ - Polygon.prototype.addEffect = function (effect) { - // not supported on polygons + Engine.prototype.getAntialiasing = function () { + return this.ctx.imageSmoothingEnabled || + this.ctx.webkitImageSmoothingEnabled || + this.ctx.mozImageSmoothingEnabled || + this.ctx.msImageSmoothingEnabled; }; /** - * @notimplemented Effects are not supported on `Polygon` + * Updates the entire state of the game + * @param delta Number of milliseconds elapsed since the last update. */ - Polygon.prototype.removeEffect = function (param) { - // not supported on polygons + Engine.prototype._update = function (delta) { + if (this._isLoading) { + // suspend updates untill loading is finished + return; + } + this.emit('preupdate', new ex.PreUpdateEvent(this, delta, this)); + // process engine level events + this.currentScene.update(this, delta); + // update animations + this._animations = this._animations.filter(function (a) { + return !a.animation.isDone(); + }); + // Update input listeners + this.input.keyboard.update(delta); + this.input.pointers.update(delta); + this.input.gamepads.update(delta); + // Publish update event + this.eventDispatcher.emit('update', new ex.UpdateEvent(delta)); + this.emit('postupdate', new ex.PreUpdateEvent(this, delta, this)); }; /** - * @notimplemented Effects are not supported on `Polygon` + * Draws the entire game + * @param draw Number of milliseconds elapsed since the last draw. */ - Polygon.prototype.clearEffects = function () { - // not supported on polygons - }; - Polygon.prototype.reset = function () { - //pass - }; - Polygon.prototype.draw = function (ctx, x, y) { - ctx.save(); - ctx.translate(x + this.anchor.x, y + this.anchor.y); - ctx.scale(this.scale.x, this.scale.y); - ctx.rotate(this.rotation); - ctx.beginPath(); - ctx.lineWidth = this.lineWidth; - // Iterate through the supplied points and contruct a 'polygon' - var firstPoint = this._points[0]; - ctx.moveTo(firstPoint.x, firstPoint.y); - var i = 0, len = this._points.length; - for (i; i < len; i++) { - ctx.lineTo(this._points[i].x, this._points[i].y); + Engine.prototype._draw = function (delta) { + var ctx = this.ctx; + this.emit('predraw', new ex.PreDrawEvent(ctx, delta, this)); + if (this._isLoading) { + ctx.fillStyle = 'black'; + ctx.fillRect(0, 0, this.width, this.height); + this._drawLoadingBar(ctx, this._progress, this._total); + // Drawing nothing else while loading + return; } - ctx.lineTo(firstPoint.x, firstPoint.y); - ctx.closePath(); - if (this.filled) { - ctx.fillStyle = this.fillColor.toString(); - ctx.fill(); + ctx.clearRect(0, 0, this.width, this.height); + ctx.fillStyle = this.backgroundColor.toString(); + ctx.fillRect(0, 0, this.width, this.height); + this.currentScene.draw(this.ctx, delta); + // todo needs to be a better way of doing this + var a = 0, len = this._animations.length; + for (a; a < len; a++) { + this._animations[a].animation.draw(ctx, this._animations[a].x, this._animations[a].y); } - ctx.strokeStyle = this.lineColor.toString(); - if (this.flipHorizontal) { - ctx.translate(this.width, 0); - ctx.scale(-1, 1); + this.fps = 1.0 / (delta / 1000); + // Draw debug information + if (this.isDebug) { + this.ctx.font = 'Consolas'; + this.ctx.fillStyle = this.debugColor.toString(); + var keys = this.input.keyboard.getKeys(); + for (var j = 0; j < keys.length; j++) { + this.ctx.fillText(keys[j].toString() + ' : ' + (ex.Input.Keys[keys[j]] ? ex.Input.Keys[keys[j]] : 'Not Mapped'), 100, 10 * j + 10); + } + this.ctx.fillText('FPS:' + this.fps.toFixed(2).toString(), 10, 10); } - if (this.flipVertical) { - ctx.translate(0, this.height); - ctx.scale(1, -1); + // Post processing + for (var i = 0; i < this.postProcessors.length; i++) { + this.postProcessors[i].process(this.ctx.getImageData(0, 0, this.width, this.height), this.ctx); } - ctx.stroke(); - ctx.restore(); + this.emit('postdraw', new ex.PreDrawEvent(ctx, delta, this)); }; - return Polygon; - })(); - ex.Polygon = Polygon; -})(ex || (ex = {})); -/// -var ex; -(function (ex) { - (function (ColorBlindness) { - ColorBlindness[ColorBlindness["Protanope"] = 0] = "Protanope"; - ColorBlindness[ColorBlindness["Deuteranope"] = 1] = "Deuteranope"; - ColorBlindness[ColorBlindness["Tritanope"] = 2] = "Tritanope"; - })(ex.ColorBlindness || (ex.ColorBlindness = {})); - var ColorBlindness = ex.ColorBlindness; - // Color correction algorithm originally sourced from http://www.daltonize.org/ - var ColorBlindCorrector = (function () { - function ColorBlindCorrector(engine, simulate, colorMode) { - if (simulate === void 0) { simulate = false; } - if (colorMode === void 0) { colorMode = ColorBlindness.Protanope; } - this.engine = engine; - this.simulate = simulate; - this.colorMode = colorMode; - this._vertexShader = 'attribute vec2 a_position;' + - 'attribute vec2 a_texCoord;' + - 'uniform vec2 u_resolution;' + - 'varying vec2 v_texCoord;' + - 'void main() {' + - // convert the rectangle from pixels to 0.0 to 1.0 - 'vec2 zeroToOne = a_position / u_resolution;' + - // convert from 0->1 to 0->2 - 'vec2 zeroToTwo = zeroToOne * 2.0;' + - // convert from 0->2 to -1->+1 (clipspace) - 'vec2 clipSpace = zeroToTwo - 1.0;' + - 'gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);' + - // pass the texCoord to the fragment shader - // The GPU will interpolate this value between points. - 'v_texCoord = a_texCoord;' + - '}'; - this._fragmentShader = 'precision mediump float;' + - // our texture - 'uniform sampler2D u_image;' + - // the texCoords passed in from the vertex shader. - 'varying vec2 v_texCoord;' + - // Color blind conversions - /*'mat3 m[9] =' + - '{' + - 'mat3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0 ),' + // normal - 'mat3(0.567, 0.433, 0.0, 0.558, 0.442, 0.0, 0.0, 0.242, 0.758),' + // protanopia - 'mat3(0.817, 0.183, 0.0, 0.333, 0.667, 0.0, 0.0, 0.125,0.875),' + // protanomaly - 'mat3(0.625, 0.375, 0.0, 0.7, 0.3, 0.0, 0.0, 0.3,0.7 ),' + // deuteranopia - 'mat3(0.8, 0.2, 0.0, 0.258, 0.742, 0.0, 0.0, 0.142,0.858),' + // deuteranomaly - 'mat3(0.95, 0.05, 0.0, 0.0, 0.433, 0.567, 0.0, 0.475,0.525),' + // tritanopia - 'mat3(0.967, 0.033, 0.0, 0.0, 0.733, 0.267, 0.0, 0.183,0.817),' + // tritanomaly - 'mat3(0.299, 0.587, 0.114, 0.299, 0.587, 0.114, 0.299, 0.587,0.114),' + // achromatopsia - 'mat3(0.618, 0.320, 0.062, 0.163, 0.775, 0.062, 0.163, 0.320,0.516)' + // achromatomaly - '};' +*/ - 'void main() {' + - 'vec4 o = texture2D(u_image, v_texCoord);' + - // RGB to LMS matrix conversion - 'float L = (17.8824 * o.r) + (43.5161 * o.g) + (4.11935 * o.b);' + - 'float M = (3.45565 * o.r) + (27.1554 * o.g) + (3.86714 * o.b);' + - 'float S = (0.0299566 * o.r) + (0.184309 * o.g) + (1.46709 * o.b);' + - // Simulate color blindness - '//MODE CODE//' + - /* Deuteranope for testing - 'float l = 1.0 * L + 0.0 * M + 0.0 * S;' + - 'float m = 0.494207 * L + 0.0 * M + 1.24827 * S;' + - 'float s = 0.0 * L + 0.0 * M + 1.0 * S;' +*/ - // LMS to RGB matrix conversion - 'vec4 error;' + - 'error.r = (0.0809444479 * l) + (-0.130504409 * m) + (0.116721066 * s);' + - 'error.g = (-0.0102485335 * l) + (0.0540193266 * m) + (-0.113614708 * s);' + - 'error.b = (-0.000365296938 * l) + (-0.00412161469 * m) + (0.693511405 * s);' + - 'error.a = 1.0;' + - 'vec4 diff = o - error;' + - 'vec4 correction;' + - 'correction.r = 0.0;' + - 'correction.g = (diff.r * 0.7) + (diff.g * 1.0);' + - 'correction.b = (diff.r * 0.7) + (diff.b * 1.0);' + - 'correction = o + correction;' + - 'correction.a = o.a;' + - '//SIMULATE//' + - '}'; - this._internalCanvas = document.createElement('canvas'); - this._internalCanvas.width = engine.getWidth(); - this._internalCanvas.height = engine.getHeight(); - this._gl = this._internalCanvas.getContext('webgl', { preserveDrawingBuffer: true }); - this._program = this._gl.createProgram(); - var fragmentShader = this._getShader('Fragment', this._getFragmentShaderByMode(colorMode)); - var vertextShader = this._getShader('Vertex', this._vertexShader); - this._gl.attachShader(this._program, vertextShader); - this._gl.attachShader(this._program, fragmentShader); - this._gl.linkProgram(this._program); - if (!this._gl.getProgramParameter(this._program, this._gl.LINK_STATUS)) { - ex.Logger.getInstance().error('Unable to link shader program!'); - } - this._gl.useProgram(this._program); - } - ColorBlindCorrector.prototype._getFragmentShaderByMode = function (colorMode) { - var code = ''; - if (colorMode === ColorBlindness.Protanope) { - code = - 'float l = 0.0 * L + 2.02344 * M + -2.52581 * S;' + - 'float m = 0.0 * L + 1.0 * M + 0.0 * S;' + - 'float s = 0.0 * L + 0.0 * M + 1.0 * S;'; - } - else if (colorMode === ColorBlindness.Deuteranope) { - code = - 'float l = 1.0 * L + 0.0 * M + 0.0 * S;' + - 'float m = 0.494207 * L + 0.0 * M + 1.24827 * S;' + - 'float s = 0.0 * L + 0.0 * M + 1.0 * S;'; - } - else if (colorMode === ColorBlindness.Tritanope) { - code = - 'float l = 1.0 * L + 0.0 * M + 0.0 * S;' + - 'float m = 0.0 * L + 1.0 * M + 0.0 * S;' + - 'float s = -0.395913 * L + 0.801109 * M + 0.0 * S;'; - } - if (this.simulate) { - this._fragmentShader = this._fragmentShader.replace('//SIMULATE//', 'gl_FragColor = error.rgba;'); + /** + * Starts the internal game loop for Excalibur after loading + * any provided assets. + * @param loader Optional resources to load before starting the main loop. Some [[ILoadable]] such as a [[Loader]] collection, + * [[Sound]], or [[Texture]]. + */ + Engine.prototype.start = function (loader) { + if (!this._compatible) { + var promise = new ex.Promise(); + return promise.reject('Excalibur is incompatible with your browser'); + } + var loadingComplete; + if (loader) { + loader.wireEngine(this); + loadingComplete = this.load(loader); } else { - this._fragmentShader = this._fragmentShader.replace('//SIMULATE//', 'gl_FragColor = correction.rgba;'); - } - return this._fragmentShader.replace('//MODE CODE//', code); - }; - ColorBlindCorrector.prototype._setRectangle = function (gl, x, y, width, height) { - var x1 = x; - var x2 = x + width; - var y1 = y; - var y2 = y + height; - this._gl.bufferData(this._gl.ARRAY_BUFFER, new Float32Array([ - x1, y1, - x2, y1, - x1, y2, - x1, y2, - x2, y1, - x2, y2]), this._gl.STATIC_DRAW); - }; - ColorBlindCorrector.prototype._getShader = function (type, program) { - var shader; - if (type === 'Fragment') { - shader = this._gl.createShader(this._gl.FRAGMENT_SHADER); - } - else if (type === 'Vertex') { - shader = this._gl.createShader(this._gl.VERTEX_SHADER); + loadingComplete = ex.Promise.wrap(); + } + if (!this._hasStarted) { + this._hasStarted = true; + this._logger.debug('Starting game...'); + // Mainloop + var lastTime = Date.now(); + var game = this; + (function mainloop() { + if (!game._hasStarted) { + return; + } + try { + game._requestId = window.requestAnimationFrame(mainloop); + // Get the time to calculate time-elapsed + var now = Date.now(); + var elapsed = Math.floor(now - lastTime) || 1; + // Resolves issue #138 if the game has been paused, or blurred for + // more than a 200 milliseconds, reset elapsed time to 1. This improves reliability + // and provides more expected behavior when the engine comes back + // into focus + if (elapsed > 200) { + elapsed = 1; + } + game._update(elapsed); + game._draw(elapsed); + lastTime = now; + } + catch (e) { + window.cancelAnimationFrame(game._requestId); + game.stop(); + game.onFatalException(e); + } + })(); + this._logger.debug('Game started'); } else { - ex.Logger.getInstance().error('Error unknown shader type', type); } - this._gl.shaderSource(shader, program); - this._gl.compileShader(shader); - if (!this._gl.getShaderParameter(shader, this._gl.COMPILE_STATUS)) { - ex.Logger.getInstance().error('Unable to compile shader!', this._gl.getShaderInfoLog(shader)); - return null; + return loadingComplete; + }; + /** + * Stops Excalibur's main loop, useful for pausing the game. + */ + Engine.prototype.stop = function () { + if (this._hasStarted) { + this._hasStarted = false; + this._logger.debug('Game stopped'); + } + }; + /** + * Takes a screen shot of the current viewport and returns it as an + * HTML Image Element. + */ + Engine.prototype.screenshot = function () { + var result = new Image(); + var raw = this.canvas.toDataURL('image/png'); + result.src = raw; + return result; + }; + /** + * Draws the Excalibur loading bar + * @param ctx The canvas rendering context + * @param loaded Number of bytes loaded + * @param total Total number of bytes to load + */ + Engine.prototype._drawLoadingBar = function (ctx, loaded, total) { + if (this._loadingDraw) { + this._loadingDraw(ctx, loaded, total); + return; } - return shader; - }; - ColorBlindCorrector.prototype.process = function (image, out) { - // look up where the vertex data needs to go. - var positionLocation = this._gl.getAttribLocation(this._program, 'a_position'); - var texCoordLocation = this._gl.getAttribLocation(this._program, 'a_texCoord'); - var texCoordBuffer = this._gl.createBuffer(); - this._gl.bindBuffer(this._gl.ARRAY_BUFFER, texCoordBuffer); - this._gl.bufferData(this._gl.ARRAY_BUFFER, new Float32Array([ - 0.0, 0.0, - 1.0, 0.0, - 0.0, 1.0, - 0.0, 1.0, - 1.0, 0.0, - 1.0, 1.0]), this._gl.STATIC_DRAW); - this._gl.enableVertexAttribArray(texCoordLocation); - this._gl.vertexAttribPointer(texCoordLocation, 2, this._gl.FLOAT, false, 0, 0); - // Create a texture. - var texture = this._gl.createTexture(); - this._gl.bindTexture(this._gl.TEXTURE_2D, texture); - // Set the parameters so we can render any size image. - this._gl.texParameteri(this._gl.TEXTURE_2D, this._gl.TEXTURE_WRAP_S, this._gl.CLAMP_TO_EDGE); - this._gl.texParameteri(this._gl.TEXTURE_2D, this._gl.TEXTURE_WRAP_T, this._gl.CLAMP_TO_EDGE); - this._gl.texParameteri(this._gl.TEXTURE_2D, this._gl.TEXTURE_MIN_FILTER, this._gl.NEAREST); - this._gl.texParameteri(this._gl.TEXTURE_2D, this._gl.TEXTURE_MAG_FILTER, this._gl.NEAREST); - // Flip the texture when unpacking into the gl context, gl reads textures in the opposite order as everything else :/ - this._gl.pixelStorei(this._gl.UNPACK_FLIP_Y_WEBGL, 1); - // Upload the image into the texture. - this._gl.texImage2D(this._gl.TEXTURE_2D, 0, this._gl.RGBA, this._gl.RGBA, this._gl.UNSIGNED_BYTE, image); - // lookup uniforms - var resolutionLocation = this._gl.getUniformLocation(this._program, 'u_resolution'); - // set the resolution - this._gl.uniform2f(resolutionLocation, this._internalCanvas.width, this._internalCanvas.height); - // Create a buffer for the position of the rectangle corners. - var positionBuffer = this._gl.createBuffer(); - this._gl.bindBuffer(this._gl.ARRAY_BUFFER, positionBuffer); - this._gl.enableVertexAttribArray(positionLocation); - this._gl.vertexAttribPointer(positionLocation, 2, this._gl.FLOAT, false, 0, 0); - // Set a rectangle the same size as the image. - this._setRectangle(this._gl, 0, 0, image.width, image.height); - // Draw the rectangle. - this._gl.drawArrays(this._gl.TRIANGLES, 0, 6); - // Grab tranformed image from internal canvas - var pixelData = new Uint8Array(image.width * image.height * 4); - this._gl.readPixels(0, 0, image.width, image.height, this._gl.RGBA, this._gl.UNSIGNED_BYTE, pixelData); - image.data.set(pixelData); - out.putImageData(image, 0, 0); - }; - return ColorBlindCorrector; + var y = this.canvas.height / 2; + var width = this.canvas.width / 3; + var x = width; + // loading image + var image = new Image(); + /* tslint:disable:max-line-length */ + // 64 bit string encoding of the excalibur logo + image.src = 'data:image/png;base64,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'; + /* tslint:enable:max-line-length */ + var imageHeight = width * 3 / 8; + var oldAntialias = this.getAntialiasing(); + this.setAntialiasing(true); + ctx.drawImage(image, 0, 0, 800, 300, x, y - imageHeight - 20, width, imageHeight); + // loading box + ctx.strokeStyle = 'white'; + ctx.lineWidth = 2; + ctx.strokeRect(x, y, width, 20); + var progress = width * (loaded / total); + ctx.fillStyle = 'white'; + var margin = 5; + var progressWidth = progress - margin * 2; + var height = 20 - margin * 2; + ctx.fillRect(x + margin, y + margin, progressWidth > 0 ? progressWidth : 0, height); + this.setAntialiasing(oldAntialias); + }; + /** + * Sets the loading screen draw function if you want to customize the draw + * @param fcn Callback to draw the loading screen which is passed a rendering context, the number of bytes loaded, and the total + * number of bytes to load. + */ + Engine.prototype.setLoadingDrawFunction = function (fcn) { + this._loadingDraw = fcn; + }; + /** + * Another option available to you to load resources into the game. + * Immediately after calling this the game will pause and the loading screen + * will appear. + * @param loader Some [[ILoadable]] such as a [[Loader]] collection, [[Sound]], or [[Texture]]. + */ + Engine.prototype.load = function (loader) { + var _this = this; + var complete = new ex.Promise(); + this._isLoading = true; + loader.onprogress = function (e) { + _this._progress = e.loaded; + _this._total = e.total; + _this._logger.debug('Loading ' + (100 * _this._progress / _this._total).toFixed(0)); + }; + loader.oncomplete = function () { + setTimeout(function () { + _this._isLoading = false; + complete.resolve(); + }, 500); + }; + loader.load(); + return complete; + }; + return Engine; + })(ex.Class); + ex.Engine = Engine; + /** + * Enum representing the different display modes available to Excalibur + */ + (function (DisplayMode) { + /** + * Show the game as full screen + */ + DisplayMode[DisplayMode["FullScreen"] = 0] = "FullScreen"; + /** + * Scale the game to the parent DOM container + */ + DisplayMode[DisplayMode["Container"] = 1] = "Container"; + /** + * Show the game as a fixed size + */ + DisplayMode[DisplayMode["Fixed"] = 2] = "Fixed"; + })(ex.DisplayMode || (ex.DisplayMode = {})); + var DisplayMode = ex.DisplayMode; + /** + * @internal + */ + var AnimationNode = (function () { + function AnimationNode(animation, x, y) { + this.animation = animation; + this.x = x; + this.y = y; + } + return AnimationNode; })(); - ex.ColorBlindCorrector = ColorBlindCorrector; })(ex || (ex = {})); -//# sourceMappingURL=excalibur.js.map \ No newline at end of file +//# sourceMappingURL=excalibur-0.6.0.js.map +; +// Concatenated onto excalibur after build +// Exports the excalibur module so it can be used with browserify +// https://github.com/excaliburjs/Excalibur/issues/312 +if (typeof module !== 'undefined') {module.exports = ex;} \ No newline at end of file diff --git a/sandbox/web/src/game.js b/sandbox/web/src/game.js index 016a6de4c..a9a8a3911 100644 --- a/sandbox/web/src/game.js +++ b/sandbox/web/src/game.js @@ -33,7 +33,7 @@ * Excalibur.js team */ var logger = ex.Logger.getInstance(); -logger.defaultLevel = 0 /* Debug */; +logger.defaultLevel = ex.LogLevel.Debug; // Create an the game container var game = new ex.Engine(800, 600, 'game'); game.setAntialiasing(false); @@ -93,39 +93,40 @@ var Animations; Animations[Animations["JumpLeft"] = 5] = "JumpLeft"; })(Animations || (Animations = {})); var currentX = 0; +// Create the level for (var i = 0; i < 36; i++) { currentX = tileBlockWidth * i + 10; var color = new ex.Color(Math.random() * 255, Math.random() * 255, Math.random() * 255); var block = new ex.Actor(currentX, 350 + Math.random() * 100, tileBlockWidth, tileBlockHeight, color); - block.collisionType = 4 /* Fixed */; + block.collisionType = ex.CollisionType.Fixed; block.addCollisionGroup('ground'); - block.addDrawing(0 /* Block */, blockAnimation); + block.addDrawing(Animations.Block, blockAnimation); game.add(block); } var platform = new ex.Actor(400, 300, 200, 50, new ex.Color(0, 200, 0)); -platform.collisionType = 4 /* Fixed */; +platform.collisionType = ex.CollisionType.Fixed; platform.moveTo(200, 300, 100).moveTo(600, 300, 100).moveTo(400, 300, 100).repeatForever(); game.add(platform); var platform2 = new ex.Actor(800, 300, 200, 20, new ex.Color(0, 0, 140)); -platform2.collisionType = 4 /* Fixed */; +platform2.collisionType = ex.CollisionType.Fixed; platform2.moveTo(2000, 300, 100).moveTo(2000, 100, 100).moveTo(800, 100, 100).moveTo(800, 300, 100).repeatForever(); game.add(platform2); var platform3 = new ex.Actor(-200, 400, 200, 20, new ex.Color(50, 0, 100)); -platform3.collisionType = 4 /* Fixed */; +platform3.collisionType = ex.CollisionType.Fixed; platform3.moveTo(-200, 800, 300).moveTo(-200, 400, 50).delay(3000).moveTo(-200, 300, 800).moveTo(-200, 400, 800).repeatForever(); game.add(platform3); var platform4 = new ex.Actor(200, 200, 100, 50, ex.Color.Azure); -platform4.collisionType = 4 /* Fixed */; +platform4.collisionType = ex.CollisionType.Fixed; platform4.moveBy(75, 300, .20); game.add(platform4); // Test follow api var follower = new ex.Actor(50, 100, 20, 20, ex.Color.Black); -follower.collisionType = 0 /* PreventCollision */; +follower.collisionType = ex.CollisionType.PreventCollision; game.add(follower); // Create the player var player = new ex.Actor(100, -200, 32, 96); player.enableCapturePointer = true; -player.collisionType = 2 /* Active */; +player.collisionType = ex.CollisionType.Active; follower.meet(player, 60).asPromise().then(function () { console.log("Player met!!"); }); @@ -134,10 +135,10 @@ player.scale.setTo(1, 1); player.rotation = 0; // Health bar example var healthbar = new ex.Actor(0, -70, 140, 5, new ex.Color(0, 255, 0)); -player.addChild(healthbar); +player.add(healthbar); // Add Title above player var playerLabel = new ex.Label('My Player', -70, -69, null, spriteFont); -player.addChild(playerLabel); +player.add(playerLabel); // Retrieve animations for player from sprite sheet var left = spriteSheetRun.getAnimationBetween(game, 1, 11, 50); var right = spriteSheetRun.getAnimationBetween(game, 1, 11, 50); @@ -151,13 +152,13 @@ idle.loop = true; jumpRight.freezeFrame = 0; jumpLeft.freezeFrame = 11; // Add animations to player -player.addDrawing(2 /* Left */, left); -player.addDrawing(3 /* Right */, right); -player.addDrawing(1 /* Idle */, idle); -player.addDrawing(4 /* JumpRight */, jumpRight); -player.addDrawing(5 /* JumpLeft */, jumpLeft); +player.addDrawing(Animations.Left, left); +player.addDrawing(Animations.Right, right); +player.addDrawing(Animations.Idle, idle); +player.addDrawing(Animations.JumpRight, jumpRight); +player.addDrawing(Animations.JumpLeft, jumpLeft); // Set default animation -player.setDrawing(1 /* Idle */); +player.setDrawing(Animations.Idle); player.setCenterDrawing(true); var jumpSound = jump.sound; var inAir = true; @@ -166,10 +167,10 @@ var airSpeed = 130; var jumpSpeed = 500; var direction = 1; player.on('update', function () { - if (game.input.keyboard.isKeyPressed(37 /* Left */)) { + if (game.input.keyboard.isHeld(ex.Input.Keys.Left)) { direction = -1; if (!inAir) { - player.setDrawing(2 /* Left */); + player.setDrawing(Animations.Left); } if (inAir) { player.dx = -airSpeed; @@ -177,10 +178,10 @@ player.on('update', function () { } player.dx = -groundSpeed; } - else if (game.input.keyboard.isKeyPressed(39 /* Right */)) { + else if (game.input.keyboard.isHeld(ex.Input.Keys.Right)) { direction = 1; if (!inAir) { - player.setDrawing(3 /* Right */); + player.setDrawing(Animations.Right); } if (inAir) { player.dx = airSpeed; @@ -188,15 +189,15 @@ player.on('update', function () { } player.dx = groundSpeed; } - if (game.input.keyboard.isKeyPressed(38 /* Up */)) { + if (game.input.keyboard.isHeld(ex.Input.Keys.Up)) { if (!inAir) { player.dy = -jumpSpeed; inAir = true; if (direction === 1) { - player.setDrawing(4 /* JumpRight */); + player.setDrawing(Animations.JumpRight); } else { - player.setDrawing(5 /* JumpLeft */); + player.setDrawing(Animations.JumpLeft); } jumpSound.play(); } @@ -205,8 +206,9 @@ player.on('update', function () { game.input.keyboard.on('up', function (e) { if (inAir) return; - if (e.key === 37 /* Left */ || e.key === 39 /* Right */) { - player.setDrawing(1 /* Idle */); + if (e.key === ex.Input.Keys.Left || + e.key === ex.Input.Keys.Right) { + player.setDrawing(Animations.Idle); } }); player.on('pointerdown', function (e) { @@ -220,27 +222,27 @@ newScene.add(new ex.Label("MAH LABEL!", 200, 100)); //newScene.onDeactivate = function(){ // console.log('deactivated newScene'); //}; -newScene.addEventListener('activate', function (evt) { +newScene.on('activate', function (evt) { console.log('activate newScene'); }); -newScene.addEventListener('deactivate', function (evt) { +newScene.on('deactivate', function (evt) { console.log('deactivate newScene'); }); game.addScene('label', newScene); game.input.keyboard.on('down', function (keyDown) { - if (keyDown.key === 70 /* F */) { + if (keyDown.key === ex.Input.Keys.F) { var a = new ex.Actor(player.x + 10, player.y - 50, 10, 10, new ex.Color(222, 222, 222)); a.dx = 200 * direction; a.dy = 0; - a.collisionType = 3 /* Elastic */; + a.collisionType = ex.CollisionType.Elastic; var inAir = true; - a.addEventListener('collision', function (data) { + a.on('collision', function (data) { inAir = false; //a.dx = data.other.dx; //a.dy = data.other.dy; //a.kill(); }); - a.addEventListener('update', function (data) { + a.on('update', function (data) { if (inAir) { a.ay = 400; // * data.delta/1000; } @@ -251,23 +253,23 @@ game.input.keyboard.on('down', function (keyDown) { }); game.addChild(a); } - else if (keyDown.key === 85 /* U */) { + else if (keyDown.key === ex.Input.Keys.U) { game.goToScene('label'); } - else if (keyDown.key === 73 /* I */) { + else if (keyDown.key === ex.Input.Keys.I) { game.goToScene('root'); } }); var isColliding = false; -player.addEventListener('collision', function (data) { - if (data.side === 2 /* Bottom */) { +player.on('collision', function (data) { + if (data.side === ex.Side.Bottom) { isColliding = true; if (inAir) { //console.log("Collided on bottom with inAir", inAir); - player.setDrawing(1 /* Idle */); + player.setDrawing(Animations.Idle); } inAir = false; - if (data.other && !(game.input.keyboard.isKeyPressed(37 /* Left */) || game.input.keyboard.isKeyPressed(39 /* Right */) || game.input.keyboard.isKeyPressed(38 /* Up */) || game.input.keyboard.isKeyPressed(40 /* Down */))) { + if (data.other && !(game.input.keyboard.isHeld(ex.Input.Keys.Left) || game.input.keyboard.isHeld(ex.Input.Keys.Right) || game.input.keyboard.isHeld(ex.Input.Keys.Up) || game.input.keyboard.isHeld(ex.Input.Keys.Down))) { player.dx = data.other.dx; player.dy = data.other.dy; } @@ -276,7 +278,7 @@ player.addEventListener('collision', function (data) { player.dy = 0; } } - if (data.side === 1 /* Top */) { + if (data.side === ex.Side.Top) { if (data.other) { player.dy = data.other.dy - player.dy; } @@ -285,7 +287,7 @@ player.addEventListener('collision', function (data) { } } }); -player.addEventListener('update', function (data) { +player.on('update', function (data) { // apply gravity if player is in the air // only apply gravity when not colliding if (!isColliding) { @@ -299,22 +301,22 @@ player.addEventListener('update', function (data) { isColliding = false; //console.log("Player Pos", player.x, player.y, player.getWidth(), player.getHeight()); }); -player.addEventListener('initialize', function (evt) { +player.on('initialize', function (evt) { console.log("Player initialized", evt.engine); }); game.input.keyboard.on('down', function (keyDown) { - if (keyDown.key === 66 /* B */) { + if (keyDown.key === ex.Input.Keys.B) { var block = new ex.Actor(currentX, 350, 44, 50, color); currentX += 46; - block.addDrawing(0 /* Block */, blockAnimation); + block.addDrawing(Animations.Block, blockAnimation); game.addChild(block); } - if (keyDown.key === 68 /* D */) { + if (keyDown.key === ex.Input.Keys.D) { game.isDebug = !game.isDebug; } }); var paused = false; -game.addEventListener('p', function () { +game.on('p', function () { if (!paused) { game.stop(); } @@ -389,10 +391,10 @@ game.input.pointers.primary.on('down', function (evt) { //emitter.focus = new ex.Vector(evt.x - emitter.x, evt.y - emitter.y); }); game.input.keyboard.on('up', function (evt) { - if (evt.key == 70 /* F */) { + if (evt.key == ex.Input.Keys.F) { jump.play(); } - if (evt.key == 83 /* S */) { + if (evt.key == ex.Input.Keys.S) { jump.stop(); } }); diff --git a/sandbox/web/tests/animation/animation.js b/sandbox/web/tests/animation/animation.js index 9dc6acfe4..1d53e1704 100644 --- a/sandbox/web/tests/animation/animation.js +++ b/sandbox/web/tests/animation/animation.js @@ -22,4 +22,3 @@ engine.input.keyboard.on('down', function (keyDown) { }); engine.start(new ex.Loader([playerTexture])).then(function () { }); -//# sourceMappingURL=animation.js.map \ No newline at end of file diff --git a/sandbox/web/tests/audio/index.js b/sandbox/web/tests/audio/index.js index 6313c0800..215ca7633 100644 --- a/sandbox/web/tests/audio/index.js +++ b/sandbox/web/tests/audio/index.js @@ -1,7 +1,7 @@ /// // uncomment to hint fallback implementation //(window).AudioContext = null; -ex.Logger.getInstance().defaultLevel = 0 /* Debug */; +ex.Logger.getInstance().defaultLevel = ex.LogLevel.Debug; var game = new ex.Engine(); var loader = new ex.Loader(); var testSound = new ex.Sound("loop.mp3"); @@ -25,4 +25,3 @@ game.add(button); } });*/ game.start(loader); -//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/sandbox/web/tests/collision/index.js b/sandbox/web/tests/collision/index.js index 2a265a2ba..ee7f36869 100644 --- a/sandbox/web/tests/collision/index.js +++ b/sandbox/web/tests/collision/index.js @@ -1,13 +1,13 @@ var engine = new ex.Engine(600, 400); var active = new ex.Actor(0, -50, 100, 100, ex.Color.Cyan); -active.collisionType = 2 /* Active */; +active.collisionType = ex.CollisionType.Active; active.dy = 100; active.ay = 900; active.on('update', function () { //console.log('current dy', active.dy); }); var fixed = new ex.Actor(0, 50, 100, 100, ex.Color.Green); -fixed.collisionType = 4 /* Fixed */; +fixed.collisionType = ex.CollisionType.Fixed; fixed.moveTo(0, 100, 300).moveTo(0, 50, 300).repeatForever(); engine.add(active); engine.add(fixed); @@ -19,4 +19,3 @@ engine.start().then(function () { console.log("loaded"); engine.currentScene.camera.setFocus(0, 0); }); -//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/sandbox/web/tests/culling/culling.js b/sandbox/web/tests/culling/culling.js index 4c3dd9366..8dac9dd10 100644 --- a/sandbox/web/tests/culling/culling.js +++ b/sandbox/web/tests/culling/culling.js @@ -11,36 +11,35 @@ player.currentDrawing.anchor = new ex.Point(0.5, 0.5); //TODO what if we don't d //player.currentDrawing.scale = new ex.Point(0.5, 0.5); engine.currentScene.add(player); engine.input.keyboard.on('down', function (keyDown) { - if (keyDown.key === 68 /* D */) { + if (keyDown.key === ex.Input.Keys.D) { engine.isDebug = !engine.isDebug; } - else if (keyDown.key === 38 /* Up */) { + else if (keyDown.key === ex.Input.Keys.Up) { player.dy = -speed; } - else if (keyDown.key === 40 /* Down */) { + else if (keyDown.key === ex.Input.Keys.Down) { player.dy = speed; } - else if (keyDown.key === 37 /* Left */) { + else if (keyDown.key === ex.Input.Keys.Left) { player.dx = -speed; } - else if (keyDown.key === 39 /* Right */) { + else if (keyDown.key === ex.Input.Keys.Right) { player.dx = speed; } }); engine.input.keyboard.on('up', function (keyUp) { - if (keyUp.key === 38 /* Up */) { + if (keyUp.key === ex.Input.Keys.Up) { player.dy = 0; } - else if (keyUp.key === 40 /* Down */) { + else if (keyUp.key === ex.Input.Keys.Down) { player.dy = 0; } - else if (keyUp.key === 37 /* Left */) { + else if (keyUp.key === ex.Input.Keys.Left) { player.dx = 0; } - else if (keyUp.key === 39 /* Right */) { + else if (keyUp.key === ex.Input.Keys.Right) { player.dx = 0; } }); engine.start(new ex.Loader([playerTexture])).then(function () { }); -//# sourceMappingURL=culling.js.map \ No newline at end of file diff --git a/sandbox/web/tests/group/group.js b/sandbox/web/tests/group/group.js index 47874590f..3c6ba1801 100644 --- a/sandbox/web/tests/group/group.js +++ b/sandbox/web/tests/group/group.js @@ -10,12 +10,12 @@ var blockGroup = engine.currentScene.createGroup("blocks"); var blockSprite = blockTexture.asSprite(); blockSprite.scale.setTo(.2, .2); var player = new ex.Actor(width / 2, height / 2, 30, 30, ex.Color.Cyan); -player.collisionType = 4 /* Fixed */; +player.collisionType = ex.CollisionType.Fixed; engine.currentScene.add(player); for (var i = 0; i < numActors; i++) { var actor = new ex.Actor(Math.random() * width, Math.random() * height, .2 * 64, .2 * 48); actor.addDrawing("default", blockSprite); - actor.collisionType = 3 /* Elastic */; + actor.collisionType = ex.CollisionType.Elastic; actor.on('update', function (e) { if (this.x < 0) { this.dx = Math.abs(this.dx); @@ -48,4 +48,3 @@ blockGroup.on('collision', function (e) { engine.start(new ex.Loader([blockTexture])).then(function () { // do stuff }); -//# sourceMappingURL=group.js.map \ No newline at end of file diff --git a/sandbox/web/tests/input/gamepad.js b/sandbox/web/tests/input/gamepad.js index a03ca08de..d39c15e7b 100644 --- a/sandbox/web/tests/input/gamepad.js +++ b/sandbox/web/tests/input/gamepad.js @@ -2,8 +2,7 @@ var __extends = (this && this.__extends) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } - __.prototype = b.prototype; - d.prototype = new __(); + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; var game = new ex.Engine(800, 503, "game"); var padTexture = new ex.Texture("gamepad.png"); @@ -114,4 +113,3 @@ var CircleActor = (function (_super) { }; return CircleActor; })(ex.Actor); -//# sourceMappingURL=gamepad.js.map \ No newline at end of file diff --git a/sandbox/web/tests/input/gamepad.ts b/sandbox/web/tests/input/gamepad.ts index 2b4ce5c77..b78f5b31b 100644 --- a/sandbox/web/tests/input/gamepad.ts +++ b/sandbox/web/tests/input/gamepad.ts @@ -18,11 +18,11 @@ function start() { }); // Log when pads disconnect and connect - game.input.gamepads.on("connect", (evet: ex.Input.GamepadConnectEvent) => { + game.input.gamepads.on("connect", (evet: ex.GamepadConnectEvent) => { console.log("Gamepad connect"); }); - game.input.gamepads.on("disconnect", (evet: ex.Input.GamepadDisconnectEvent) => { + game.input.gamepads.on("disconnect", (evet: ex.GamepadDisconnectEvent) => { console.log("Gamepad disconnect"); }); diff --git a/sandbox/web/tests/input/index.js b/sandbox/web/tests/input/index.js index 85665cfde..b2e2492e9 100644 --- a/sandbox/web/tests/input/index.js +++ b/sandbox/web/tests/input/index.js @@ -7,23 +7,27 @@ game.input.gamepads.enabled = true; // Move box with Gamepad axes and D-pad box.on("update", function (ue) { var pad1 = game.input.gamepads.at(0); - var axesLeftX = pad1.getAxes(0 /* LeftStickX */); - var axesLeftY = pad1.getAxes(1 /* LeftStickY */); + var axesLeftX = pad1.getAxes(ex.Input.Axes.LeftStickX); + var axesLeftY = pad1.getAxes(ex.Input.Axes.LeftStickY); // Right/Left - if (game.input.keyboard.isKeyPressed(39 /* Right */) || pad1.isButtonPressed(15 /* DpadRight */)) { + if (game.input.keyboard.isHeld(ex.Input.Keys.Right) || + pad1.isButtonPressed(ex.Input.Buttons.DpadRight)) { box.dx = 20; } - else if (game.input.keyboard.isKeyPressed(37 /* Left */) || pad1.isButtonPressed(14 /* DpadLeft */)) { + else if (game.input.keyboard.isHeld(ex.Input.Keys.Left) || + pad1.isButtonPressed(ex.Input.Buttons.DpadLeft)) { box.dx = -20; } else if (!axesLeftX && !axesLeftY) { box.dx = 0; } // Up/Down - if (game.input.keyboard.isKeyPressed(38 /* Up */) || pad1.isButtonPressed(12 /* DpadUp */)) { + if (game.input.keyboard.isHeld(ex.Input.Keys.Up) || + pad1.isButtonPressed(ex.Input.Buttons.DpadUp)) { box.dy = -20; } - else if (game.input.keyboard.isKeyPressed(40 /* Down */) || pad1.isButtonPressed(13 /* DpadDown */)) { + else if (game.input.keyboard.isHeld(ex.Input.Keys.Down) || + pad1.isButtonPressed(ex.Input.Buttons.DpadDown)) { box.dy = 20; } else if (!axesLeftY && !axesLeftX) { @@ -39,4 +43,3 @@ box.on("update", function (ue) { }); game.add(box); game.start(); -//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/sandbox/web/tests/input/keyboard.js b/sandbox/web/tests/input/keyboard.js index 4e8f426e0..828d627d9 100644 --- a/sandbox/web/tests/input/keyboard.js +++ b/sandbox/web/tests/input/keyboard.js @@ -2,7 +2,7 @@ var game = new ex.Engine(800, 600, "game"); var label = new ex.Label(null, 400, 300, "48px Arial"); label.color = ex.Color.Chartreuse; -label.textAlign = 2 /* Center */; +label.textAlign = ex.TextAlign.Center; game.add(label); game.on("update", function (ue) { var keys = game.input.keyboard.getKeys().map(function (k) { @@ -11,4 +11,3 @@ game.on("update", function (ue) { label.text = keys; }); game.start(); -//# sourceMappingURL=keyboard.js.map \ No newline at end of file diff --git a/sandbox/web/tests/input/pointer.js b/sandbox/web/tests/input/pointer.js index d01ce32b5..53a4c5602 100644 --- a/sandbox/web/tests/input/pointer.js +++ b/sandbox/web/tests/input/pointer.js @@ -3,7 +3,7 @@ var game = new ex.Engine({ width: 800, height: 600, canvasElementId: "game", - pointerScope: 1 /* Document */ + pointerScope: ex.Input.PointerScope.Document }); var box = new ex.Actor(200, 200, 100, 100, ex.Color.Red); var cursor = new ex.Actor(0, 0, 10, 10, ex.Color.Chartreuse); @@ -59,7 +59,7 @@ var paintBrush = { }; function handleTouch(color) { return function (pe) { - if (pe.pointerType !== 0 /* Touch */) + if (pe.pointerType !== ex.Input.PointerType.Touch) return; paintBrush.paint(pe.x, pe.y, color); }; @@ -76,4 +76,3 @@ game.add(box); game.add(cursor); game.add(uiElement); game.start(); -//# sourceMappingURL=pointer.js.map \ No newline at end of file diff --git a/sandbox/web/tests/label/label.html b/sandbox/web/tests/label/label.html index f44510b98..4a2eb2a6a 100644 --- a/sandbox/web/tests/label/label.html +++ b/sandbox/web/tests/label/label.html @@ -5,7 +5,7 @@ -

The label text should be white

+

The label text should be white, 20px consolas.

diff --git a/sandbox/web/tests/label/label.js b/sandbox/web/tests/label/label.js index a63f5abff..6cc44ca4d 100644 --- a/sandbox/web/tests/label/label.js +++ b/sandbox/web/tests/label/label.js @@ -3,12 +3,19 @@ var engine = new ex.Engine({ width: 600, height: 400 }); -var label = new ex.Label("Test Label", 50, 50); +var label = new ex.Label("This font should be white 20px consolas", 50, 50); /*label.onInitialize = function() { label.color = ex.Color.White; }*/ label.color = ex.Color.White; -label.font = '20pt Consolas'; +label.fontFamily = 'Consolas'; +label.fontUnit = ex.FontUnit.Px; +label.fontSize = 20; +var label2 = new ex.Label("Should be azure 20px Tahoma", 20, 150, "12px Arial"); +label2.fontFamily = "Tahoma"; +label2.fontUnit = ex.FontUnit.Px; +label2.fontSize = 20; +label2.color = ex.Color.Azure; engine.add(label); +engine.add(label2); engine.start(); -//# sourceMappingURL=label.js.map \ No newline at end of file diff --git a/sandbox/web/tests/label/label.ts b/sandbox/web/tests/label/label.ts index 672f97a7b..7261a33db 100644 --- a/sandbox/web/tests/label/label.ts +++ b/sandbox/web/tests/label/label.ts @@ -5,13 +5,22 @@ }); -var label = new ex.Label("Test Label", 50, 50); +var label = new ex.Label("This font should be white 20px consolas", 50, 50); /*label.onInitialize = function() { label.color = ex.Color.White; }*/ label.color = ex.Color.White; -label.font = '20pt Consolas'; +label.fontFamily = 'Consolas'; +label.fontUnit = ex.FontUnit.Px +label.fontSize = 20; + +var label2 = new ex.Label("Should be azure 20px Tahoma", 20, 150, "12px Arial"); +label2.fontFamily = "Tahoma"; +label2.fontUnit = ex.FontUnit.Px; +label2.fontSize = 20; +label2.color = ex.Color.Azure; engine.add(label); +engine.add(label2); engine.start(); \ No newline at end of file diff --git a/sandbox/web/tests/rotation/rotation.js b/sandbox/web/tests/rotation/rotation.js index c1384d4ed..cca0e1ea7 100644 --- a/sandbox/web/tests/rotation/rotation.js +++ b/sandbox/web/tests/rotation/rotation.js @@ -2,20 +2,80 @@ var width = 600; var height = 400; var playerTexture = new ex.Texture("rotation-sprite.png"); var speed = 100; -var engine = new ex.Engine(width, height, 'game'); +var rotationType = ex.RotationType.ShortestPath; +var engine = new ex.Engine({ + width: width, + height: height, + canvasElementId: 'game', + pointerScope: ex.Input.PointerScope.Canvas +}); engine.backgroundColor = ex.Color.Black; -var player = new ex.Actor(width / 2, height / 2, 30, 100, ex.Color.Red); +var labelCurrentRotation = new ex.Label(rotationType.toString(), 500, 100); +labelCurrentRotation.color = ex.Color.White; +labelCurrentRotation.textAlign = ex.TextAlign.Center; +labelCurrentRotation.scale = new ex.Vector(2, 2); +engine.add(labelCurrentRotation); +engine.on('update', function (ev) { + labelCurrentRotation.text = ex.RotationType[rotationType]; +}); +var player = new ex.Actor(width / 2, height / 2, 100, 30, ex.Color.Red); var playerSprite = playerTexture.asSprite(); player.addDrawing("default", playerSprite); engine.currentScene.add(player); -//player.rotateTo() +// rotation type buttons +var shortestPath = new ex.Actor(50, 50, 50, 50, ex.Color.White); +shortestPath.on('pointerdown', function (e) { + rotationType = ex.RotationType.ShortestPath; +}); +engine.add(shortestPath); +var labelShortestPath = new ex.Label("Shortest Path", shortestPath.x, 100); +labelShortestPath.color = ex.Color.White; +labelShortestPath.textAlign = ex.TextAlign.Center; +engine.add(labelShortestPath); +var longestPath = new ex.Actor(150, 50, 50, 50, ex.Color.White); +longestPath.on('pointerdown', function (e) { + rotationType = ex.RotationType.LongestPath; +}); +engine.add(longestPath); +var labelLongestPath = new ex.Label("Longest Path", longestPath.x, 100); +labelLongestPath.color = ex.Color.White; +labelLongestPath.textAlign = ex.TextAlign.Center; +engine.add(labelLongestPath); +var clockwise = new ex.Actor(250, 50, 50, 50, ex.Color.White); +clockwise.on('pointerdown', function (e) { + rotationType = ex.RotationType.Clockwise; +}); +engine.add(clockwise); +var labelClockwise = new ex.Label("Clockwise", clockwise.x, 100); +labelClockwise.color = ex.Color.White; +labelClockwise.textAlign = ex.TextAlign.Center; +engine.add(labelClockwise); +var counterclockwise = new ex.Actor(350, 50, 50, 50, ex.Color.White); +counterclockwise.on('pointerdown', function (e) { + rotationType = ex.RotationType.CounterClockwise; +}); +engine.add(counterclockwise); +var labelCounterClockwise = new ex.Label("CounterClockwise", counterclockwise.x, 100); +labelCounterClockwise.color = ex.Color.White; +labelCounterClockwise.textAlign = ex.TextAlign.Center; +engine.add(labelCounterClockwise); +engine.input.pointers.primary.on('down', function (e) { + if (!shortestPath.contains(e.x, e.y) && + !longestPath.contains(e.x, e.y) && + !clockwise.contains(e.x, e.y) && + !counterclockwise.contains(e.x, e.y)) { + var vector = new ex.Vector(e.x - player.x, e.y - player.y); + var angle = vector.toAngle(); + player.rotateTo(angle, 1, rotationType); + } +}); +function distance(x1, y1, x2, y2) { + return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)); +} engine.input.keyboard.on('down', function (keyDown) { - if (keyDown.key === 68 /* D */) { + if (keyDown.key === ex.Input.Keys.D) { engine.isDebug = !engine.isDebug; } }); -engine.input.keyboard.on('up', function (keyUp) { -}); engine.start(new ex.Loader([playerTexture])).then(function () { }); -//# sourceMappingURL=rotation.js.map \ No newline at end of file diff --git a/sandbox/web/tests/scene/lifecycle.js b/sandbox/web/tests/scene/lifecycle.js index de012e0f3..292a08d23 100644 --- a/sandbox/web/tests/scene/lifecycle.js +++ b/sandbox/web/tests/scene/lifecycle.js @@ -1,4 +1,4 @@ -ex.Logger.getInstance().defaultLevel = 0 /* Debug */; +ex.Logger.getInstance().defaultLevel = ex.LogLevel.Debug; var game = new ex.Engine(300, 300, "game"); var scene2 = new ex.Scene(); game.add("scene2", scene2); @@ -8,4 +8,3 @@ var actor2 = new ex.Actor(60, 60, 20, 20, ex.Color.Red); scene2.add(actor2); game.start(); document.getElementById("goToScene").addEventListener("click", function () { return game.goToScene("scene2"); }); -//# sourceMappingURL=lifecycle.js.map \ No newline at end of file diff --git a/sandbox/web/tests/zoom/zoom.js b/sandbox/web/tests/zoom/zoom.js index aa690b86e..067b142c8 100644 --- a/sandbox/web/tests/zoom/zoom.js +++ b/sandbox/web/tests/zoom/zoom.js @@ -24,25 +24,24 @@ target.on('pointerup', function (ev) { }); game.add(target); game.input.keyboard.on('down', function (ev) { - if (ev.key == 107) { + if (ev.key == 107 /* + */) { game.currentScene.camera.zoom(currentZoom += .03); } - if (ev.key == 109) { + if (ev.key == 109 /* - */) { game.currentScene.camera.zoom(currentZoom -= .03); } var currentFocus = game.currentScene.camera.getFocus(); - if (ev.key == 37 /* Left */) { + if (ev.key == ex.Input.Keys.Left) { game.currentScene.camera.setFocus(currentFocus.x - 10, currentFocus.y); } - if (ev.key == 39 /* Right */) { + if (ev.key == ex.Input.Keys.Right) { game.currentScene.camera.setFocus(currentFocus.x + 10, currentFocus.y); } - if (ev.key == 38 /* Up */) { + if (ev.key == ex.Input.Keys.Up) { game.currentScene.camera.setFocus(currentFocus.x, currentFocus.y - 10); } - if (ev.key == 40 /* Down */) { + if (ev.key == ex.Input.Keys.Down) { game.currentScene.camera.setFocus(currentFocus.x, currentFocus.y + 10); } }); game.start(raptorTex); -//# sourceMappingURL=zoom.js.map \ No newline at end of file diff --git a/src/engine/Camera.ts b/src/engine/Camera.ts index 287912802..1f2fa10c1 100644 --- a/src/engine/Camera.ts +++ b/src/engine/Camera.ts @@ -232,18 +232,18 @@ module ex { if (this._currentLerpTime < this._lerpDuration && this._cameraMoving) { if (this._lerpEnd.x < this._lerpStart.x) { - this.focus.x = this._lerpStart.x - (this._easeInOutCubic(this._currentLerpTime, + this.x = this._lerpStart.x - (this._easeInOutCubic(this._currentLerpTime, this._lerpEnd.x, this._lerpStart.x, this._lerpDuration) - this._lerpEnd.x); } else { - this.focus.x = this._easeInOutCubic(this._currentLerpTime, + this.x = this._easeInOutCubic(this._currentLerpTime, this._lerpStart.x, this._lerpEnd.x, this._lerpDuration); } if (this._lerpEnd.y < this._lerpStart.y) { - this.focus.y = this._lerpStart.y - (this._easeInOutCubic(this._currentLerpTime, + this.y = this._lerpStart.y - (this._easeInOutCubic(this._currentLerpTime, this._lerpEnd.y, this._lerpStart.y, this._lerpDuration) - this._lerpEnd.y); } else { - this.focus.y = this._easeInOutCubic(this._currentLerpTime, + this.y = this._easeInOutCubic(this._currentLerpTime, this._lerpStart.y, this._lerpEnd.y, this._lerpDuration); } this._currentLerpTime += delta; diff --git a/src/engine/Label.ts b/src/engine/Label.ts index f3fe4e5bd..e481af717 100644 --- a/src/engine/Label.ts +++ b/src/engine/Label.ts @@ -1,6 +1,33 @@ /// module ex { + /** + * Enum representing the different font size units + * https://developer.mozilla.org/en-US/docs/Web/CSS/font-size + */ + export enum FontUnit { + /** + * Em is a scalable unit, 1 em is equal to the current font size of the current element, parent elements can effect em values + */ + Em, + /** + * Rem is similar to the Em, it is a scalable unit. 1 rem is eqaul to the font size of the root element + */ + Rem, + /** + * Pixel is a unit of length in screen pixels + */ + Px, + /** + * Point is a physical unit length (1/72 of an inch) + */ + Pt, + /** + * Percent is a scalable unit similar to Em, the only difference is the Em units scale faster when Text-Size stuff + */ + Percent + } + /** * Enum representing the different horizontal text alignments */ @@ -89,7 +116,9 @@ module ex { * var label = new ex.Label(); * label.x = 50; * label.y = 50; - * label.font = "10px Arial"; + * label.fontFamily = "Arial"; + * label.fontSize = 10; + * lable.fontUnit = ex.FontUnit.Px // pixels are the default * label.text = "Foo"; * label.color = ex.Color.White; * label.textAlign = ex.TextAlign.Center; @@ -130,7 +159,8 @@ module ex { * var game = new ex.Engine(); * * var label = new ex.Label(); - * label.font = "12px Foobar, Arial, Sans-Serif"; + * label.fontFamily = "Foobar, Arial, Sans-Serif"; + * label.fontSize = 10; * label.text = "Hello World"; * * game.add(label); @@ -161,16 +191,21 @@ module ex { public spriteFont: SpriteFont; /** - * The CSS font string (e.g. `sans-serif`, `Droid Sans Pro`). Web fonts + * The CSS font family string (e.g. `sans-serif`, `Droid Sans Pro`). Web fonts * are supported, same as in CSS. */ - public font: string; + public fontFamily: string; /** - * The font size in pixels, default is 10px + * The font size in the selected units, default is 10 (default units is pixel) */ public fontSize: number = 10; + /** + * The css units for a font size such as px, pt, em (SpriteFont only support px), by default is 'px'; + */ + public fontUnit: FontUnit = FontUnit.Px; + /** * Gets or sets the horizontal text alignment property for the label. */ @@ -215,13 +250,13 @@ module ex { * @param spriteFont Use an Excalibur sprite font for the label's font, if a SpriteFont is provided it will take precendence * over a css font. */ - constructor(text?: string, x?: number, y?: number, font?: string, spriteFont?: SpriteFont) { + constructor(text?: string, x?: number, y?: number, fontFamily?: string, spriteFont?: SpriteFont) { super(x, y); this.text = text || ''; this.color = Color.Black.clone(); this.spriteFont = spriteFont; this.collisionType = CollisionType.PreventCollision; - this.font = font || '10px sans-serif'; // coallesce to default canvas font + this.fontFamily = fontFamily || '10px sans-serif'; // coallesce to default canvas font if (spriteFont) { //this._textSprites = spriteFont.getTextSprites(); } @@ -234,13 +269,30 @@ module ex { */ public getTextWidth(ctx: CanvasRenderingContext2D): number { var oldFont = ctx.font; - ctx.font = this.font; + ctx.font = this.fontFamily; var width = ctx.measureText(this.text).width; ctx.font = oldFont; return width; } // TypeScript doesn't support string enums :( + private _lookupFontUnit(fontUnit: FontUnit): string { + switch (fontUnit) { + case FontUnit.Em: + return 'em'; + case FontUnit.Rem: + return 'rem'; + case FontUnit.Pt: + return 'pt'; + case FontUnit.Px: + return 'px'; + case FontUnit.Percent: + return '%'; + default: + return 'px'; + } + } + private _lookupTextAlign(textAlign: TextAlign): string { switch (textAlign) { case TextAlign.Left: @@ -368,7 +420,7 @@ module ex { this.color.a = this.opacity; } ctx.fillStyle = this.color.toString(); - ctx.font = `${this.fontSize} ${this.font}`; + ctx.font = `${this.fontSize}${this._lookupFontUnit(this.fontUnit)} ${this.fontFamily}`; if (this.maxWidth) { ctx.fillText(this.text, 0, 0, this.maxWidth); } else {