Skip to main content

fyrox_impl/scene/particle_system/emitter/
base.rs

1// Copyright (c) 2019-present Dmitry Stepanov and Fyrox Engine contributors.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy
4// of this software and associated documentation files (the "Software"), to deal
5// in the Software without restriction, including without limitation the rights
6// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7// copies of the Software, and to permit persons to whom the Software is
8// furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in all
11// copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19// SOFTWARE.
20
21//! Base emitter contains properties for all other "derived" emitters.
22
23use crate::{
24    core::{
25        algebra::Vector3, color::Color, numeric_range::RangeExt, reflect::prelude::*,
26        visitor::prelude::*,
27    },
28    scene::particle_system::{Particle, ParticleSystemRng},
29};
30use std::ops::Range;
31
32/// See module docs.
33#[derive(Debug, Visit, PartialEq, Reflect)]
34pub struct BaseEmitter {
35    /// Offset from center of particle system.
36    position: Vector3<f32>,
37    /// Particle spawn rate in unit-per-second. If < 0, spawns `max_particles`,
38    /// spawns nothing if `max_particles` < 0
39    #[visit(rename = "SpawnRate")]
40    particle_spawn_rate: u32,
41    /// Maximum amount of particles emitter can emit. Unlimited if < 0
42    max_particles: Option<u32>,
43    /// Range of initial lifetime of a particle
44    #[visit(rename = "LifeTime")]
45    lifetime: Range<f32>,
46    /// Range of initial size of a particle
47    size: Range<f32>,
48    /// Range of initial size modifier of a particle
49    size_modifier: Range<f32>,
50    /// Range of initial X-component of velocity for a particle
51    x_velocity: Range<f32>,
52    /// Range of initial Y-component of velocity for a particle
53    y_velocity: Range<f32>,
54    /// Range of initial Z-component of velocity for a particle
55    z_velocity: Range<f32>,
56    /// Range of initial rotation speed for a particle
57    rotation_speed: Range<f32>,
58    /// Range of initial rotation for a particle
59    rotation: Range<f32>,
60    #[reflect(hidden)]
61    pub(crate) alive_particles: u32,
62    #[visit(skip)]
63    #[reflect(hidden)]
64    time: f32,
65    #[visit(skip)]
66    #[reflect(hidden)]
67    pub(crate) particles_to_spawn: u32,
68    resurrect_particles: bool,
69    #[reflect(hidden)]
70    pub(crate) spawned_particles: u64,
71}
72
73/// Emitter builder allows you to construct emitter in declarative manner.
74/// This is typical implementation of Builder pattern.
75pub struct BaseEmitterBuilder {
76    position: Option<Vector3<f32>>,
77    particle_spawn_rate: Option<u32>,
78    max_particles: Option<u32>,
79    lifetime: Range<f32>,
80    size: Range<f32>,
81    size_modifier: Range<f32>,
82    x_velocity: Range<f32>,
83    y_velocity: Range<f32>,
84    z_velocity: Range<f32>,
85    rotation_speed: Range<f32>,
86    rotation: Range<f32>,
87    resurrect_particles: bool,
88}
89
90impl Default for BaseEmitterBuilder {
91    fn default() -> Self {
92        Self::new()
93    }
94}
95
96impl BaseEmitterBuilder {
97    /// Creates new emitter builder in declarative manner.
98    pub fn new() -> Self {
99        Self {
100            position: None,
101            particle_spawn_rate: None,
102            max_particles: None,
103            lifetime: 5.0..10.0,
104            size: 0.125..0.250,
105            size_modifier: 0.0005..0.0010,
106            x_velocity: -0.001..0.001,
107            y_velocity: -0.001..0.001,
108            z_velocity: -0.001..0.001,
109            rotation_speed: -0.02..0.02,
110            rotation: -std::f32::consts::PI..std::f32::consts::PI,
111            resurrect_particles: true,
112        }
113    }
114
115    /// Sets desired position of emitter in local coordinates.
116    pub fn with_position(mut self, position: Vector3<f32>) -> Self {
117        self.position = Some(position);
118        self
119    }
120
121    /// Sets desired particle spawn rate in s⁻¹ (particles per second)
122    pub fn with_spawn_rate(mut self, rate: u32) -> Self {
123        self.particle_spawn_rate = Some(rate);
124        self
125    }
126
127    /// Sets desired max amount of particles.
128    pub fn with_max_particles(mut self, value: u32) -> Self {
129        self.max_particles = Some(value);
130        self
131    }
132
133    /// Sets desired lifetime range.
134    pub fn with_lifetime_range(mut self, time_range: Range<f32>) -> Self {
135        self.lifetime = time_range;
136        self
137    }
138
139    /// Sets desired size range.
140    pub fn with_size_range(mut self, size_range: Range<f32>) -> Self {
141        self.size = size_range;
142        self
143    }
144
145    /// Sets desired size modifier range.
146    pub fn with_size_modifier_range(mut self, mod_range: Range<f32>) -> Self {
147        self.size_modifier = mod_range;
148        self
149    }
150
151    /// Sets desired x velocity range.
152    pub fn with_x_velocity_range(mut self, x_vel_range: Range<f32>) -> Self {
153        self.x_velocity = x_vel_range;
154        self
155    }
156
157    /// Sets desired y velocity range.
158    pub fn with_y_velocity_range(mut self, y_vel_range: Range<f32>) -> Self {
159        self.y_velocity = y_vel_range;
160        self
161    }
162
163    /// Sets desired z velocity range.
164    pub fn with_z_velocity_range(mut self, z_vel_range: Range<f32>) -> Self {
165        self.z_velocity = z_vel_range;
166        self
167    }
168
169    /// Sets desired rotation speed range.
170    pub fn with_rotation_speed_range(mut self, speed_range: Range<f32>) -> Self {
171        self.rotation_speed = speed_range;
172        self
173    }
174
175    /// Sets desired rotation range.
176    pub fn with_rotation_range(mut self, angle_range: Range<f32>) -> Self {
177        self.rotation = angle_range;
178        self
179    }
180
181    /// Sets whether to resurrect dead particle or not.
182    pub fn resurrect_particles(mut self, value: bool) -> Self {
183        self.resurrect_particles = value;
184        self
185    }
186
187    /// Creates new instance of emitter.
188    pub fn build(self) -> BaseEmitter {
189        BaseEmitter {
190            position: self.position.unwrap_or_default(),
191            particle_spawn_rate: self.particle_spawn_rate.unwrap_or(25),
192            max_particles: self.max_particles,
193            lifetime: self.lifetime,
194            size: self.size,
195            size_modifier: self.size_modifier,
196            x_velocity: self.x_velocity,
197            y_velocity: self.y_velocity,
198            z_velocity: self.z_velocity,
199            rotation_speed: self.rotation_speed,
200            rotation: self.rotation,
201            alive_particles: 0,
202            time: 0.0,
203            particles_to_spawn: 0,
204            resurrect_particles: self.resurrect_particles,
205            spawned_particles: 0,
206        }
207    }
208}
209
210impl BaseEmitter {
211    /// Updates emitter and emits required amount of particles each call. There is no
212    /// need to call it manually, it will be automatically called by scene update call.
213    pub fn tick(&mut self, dt: f32) {
214        self.time += dt;
215        let time_amount_per_particle = 1.0 / self.particle_spawn_rate as f32;
216        self.particles_to_spawn = (self.time / time_amount_per_particle) as u32;
217        self.time -= time_amount_per_particle * self.particles_to_spawn as f32;
218        if let Some(max_particles) = self.max_particles {
219            let alive_particles = self.alive_particles;
220            if alive_particles < max_particles
221                && alive_particles + self.particles_to_spawn > max_particles
222            {
223                self.particles_to_spawn = max_particles.saturating_sub(alive_particles);
224            }
225            if !self.resurrect_particles && self.spawned_particles >= u64::from(max_particles) {
226                self.particles_to_spawn = 0;
227            }
228        }
229        self.spawned_particles += self.particles_to_spawn as u64;
230    }
231
232    /// Initializes particle with new state. Every custom emitter must call this method,
233    /// otherwise you will get weird behavior of emitted particles.
234    pub fn emit(&self, particle: &mut Particle, rng: &mut ParticleSystemRng) {
235        particle.lifetime = 0.0;
236        particle.initial_lifetime = self.lifetime.random(rng);
237        particle.color = Color::WHITE;
238        particle.size = self.size.random(rng);
239        particle.size_modifier = self.size_modifier.random(rng);
240        particle.velocity = Vector3::new(
241            self.x_velocity.random(rng),
242            self.y_velocity.random(rng),
243            self.z_velocity.random(rng),
244        );
245        particle.rotation = self.rotation.random(rng);
246        particle.rotation_speed = self.rotation_speed.random(rng);
247    }
248
249    /// Sets new position of emitter in local coordinates.
250    pub fn set_position(&mut self, position: Vector3<f32>) -> &mut Self {
251        self.position = position;
252        self
253    }
254
255    /// Returns position of emitter in local coordinates.
256    pub fn position(&self) -> Vector3<f32> {
257        self.position
258    }
259
260    /// Sets new spawn rate in particle per second.
261    pub fn set_spawn_rate(&mut self, rate: u32) -> &mut Self {
262        self.particle_spawn_rate = rate;
263        self
264    }
265
266    /// Return spawn rate in particles per second.
267    pub fn spawn_rate(&self) -> u32 {
268        self.particle_spawn_rate
269    }
270
271    /// Sets maximum amount of particles.
272    pub fn set_max_particles(&mut self, max: Option<u32>) -> &mut Self {
273        self.max_particles = max;
274        self
275    }
276
277    /// Returns maximum amount of particles.
278    pub fn max_particles(&self) -> Option<u32> {
279        self.max_particles
280    }
281
282    /// Sets new range of lifetimes which will be used to generate random lifetime
283    /// of new particle.
284    pub fn set_life_time_range(&mut self, range: Range<f32>) -> &mut Self {
285        self.lifetime = range;
286        self
287    }
288
289    /// Returns current lifetime range.
290    pub fn life_time_range(&self) -> Range<f32> {
291        self.lifetime.clone()
292    }
293
294    /// Sets new range of sizes which will be used to generate random size
295    /// of new particle.
296    pub fn set_size_range(&mut self, range: Range<f32>) -> &mut Self {
297        self.size = range;
298        self
299    }
300
301    /// Returns current size range.
302    pub fn size_range(&self) -> Range<f32> {
303        self.size.clone()
304    }
305
306    /// Sets new range of size modifier which will be used to generate random size modifier
307    /// of new particle.
308    pub fn set_size_modifier_range(&mut self, range: Range<f32>) -> &mut Self {
309        self.size_modifier = range;
310        self
311    }
312
313    /// Returns current size modifier.
314    pub fn size_modifier_range(&self) -> Range<f32> {
315        self.size_modifier.clone()
316    }
317
318    /// Sets new range of initial x velocity that will be used to generate random
319    /// value of initial x velocity of a particle.
320    pub fn set_x_velocity_range(&mut self, range: Range<f32>) -> &mut Self {
321        self.x_velocity = range;
322        self
323    }
324
325    /// Returns current range of initial x velocity that will be used to generate
326    /// random value of initial x velocity of a particle.
327    pub fn x_velocity_range(&self) -> Range<f32> {
328        self.x_velocity.clone()
329    }
330
331    /// Sets new range of initial y velocity that will be used to generate random
332    /// value of initial y velocity of a particle.
333    pub fn set_y_velocity_range(&mut self, range: Range<f32>) -> &mut Self {
334        self.y_velocity = range;
335        self
336    }
337
338    /// Returns current range of initial y velocity that will be used to generate
339    /// random value of initial y velocity of a particle.
340    pub fn y_velocity_range(&self) -> Range<f32> {
341        self.y_velocity.clone()
342    }
343
344    /// Sets new range of initial z velocity that will be used to generate random
345    /// value of initial z velocity of a particle.
346    pub fn set_z_velocity_range(&mut self, range: Range<f32>) -> &mut Self {
347        self.z_velocity = range;
348        self
349    }
350
351    /// Returns current range of initial z velocity that will be used to generate
352    /// random value of initial z velocity of a particle.
353    pub fn z_velocity_range(&self) -> Range<f32> {
354        self.z_velocity.clone()
355    }
356
357    /// Sets new range of rotation speed that will be used to generate random value
358    /// of rotation speed of a particle.
359    pub fn set_rotation_speed_range(&mut self, range: Range<f32>) -> &mut Self {
360        self.rotation_speed = range;
361        self
362    }
363
364    /// Returns current range of rotation speed that will be used to generate random
365    /// value of rotation speed of a particle.
366    pub fn rotation_speed_range(&self) -> Range<f32> {
367        self.rotation_speed.clone()
368    }
369
370    /// Sets new range of initial rotations that will be used to generate random
371    /// value of initial rotation of a particle.
372    pub fn set_rotation_range(&mut self, range: Range<f32>) -> &mut Self {
373        self.rotation = range;
374        self
375    }
376
377    /// Returns current range of initial rotations that will be used to generate
378    /// random value of initial rotation of a particle.
379    pub fn rotation_range(&self) -> Range<f32> {
380        self.rotation.clone()
381    }
382
383    /// Enables or disables automatic particle resurrection. Setting this option to
384    /// true is useful for "endless" effects.
385    pub fn enable_particle_resurrection(&mut self, state: bool) -> &mut Self {
386        self.resurrect_particles = state;
387        self
388    }
389
390    /// Returns true if dead particles will be automatically resurrected, false - otherwise.
391    pub fn is_particles_resurrects(&self) -> bool {
392        self.resurrect_particles
393    }
394
395    /// Returns amount of spawned particles from moment of creation of particle system.
396    pub fn spawned_particles(&self) -> u64 {
397        self.spawned_particles
398    }
399}
400
401impl Clone for BaseEmitter {
402    fn clone(&self) -> Self {
403        Self {
404            position: self.position,
405            particle_spawn_rate: self.particle_spawn_rate,
406            max_particles: self.max_particles,
407            lifetime: self.lifetime.clone(),
408            size: self.size.clone(),
409            size_modifier: self.size_modifier.clone(),
410            x_velocity: self.x_velocity.clone(),
411            y_velocity: self.y_velocity.clone(),
412            z_velocity: self.z_velocity.clone(),
413            rotation_speed: self.rotation_speed.clone(),
414            rotation: self.rotation.clone(),
415            alive_particles: self.alive_particles,
416            time: self.time,
417            particles_to_spawn: 0,
418            resurrect_particles: self.resurrect_particles,
419            spawned_particles: self.spawned_particles,
420        }
421    }
422}
423
424impl Default for BaseEmitter {
425    fn default() -> Self {
426        Self {
427            position: Vector3::default(),
428            particle_spawn_rate: 100,
429            max_particles: None,
430            lifetime: 5.0..10.0,
431            size: 0.125..0.250,
432            size_modifier: 0.0005..0.0010,
433            x_velocity: -0.001..0.001,
434            y_velocity: -0.001..0.001,
435            z_velocity: -0.001..0.001,
436            rotation_speed: -0.02..0.02,
437            rotation: -std::f32::consts::PI..std::f32::consts::PI,
438            alive_particles: 0,
439            time: 0.0,
440            particles_to_spawn: 0,
441            resurrect_particles: true,
442            spawned_particles: 0,
443        }
444    }
445}