Commit 53c66a5f authored by Viktor Lidholt's avatar Viktor Lidholt

Optimizations to particle systems. Uses single instance of Random and faster atan2 function.

parent f3e51d9f
......@@ -80,8 +80,6 @@ class ParticleSystem extends Node {
// double _elapsedTime;
int _numEmittedParticles = 0;
math.Random _rand;
ParticleSystem(this.texture,
{this.life: 1.5,
this.lifeVar: 1.0,
......@@ -116,7 +114,6 @@ class ParticleSystem extends Node {
this.numParticlesToEmit: 0,
this.autoRemoveOnFinish: true}) {
_particles = new List<_Particle>();
_rand = new math.Random();
_emitCounter = 0.0;
// _elapsedTime = 0.0;
if (gravity == null) gravity = new Vector2.zero();
......@@ -124,6 +121,8 @@ class ParticleSystem extends Node {
}
void update(double dt) {
// TODO: Fix this (it's a temp fix for low framerates)
if (dt > 0.1) dt = 0.1;
// Create new particles
double rate = 1.0 / emissionRate;
......@@ -196,34 +195,34 @@ class ParticleSystem extends Node {
_Particle particle = new _Particle();
// Time to live
particle.timeToLive = math.max(life + lifeVar * randMinus1To1(), 0.0);
particle.timeToLive = math.max(life + lifeVar * randomSignedDouble(), 0.0);
// Position
Point srcPos = Point.origin;
particle.pos = new Vector2(srcPos.x + posVar.x * randMinus1To1(),
srcPos.y + posVar.y * randMinus1To1());
particle.pos = new Vector2(srcPos.x + posVar.x * randomSignedDouble(),
srcPos.y + posVar.y * randomSignedDouble());
// Size
particle.size = math.max(startSize + startSizeVar * randMinus1To1(), 0.0);
double endSizeFinal = math.max(endSize + endSizeVar * randMinus1To1(), 0.0);
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 * randMinus1To1();
double endRotationFinal = endRotation + endRotationVar * randMinus1To1();
particle.rotation = startRotation + startRotationVar * randomSignedDouble();
double endRotationFinal = endRotation + endRotationVar * randomSignedDouble();
particle.deltaRotation = (endRotationFinal - particle.rotation) / particle.timeToLive;
// Direction
double dirRadians = convertDegrees2Radians(direction + directionVar * randMinus1To1());
double dirRadians = convertDegrees2Radians(direction + directionVar * randomSignedDouble());
Vector2 dirVector = new Vector2(math.cos(dirRadians), math.sin(dirRadians));
double speedFinal = speed + speedVar * randMinus1To1();
double speedFinal = speed + speedVar * randomSignedDouble();
particle.dir = dirVector.scale(speedFinal);
// Radial acceleration
particle.radialAccel = radialAcceleration + radialAccelerationVar * randMinus1To1();
particle.radialAccel = radialAcceleration + radialAccelerationVar * randomSignedDouble();
// Tangential acceleration
particle.tangentialAccel = tangentialAcceleration + tangentialAccelerationVar * randMinus1To1();
particle.tangentialAccel = tangentialAcceleration + tangentialAccelerationVar * randomSignedDouble();
// Color
particle.colorPos = 0.0;
......@@ -248,7 +247,7 @@ class ParticleSystem extends Node {
double scos;
double ssin;
if (rotateToMovement) {
double extraRotation = math.atan2(particle.dir[1], particle.dir[0]);
double extraRotation = GameMath.atan2(particle.dir[1], particle.dir[0]);
scos = math.cos(convertDegrees2Radians(particle.rotation) + extraRotation) * particle.size;
ssin = math.sin(convertDegrees2Radians(particle.rotation) + extraRotation) * particle.size;
} else {
......@@ -276,14 +275,12 @@ class ParticleSystem extends Node {
Paint paint = new Paint()..setTransferMode(transferMode)
..setFilterQuality(FilterQuality.low) // All Skia examples do this.
..isAntiAlias = false; // Antialiasing breaks SkCanvas.drawAtlas?
// return canvas.drawAtlas(texture.image, transforms, rects, colors,
// TransferMode.modulate, null, paint);
return canvas.drawAtlas(texture.image, transforms, rects, colors,
TransferMode.modulate, null, paint);
dartDrawAtlas(canvas, texture.image, transforms, rects, colors,
TransferMode.modulate, paint);
}
double randMinus1To1() => _rand.nextDouble() * 2.0 - 1.0;
}
void dartDrawAtlas(Canvas canvas, Image image, List<RSTransform> transforms,
......
part of sprites;
math.Random _random = new math.Random();
// Random methods
double randomDouble() {
return _random.nextDouble();
}
double randomSignedDouble() {
return _random.nextDouble() * 2.0 - 1.0;
}
int randomInt(int max) {
return _random.nextInt(max);
}
// atan2
class GameMath {
static bool _inited = false;
static final int size = 1024;
static final double stretch = math.PI;
static final int ezis = -size;
static Float64List atan2_table_ppy = new Float64List(size + 1);
static Float64List atan2_table_ppx = new Float64List(size + 1);
static Float64List atan2_table_pny = new Float64List(size + 1);
static Float64List atan2_table_pnx = new Float64List(size + 1);
static Float64List atan2_table_npy = new Float64List(size + 1);
static Float64List atan2_table_npx = new Float64List(size + 1);
static Float64List atan2_table_nny = new Float64List(size + 1);
static Float64List atan2_table_nnx = new Float64List(size + 1);
static void init() {
if (_inited) return;
for (int i = 0; i <= size; i++) {
double f = i.toDouble() / size.toDouble();
atan2_table_ppy[i] = math.atan(f) * stretch / math.PI;
atan2_table_ppx[i] = stretch * 0.5 - atan2_table_ppy[i];
atan2_table_pny[i] = -atan2_table_ppy[i];
atan2_table_pnx[i] = atan2_table_ppy[i] - stretch * 0.5;
atan2_table_npy[i] = stretch - atan2_table_ppy[i];
atan2_table_npx[i] = atan2_table_ppy[i] + stretch * 0.5;
atan2_table_nny[i] = atan2_table_ppy[i] - stretch;
atan2_table_nnx[i] = -stretch * 0.5 - atan2_table_ppy[i];
}
_inited = true;
}
static double atan2(double y, double x) {
if (!_inited)
init();
if (x >= 0) {
if (y >= 0) {
if (x >= y)
return atan2_table_ppy[(size * y / x + 0.5).toInt()];
else
return atan2_table_ppx[(size * x / y + 0.5).toInt()];
} else {
if (x >= -y)
return atan2_table_pny[(ezis * y / x + 0.5).toInt()];
else
return atan2_table_pnx[(ezis * x / y + 0.5).toInt()];
}
} else {
if (y >= 0) {
if (-x >= y)
return atan2_table_npy[(ezis * y / x + 0.5).toInt()];
else
return atan2_table_npx[(ezis * x / y + 0.5).toInt()];
} else {
if (x <= y)
return atan2_table_nny[(size * y / x + 0.5).toInt()];
else
return atan2_table_nnx[(size * x / y + 0.5).toInt()];
}
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment