diff --git a/src/controls/controls.js b/src/controls/controls.js index 7a5f2af5..1a3f59d1 100644 --- a/src/controls/controls.js +++ b/src/controls/controls.js @@ -1009,67 +1009,68 @@ Crafty.c("Keyboard", { /**@ * #Multiway * @category Input - * Used to bind keys to directions and have the entity move accordingly - * @trigger NewDirection - triggered when direction changes - { x:Number, y:Number } - New direction - * @trigger Moved - triggered on movement on either x or y axis. If the entity has moved on both axes for diagonal movement the event is triggered twice - { x:Number, y:Number } - Old position + * @trigger NewDirection - When entity has changed direction due to velocity on either x or y axis a NewDirection event is triggered. The event is triggered once, if direction is different from last frame. - { x: -1 | 0 | 1, y: -1 | 0 | 1 } - New direction + * @trigger Moved - When entity has moved due to velocity/acceleration on either x or y axis a Moved event is triggered. If the entity has moved on both axes for diagonal movement the event is triggered twice. - { axis: 'x' | 'y', oldValue: Number } - Old position + * + * Used to bind keys to directions and have the entity move accordingly. + * + * @see Motion */ Crafty.c("Multiway", { _speed: 3, - _keydown: function (e) { - if (this._keys[e.key] && !this.disableControls) { - this._movement.x = Math.round((this._movement.x + this._keys[e.key].x) * 1000) / 1000; - this._movement.y = Math.round((this._movement.y + this._keys[e.key].y) * 1000) / 1000; - this.trigger('NewDirection', this._movement); - } - }, + init: function () { + this.requires("Motion"); - _keyup: function (e) { - if (this._keys[e.key] && !this.disableControls) { - this._movement.x = Math.round((this._movement.x - this._keys[e.key].x) * 1000) / 1000; - this._movement.y = Math.round((this._movement.y - this._keys[e.key].y) * 1000) / 1000; - this.trigger('NewDirection', this._movement); - } + this._keyDirection = {}; // keyCode -> direction + this._activeDirections = {}; // direction -> # of keys pressed for that direction + this._directionSpeed = {}; // direction -> {x: x_speed, y: y_speed} + this._speed = { x: 3, y: 3 }; + + this.bind("KeyDown", this._keydown) + .bind("KeyUp", this._keyup); }, - _enterframe: function () { - if (this.disableControls) return; + remove: function() { + this.unbind("KeyDown", this._keydown) + .unbind("KeyUp", this._keyup); - if (this._movement.x !== 0) { - this.x += this._movement.x; - this.trigger('Moved', { - x: this.x - this._movement.x, - y: this.y - }); - } - if (this._movement.y !== 0) { - this.y += this._movement.y; - this.trigger('Moved', { - x: this.x, - y: this.y - this._movement.y - }); + // unapply movement of pressed keys + this.__unapplyActiveDirections(); + }, + + _keydown: function (e) { + var direction = this._keyDirection[e.key]; + if (direction !== undefined) { // if this is a key we are interested in + if (this._activeDirections[direction] === 0 && !this.disableControls) { // if key is first one pressed for this direction + this.vx += this._directionSpeed[direction].x; + this.vy += this._directionSpeed[direction].y; + } + this._activeDirections[direction]++; } }, - _initializeControl: function () { - return this.unbind("KeyDown", this._keydown) - .unbind("KeyUp", this._keyup) - .unbind("EnterFrame", this._enterframe) - .bind("KeyDown", this._keydown) - .bind("KeyUp", this._keyup) - .bind("EnterFrame", this._enterframe); + _keyup: function (e) { + var direction = this._keyDirection[e.key]; + if (direction !== undefined) { // if this is a key we are interested in + this._activeDirections[direction]--; + if (this._activeDirections[direction] === 0 && !this.disableControls) { // if key is last one unpressed for this direction + this.vx -= this._directionSpeed[direction].x; + this.vy -= this._directionSpeed[direction].y; + } + } }, + /**@ * #.multiway * @comp Multiway * @sign public this .multiway([Number speed,] Object keyBindings ) * @param speed - Amount of pixels to move the entity whilst a key is down * @param keyBindings - What keys should make the entity go in which direction. Direction is specified in degrees - * Constructor to initialize the speed and keyBindings. Component will listen to key events and move the entity appropriately. * - * When direction changes a NewDirection event is triggered with an object detailing the new direction: {x: x_movement, y: y_movement} - * When entity has moved on either x- or y-axis a Moved event is triggered with an object specifying the old position {x: old_x, y: old_y} + * Constructor to initialize the speed and keyBindings. Component will listen to key events and move the entity appropriately. + * Can be called while a key is pressed to change direction & speed on the fly. * * @example * ~~~ @@ -1077,19 +1078,10 @@ Crafty.c("Multiway", { * this.multiway({x:3,y:1.5}, {UP_ARROW: -90, DOWN_ARROW: 90, RIGHT_ARROW: 0, LEFT_ARROW: 180}); * this.multiway({W: -90, S: 90, D: 0, A: 180}); * ~~~ + * + * @see Motion */ multiway: function (speed, keys) { - this._keyDirection = {}; - this._keys = {}; - this._movement = { - x: 0, - y: 0 - }; - this._speed = { - x: 3, - y: 3 - }; - if (keys) { if (speed.x !== undefined && speed.y !== undefined) { this._speed.x = speed.x; @@ -1102,21 +1094,95 @@ Crafty.c("Multiway", { keys = speed; } - this._keyDirection = keys; - this.speed(this._speed); - this._initializeControl(); + if (!this.disableControls) { + this.__unapplyActiveDirections(); + } + + this._updateKeys(keys); + this._updateSpeed(this._speed); + + if (!this.disableControls) { + this.__applyActiveDirections(); + } + + return this; + }, + + /**@ + * #.speed + * @comp Multiway + * @sign public this .speed(Object speed) + * @param speed - New speed the entity has, for x and y axis. + * + * Change the speed that the entity moves with. + * Can be called while a key is pressed to change speed on the fly. + * + * @example + * ~~~ + * this.speed({ x: 3, y: 1 }); + * ~~~ + */ + speed: function (speed) { + if (!this.disableControls) { + this.__unapplyActiveDirections(); + } + + this._updateSpeed(speed); + + if (!this.disableControls) { + this.__applyActiveDirections(); + } + + return this; + }, + + _updateKeys: function(keys) { + // reset data + this._keyDirection = {}; + this._activeDirections = {}; - //Apply movement if key is down when created for (var k in keys) { - if (Crafty.keydown[Crafty.keys[k]]) { - this.trigger("KeyDown", { - key: Crafty.keys[k] - }); + var keyCode = Crafty.keys[k] || k; + // add new data + var direction = this._keyDirection[keyCode] = keys[k]; + this._activeDirections[direction] = this._activeDirections[direction] || 0; + if (Crafty.keydown[keyCode]) // add directions of already pressed keys + this._activeDirections[direction]++; + } + }, + + _updateSpeed: function(speed) { + // reset data + this._directionSpeed = {}; + + var direction; + for (var keyCode in this._keyDirection) { + direction = this._keyDirection[keyCode]; + // add new data + this._directionSpeed[direction] = { + x: this.__convertPixelsToMeters(Math.round(Math.cos(direction * (Math.PI / 180)) * 1000 * speed.x) / 1000), + y: this.__convertPixelsToMeters(Math.round(Math.sin(direction * (Math.PI / 180)) * 1000 * speed.y) / 1000) + }; + } + }, + + __applyActiveDirections: function() { + for (var direction in this._activeDirections) { + if (this._activeDirections[direction] > 0) { + this.vx += this._directionSpeed[direction].x; + this.vy += this._directionSpeed[direction].y; } } + }, - return this; + __unapplyActiveDirections: function() { + for (var direction in this._activeDirections) { + if (this._activeDirections[direction] > 0) { + this.vx -= this._directionSpeed[direction].x; + this.vy -= this._directionSpeed[direction].y; + } + } }, /**@ @@ -1132,7 +1198,11 @@ Crafty.c("Multiway", { * ~~~ */ enableControl: function () { + if (this.disableControls) { + this.__applyActiveDirections(); + } this.disableControls = false; + return this; }, @@ -1150,33 +1220,11 @@ Crafty.c("Multiway", { */ disableControl: function () { - this._movement.x = 0; - this._movement.y = 0; + if (!this.disableControls) { + this.__unapplyActiveDirections(); + } this.disableControls = true; - return this; - }, - /**@ - * #.speed - * @comp Multiway - * @sign public this .speed(Object speed) - * @param speed - New speed the entity has, for x and y axis. - * - * Change the speed that the entity moves with. - * - * @example - * ~~~ - * this.speed({ x: 3, y: 1 }); - * ~~~ - */ - speed: function (speed) { - for (var k in this._keyDirection) { - var keyCode = Crafty.keys[k] || k; - this._keys[keyCode] = { - x: Math.round(Math.cos(this._keyDirection[k] * (Math.PI / 180)) * 1000 * speed.x) / 1000, - y: Math.round(Math.sin(this._keyDirection[k] * (Math.PI / 180)) * 1000 * speed.y) / 1000 - }; - } return this; } }); @@ -1184,8 +1232,13 @@ Crafty.c("Multiway", { /**@ * #Fourway * @category Input + * @trigger NewDirection - When entity has changed direction due to velocity on either x or y axis a NewDirection event is triggered. The event is triggered once, if direction is different from last frame. - { x: -1 | 0 | 1, y: -1 | 0 | 1 } - New direction + * @trigger Moved - When entity has moved due to velocity/acceleration on either x or y axis a Moved event is triggered. If the entity has moved on both axes for diagonal movement the event is triggered twice. - { axis: 'x' | 'y', oldValue: Number } - Old position + * * Move an entity in four directions by using the * arrow keys or `W`, `A`, `S`, `D`. + * + * @see Multiway, Motion */ Crafty.c("Fourway", { @@ -1198,15 +1251,13 @@ Crafty.c("Fourway", { * @comp Fourway * @sign public this .fourway(Number speed) * @param speed - Amount of pixels to move the entity whilst a key is down + * * Constructor to initialize the speed. Component will listen for key events and move the entity appropriately. * This includes `Up Arrow`, `Right Arrow`, `Down Arrow`, `Left Arrow` as well as `W`, `A`, `S`, `D`. * - * When direction changes a NewDirection event is triggered with an object detailing the new direction: {x: x_movement, y: y_movement} - * When entity has moved on either x- or y-axis a Moved event is triggered with an object specifying the old position {x: old_x, y: old_y} - * * The key presses will move the entity in that direction by the speed passed in the argument. * - * @see Multiway + * @see Multiway, Motion */ fourway: function (speed) { this.multiway(speed, { @@ -1229,11 +1280,13 @@ Crafty.c("Fourway", { /**@ * #Twoway * @category Input - * @trigger NewDirection - When direction changes a NewDirection event is triggered with an object detailing the new direction: {x: x_movement, y: y_movement}. This is consistent with Fourway and Multiway components. - * @trigger Moved - triggered on movement on either x or y axis. If the entity has moved on both axes for diagonal movement the event is triggered twice - { x:Number, y:Number } - Old position + * @trigger NewDirection - When entity has changed direction due to velocity on either x or y axis a NewDirection event is triggered. The event is triggered once, if direction is different from last frame. - { x: -1 | 0 | 1, y: -1 | 0 | 1 } - New direction + * @trigger Moved - When entity has moved due to velocity/acceleration on either x or y axis a Moved event is triggered. If the entity has moved on both axes for diagonal movement the event is triggered twice. - { axis: 'x' | 'y', oldValue: Number } - Old position * @trigger CheckJumping - When entity is about to jump. This event is triggered with the object the entity is about to jump from (if it exists). Third parties can respond to this event and enable the entity to jump. * * Move an entity left or right using the arrow keys or `D` and `A` and jump using up arrow or `W`. + * + * @see Gravity, Multiway, Fourway, Motion */ Crafty.c("Twoway", { _speed: 3, @@ -1241,7 +1294,7 @@ Crafty.c("Twoway", { * #.canJump * @comp Twoway * - * The canJump function determines if the entity is allowed to jump or not (e.g. perhaps the entity should not jump if it's already falling). + * The canJump function determines if the entity is allowed to jump or not (e.g. perhaps the entity should be able to double jump). * The Twoway component will trigger a "CheckJumping" event. * Interested parties can listen to this event and enable the entity to jump by setting `canJump` to true. * @@ -1277,7 +1330,7 @@ Crafty.c("Twoway", { * The key presses will move the entity in that direction by the speed passed in * the argument. Pressing the `Up Arrow` or `W` will cause the entity to jump. * - * @see Gravity, Fourway, Motion + * @see Gravity, Multiway, Fourway, Motion */ twoway: function (speed, jump) { @@ -1304,7 +1357,7 @@ Crafty.c("Twoway", { this.canJump = !!ground; this.trigger("CheckJumping", ground); if (this.canJump) { - this.vy = -this._jumpSpeed; // Motion component will trigger Move events + this.vy = -this._jumpSpeed; } } }); diff --git a/src/spatial/2d.js b/src/spatial/2d.js index d43e1c84..b18080a4 100644 --- a/src/spatial/2d.js +++ b/src/spatial/2d.js @@ -1093,11 +1093,12 @@ Crafty.c("GroundAttacher", { /**@ * #Gravity * @category 2D - * @trigger Moved - triggered on movement on either x or y axis. If the entity has moved on both axes for diagonal movement the event is triggered twice - { x:Number, y:Number } - Old position + * @trigger Moved - When entity has moved due to velocity/acceleration on either x or y axis a Moved event is triggered. If the entity has moved on both axes for diagonal movement the event is triggered twice. - { axis: 'x' | 'y', oldValue: Number } - Old position + * @trigger NewDirection - When entity has changed direction due to velocity on either x or y axis a NewDirection event is triggered. The event is triggered once, if direction is different from last frame. - { x: -1 | 0 | 1, y: -1 | 0 | 1 } - New direction * * Adds gravitational pull to the entity. * - * @see Motion + * @see Supportable, Motion */ Crafty.c("Gravity", { init: function () { @@ -1123,7 +1124,7 @@ Crafty.c("Gravity", { * @sign public this .gravity([comp]) * @param comp - The name of a component that will stop this entity from falling * - * Enable gravity for this entity no matter whether comp parameter is not specified, + * Enable gravity for this entity no matter whether comp parameter is specified or not. * If comp parameter is specified all entities with that component will stop this entity from falling. * For a player entity in a platform game this would be a component that is added to all entities * that the player should be able to walk on. @@ -1136,7 +1137,8 @@ Crafty.c("Gravity", { * .attr({ w: 100, h: 100 }) * .gravity("platform"); * ~~~ - * @see Supportable + * + * @see Supportable, Motion */ gravity: function (comp) { this.bind("CheckLanding", this._gravityCheckLanding); @@ -1195,11 +1197,12 @@ Crafty.c("Gravity", { } }); + var __motionProp = function(self, prefix, prop, setter) { var publicProp = prefix + prop; var privateProp = "_" + publicProp; - var motionEvent = { key: "", value: 0}; + var motionEvent = { key: "", oldValue: 0}; // getters & setters for public property if (setter) { Crafty.defineField(self, publicProp, function() { return this[privateProp]; }, function(newValue) { @@ -1208,7 +1211,7 @@ var __motionProp = function(self, prefix, prop, setter) { this[privateProp] = newValue; motionEvent.key = publicProp; - motionEvent.value = oldValue; + motionEvent.oldValue = oldValue; this.trigger("MotionChange", motionEvent); } }); @@ -1247,7 +1250,8 @@ var __motionVector = function(self, prefix, setter, vector) { * #AngularMotion * @category 2D * @trigger Rotated - When entity has rotated due to angular velocity/acceleration a Rotated event is triggered. - Number - Old rotation - * @trigger MotionChange - when a motion property has changed - { key: String propertyName, value: Number oldPropertyValue } + * @trigger NewRevolution - When entity has changed rotational direction due to rotational velocity a NewRevolution event is triggered. The event is triggered once, if direction is different from last frame. - -1 | 0 | 1 - New direction + * @trigger MotionChange - When a motion property has changed a MotionChange event is triggered. - { key: String, oldValue: Number } - Motion property name and old value * * Component that allows rotating an entity by applying angular velocity and acceleration. */ @@ -1310,6 +1314,8 @@ Crafty.c("AngularMotion", { __motionProp(this, "a", "rotation", true); __motionProp(this, "d", "rotation", false); + this.__oldRevolution = 0; + this.bind("EnterFrame", this._angularMotionTick); }, remove: function(destroyed) { @@ -1339,17 +1345,27 @@ Crafty.c("AngularMotion", { _angularMotionTick: function(frameData) { var dt = frameData.dt/1000; - var oldRotation = this._rotation; + var _vr = this._vrotation, + dvr = _vr >> 31 | -_vr >>> 31; // Math.sign(this._vrotation) + if (this.__oldRevolution !== dvr) { + this.__oldRevolution = dvr; + this.trigger('NewRevolution', dvr); + } + + var oldR = this._rotation, + vr = this._vrotation, + ar = this._arotation; + // s += v * Δt + (0.5 * a) * Δt * Δt - var newRotation = oldRotation + this._vrotation * dt + 0.5 * this._arotation * dt * dt; + var newR = oldR + vr * dt + 0.5 * ar * dt * dt; // v += a * Δt - this.vrotation = this._vrotation + this._arotation * dt; + this.vrotation = vr + ar * dt; // Δs = s[t] - s[t-1] - this._drotation = newRotation - oldRotation; + this._drotation = newR - oldR; if (this._drotation !== 0) { - this.rotation = newRotation; - this.trigger('Rotated', oldRotation); + this.rotation = newR; + this.trigger('Rotated', oldR); } } }); @@ -1357,8 +1373,9 @@ Crafty.c("AngularMotion", { /**@ * #Motion * @category 2D - * @trigger Moved - When entity has moved due to velocity/acceleration on either x or y axis a Moved event is triggered. If the entity has moved on both axes for diagonal movement the event is triggered twice. - { x:Number, y:Number } - Old position - * @trigger MotionChange - when a motion property has changed - { key: String propertyName, value: Number oldPropertyValue } + * @trigger Moved - When entity has moved due to velocity/acceleration on either x or y axis a Moved event is triggered. If the entity has moved on both axes for diagonal movement the event is triggered twice. - { axis: 'x' | 'y', oldValue: Number } - Old position + * @trigger NewDirection - When entity has changed direction due to velocity on either x or y axis a NewDirection event is triggered. The event is triggered once, if direction is different from last frame. - { x: -1 | 0 | 1, y: -1 | 0 | 1 } - New direction + * @trigger MotionChange - When a motion property has changed a MotionChange event is triggered. - { key: String, oldValue: Number } - Motion property name and old value * * Component that allows moving an entity by applying linear velocity and acceleration. */ @@ -1485,6 +1502,10 @@ Crafty.c("Motion", { __motionProp(this, "d", "y", false); this._motionDelta = __motionVector(this, "d", false, new Crafty.math.Vector2D()); + this.__movedEvent = {axis: '', oldValue: 0}; + this.__directionEvent = {x: 0, y: 0}; + this.__oldDirection = {x: 0, y: 0}; + this.bind("EnterFrame", this._linearMotionTick); }, remove: function(destroyed) { @@ -1585,25 +1606,41 @@ Crafty.c("Motion", { _linearMotionTick: function(frameData) { var dt = frameData.dt/1000; - var oldX = this._x; - var oldY = this._y; + var oldDirection = this.__oldDirection; + var _vx = this._vx, dvx = _vx >> 31 | -_vx >>> 31, // Math.sign(this._vx) + _vy = this._vy, dvy = _vy >> 31 | -_vy >>> 31; // Math.sign(this._vy) + if (oldDirection.x !== dvx || oldDirection.y !== dvy) { + var directionEvent = this.__directionEvent; + directionEvent.x = oldDirection.x = dvx; + directionEvent.y = oldDirection.y = dvy; + this.trigger('NewDirection', directionEvent); + } + + var oldX = this._x, vx = this._vx, ax = this._ax, + oldY = this._y, vy = this._vy, ay = this._ay; + // s += v * Δt + (0.5 * a) * Δt * Δt - var newX = oldX + this._vx * dt + 0.5 * this._ax * dt * dt; - var newY = oldY + this._vy * dt + 0.5 * this._ay * dt * dt; + var newX = oldX + vx * dt + 0.5 * ax * dt * dt; + var newY = oldY + vy * dt + 0.5 * ay * dt * dt; // v += a * Δt - this.vx = this._vx + this._ax * dt; - this.vy = this._vy + this._ay * dt; + this.vx = vx + ax * dt; + this.vy = vy + ay * dt; // Δs = s[t] - s[t-1] this._dx = newX - oldX; this._dy = newY - oldY; + var movedEvent = this.__movedEvent; if (this._dx !== 0) { this.x = newX; - this.trigger('Moved', {x: oldX, y: newY}); + movedEvent.axis = 'x'; + movedEvent.oldValue = oldX; + this.trigger('Moved', movedEvent); } if (this._dy !== 0) { this.y = newY; - this.trigger('Moved', {x: newX, y: oldY}); + movedEvent.axis = 'y'; + movedEvent.oldValue = oldY; + this.trigger('Moved', movedEvent); } } }); diff --git a/tests/2d.js b/tests/2d.js index 4264d0f4..e7ebdbc9 100644 --- a/tests/2d.js +++ b/tests/2d.js @@ -304,53 +304,195 @@ }); + test("Multiway", function() { + var e = Crafty.e("2D, Fourway") + .attr({ x: 0, y: 0}); - test("disableControl and enableControl", function() { + Crafty.trigger('KeyDown', { + key: Crafty.keys.W + }); + Crafty.keydown[Crafty.keys.W] = true; + e.multiway(1, { W: -90 }); + Crafty.trigger('EnterFrame', {dt: 1000}); + equal(e._vy, e.__convertPixelsToMeters(-1)); + equal(e._y, e.__convertPixelsToMeters(-1)); + + e.multiway(2, { W: 90 }); + Crafty.trigger('EnterFrame', {dt: 1000}); + equal(e._vy, e.__convertPixelsToMeters(2)); + equal(e._y, e.__convertPixelsToMeters(1)); + + e.fourway(1); + Crafty.trigger('EnterFrame', {dt: 1000}); + equal(e._vy, e.__convertPixelsToMeters(-1)); + equal(e._y, e.__convertPixelsToMeters(0)); + + Crafty.trigger('EnterFrame', {dt: 1000}); + equal(e._vy, e.__convertPixelsToMeters(-1)); + equal(e._y, e.__convertPixelsToMeters(-1)); + + + Crafty.trigger('KeyDown', { + key: Crafty.keys.UP_ARROW + }); + Crafty.trigger('EnterFrame', {dt: 1000}); + equal(e._vy, e.__convertPixelsToMeters(-1)); + equal(e._y, e.__convertPixelsToMeters(-2)); + + Crafty.trigger('KeyUp', { + key: Crafty.keys.W + }); + delete Crafty.keydown[Crafty.keys.W]; + Crafty.trigger('KeyUp', { + key: Crafty.keys.UP_ARROW + }); + Crafty.trigger('EnterFrame', {dt: 1000}); + equal(e._vy, e.__convertPixelsToMeters(0)); + equal(e._y, e.__convertPixelsToMeters(-2)); + + + Crafty.trigger('KeyDown', { + key: Crafty.keys.DOWN_ARROW + }); + Crafty.trigger('KeyDown', { + key: Crafty.keys.LEFT_ARROW + }); + Crafty.trigger('EnterFrame', {dt: 1000}); + equal(e._vy, e.__convertPixelsToMeters(1)); + equal(e._y, e.__convertPixelsToMeters(-1)); + equal(e._vx, e.__convertPixelsToMeters(-1)); + equal(e._x, e.__convertPixelsToMeters(-1)); + + Crafty.trigger('KeyUp', { + key: Crafty.keys.DOWN_ARROW + }); + Crafty.trigger('EnterFrame', {dt: 1000}); + equal(e._vy, e.__convertPixelsToMeters(0)); + equal(e._y, e.__convertPixelsToMeters(-1)); + equal(e._vx, e.__convertPixelsToMeters(-1)); + equal(e._x, e.__convertPixelsToMeters(-2)); + + e.removeComponent("Multiway"); + Crafty.trigger('EnterFrame', {dt: 1000}); + equal(e._vy, e.__convertPixelsToMeters(0)); + equal(e._y, e.__convertPixelsToMeters(-1)); + equal(e._vx, e.__convertPixelsToMeters(0)); + equal(e._x, e.__convertPixelsToMeters(-2)); + + Crafty.trigger('KeyUp', { + key: Crafty.keys.LEFT_ARROW + }); + Crafty.trigger('EnterFrame', {dt: 1000}); + equal(e._vy, e.__convertPixelsToMeters(0)); + equal(e._y, e.__convertPixelsToMeters(-1)); + equal(e._vx, e.__convertPixelsToMeters(0)); + equal(e._x, e.__convertPixelsToMeters(-2)); + + + e.destroy(); + }); + + test("disableControl and enableControl and speed", function() { var e = Crafty.e("2D, Twoway") .attr({ x: 0 }) - .twoway(1); + .twoway(2); + + equal(e._vx, e.__convertPixelsToMeters(0)); + equal(e._x, e.__convertPixelsToMeters(0)); + + e.enableControl(); + e.speed({ x: 1, y: 1 }); + Crafty.trigger('EnterFrame', {dt: 1000}); + equal(e._vx, e.__convertPixelsToMeters(0)); + equal(e._x, e.__convertPixelsToMeters(0)); - equal(e._movement.x, 0); - equal(e._x, 0); Crafty.trigger('KeyDown', { key: Crafty.keys.D }); Crafty.trigger('EnterFrame', {dt: 1000}); - equal(e._movement.x, 1); - equal(e._x, 1); + equal(e._vx, e.__convertPixelsToMeters(1)); + equal(e._x, e.__convertPixelsToMeters(1)); e.disableControl(); Crafty.trigger('EnterFrame', {dt: 1000}); - equal(e._movement.x, 0); - equal(e._x, 1); + equal(e._vx, e.__convertPixelsToMeters(0)); + equal(e._x, e.__convertPixelsToMeters(1)); Crafty.trigger('KeyUp', { key: Crafty.keys.D }); Crafty.trigger('EnterFrame', {dt: 1000}); - equal(e._movement.x, 0); - equal(e._x, 1); + equal(e._vx, e.__convertPixelsToMeters(0)); + equal(e._x, e.__convertPixelsToMeters(1)); + + e.disableControl(); + Crafty.trigger('EnterFrame', {dt: 1000}); + equal(e._vx, e.__convertPixelsToMeters(0)); + equal(e._x, e.__convertPixelsToMeters(1)); + e.enableControl(); Crafty.trigger('EnterFrame', {dt: 1000}); - equal(e._movement.x, 0); - equal(e._x, 1); + equal(e._vx, e.__convertPixelsToMeters(0)); + equal(e._x, e.__convertPixelsToMeters(1)); + + Crafty.trigger('KeyDown', { + key: Crafty.keys.D + }); + Crafty.trigger('EnterFrame', {dt: 1000}); + equal(e._vx, e.__convertPixelsToMeters(1)); + equal(e._x, e.__convertPixelsToMeters(2)); + + Crafty.trigger('KeyUp', { + key: Crafty.keys.D + }); + Crafty.trigger('EnterFrame', {dt: 1000}); + equal(e._vx, e.__convertPixelsToMeters(0)); + equal(e._x, e.__convertPixelsToMeters(2)); + Crafty.trigger('KeyDown', { key: Crafty.keys.D }); + Crafty.trigger('KeyDown', { + key: Crafty.keys.RIGHT_ARROW + }); + Crafty.trigger('EnterFrame', {dt: 1000}); + equal(e._vx, e.__convertPixelsToMeters(1)); + equal(e._x, e.__convertPixelsToMeters(3)); + + e.disableControl(); + e.speed({ x: 2, y: 2 }); Crafty.trigger('EnterFrame', {dt: 1000}); - equal(e._movement.x, 1); - equal(e._x, 2); + equal(e._vx, e.__convertPixelsToMeters(0)); + equal(e._x, e.__convertPixelsToMeters(3)); + + e.enableControl(); + Crafty.trigger('EnterFrame', {dt: 1000}); + equal(e._vx, e.__convertPixelsToMeters(2)); + equal(e._x, e.__convertPixelsToMeters(5)); + + e.speed({ x: 3, y: 3 }); + Crafty.trigger('EnterFrame', {dt: 1000}); + equal(e._vx, e.__convertPixelsToMeters(3)); + equal(e._x, e.__convertPixelsToMeters(8)); Crafty.trigger('KeyUp', { key: Crafty.keys.D }); Crafty.trigger('EnterFrame', {dt: 1000}); - equal(e._movement.x, 0); - equal(e._x, 2); + equal(e._vx, e.__convertPixelsToMeters(3)); + equal(e._x, e.__convertPixelsToMeters(11)); + + Crafty.trigger('KeyUp', { + key: Crafty.keys.RIGHT_ARROW + }); + Crafty.trigger('EnterFrame', {dt: 1000}); + equal(e._vx, e.__convertPixelsToMeters(0)); + equal(e._x, e.__convertPixelsToMeters(11)); + e.destroy(); }); @@ -586,6 +728,129 @@ ent.destroy(); }); + test("Motion - Events", function() { + var Vector2D = Crafty.math.Vector2D; + var zero = new Vector2D(); + var e = Crafty.e("2D, Motion, AngularMotion") + .attr({x: 0, y:0}); + + var newDirectionEvents = 0, + newRevolutionEvents = 0, + movedEvents = 0, + motionEvents = 0; + e.bind("NewDirection", function(evt) { + newDirectionEvents++; + }); + e.bind("NewRevolution", function(evt) { + newRevolutionEvents++; + }); + e.bind("Moved", function(evt) { + movedEvents++; + }); + e.bind("MotionChange", function(evt) { + motionEvents++; + }); + + + e.one("NewDirection", function(evt) { + equal(evt.x, 0); + equal(evt.y, 1); + }); + e.one("Moved", function(evt) { strictEqual(evt.axis, "y"); strictEqual(evt.oldValue, 0); }); + e.one("MotionChange", function(evt) { strictEqual(evt.key, "vy"); strictEqual(evt.oldValue, 0); }); + e.vy = 1; + Crafty.trigger('EnterFrame', {dt: 1000}); + + e.one("NewDirection", function(evt) { + equal(evt.x, -1); + equal(evt.y, -1); + }); + e.one("Moved", function(evt) { strictEqual(evt.axis, "x"); strictEqual(evt.oldValue, 0); + e.one("Moved", function(evt) { strictEqual(evt.axis, "y"); strictEqual(evt.oldValue, 1); });}); + e.one("MotionChange", function(evt) { strictEqual(evt.key, "vx"); strictEqual(evt.oldValue, 0); }); + e.vx = -1; + e.one("MotionChange", function(evt) { strictEqual(evt.key, "vy"); strictEqual(evt.oldValue, 1); }); + e.vy = 0; + e.one("MotionChange", function(evt) { strictEqual(evt.key, "vy"); strictEqual(evt.oldValue, 0); }); + e.vy = -1; + Crafty.trigger('EnterFrame', {dt: 1000}); + + e.one("Moved", function(evt) { strictEqual(evt.axis, "x"); strictEqual(evt.oldValue, -1); + e.one("Moved", function(evt) { strictEqual(evt.axis, "y"); strictEqual(evt.oldValue, 0); });}); + e.vx = -1; + e.one("MotionChange", function(evt) { strictEqual(evt.key, "vy"); strictEqual(evt.oldValue, -1); }); + e.vy = 0; + e.one("MotionChange", function(evt) { strictEqual(evt.key, "vy"); strictEqual(evt.oldValue, 0); }); + e.vy = -1; + Crafty.trigger('EnterFrame', {dt: 1000}); + + e.one("NewDirection", function(evt) { + equal(evt.x, 0); + equal(evt.y, -1); + }); + e.one("Moved", function(evt) { strictEqual(evt.axis, "y"); strictEqual(evt.oldValue, -1); }); + e.one("MotionChange", function(evt) { strictEqual(evt.key, "vx"); strictEqual(evt.oldValue, -1); }); + e.vx = 0; + e.one("MotionChange", function(evt) { strictEqual(evt.key, "vy"); strictEqual(evt.oldValue, -1); }); + e.vy = 0; + e.one("MotionChange", function(evt) { strictEqual(evt.key, "vy"); strictEqual(evt.oldValue, 0); }); + e.vy = -1; + Crafty.trigger('EnterFrame', {dt: 1000}); + + e.one("NewDirection", function(evt) { + equal(evt.x, 0); + equal(evt.y, 0); + evt.x = 1; // bad boy! + }); + e.one("MotionChange", function(evt) { strictEqual(evt.key, "vy"); strictEqual(evt.oldValue, -1); }); + e.vy = 0; + Crafty.trigger('EnterFrame', {dt: 1000}); + + e.vx = 0; + e.one("MotionChange", function(evt) { strictEqual(evt.key, "vy"); strictEqual(evt.oldValue, 0); }); + e.vy = 1; + e.one("MotionChange", function(evt) { strictEqual(evt.key, "vy"); strictEqual(evt.oldValue, 1); }); + e.vy = 0; + Crafty.trigger('EnterFrame', {dt: 1000}); + + + e.vrotation = 0; + Crafty.trigger('EnterFrame', {dt: 1000}); + + e.one("MotionChange", function(evt) { strictEqual(evt.key, "vrotation"); strictEqual(evt.oldValue, 0); }); + e.vrotation = 1; + e.one("MotionChange", function(evt) { strictEqual(evt.key, "vrotation"); strictEqual(evt.oldValue, 1); }); + e.vrotation = 0; + Crafty.trigger('EnterFrame', {dt: 1000}); + + e.one("NewRevolution", function(evt) { + equal(evt, 1); + }); + e.one("MotionChange", function(evt) { strictEqual(evt.key, "vrotation"); strictEqual(evt.oldValue, 0); }); + e.vrotation = 1; + Crafty.trigger('EnterFrame', {dt: 1000}); + + e.one("NewRevolution", function(evt) { + equal(evt, -1); + }); + e.one("MotionChange", function(evt) { strictEqual(evt.key, "vrotation"); strictEqual(evt.oldValue, 1); }); + e.vrotation = -1; + Crafty.trigger('EnterFrame', {dt: 1000}); + + e.one("NewRevolution", function(evt) { + equal(evt, 0); + }); + e.one("MotionChange", function(evt) { strictEqual(evt.key, "vrotation"); strictEqual(evt.oldValue, -1); }); + e.vrotation = 0; + Crafty.trigger('EnterFrame', {dt: 1000}); + + equal(newDirectionEvents, 4); + equal(newRevolutionEvents, 3); + equal(movedEvents, 6); + equal(motionEvents, 17); + e.destroy(); + }); + test("Supportable", function() { var ground = Crafty.e("2D, Ground").attr({x: 0, y: 10, w:10, h:10}); // [0,10] to [0,20] @@ -745,6 +1010,8 @@ ground.destroy(); player.destroy(); + this.trigger("KeyUp", {key: Crafty.keys.UP_ARROW}); + this.trigger("KeyUp", {key: Crafty.keys.UP_ARROW}); start(); } });