splat-ecs
Version:
A 2D HTML5 Canvas game engine
207 lines (193 loc) • 7.17 kB
JavaScript
/** @module splat-ecs/lib/particles */
var random = require("splat-ecs/lib/random");
module.exports = {
/**
* Create between {@link module:splat-ecs/lib/particles.Config#qtyMin qtyMin} and {@link module:splat-ecs/lib/particles.Config#qtyMax qtyMax} particles, and randomize their properties according to <code>config</code>.
* @param {object} game The <code>game</code> object that you get in systems and scripts.
* @param {module:splat-ecs/lib/particles.Config} config The settings to use to create the particles.
*/
"create": function(game, config) {
var particleCount = Math.floor(random.inRange(config.qtyMin, config.qtyMax));
for (var i = 0; i < particleCount; i++) {
var particle = game.prefabs.instantiate(game.entities, config.prefab);
// check if origin is an entity
var origin = config.origin;
if (typeof config.origin === "number") {
origin = choosePointInEntity(game, origin);
}
var randomSize = random.inRange(config.sizeMin, config.sizeMax);
scaleEntityRect(game, particle, randomSize);
centerEntityOnPoint(game, particle, origin);
var velocity = random.inRange(config.velocityMin, config.velocityMax);
var angle = pickAngle(config, i, particleCount);
var velocityComponent = game.entities.addComponent(particle, "velocity");
var direction = pointOnCircle(angle, velocity);
velocityComponent.x = direction.x;
velocityComponent.y = direction.y;
if (config.accelerationX || config.accelerationY) {
var accel = game.entities.addComponent(particle, "acceleration");
accel.x = config.accelerationX;
accel.y = config.accelerationY;
}
var lifeSpan = game.entities.addComponent(particle, "lifeSpan");
lifeSpan.max = random.inRange(config.lifeSpanMin, config.lifeSpanMax);
}
},
/**
* The settings for a type of particle.
* @constructor
* @param {string} prefab The name of a prefab to instantiate for the particle, as defined in <code>prefabs.json</code>.
*/
"Config": function(prefab) {
/**
* The name of a prefab to instantiate for the particle, as defined in <code>prefabs.json</code>.
* @member {string}
*/
this.prefab = prefab;
/**
* The origin point in which to create particles.
*
* If the origin is a number it represents an entity and a random point inside the entity will be used.
* If origin is a point like <code>{"x": 50, "y": 50}</code> particles will spawn at that position.
* @member {object | number}
*/
this.origin = { "x": 0, "y": 0 };
/**
* How to distribute particles along the {@link module:splat-ecs/lib/particles.Config#arcWidth arcWidth}.
*
* Possible values:
* <dl>
* <dt><code>"even"</code></dt>
* <dd>Distribute the particles evenly along the arc.</dd>
* <dt><code>"random"</code></dt>
* <dd>Scatter the particles on random points of the arc.</dd>
* </dl>
* @member {string}
*/
this.spreadType = "random";
/**
* The direction (an angle in radians) that the particles should move.
* @member {number}
*/
this.angle = 0;
/**
* The width of an arc (represented by an angle in radians) to spread the particles. The arc is centered around {@link module:splat-ecs/lib/particles.Config#angle angle}.
* @member {number}
*/
this.arcWidth = Math.PI / 2;
/**
* The minimum number of particles to create.
* @member {number}
*/
this.qtyMin = 1;
/**
* The maximum number of particles to create.
* @member {number}
*/
this.qtyMax = 1;
/**
* The minimum percentage to scale each particle.
* <ul>
* <li>A scale of 0.5 means the particle will spawn at 50% (half) of the original size.</li>
* <li>A scale of 1 means the particle will spawn at the original size.</li>
* <li>A scale of 2 means the particle will spawn at 200% (double) the original size.</li>
* </ul>
* @member {number}
*/
this.sizeMin = 1;
/**
* The maximum percentage to scale each particle.
* <ul>
* <li>A scale of 0.5 means the particle will spawn at 50% (half) of the original size.</li>
* <li>A scale of 1 means the particle will spawn at the original size.</li>
* <li>A scale of 2 means the particle will spawn at 200% (double) the original size.</li>
* </ul>
* @member {number}
*/
this.sizeMax = 1;
/**
* The minimum velocity to apply to each particle.
* @member {number}
*/
this.velocityMin = 0.5;
/**
* The maximum velocity to apply to each particle.
* @member {number}
*/
this.velocityMax = 0.5;
/**
* The acceleration on the x-axis to apply to each particle.
* @member {number}
*/
this.accelerationX = 0;
/**
* The acceleration on the y-axis to apply to each particle.
* @member {number}
*/
this.accelerationY = 0;
/**
* The minimum life span to apply to each particle.
* @member {number}
*/
this.lifeSpanMin = 0;
/**
* The maximum life span to apply to each particle.
* @member {number}
*/
this.lifeSpanMax = 500;
}
};
function pickAngle(config, particleNumber, particleCount) {
var startAngle = config.angle - (config.arcWidth / 2);
if (config.spreadType === "even") {
return (particleNumber * (config.arcWidth / (particleCount - 1))) + startAngle;
} else {
var endAngle = startAngle + config.arcWidth;
return random.inRange(startAngle, endAngle);
}
}
function scaleEntityRect(game, entity, scaleFactor) {
var size = game.entities.getComponent(entity, "size");
size.width = size.width * scaleFactor;
size.height = size.height * scaleFactor;
}
function pointOnCircle(angle, radius) {
return {
"x": (radius * Math.cos(angle)),
"y": (radius * Math.sin(angle))
};
}
/**
* Center an entity on a given point.
* @private
* @param {object} game Required for game.entities.get().
* @param {integer} entity The id of entity to center.
* @param {object} point A point object <code>{"x": 50, "y": 50}</code> on which to center the entity.
*/
function centerEntityOnPoint(game, entity, point) {
var size = game.entities.getComponent(entity, "size");
var position = game.entities.addComponent(entity, "position");
position.x = point.x - (size.width / 2);
position.y = point.y - (size.height / 2);
}
/**
* Choose a random point inside the bounding rectangle of an entity.
* @private
* @param {object} game Required for game.entities.get().
* @param {integer} entity The id of entity to pick a point within.
* @returns {object} an point object <code>{"x": 50, "y": 50}</code>.
*/
function choosePointInEntity(game, entity) {
var position = game.entities.getComponent(entity, "position");
var size = game.entities.getComponent(entity, "size");
if (size === undefined) {
return {
"x": position.x,
"y": position.y
};
}
return {
"x": random.inRange(position.x, (position.x + size.width)),
"y": random.inRange(position.y, (position.y + size.height))
};
}