1 /** 2 Particle 3 4 Copyright: (c) Enalye 2017 5 License: Zlib 6 Authors: Enalye 7 */ 8 9 module atelier.core.particle; 10 11 import std.random; 12 13 import atelier.render; 14 15 import atelier.core.vec2; 16 import atelier.core.color; 17 import atelier.core.stream; 18 import atelier.core.indexedarray; 19 import atelier.core.particlefilter; 20 21 /+ 22 class Particle { 23 Vec2f position, velocity; 24 float time, timeToLive; 25 float scale, spriteAngle, spriteAngleSpeed; 26 Color color; 27 } 28 29 class ParticleSource { 30 IndexedArray!(Particle, 5000u) particles; 31 IndexedArray!(ParticleFilter, 20u) filters; 32 Sprite sprite; 33 Vec2f position = Vec2f.zero; 34 35 private { 36 float _timeUntilNextSpawn = 0f; 37 } 38 39 float timeToLive = 1f, timeToLiveDelta = 0f; 40 float spawnDelay = 1f, spawnDelayDelta = 0f; 41 float scale = 1f, radius = 1f, angle = 0f, angleDelta = 0f, speed = 1f, speedDelta = 0f; 42 43 this() { 44 particles = new IndexedArray!(Particle, 5000u); 45 filters = new IndexedArray!(ParticleFilter, 20u); 46 } 47 48 void update(float deltaTime) { 49 foreach(Particle particle, uint index; particles) { 50 particle.time += deltaTime; 51 float t = particle.time / particle.timeToLive; 52 if(t > 1f) 53 particles.markInternalForRemoval(index); 54 else { 55 foreach(filter; filters) { 56 filter.apply(particle, deltaTime); 57 } 58 59 particle.position += particle.velocity * deltaTime; 60 particle.spriteAngle += particle.spriteAngleSpeed * deltaTime; 61 } 62 } 63 64 float random(float step, float delta) { 65 if(delta == 0f) 66 return step; 67 return uniform!"[]"((1f - delta) * step, (1f + delta) * step); 68 } 69 70 float random2(float step, float delta) { 71 if(delta == 0f) 72 return step; 73 return uniform!"[]"(step - delta / 2f, step + delta / 2f); 74 } 75 76 particles.sweepMarkedData(); 77 _timeUntilNextSpawn -= deltaTime; 78 if(_timeUntilNextSpawn < 0f) { 79 _timeUntilNextSpawn = random(spawnDelay, spawnDelayDelta); 80 81 auto particle = new Particle; 82 particle.position = position + Vec2f.angled(uniform(0f, 360f)) * (radius > 1f ? uniform(0f, radius) : 1f); 83 particle.time = 0f; 84 particle.timeToLive = random(timeToLive, timeToLiveDelta); 85 if(particle.timeToLive == 0f) 86 particle.timeToLive = 1f; 87 88 float angle = random2(angle, angleDelta); 89 particle.velocity = Vec2f.angled(angle) * random(speed, speedDelta); 90 particle.scale = scale; 91 92 particle.color = Color.white; 93 particles.push(particle); 94 } 95 } 96 97 void draw() { 98 if(sprite.texture is null) { 99 foreach(Particle particle, uint index; particles) { 100 float t = particle.time / particle.timeToLive; 101 drawFilledRect(particle.position, Vec2f.one * particle.scale, particle.color); 102 103 } 104 } 105 else { 106 foreach(Particle particle, uint index; particles) { 107 float t = particle.time / particle.timeToLive; 108 sprite.scale = Vec2f.one * particle.scale; 109 //sprite.angle = particle.spriteAngle; 110 sprite.color = particle.color; 111 sprite.draw(particle.position); 112 } 113 } 114 } 115 116 void save(OutStream stream) { 117 stream.write!float(timeToLive); 118 stream.write!float(timeToLiveDelta); 119 stream.write!float(spawnDelay); 120 stream.write!float(spawnDelayDelta); 121 stream.write!float(scale); 122 stream.write!float(radius); 123 stream.write!float(angle); 124 stream.write!float(angleDelta); 125 stream.write!float(speed); 126 stream.write!float(speedDelta); 127 } 128 129 void load(InStream stream) { 130 timeToLive = stream.read!float(); 131 timeToLiveDelta = stream.read!float(); 132 spawnDelay = stream.read!float(); 133 spawnDelayDelta = stream.read!float(); 134 scale = stream.read!float(); 135 radius = stream.read!float(); 136 angle = stream.read!float(); 137 angleDelta = stream.read!float(); 138 speed = stream.read!float(); 139 speedDelta = stream.read!float(); 140 } 141 }+/