UNPKG

7.17 kBJavaScriptView Raw
1/** @module splat-ecs/lib/particles */
2
3var random = require("splat-ecs/lib/random");
4
5module.exports = {
6 /**
7 * 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>.
8 * @param {object} game The <code>game</code> object that you get in systems and scripts.
9 * @param {module:splat-ecs/lib/particles.Config} config The settings to use to create the particles.
10 */
11 "create": function(game, config) {
12 var particleCount = Math.floor(random.inRange(config.qtyMin, config.qtyMax));
13 for (var i = 0; i < particleCount; i++) {
14 var particle = game.prefabs.instantiate(game.entities, config.prefab);
15 // check if origin is an entity
16 var origin = config.origin;
17 if (typeof config.origin === "number") {
18 origin = choosePointInEntity(game, origin);
19 }
20
21 var randomSize = random.inRange(config.sizeMin, config.sizeMax);
22 scaleEntityRect(game, particle, randomSize);
23
24 centerEntityOnPoint(game, particle, origin);
25
26 var velocity = random.inRange(config.velocityMin, config.velocityMax);
27
28 var angle = pickAngle(config, i, particleCount);
29 var velocityComponent = game.entities.addComponent(particle, "velocity");
30 var direction = pointOnCircle(angle, velocity);
31 velocityComponent.x = direction.x;
32 velocityComponent.y = direction.y;
33
34 if (config.accelerationX || config.accelerationY) {
35 var accel = game.entities.addComponent(particle, "acceleration");
36 accel.x = config.accelerationX;
37 accel.y = config.accelerationY;
38 }
39 var lifeSpan = game.entities.addComponent(particle, "lifeSpan");
40 lifeSpan.max = random.inRange(config.lifeSpanMin, config.lifeSpanMax);
41 }
42 },
43
44 /**
45 * The settings for a type of particle.
46 * @constructor
47 * @param {string} prefab The name of a prefab to instantiate for the particle, as defined in <code>prefabs.json</code>.
48 */
49 "Config": function(prefab) {
50 /**
51 * The name of a prefab to instantiate for the particle, as defined in <code>prefabs.json</code>.
52 * @member {string}
53 */
54 this.prefab = prefab;
55 /**
56 * The origin point in which to create particles.
57 *
58 * If the origin is a number it represents an entity and a random point inside the entity will be used.
59 * If origin is a point like <code>{"x": 50, "y": 50}</code> particles will spawn at that position.
60 * @member {object | number}
61 */
62 this.origin = { "x": 0, "y": 0 };
63 /**
64 * How to distribute particles along the {@link module:splat-ecs/lib/particles.Config#arcWidth arcWidth}.
65 *
66 * Possible values:
67 * <dl>
68 * <dt><code>"even"</code></dt>
69 * <dd>Distribute the particles evenly along the arc.</dd>
70 * <dt><code>"random"</code></dt>
71 * <dd>Scatter the particles on random points of the arc.</dd>
72 * </dl>
73 * @member {string}
74 */
75 this.spreadType = "random";
76 /**
77 * The direction (an angle in radians) that the particles should move.
78 * @member {number}
79 */
80 this.angle = 0;
81 /**
82 * 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}.
83 * @member {number}
84 */
85 this.arcWidth = Math.PI / 2;
86 /**
87 * The minimum number of particles to create.
88 * @member {number}
89 */
90 this.qtyMin = 1;
91 /**
92 * The maximum number of particles to create.
93 * @member {number}
94 */
95 this.qtyMax = 1;
96 /**
97 * The minimum percentage to scale each particle.
98 * <ul>
99 * <li>A scale of 0.5 means the particle will spawn at 50% (half) of the original size.</li>
100 * <li>A scale of 1 means the particle will spawn at the original size.</li>
101 * <li>A scale of 2 means the particle will spawn at 200% (double) the original size.</li>
102 * </ul>
103 * @member {number}
104 */
105 this.sizeMin = 1;
106 /**
107 * The maximum percentage to scale each particle.
108 * <ul>
109 * <li>A scale of 0.5 means the particle will spawn at 50% (half) of the original size.</li>
110 * <li>A scale of 1 means the particle will spawn at the original size.</li>
111 * <li>A scale of 2 means the particle will spawn at 200% (double) the original size.</li>
112 * </ul>
113 * @member {number}
114 */
115 this.sizeMax = 1;
116 /**
117 * The minimum velocity to apply to each particle.
118 * @member {number}
119 */
120 this.velocityMin = 0.5;
121 /**
122 * The maximum velocity to apply to each particle.
123 * @member {number}
124 */
125 this.velocityMax = 0.5;
126 /**
127 * The acceleration on the x-axis to apply to each particle.
128 * @member {number}
129 */
130 this.accelerationX = 0;
131 /**
132 * The acceleration on the y-axis to apply to each particle.
133 * @member {number}
134 */
135 this.accelerationY = 0;
136 /**
137 * The minimum life span to apply to each particle.
138 * @member {number}
139 */
140 this.lifeSpanMin = 0;
141 /**
142 * The maximum life span to apply to each particle.
143 * @member {number}
144 */
145 this.lifeSpanMax = 500;
146 }
147};
148
149function pickAngle(config, particleNumber, particleCount) {
150 var startAngle = config.angle - (config.arcWidth / 2);
151 if (config.spreadType === "even") {
152 return (particleNumber * (config.arcWidth / (particleCount - 1))) + startAngle;
153 } else {
154 var endAngle = startAngle + config.arcWidth;
155 return random.inRange(startAngle, endAngle);
156 }
157}
158
159function scaleEntityRect(game, entity, scaleFactor) {
160 var size = game.entities.getComponent(entity, "size");
161 size.width = size.width * scaleFactor;
162 size.height = size.height * scaleFactor;
163}
164
165function pointOnCircle(angle, radius) {
166 return {
167 "x": (radius * Math.cos(angle)),
168 "y": (radius * Math.sin(angle))
169 };
170}
171
172/**
173 * Center an entity on a given point.
174 * @private
175 * @param {object} game Required for game.entities.get().
176 * @param {integer} entity The id of entity to center.
177 * @param {object} point A point object <code>{"x": 50, "y": 50}</code> on which to center the entity.
178 */
179function centerEntityOnPoint(game, entity, point) {
180 var size = game.entities.getComponent(entity, "size");
181 var position = game.entities.addComponent(entity, "position");
182 position.x = point.x - (size.width / 2);
183 position.y = point.y - (size.height / 2);
184}
185
186/**
187 * Choose a random point inside the bounding rectangle of an entity.
188 * @private
189 * @param {object} game Required for game.entities.get().
190 * @param {integer} entity The id of entity to pick a point within.
191 * @returns {object} an point object <code>{"x": 50, "y": 50}</code>.
192 */
193function choosePointInEntity(game, entity) {
194 var position = game.entities.getComponent(entity, "position");
195 var size = game.entities.getComponent(entity, "size");
196 if (size === undefined) {
197 return {
198 "x": position.x,
199 "y": position.y
200 };
201 }
202 return {
203 "x": random.inRange(position.x, (position.x + size.width)),
204 "y": random.inRange(position.y, (position.y + size.height))
205 };
206}