Lorsque j'ai créé un test de particules, j'ai simplement mis en cache des images basées sur la rotation (comme 35 rotations), la teinte de la couleur et l'alpha et j'ai créé un wrapper pour qu'elles soient créées automatiquement. Cela a bien fonctionné. Oui, il devrait y avoir une sorte d'opération de teinte, mais lorsqu'il s'agit d'un rendu logiciel, le mieux est de tout mettre en cache, comme dans Flash. Exemple de particule que j'ai fait pour le plaisir
<!DOCTYPE HTML>
<html lang="en">
<head>
<title>Particle Test</title>
<script language="javascript" src="../Vector.js"></script>
<script type="text/javascript">
function Particle(x, y)
{
this.position = new Vector(x, y);
this.velocity = new Vector(0.0, 0.0);
this.force = new Vector(0.0, 0.0);
this.mass = 1;
this.alpha = 0;
}
// Canvas
var canvas = null;
var context2D = null;
// Blue Particle Texture
var blueParticleTexture = new Image();
var blueParticleTextureLoaded = false;
var blueParticleTextureAlpha = new Array();
var mousePosition = new Vector();
var mouseDownPosition = new Vector();
// Particles
var particles = new Array();
var center = new Vector(250, 250);
var imageData;
function Initialize()
{
canvas = document.getElementById('canvas');
context2D = canvas.getContext('2d');
for (var createEntity = 0; createEntity < 150; ++createEntity)
{
var randomAngle = Math.random() * Math.PI * 2;
var particle = new Particle(Math.cos(randomAngle) * 250 + 250, Math.sin(randomAngle) * 250 + 250);
particle.velocity = center.Subtract(particle.position).Normal().Normalize().Multiply(Math.random() * 5 + 2);
particle.mass = Math.random() * 3 + 0.5;
particles.push(particle);
}
blueParticleTexture.onload = function()
{
context2D.drawImage(blueParticleTexture, 0, 0);
imageData = context2D.getImageData(0, 0, 5, 5);
var imageDataPixels = imageData.data;
for (var i = 0; i <= 255; ++i)
{
var newImageData = context2D.createImageData(5, 5);
var pixels = newImageData.data;
for (var j = 0, n = pixels.length; j < n; j += 4)
{
pixels[j] = imageDataPixels[j];
pixels[j + 1] = imageDataPixels[j + 1];
pixels[j + 2] = imageDataPixels[j + 2];
pixels[j + 3] = Math.floor(imageDataPixels[j + 3] * i / 255);
}
blueParticleTextureAlpha.push(newImageData);
}
blueParticleTextureLoaded = true;
}
blueParticleTexture.src = 'blueparticle.png';
setInterval(Update, 50);
}
function Update()
{
// Clear the screen
context2D.clearRect(0, 0, canvas.width, canvas.height);
for (var i = 0; i < particles.length; ++i)
{
var particle = particles[i];
var v = center.Subtract(particle.position).Normalize().Multiply(0.5);
particle.force = v;
particle.velocity.ThisAdd(particle.force.Divide(particle.mass));
particle.velocity.ThisMultiply(0.98);
particle.position.ThisAdd(particle.velocity);
particle.force = new Vector();
//if (particle.alpha + 5 < 255) particle.alpha += 5;
if (particle.position.Subtract(center).LengthSquared() < 20 * 20)
{
var randomAngle = Math.random() * Math.PI * 2;
particle.position = new Vector(Math.cos(randomAngle) * 250 + 250, Math.sin(randomAngle) * 250 + 250);
particle.velocity = center.Subtract(particle.position).Normal().Normalize().Multiply(Math.random() * 5 + 2);
//particle.alpha = 0;
}
}
if (blueParticleTextureLoaded)
{
for (var i = 0; i < particles.length; ++i)
{
var particle = particles[i];
var intensity = Math.min(1, Math.max(0, 1 - Math.abs(particle.position.Subtract(center).Length() - 125) / 125));
context2D.putImageData(blueParticleTextureAlpha[Math.floor(intensity * 255)], particle.position.X - 2.5, particle.position.Y - 2.5, 0, 0, blueParticleTexture.width, blueParticleTexture.height);
//context2D.drawImage(blueParticleTexture, particle.position.X - 2.5, particle.position.Y - 2.5);
}
}
}
</script>
<body onload="Initialize()" style="background-color:black">
<canvas id="canvas" width="500" height="500" style="border:2px solid gray;"/>
<h1>Canvas is not supported in this browser.</h1>
</canvas>
<p>No directions</p>
</body>
</html>
où vector.js est juste un objet vectoriel naïf :
// Vector class
// TODO: EXamples
// v0 = v1 * 100 + v3 * 200;
// v0 = v1.MultiplY(100).Add(v2.MultiplY(200));
// TODO: In the future maYbe implement:
// VectorEval("%1 = %2 * %3 + %4 * %5", v0, v1, 100, v2, 200);
function Vector(X, Y)
{
/*
this.__defineGetter__("X", function() { return this.X; });
this.__defineSetter__("X", function(value) { this.X = value });
this.__defineGetter__("Y", function() { return this.Y; });
this.__defineSetter__("Y", function(value) { this.Y = value });
*/
this.Add = function(v)
{
return new Vector(this.X + v.X, this.Y + v.Y);
}
this.Subtract = function(v)
{
return new Vector(this.X - v.X, this.Y - v.Y);
}
this.Multiply = function(s)
{
return new Vector(this.X * s, this.Y * s);
}
this.Divide = function(s)
{
return new Vector(this.X / s, this.Y / s);
}
this.ThisAdd = function(v)
{
this.X += v.X;
this.Y += v.Y;
return this;
}
this.ThisSubtract = function(v)
{
this.X -= v.X;
this.Y -= v.Y;
return this;
}
this.ThisMultiply = function(s)
{
this.X *= s;
this.Y *= s;
return this;
}
this.ThisDivide = function(s)
{
this.X /= s;
this.Y /= s;
return this;
}
this.Length = function()
{
return Math.sqrt(this.X * this.X + this.Y * this.Y);
}
this.LengthSquared = function()
{
return this.X * this.X + this.Y * this.Y;
}
this.Normal = function()
{
return new Vector(-this.Y, this.X);
}
this.ThisNormal = function()
{
var X = this.X;
this.X = -this.Y
this.Y = X;
return this;
}
this.Normalize = function()
{
var length = this.Length();
if(length != 0)
{
return new Vector(this.X / length, this.Y / length);
}
}
this.ThisNormalize = function()
{
var length = this.Length();
if (length != 0)
{
this.X /= length;
this.Y /= length;
}
return this;
}
this.Negate = function()
{
return new Vector(-this.X, -this.Y);
}
this.ThisNegate = function()
{
this.X = -this.X;
this.Y = -this.Y;
return this;
}
this.Compare = function(v)
{
return Math.abs(this.X - v.X) < 0.0001 && Math.abs(this.Y - v.Y) < 0.0001;
}
this.Dot = function(v)
{
return this.X * v.X + this.Y * v.Y;
}
this.Cross = function(v)
{
return this.X * v.Y - this.Y * v.X;
}
this.Projection = function(v)
{
return this.MultiplY(v, (this.X * v.X + this.Y * v.Y) / (v.X * v.X + v.Y * v.Y));
}
this.ThisProjection = function(v)
{
var temp = (this.X * v.X + this.Y * v.Y) / (v.X * v.X + v.Y * v.Y);
this.X = v.X * temp;
this.Y = v.Y * temp;
return this;
}
// If X and Y aren't supplied, default them to zero
if (X == undefined) this.X = 0; else this.X = X;
if (Y == undefined) this.Y = 0; else this.Y = Y;
}
/*
Object.definePropertY(Vector, "X", {get : function(){ return X; },
set : function(value){ X = value; },
enumerable : true,
configurable : true});
Object.definePropertY(Vector, "Y", {get : function(){ return X; },
set : function(value){ X = value; },
enumerable : true,
configurable : true});
*/