File: physics\ForceGenerators.js
//=====Generic force generator=====
/**
A generic force generator. It applies the specified force directly to the entity.
@class ForceGenerator
@constructor
@param forceX {Number} The x component of the force vector.
@param forceY {Number} The y component of the force vector.
*/
function ForceGenerator(forceX, forceY){
this._forceVector = new Vector2D(forceX, forceY);
}
/**
@method applyForce
@param entity {Entity} The entity this force should be applied to. It's required that the entity has the Movable component.
*/
ForceGenerator.prototype.applyForce = function(entity){
var movableComponent = entity.get(Movable);
if(!movableComponent){
return;
}
movableComponent.applyForce(this._forceVector);
};
/**
Retrieves the force vector.
@method getForceVector
@param vector {Vector2D} The vector to which the force vector will be copied.
*/
ForceGenerator.prototype.getForceVector = function(vector){
vector.x = this._forceVector.x;
vector.y = this._forceVector.y;
};
/**
Sets new values for the force vector.
@method setForceVector
@param forceX {Number} The x component of the new force vector.
@param forceY {Number} The y component of the new force vector.
*/
ForceGenerator.prototype.setForceVector = function(forceX, forceY){
this._forceVector.x = forceX;
this._forceVector.y = forceY;
};
//=====Gravity force generator=====
/**
This generator applies a force to the entity that gives it the specified acceleration.
@class GravityGenerator
@constructor
@param gravityX {Number} The x component of the acceleration vector.
@param gravityY {Number} The y component of the acceleration vector.
*/
function GravityGenerator(gravityX, gravityY){
this._gravityVector = new Vector2D(gravityX, gravityY);
}
/**
@method applyForce
@param entity {Entity} The entity this force should be applied to. It's required that the entity has the Movable component.
*/
GravityGenerator.prototype.applyForce = (function(){
var force = new Vector2D();
return function(entity){
var movableComponent = entity.get(Movable);
if(!movableComponent){
return;
}
//If the entity's mass is infinite, then if either of the gravity vector's components is 0,
//the multiplication by mass will result in NaN (0 * infinity = NaN).
//To avoid this, simply don't apply the force if mass is infinite.
if(movableComponent.getMass() !== Number.POSITIVE_INFINITY){
this._gravityVector.multiplied(movableComponent.getMass(), force)
movableComponent.applyForce(force);
}
};
})();
/**
Retrieves the gravity acceleration vector.
@method getGravityVector
@param vector {Vector2D} The vector to which the gravity vector will be copied.
*/
GravityGenerator.prototype.getGravityVector = function(vector){
vector.x = this._gravityVector.x;
vector.y = this._gravityVector.y;
};
/**
Sets new values for the gravity acceleration vector.
@method setGravityVector
@param gravityX {Number} The x component of the new acceleration vector.
@param gravityY {Number} The y component of the new acceleration vector.
*/
GravityGenerator.prototype.setGravityVector = function(gravityX, gravityY){
this._gravityVector.x = gravityX;
this._gravityVector.y = gravityY;
};
//=====Anchored spring force generator=====
/**
This generator simulates a spring with one end attached to a fixed point in space and the other to an entity.
@class AnchoredSpringGenerator
@constructor
@param anchorPointX {Number} The x component of the fixed point.
@param anchorPointY {Number} The y component of the fixed point.
@param restLength {Number}
@param stiffness {Number}
*/
function AnchoredSpringGenerator(anchorPointX, anchorPointY, restLength, stiffness){
this._anchorPoint = new Vector2D(anchorPointX, anchorPointY);
this._restLength = restLength || 0;
this._stiffness = stiffness || 0;
}
/**
@method applyForce
@param entity {Entity} The entity the spring force should be applied to. It's required that the entity has the Movable and Position components.
*/
AnchoredSpringGenerator.prototype.applyForce = (function(){
var force = new Vector2D();
return function(entity){
var positionComponent = entity.get(Position),
movableComponent = entity.get(Movable);
if( !(positionComponent && movableComponent) ){
return;
}
this._anchorPoint.subtracted(positionComponent, force);
var distance = force.magnitude();
//Don't do anything if the beginning and the end of the spring are right on top of each other.
if(distance === 0){
return;
}
//Use the already calculated distance to normalize the force vector.
force.divide(distance);
force.multiply((distance - this._restLength) * this._stiffness);
movableComponent.applyForce(force);
};
})();
/**
Retrieves the position of the anchor point.
@method getAnchorPoint
@param vector {Vector2D} The vector to which the anchor point's position will be copied.
*/
AnchoredSpringGenerator.prototype.getAnchorPoint = function(vector){
vector.x = this._anchorPoint.x;
vector.y = this._anchorPoint.y;
};
/**
Sets a new position for the anchor point.
@method setAnchorPoint
@param anchorPointX {Number} The x component of the new anchor point.
@param anchorPointY {Number} The y component of the new anchor point.
*/
AnchoredSpringGenerator.prototype.setAnchorPoint = function(anchorPointX, anchorPointY){
this._anchorPoint.x = anchorPointX;
this._anchorPoint.y = anchorPointY;
};
/**
@method getRestLength
@return {Number}
*/
AnchoredSpringGenerator.prototype.getRestLength = function(){
return this._restLength;
};
/**
@method setRestLength
@param restLength {Number}
*/
AnchoredSpringGenerator.prototype.setRestLength = function(restLength){
this._restLength = restLength;
};
/**
@method getStiffness
@return {Number}
*/
AnchoredSpringGenerator.prototype.getStiffness = function(){
return this._stiffness;
};
/**
@method setStiffness
@param stiffness {Number}
*/
AnchoredSpringGenerator.prototype.setStiffness = function(stiffness){
this._stiffness = stiffness;
};
//=====Spring force generator that applies the force to both ends=====
/**
This generator simulates a spring with both ends attached to entities.
@class SpringGenerator
@constructor
@param entity {Entity} This entity should have the Position and Movable components.
@param restLength {Number}
@param stiffness {Number}
*/
function SpringGenerator(entity, restLength, stiffness){
this._entity = entity;
this._restLength = restLength || 0;
this._stiffness = stiffness || 0;
}
/**
@method applyForce
@param entity {Entity} The other entity the spring force should be applied to. This entity should have the Position and Movable components.
*/
SpringGenerator.prototype.applyForce = (function(){
var force = new Vector2D();
return function(entity){
if(!this._entity){
return;
}
var positionA = this._entity.get(Position),
movableA = this._entity.get(Movable),
positionB = entity.get(Position),
movableB = entity.get(Movable);
if(!(positionA && movableA && positionB && movableB)){
return;
}
positionA.subtracted(positionB, force);
var distance = force.magnitude();
//Don't do anything if the beginning and the end of the spring are right on top of each other.
if(distance === 0){
return;
}
//Use the already calculated distance to normalize the force vector.
force.divide(distance);
force.multiply((distance - this._restLength) * this._stiffness);
movableB.applyForce(force);
movableA.applyForce(force.invert());
};
})();
/**
@method setEntity
@param entity {Entity} This entity should have the Position and Movable components.
*/
SpringGenerator.prototype.setEntity = function(entity){
this._entity = entity;
};
/**
@method getEntity
@return {Entity}
*/
SpringGenerator.prototype.getEntity = function(){
return this._entity;
};
/**
@method getRestLength
@return {Number}
*/
SpringGenerator.prototype.getRestLength = function(){
return this._restLength;
};
/**
@method setRestLength
@param restLength {Number}
*/
SpringGenerator.prototype.setRestLength = function(restLength){
this._restLength = restLength;
};
/**
@method getStiffness
@return {Number}
*/
SpringGenerator.prototype.getStiffness = function(){
return this._stiffness;
};
/**
@method setStiffness
@param stiffness {Number}
*/
SpringGenerator.prototype.setStiffness = function(stiffness){
this._stiffness = stiffness;
};
//=====Drag force generator=====
/**
This generator simulates the force of drag.
@class DragGenerator
@constructor
*/
function DragGenerator(){
}
/**
@method applyForce
@param entity {Entity} The entity to which the drag should be applied. It's required that the entity has the Movable component.
*/
DragGenerator.prototype.applyForce = (function(){
var force = new Vector2D();
return function(entity){
var movableComponent = entity.get(Movable);
if(!movableComponent){
return;
}
movableComponent.getVelocity(force);
force.multiply(-movableComponent.getDragCoefficient());
movableComponent.applyForce(force);
};
})();