| import 'dart:math' as math; |
| import 'dart:typed_data'; |
| |
| import 'package:vector_math/vector_math.dart'; |
| |
| main() { |
| runTest(); |
| } |
| |
| const int numSystems = 1000; |
| const int numFrames = 1000; |
| |
| void runTest() { |
| int timeStart; |
| timeStart = new DateTime.now().millisecondsSinceEpoch; |
| |
| // Create systems |
| List<TestParticleSystem> systems = []; |
| for (int i = 0; i < numSystems; i++) { |
| systems.add(new TestParticleSystem()); |
| } |
| |
| int timeAfterCreate = new DateTime.now().millisecondsSinceEpoch; |
| print("TIME creation ${(timeAfterCreate - timeStart) / 1000.0}"); |
| timeStart = new DateTime.now().millisecondsSinceEpoch; |
| |
| // Update systems |
| for (int frame = 0; frame < numFrames; frame++) { |
| for (int i = 0; i < numSystems; i++) { |
| systems[i].update(1.0 / 60.0); |
| } |
| } |
| |
| int timeAfterUpdates = new DateTime.now().millisecondsSinceEpoch; |
| print("TIME updates ${(timeAfterUpdates - timeStart) / 1000.0}"); |
| timeStart = new DateTime.now().millisecondsSinceEpoch; |
| |
| // Calculate matrices |
| for (int frame = 0; frame < numFrames; frame++) { |
| for (int i = 0; i < numSystems; i++) { |
| systems[i].paint(); |
| } |
| } |
| |
| int timeAfterMatrices = new DateTime.now().millisecondsSinceEpoch; |
| print("TIME matrices ${(timeAfterMatrices - timeStart) / 1000.0}"); |
| } |
| |
| class TestParticle { |
| Vector2 pos; |
| Vector2 startPos; |
| |
| double colorPos; |
| double deltaColorPos; |
| |
| double size; |
| double deltaSize; |
| |
| double rotation; |
| double deltaRotation; |
| |
| double timeToLive; |
| |
| Vector2 dir; |
| |
| double radialAccel; |
| double tangentialAccel; |
| |
| Float64List simpleColorSequence; |
| |
| Matrix4 transform; |
| } |
| |
| class TestParticleSystem { |
| double life; |
| double lifeVar; |
| |
| Vector2 posVar; |
| |
| double startSize; |
| double startSizeVar; |
| |
| double endSize; |
| double endSizeVar; |
| |
| double startRotation; |
| double startRotationVar; |
| |
| double endRotation; |
| double endRotationVar; |
| |
| double direction; |
| double directionVar; |
| |
| double speed; |
| double speedVar; |
| |
| double radialAcceleration; |
| double radialAccelerationVar; |
| |
| double tangentialAcceleration; |
| double tangentialAccelerationVar; |
| |
| Vector2 gravity; |
| |
| int maxParticles; |
| int numParticlesToEmit; |
| double emissionRate; |
| |
| List<TestParticle> _particles; |
| |
| double _emitCounter; |
| int _numEmittedParticles = 0; |
| |
| TestParticleSystem({this.life: 1.5, |
| this.lifeVar: 0.0, |
| this.startSize: 2.5, |
| this.startSizeVar: 0.5, |
| this.endSize: 0.0, |
| this.endSizeVar: 0.0, |
| this.startRotation: 0.0, |
| this.startRotationVar: 0.0, |
| this.endRotation: 0.0, |
| this.endRotationVar: 0.0, |
| this.direction: 0.0, |
| this.directionVar: 360.0, |
| this.speed: 100.0, |
| this.speedVar: 50.0, |
| this.radialAcceleration: 0.0, |
| this.radialAccelerationVar: 0.0, |
| this.tangentialAcceleration: 0.0, |
| this.tangentialAccelerationVar: 0.0, |
| this.gravity, |
| this.maxParticles: 100, |
| this.emissionRate: 50.0, |
| this.numParticlesToEmit: 0}) { |
| posVar = new Vector2.zero(); |
| _particles = new List<TestParticle>(); |
| _emitCounter = 0.0; |
| gravity = new Vector2.zero(); |
| } |
| |
| void update(double dt) { |
| // Create new particles |
| double rate = 1.0 / emissionRate; |
| |
| if (_particles.length < maxParticles) { |
| _emitCounter += dt; |
| } |
| |
| while(_particles.length < maxParticles |
| && _emitCounter > rate |
| && (numParticlesToEmit == 0 || _numEmittedParticles < numParticlesToEmit)) { |
| // Add a new particle |
| _addParticle(); |
| _emitCounter -= rate; |
| } |
| |
| // Iterate over all particles |
| for (int i = _particles.length -1; i >= 0; i--) { |
| TestParticle particle = _particles[i]; |
| |
| // Manage life time |
| particle.timeToLive -= dt; |
| if (particle.timeToLive <= 0) { |
| _particles.removeAt(i); |
| continue; |
| } |
| |
| // Update the particle |
| |
| // Radial acceleration |
| Vector2 radial; |
| if (particle.pos[0] != 0 || particle.pos[1] != 0) { |
| radial = new Vector2.copy(particle.pos).normalize(); |
| } else { |
| radial = new Vector2.zero(); |
| } |
| Vector2 tangential = new Vector2.copy(radial); |
| radial.scale(particle.radialAccel); |
| |
| // Tangential acceleration |
| double newY = tangential.x; |
| tangential.x = -tangential.y; |
| tangential.y = newY; |
| tangential.scale(particle.tangentialAccel); |
| |
| // (gravity + radial + tangential) * dt |
| Vector2 accel = (gravity + radial + tangential).scale(dt); |
| particle.dir += accel; |
| |
| // Update particle position |
| particle.pos[0] += particle.dir[0] * dt; |
| particle.pos[1] += particle.dir[1] * dt; |
| |
| // Size |
| particle.size = math.max(particle.size + particle.deltaSize * dt, 0.0); |
| |
| // Angle |
| particle.rotation += particle.deltaRotation * dt; |
| |
| // Color |
| if (particle.simpleColorSequence != null) { |
| for (int i = 0; i < 4; i++) { |
| particle.simpleColorSequence[i] += particle.simpleColorSequence[i + 4] * dt; |
| } |
| } else { |
| particle.colorPos = math.min(particle.colorPos + particle.deltaColorPos * dt, 1.0); |
| } |
| } |
| } |
| |
| void _addParticle() { |
| |
| TestParticle particle = new TestParticle(); |
| |
| // Time to live |
| particle.timeToLive = math.max(life + lifeVar * randomSignedDouble(), 0.0); |
| |
| // Position |
| Vector2 srcPos = new Vector2.zero(); |
| particle.pos = new Vector2(srcPos.x + posVar.x * randomSignedDouble(), |
| srcPos.y + posVar.y * randomSignedDouble()); |
| |
| // Size |
| particle.size = math.max(startSize + startSizeVar * randomSignedDouble(), 0.0); |
| double endSizeFinal = math.max(endSize + endSizeVar * randomSignedDouble(), 0.0); |
| particle.deltaSize = (endSizeFinal - particle.size) / particle.timeToLive; |
| |
| // Rotation |
| particle.rotation = startRotation + startRotationVar * randomSignedDouble(); |
| double endRotationFinal = endRotation + endRotationVar * randomSignedDouble(); |
| particle.deltaRotation = (endRotationFinal - particle.rotation) / particle.timeToLive; |
| |
| // Direction |
| double dirRadians = radians(direction + directionVar * randomSignedDouble()); |
| Vector2 dirVector = new Vector2(math.cos(dirRadians), math.sin(dirRadians)); |
| double speedFinal = speed + speedVar * randomSignedDouble(); |
| particle.dir = dirVector.scale(speedFinal); |
| |
| // Radial acceleration |
| particle.radialAccel = radialAcceleration + radialAccelerationVar * randomSignedDouble(); |
| |
| // Tangential acceleration |
| particle.tangentialAccel = tangentialAcceleration + tangentialAccelerationVar * randomSignedDouble(); |
| |
| // Colors |
| particle.simpleColorSequence = new Float64List(8); |
| particle.simpleColorSequence[0] = 255.0; |
| particle.simpleColorSequence[1] = 255.0; |
| particle.simpleColorSequence[2] = 255.0; |
| particle.simpleColorSequence[3] = 255.0; |
| |
| particle.simpleColorSequence[4] = 255.0; |
| particle.simpleColorSequence[5] = 0.0; |
| particle.simpleColorSequence[6] = 0.0; |
| particle.simpleColorSequence[7] = 0.0; |
| |
| // Transform |
| particle.transform = new Matrix4.identity(); |
| |
| // Add particle |
| _particles.add(particle); |
| _numEmittedParticles++; |
| } |
| |
| |
| void paint() { |
| |
| if (!printed) { |
| printed = true; |
| } |
| |
| for (int i = _particles.length -1; i >= 0; i--) { |
| TestParticle particle = _particles[i]; |
| particle.rotation + randomSignedDouble(); |
| |
| // Transform |
| double c = math.cos(radians(particle.rotation)); |
| double s = math.sin(radians(particle.rotation)); |
| |
| // Create transformation matrix for scale, position and rotation |
| Matrix4 matrix = new Matrix4(c * particle.size, s * particle.size, 0.0, 0.0, |
| -s * particle.size, c * particle.size, 0.0, 0.0, |
| 0.0, 0.0, 1.0, 0.0, |
| particle.pos.x, particle.pos.y, 0.0, 1.0); |
| |
| particle.transform.multiply(matrix); |
| } |
| } |
| } |
| |
| math.Random _random = new math.Random(); |
| |
| bool printed = false; |
| |
| // Random methods |
| |
| double randomDouble() { |
| return _random.nextDouble(); |
| } |
| |
| double randomSignedDouble() { |
| return _random.nextDouble() * 2.0 - 1.0; |
| } |
| |
| int randomInt(int max) { |
| return _random.nextInt(max); |
| } |