Skip to content

Commit

Permalink
Added updateVelocity argument to Body.setPosition, Body.setAngle, Bod…
Browse files Browse the repository at this point in the history
…y.translate, Body.rotate

Added Body.setSpeed, Body.setAngularSpeed
Added Body.getSpeed, Body.getVelocity, Body.getAngularVelocity
Changed all velocity functions to be time independent
  • Loading branch information
liabru committed Sep 1, 2019
1 parent 0784a5b commit db8b73f
Showing 1 changed file with 113 additions and 24 deletions.
137 changes: 113 additions & 24 deletions src/body/Body.js
Original file line number Diff line number Diff line change
Expand Up @@ -456,15 +456,26 @@ var Axes = require('../geometry/Axes');
};

/**
* Sets the position of the body instantly. Velocity, angle, force etc. are unchanged.
* Sets the position of the body instantly. By default velocity, angle, force etc. are unchanged.
* If `updateVelocity` is `true` then velocity is inferred from the change in position.
* @method setPosition
* @param {body} body
* @param {vector} position
* @param {boolean} [updateVelocity=false]
*/
Body.setPosition = function(body, position) {
Body.setPosition = function(body, position, updateVelocity) {
var delta = Vector.sub(position, body.position);

if (updateVelocity) {

This comment has been minimized.

Copy link
@wmike1987

wmike1987 Sep 24, 2019

I think this will produce inconsistent velocities since it's setting the velocity like the previous setVelocity() method was (without considering a timescale).

This comment has been minimized.

Copy link
@liabru

liabru Sep 30, 2019

Author Owner

Ah do you mean body.velocity? This is considered internal only now and will remain as velocity-per-timestep as before. Users should instead now be using only Body.getVelocity going forwards. Does that make sense?

This comment has been minimized.

Copy link
@wmike1987

wmike1987 Oct 7, 2019

Sorry, I was referring to the velocity as verlet integration determines it (body.position.x - body.positionPrev.x). It seems like setting the positionPrev here will produce differing velocities (as the user experiences it, not as in body.velocity) depending on the frame rate.

You changed the setVelocity() method in this PR to account for this by adjusting the given velocity based on a common timeScale. I'd do the same here, with the "given" velocity in this case being the velocity necessary to go from original --> new position in one frame.

Edit: Actually I take back the "given velocity" statement. I think you'd have to determine what it means to move from point A to point B "instantly." Since "instantly" basically means "in a frame" we'd need to determine a frame-independent velocity here, so like, determine the velocity needed to move from original --> new position assuming 60fps.

body.positionPrev.x = body.position.x;
body.positionPrev.y = body.position.y;
body.velocity.x = delta.x;
body.velocity.y = delta.y;
body.speed = Vector.magnitude(delta);
} else {
body.positionPrev.x += delta.x;
body.positionPrev.y += delta.y;
}

for (var i = 0; i < body.parts.length; i++) {
var part = body.parts[i];
Expand All @@ -476,14 +487,23 @@ var Axes = require('../geometry/Axes');
};

/**
* Sets the angle of the body instantly. Angular velocity, position, force etc. are unchanged.
* Sets the angle of the body instantly. By default angular velocity, position, force etc. are unchanged.
* If `updateVelocity` is `true` then angular velocity is inferred from the change in angle.
* @method setAngle
* @param {body} body
* @param {number} angle
* @param {boolean} [updateVelocity=false]
*/
Body.setAngle = function(body, angle) {
Body.setAngle = function(body, angle, updateVelocity) {
var delta = angle - body.angle;

if (updateVelocity) {
body.anglePrev = body.angle;
body.angularVelocity = delta;
body.angularSpeed = Math.abs(delta);
} else {
body.anglePrev += delta;
}

for (var i = 0; i < body.parts.length; i++) {
var part = body.parts[i];
Expand All @@ -504,45 +524,116 @@ var Axes = require('../geometry/Axes');
* @param {vector} velocity
*/
Body.setVelocity = function(body, velocity) {
body.positionPrev.x = body.position.x - velocity.x;
body.positionPrev.y = body.position.y - velocity.y;
body.velocity.x = velocity.x;
body.velocity.y = velocity.y;
var timeScale = body.deltaTime / Common._timeUnit;

This comment has been minimized.

Copy link
@wmike1987

wmike1987 Oct 25, 2019

There's an issue here if we create a body and immediately set its velocity since body.deltaTime won't yet have been set (it requires a body.update() to be set).

body.positionPrev.x = body.position.x - velocity.x * timeScale;
body.positionPrev.y = body.position.y - velocity.y * timeScale;
body.velocity.x = velocity.x * timeScale;
body.velocity.y = velocity.y * timeScale;
body.speed = Vector.magnitude(body.velocity);
};

/**
* Gets the linear velocity of the body. Use this instead of the internal `body.velocity`.
* @method getVelocity
* @param {body} body
* @return {vector} velocity
*/
Body.getVelocity = function(body) {
var timeScale = Common._timeUnit / body.deltaTime;

return {
x: (body.position.x - body.positionPrev.x) * timeScale,
y: (body.position.y - body.positionPrev.y) * timeScale
};
};

/**
* Gets the linear speed the body. Use this instead of the internal `body.speed`.
* @method getSpeed
* @param {body} body
* @return {number} speed
*/
Body.getSpeed = function(body) {
return Vector.magnitude(Body.getVelocity(body));
};

/**
* Sets the linear speed of the body. Use this instead of the internal `body.speed`.
* @method setSpeed
* @param {body} body
* @param {number} speed
*/
Body.setSpeed = function(body, speed) {
Body.setVelocity(body, Vector.mult(Vector.normalise(Body.getVelocity(body)), speed));
};

/**
* Sets the angular velocity of the body instantly. Position, angle, force etc. are unchanged. See also `Body.applyForce`.
* @method setAngularVelocity
* @param {body} body
* @param {number} velocity
*/
Body.setAngularVelocity = function(body, velocity) {
body.anglePrev = body.angle - velocity;
body.angularVelocity = velocity;
var timeScale = body.deltaTime / Common._timeUnit;
body.anglePrev = body.angle - velocity * timeScale;
body.angularVelocity = velocity * timeScale;
body.angularSpeed = Math.abs(body.angularVelocity);
};

/**
* Moves a body by a given vector relative to its current position, without imparting any velocity.
* Gets the angular velocity of the body. Use this instead of the internal `body.angularVelocity`.
* @method getAngularVelocity
* @param {body} body
* @return {number} angular velocity
*/
Body.getAngularVelocity = function(body) {
return (body.angle - body.anglePrev) * Common._timeUnit / body.deltaTime;
};

/**
* Gets the angular speed of the body. Use this instead of the internal `body.angularSpeed`.
* @method getAngularSpeed
* @param {body} body
* @return {number} angular speed
*/
Body.getAngularSpeed = function(body) {
return Math.abs(Body.getAngularVelocity(body));
};

/**
* Sets the angular speed of the body. Use this instead of the internal `body.angularSpeed`.
* @method setAngularSpeed
* @param {body} body
* @param {number} speed
*/
Body.setAngularSpeed = function(body, speed) {
Body.setAngularVelocity(body, Common.sign(Body.getAngularVelocity(body)) * speed);
};

/**
* Moves a body by a given vector relative to its current position, without imparting any velocity by default.
* If `updateVelocity` is `true` then velocity is inferred from the change in position.
* @method translate
* @param {body} body
* @param {vector} translation
* @param {boolean} [updateVelocity=false]
*/
Body.translate = function(body, translation) {
Body.setPosition(body, Vector.add(body.position, translation));
Body.translate = function(body, translation, updateVelocity) {
Body.setPosition(body, Vector.add(body.position, translation), updateVelocity);
};

/**
* Rotates a body by a given angle relative to its current angle, without imparting any angular velocity.
* Rotates a body by a given angle relative to its current angle, without imparting any angular velocity by default.
* If `updateVelocity` is `true` then angular velocity is inferred from the change in angle.
* @method rotate
* @param {body} body
* @param {number} rotation
* @param {vector} [point]
* @param {boolean} [updateVelocity=false]
*/
Body.rotate = function(body, rotation, point) {
Body.rotate = function(body, rotation, point, updateVelocity) {
if (!point) {
Body.setAngle(body, body.angle + rotation);
Body.setAngle(body, body.angle + rotation, updateVelocity);
} else {
var cos = Math.cos(rotation),
sin = Math.sin(rotation),
Expand All @@ -552,9 +643,9 @@ var Axes = require('../geometry/Axes');
Body.setPosition(body, {
x: point.x + (dx * cos - dy * sin),
y: point.y + (dx * sin + dy * cos)
});
}, updateVelocity);

Body.setAngle(body, body.angle + rotation);
Body.setAngle(body, body.angle + rotation, updateVelocity);
}
};

Expand Down Expand Up @@ -863,7 +954,7 @@ var Axes = require('../geometry/Axes');
*/

/**
* A `Number` that _measures_ the current speed of the body after the last `Body.update`. It is read-only and always positive (it's the magnitude of `body.velocity`).
* Internal only. Use `Body.getSpeed` and `Body.setSpeed` instead.
*
* @readOnly
* @property speed
Expand All @@ -872,7 +963,7 @@ var Axes = require('../geometry/Axes');
*/

/**
* A `Number` that _measures_ the current angular speed of the body after the last `Body.update`. It is read-only and always positive (it's the magnitude of `body.angularVelocity`).
* Internal only. Use `Body.getAngularSpeed` and `Body.setAngularSpeed` instead.
*
* @readOnly
* @property angularSpeed
Expand All @@ -881,8 +972,7 @@ var Axes = require('../geometry/Axes');
*/

/**
* A `Vector` that _measures_ the current velocity of the body after the last `Body.update`. It is read-only.
* If you need to modify a body's velocity directly, you should either apply a force or simply change the body's `position` (as the engine uses position-Verlet integration).
* Internal only. Use `Body.getVelocity` and `Body.setVelocity` instead.
*
* @readOnly
* @property velocity
Expand All @@ -891,8 +981,7 @@ var Axes = require('../geometry/Axes');
*/

/**
* A `Number` that _measures_ the current angular velocity of the body after the last `Body.update`. It is read-only.
* If you need to modify a body's angular velocity directly, you should apply a torque or simply change the body's `angle` (as the engine uses position-Verlet integration).
* Internal only. Use `Body.getAngularVelocity` and `Body.setAngularVelocity` instead.
*
* @readOnly
* @property angularVelocity
Expand Down

0 comments on commit db8b73f

Please sign in to comment.