Commit 59b0e328 authored by Viktor Lidholt's avatar Viktor Lidholt

Refactors randomizations of color sequences and optimizes particle systems...

Refactors randomizations of color sequences and optimizes particle systems (uses single Paint instance, doesn't compute accelerations unless used, reduces number of created objects, faster color calculations)
Fixes indentation
Optimizes lookup in fast version of atan2 (toInt is faster than floor)
Removes frame rate printout and adds assert
parent 45399c7a
...@@ -20,25 +20,6 @@ class ColorSequence { ...@@ -20,25 +20,6 @@ class ColorSequence {
colorStops = new List<double>.from(sequence.colorStops); colorStops = new List<double>.from(sequence.colorStops);
} }
ColorSequence.copyWithVariance(ColorSequence sequence, int alphaVar, int redVar, int greenVar, int blueVar) {
colors = new List<Color>();
colorStops = new List<double>.from(sequence.colorStops);
for (Color color in sequence.colors) {
int aDelta = ((randomDouble() * 2.0 - 1.0) * alphaVar).toInt();
int rDelta = ((randomDouble() * 2.0 - 1.0) * redVar).toInt();
int gDelta = ((randomDouble() * 2.0 - 1.0) * greenVar).toInt();
int bDelta = ((randomDouble() * 2.0 - 1.0) * blueVar).toInt();
int aNew = (color.alpha + aDelta).clamp(0, 255);
int rNew = (color.red + rDelta).clamp(0, 255);
int gNew = (color.green + gDelta).clamp(0, 255);
int bNew = (color.blue + bDelta).clamp(0, 255);
colors.add(new Color.fromARGB(aNew, rNew, gNew, bNew));
}
}
Color colorAtPosition(double pos) { Color colorAtPosition(double pos) {
assert(pos >= 0.0 && pos <= 1.0); assert(pos >= 0.0 && pos <= 1.0);
......
...@@ -16,12 +16,18 @@ class _Particle { ...@@ -16,12 +16,18 @@ class _Particle {
double timeToLive; double timeToLive;
Vector2 dir; Vector2 dir;
double radialAccel;
double tangentialAccel; _ParticleAccelerations accelerations;
Float64List simpleColorSequence;
ColorSequence colorSequence; ColorSequence colorSequence;
} }
class _ParticleAccelerations {
double radialAccel;
double tangentialAccel;
}
class ParticleSystem extends Node { class ParticleSystem extends Node {
...@@ -76,10 +82,12 @@ class ParticleSystem extends Node { ...@@ -76,10 +82,12 @@ class ParticleSystem extends Node {
List<_Particle> _particles; List<_Particle> _particles;
double _emitCounter; double _emitCounter;
// Not yet used:
// double _elapsedTime;
int _numEmittedParticles = 0; int _numEmittedParticles = 0;
static Paint _paint = new Paint()
..setFilterQuality(FilterQuality.low)
..isAntiAlias = false;
ParticleSystem(this.texture, ParticleSystem(this.texture,
{this.life: 1.5, {this.life: 1.5,
this.lifeVar: 1.0, this.lifeVar: 1.0,
...@@ -154,26 +162,35 @@ class ParticleSystem extends Node { ...@@ -154,26 +162,35 @@ class ParticleSystem extends Node {
// Update the particle // Update the particle
if (particle.accelerations != null) {
// Radial acceleration // Radial acceleration
Vector2 radial; Vector2 radial;
if (particle.pos[0] != 0 || particle.pos[1] != 0) { if (particle.pos[0] != 0 || particle.pos[1] != 0) {
radial = new Vector2.copy(particle.pos).normalize(); radial = new Vector2.copy(particle.pos).normalize();
} else { } else {
radial = new Vector2.zero(); radial = new Vector2.zero();
}
Vector2 tangential = new Vector2.copy(radial);
radial.scale(particle.accelerations.radialAccel);
// Tangential acceleration
double newY = tangential.x;
tangential.x = -tangential.y;
tangential.y = newY;
tangential.scale(particle.accelerations.tangentialAccel);
// (gravity + radial + tangential) * dt
Vector2 accel = (gravity + radial + tangential).scale(dt);
particle.dir += accel;
} else if (gravity[0] != 0.0 || gravity[1] != 0) {
// gravity
Vector2 accel = gravity.scale(dt);
particle.dir += accel;
} }
Vector2 tangential = new Vector2.copy(radial);
radial.scale(particle.radialAccel);
// Tangential acceleration // Update particle position
double newY = tangential.x; particle.pos[0] += particle.dir[0] * dt;
tangential.x = -tangential.y; particle.pos[1] += particle.dir[1] * dt;
tangential.y = newY;
tangential.scale(particle.tangentialAccel);
// (gravity + radial + tangential) * dt
Vector2 accel = (gravity + radial + tangential).scale(dt);
particle.dir += accel;
particle.pos += new Vector2.copy(particle.dir).scale(dt);
// Size // Size
particle.size = math.max(particle.size + particle.deltaSize * dt, 0.0); particle.size = math.max(particle.size + particle.deltaSize * dt, 0.0);
...@@ -182,7 +199,13 @@ class ParticleSystem extends Node { ...@@ -182,7 +199,13 @@ class ParticleSystem extends Node {
particle.rotation += particle.deltaRotation * dt; particle.rotation += particle.deltaRotation * dt;
// Color // Color
particle.colorPos = math.min(particle.colorPos + particle.deltaColorPos * dt, 1.0); 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);
}
} }
if (autoRemoveOnFinish && _particles.length == 0 && _numEmittedParticles > 0) { if (autoRemoveOnFinish && _particles.length == 0 && _numEmittedParticles > 0) {
...@@ -218,18 +241,50 @@ class ParticleSystem extends Node { ...@@ -218,18 +241,50 @@ class ParticleSystem extends Node {
double speedFinal = speed + speedVar * randomSignedDouble(); double speedFinal = speed + speedVar * randomSignedDouble();
particle.dir = dirVector.scale(speedFinal); particle.dir = dirVector.scale(speedFinal);
// Radial acceleration // Accelerations
particle.radialAccel = radialAcceleration + radialAccelerationVar * randomSignedDouble(); if (radialAcceleration != 0.0 || radialAccelerationVar != 0.0 ||
tangentialAcceleration != 0.0 || tangentialAccelerationVar != 0.0) {
particle.accelerations = new _ParticleAccelerations();
// Tangential acceleration // Radial acceleration
particle.tangentialAccel = tangentialAcceleration + tangentialAccelerationVar * randomSignedDouble(); particle.accelerations.radialAccel = radialAcceleration + radialAccelerationVar * randomSignedDouble();
// Tangential acceleration
particle.accelerations.tangentialAccel = tangentialAcceleration + tangentialAccelerationVar * randomSignedDouble();
}
// Color // Color
particle.colorPos = 0.0; particle.colorPos = 0.0;
particle.deltaColorPos = 1.0 / particle.timeToLive; particle.deltaColorPos = 1.0 / particle.timeToLive;
if (alphaVar != 0 || redVar != 0 || greenVar != 0 || blueVar != 0) { if (alphaVar != 0 || redVar != 0 || greenVar != 0 || blueVar != 0) {
particle.colorSequence = new ColorSequence.copyWithVariance(colorSequence, alphaVar, redVar, greenVar, blueVar); particle.colorSequence = _ColorSequenceUtil.copyWithVariance(colorSequence, alphaVar, redVar, greenVar, blueVar);
}
// Optimizes the case where there are only two colors in the sequence
if (colorSequence.colors.length == 2) {
Color startColor;
Color endColor;
if (particle.colorSequence != null) {
startColor = particle.colorSequence.colors[0];
endColor = particle.colorSequence.colors[1];
} else {
startColor = colorSequence.colors[0];
endColor = colorSequence.colors[1];
}
// First 4 elements are start ARGB, last 4 are delta ARGB
particle.simpleColorSequence = new Float64List(8);
particle.simpleColorSequence[0] = startColor.alpha.toDouble();
particle.simpleColorSequence[1] = startColor.red.toDouble();
particle.simpleColorSequence[2] = startColor.green.toDouble();
particle.simpleColorSequence[3] = startColor.blue.toDouble();
particle.simpleColorSequence[4] = (endColor.alpha.toDouble() - startColor.alpha.toDouble()) / particle.timeToLive;
particle.simpleColorSequence[5] = (endColor.red.toDouble() - startColor.red.toDouble()) / particle.timeToLive;
particle.simpleColorSequence[6] = (endColor.green.toDouble() - startColor.green.toDouble()) / particle.timeToLive;
particle.simpleColorSequence[7] = (endColor.blue.toDouble() - startColor.blue.toDouble()) / particle.timeToLive;
} }
_particles.add(particle); _particles.add(particle);
...@@ -242,6 +297,8 @@ class ParticleSystem extends Node { ...@@ -242,6 +297,8 @@ class ParticleSystem extends Node {
List<Rect> rects = []; List<Rect> rects = [];
List<Color> colors = []; List<Color> colors = [];
_paint.setTransferMode(transferMode);
for (_Particle particle in _particles) { for (_Particle particle in _particles) {
// Transform // Transform
double scos; double scos;
...@@ -250,9 +307,12 @@ class ParticleSystem extends Node { ...@@ -250,9 +307,12 @@ class ParticleSystem extends Node {
double extraRotation = GameMath.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; scos = math.cos(convertDegrees2Radians(particle.rotation) + extraRotation) * particle.size;
ssin = math.sin(convertDegrees2Radians(particle.rotation) + extraRotation) * particle.size; ssin = math.sin(convertDegrees2Radians(particle.rotation) + extraRotation) * particle.size;
} else { } else if (particle.rotation != 0.0) {
scos = math.cos(convertDegrees2Radians(particle.rotation)) * particle.size; scos = math.cos(convertDegrees2Radians(particle.rotation)) * particle.size;
ssin = math.sin(convertDegrees2Radians(particle.rotation)) * particle.size; ssin = math.sin(convertDegrees2Radians(particle.rotation)) * particle.size;
} else {
scos = particle.size;
ssin = 0.0;
} }
RSTransform transform = new RSTransform(scos, ssin, particle.pos[0], particle.pos[1]); RSTransform transform = new RSTransform(scos, ssin, particle.pos[0], particle.pos[1]);
transforms.add(transform); transforms.add(transform);
...@@ -262,19 +322,55 @@ class ParticleSystem extends Node { ...@@ -262,19 +322,55 @@ class ParticleSystem extends Node {
rects.add(rect); rects.add(rect);
// Color // Color
Color particleColor; if (particle.simpleColorSequence != null) {
if (particle.colorSequence != null) { Color particleColor = new Color.fromARGB(
particleColor = particle.colorSequence.colorAtPosition(particle.colorPos); particle.simpleColorSequence[0].toInt().clamp(0, 255),
particle.simpleColorSequence[1].toInt().clamp(0, 255),
particle.simpleColorSequence[2].toInt().clamp(0, 255),
particle.simpleColorSequence[3].toInt().clamp(0, 255));
colors.add(particleColor);
} else { } else {
particleColor = colorSequence.colorAtPosition(particle.colorPos); Color particleColor;
if (particle.colorSequence != null) {
particleColor = particle.colorSequence.colorAtPosition(particle.colorPos);
} else {
particleColor = colorSequence.colorAtPosition(particle.colorPos);
}
colors.add(particleColor);
} }
colors.add(particleColor);
} }
Paint paint = new Paint()..setTransferMode(transferMode)
..setFilterQuality(FilterQuality.low) // All Skia examples do this.
..isAntiAlias = false; // Antialiasing breaks SkCanvas.drawAtlas?
canvas.drawAtlas(texture.image, transforms, rects, colors, canvas.drawAtlas(texture.image, transforms, rects, colors,
TransferMode.modulate, null, paint); TransferMode.modulate, null, _paint);
}
}
class _ColorSequenceUtil {
static ColorSequence copyWithVariance(
ColorSequence sequence,
int alphaVar,
int redVar,
int greenVar,
int blueVar
) {
ColorSequence copy = new ColorSequence.copy(sequence);
int i = 0;
for (Color color in sequence.colors) {
int aDelta = ((randomDouble() * 2.0 - 1.0) * alphaVar).toInt();
int rDelta = ((randomDouble() * 2.0 - 1.0) * redVar).toInt();
int gDelta = ((randomDouble() * 2.0 - 1.0) * greenVar).toInt();
int bDelta = ((randomDouble() * 2.0 - 1.0) * blueVar).toInt();
int aNew = (color.alpha + aDelta).clamp(0, 255);
int rNew = (color.red + rDelta).clamp(0, 255);
int gNew = (color.green + gDelta).clamp(0, 255);
int bNew = (color.blue + bDelta).clamp(0, 255);
copy.colors[i] = new Color.fromARGB(aNew, rNew, gNew, bNew);
i++;
}
return copy;
} }
} }
...@@ -31,6 +31,10 @@ class SpriteBox extends RenderBox { ...@@ -31,6 +31,10 @@ class SpriteBox extends RenderBox {
void set rootNode (NodeWithSize value) { void set rootNode (NodeWithSize value) {
if (value == _rootNode) return; if (value == _rootNode) return;
// Ensure that the root node has a size
assert(value.size.width > 0);
assert(value.size.height > 0);
// Remove sprite box references // Remove sprite box references
if (_rootNode != null) _removeSpriteBoxReference(_rootNode); if (_rootNode != null) _removeSpriteBoxReference(_rootNode);
...@@ -334,9 +338,9 @@ class SpriteBox extends RenderBox { ...@@ -334,9 +338,9 @@ class SpriteBox extends RenderBox {
_frameRate = 1.0/delta; _frameRate = 1.0/delta;
// Print frame rate // // Print frame rate
if (_numFrames % 60 == 0) // if (_numFrames % 60 == 0)
print("delta: $delta fps: $_frameRate"); // print("delta: $delta fps: $_frameRate");
_runActions(_rootNode, delta); _runActions(_rootNode, delta);
_callUpdate(_rootNode, delta); _callUpdate(_rootNode, delta);
......
...@@ -57,26 +57,26 @@ class GameMath { ...@@ -57,26 +57,26 @@ class GameMath {
if (x >= 0) { if (x >= 0) {
if (y >= 0) { if (y >= 0) {
if (x >= y) if (x >= y)
return _atan2.ppy[(_Atan2Constants.size * y / x + 0.5).floor()]; return _atan2.ppy[(_Atan2Constants.size * y / x + 0.5).toInt()];
else else
return _atan2.ppx[(_Atan2Constants.size * x / y + 0.5).floor()]; return _atan2.ppx[(_Atan2Constants.size * x / y + 0.5).toInt()];
} else { } else {
if (x >= -y) if (x >= -y)
return _atan2.pny[(_Atan2Constants.ezis * y / x + 0.5).floor()]; return _atan2.pny[(_Atan2Constants.ezis * y / x + 0.5).toInt()];
else else
return _atan2.pnx[(_Atan2Constants.ezis * x / y + 0.5).floor()]; return _atan2.pnx[(_Atan2Constants.ezis * x / y + 0.5).toInt()];
} }
} else { } else {
if (y >= 0) { if (y >= 0) {
if (-x >= y) if (-x >= y)
return _atan2.npy[(_Atan2Constants.ezis * y / x + 0.5).floor()]; return _atan2.npy[(_Atan2Constants.ezis * y / x + 0.5).toInt()];
else else
return _atan2.npx[(_Atan2Constants.ezis * x / y + 0.5).floor()]; return _atan2.npx[(_Atan2Constants.ezis * x / y + 0.5).toInt()];
} else { } else {
if (x <= y) if (x <= y)
return _atan2.nny[(_Atan2Constants.size * y / x + 0.5).floor()]; return _atan2.nny[(_Atan2Constants.size * y / x + 0.5).toInt()];
else else
return _atan2.nnx[(_Atan2Constants.size * x / y + 0.5).floor()]; return _atan2.nnx[(_Atan2Constants.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