1. Code
  2. JavaScript

Generieren eines Partikelsystems mit JavaScript

Scroll to top

German (Deutsch) translation by Federicco Ancie (you can also view the original English article)

Wenn Sie jemals einen in Flash erstellten Feuerwerkseffekt gesehen haben, zeige ich Ihnen, wie Sie den Effekt mit reinem JavaScript reproduzieren können! Warum sollten die Flash-Entwickler den ganzen Spaß haben?


Einrichten Ihres Arbeitsbereichs

Bedarf

Kenntnisse der Javascript-Objektnotation. Wenn Sie in diesem Bereich eine Schulung benötigen, ist dies kein Problem. Leigh Kaszick bietet ein ausführliches Tutorial zu den Grundlagen objektorientierten JavaScript.

Grundkenntnisse von Raphael.js. Wenn Sie neu darin sind, sollten Sie noch einmal eine Einführung in die Raphael JS-Bibliothek von Damian Dawber lesen.


Was ist ein Partikelsystem?

Ein Partikelsystem in Bezug auf Computergrafik bezieht sich auf die Nachbildung des Verhaltens natürlicher Partikelsysteme in einem 3D-Modell wie Explosionen, Feuer, Wolken und einer Vielzahl anderer Phänomene, die mit herkömmlichen Programmiertechniken nur schwer zu implementieren sind.


Ein Basispartikelsystem besteht aus -

  • Ein Emitter - Der Punkt im Raum, an dem die Partikel entstanden sind.
  • Die Bühne - Der Ort, an dem sich das Partikelsystem befindet.
  • Kräfte - Dies sind äußere Kräfte, die die Bewegung der Partikel beeinflussen. In unserem Tutorial wird es die Schwerkraft sein.

Schritt 1

Wir beginnen mit der Erstellung unseres Partikelbildes.

Öffnen Sie Photoshop und erstellen Sie eine Leinwand mit einer Größe von 25 x 25 Pixel.


Erstellen Sie eine neue Ebene.


Wählen Sie einen 23px Rundpinsel mit einer Härte von 100%. In diesem Tutorial verwenden wir die weiße Farbe, aber Sie können eine beliebige Pinselform oder -farbe auswählen.


Jetzt müssen wir die Hintergrundebene ausblenden und sie dann mit der Option "Für Web und Geräte speichern" als "particle_img" im PNG-24-Format speichern.


Schritt 2

Beginnen wir nun mit der Codierung. Fügen Sie zunächst den folgenden Code ein.

1
 
2
<html> 
3
<head> 
4
<script type="text/JavaScript" src="raphael-min.js"></script> 
5
<script type="text/JavaScript" src="sps.js"></script> 
6
<title>Simple Particle System</title> 
7
</head> 
8
<body style="background:#000000;color:#CCCCCC" onload="startSystem()"> 
9
<div id="pane" ></div> 
10
</body> 
11
</html>

Dies ist ein einfacher Ausschnitt aus HTML-Code, der besteht aus:

  • Importieren von raphael.js und sps.js, in denen wir mit dem JavaScript-Code unseres Partikelsystems arbeiten.
  • Dann gibt es im Körper ein Div mit einem ID der Scheibe - es wird unsere Bühne sein.
  • Das Body-Tag besteht auch aus einer startSystem() -Funktion, die beim Onload-Ereignis aufgerufen wird. Wir werden es später in unserer JavaScript-Datei definieren.

Schritt 3

Als nächstes erstellen wir unsere sps.js, in die wir den eigentlichen Code für unser Partikelsystem eingeben.


Schritt 4

Da wir mit einem 2D-Modell arbeiten, erstellen wir eine Vektorklasse, die sich um die Koordinaten kümmert, um eine Reihe von x, y-Variablen im Skript zu vermeiden.

1
 
2
function Vector() 
3
{ 
4
	this.x =0; 
5
	this.y =0; 
6
    //this.z =0;    

7
	 
8
}

Hinweis: Wir werden keine Z-Koordinaten verwenden, da wir uns nicht mit dem Partikelabstand von der Kameraansicht (Augen) befassen. Die Z-Koordinate befasst sich hauptsächlich mit Skalierungs- und Opazitätsattributen.


Schritt 5

Wir benötigen Funktionen, um die Werte der Variablen festzulegen und hinzuzufügen, damit wir die folgenden Funktionen in unserer Vector-Klasse deklarieren können.

1
 
2
function Vector() 
3
{ 
4
	this.x =0; 
5
	this.y =0; 
6
    //this.z =0;    

7
	this.set = function(X,Y) // setting the values of X,Y to our object 

8
	{ 
9
		with(this) 
10
		{ 
11
			x = X; 
12
			y =Y; 
13
			//z = Z; 

14
		} 
15
	} 
16
	this.add = function(vector2) // adding another vector's values to our current vector object 

17
	{ 
18
		this.x = this.x + vector2.x; 
19
		this.y = this.y + vector2.y; 
20
		//this.z = this.z + vector2.z;	 

21
	} 
22
}

Hinweis: Stellen Sie sicher, dass Sie Z in den eingestellten Funktionsparametern hinzufügen, wenn Sie es verwenden.


Schritt 6

Erstellen wir ein Vektorobjekt, das die Koordinaten enthält, aus denen die Partikel stammen. Außerdem werden wir ein globales Raphael-Objekt und eine Timer-Variable deklarieren, die wir später verwenden werden.

1
 
2
var canvas;  // our raphael object 

3
var timer;  
4
var emitter = new Vector(); 
5
emitter.set(400,200);

Schritt 7

Wir müssen eine Klasse für unsere Partikelobjekte erstellen. Sie besteht aus grundlegenden Eigenschaften wie:

  • Farbe und Form - grundlegende Eigenschaften des Partikels.
  • Größe - die Größe des Partikels.
  • Ort - sein Ursprungsort.
  • Geschwindigkeit - die Geschwindigkeit (hier bezieht sie sich auf die Ausbreitung der Partikel auf der Bühne).
  • Beschleunigung - Geschwindigkeitssteigerung.
  • Lebensdauer - Die Lebensdauer des Partikels.

In der JavaScript-Welt werden wir einige Variablen geringfügig ändern, z. B. die Farbe und Größe, die bereits beim Erstellen des Bilds in Photoshop definiert wurden.

1
 
2
function Particle() 
3
{ 
4
this.size = Math.random() * 10 + 15;  
5
this.particle =  canvas.image("particle_img.png",emitter.x,emitter.y,this.size,this.size); 
6
this.loc = new Vector(); 
7
this.vel = new Vector(); 
8
this.acc = new Vector(); 
9
this.lifespan = Math.random() * 250; 
10
}

In JavaScript werden Klassen mit der function deklariert und ihre Variablen mit this Funktion deklariert.

  • Wir wollen, dass die Größe der Partikel zufällig erzeugt wird und zwischen 15 und 25 liegt.
  • Das Partikel ist das Raphael-Bildobjekt mit Bildnamen, Koordinaten und Größe als Parametern.
  • loc ist der Ort des Partikels.
  • acc ist die Beschleunigung.
  • vel ist die Geschwindigkeit.
  • Die Lebensdauer ist der Zeitraum, in dem das Partikel auf der Bühne lebt.

Schritt 8

Wir müssen Funktionen für die folgenden Bedingungen erstellen:

  • Erstellen eines Partikels auf der Leinwand mit den oben deklarierten Eigenschaften.
  • Ständige Aktualisierung seiner Position in Bezug auf seine Beschleunigung.
  • Wenn wir prüfen, ob das Partikel tot ist, müssen wir es von unserer Leinwand entfernen, sonst ist unsere Bühne voller toter Partikel :).

Schritt 9

Zuerst deklarieren wir die init-Funktion, mit der wir unsere Partikel initialisieren.

1
 
2
 this.init = function(){ 
3
	with(this) 
4
	{ 
5
		particle.rotate(Math.random()*360);  
6
		acc.set(0,0.05); 
7
		vel.set(Math.random() * 4 -2,Math.random() * 3 -1); 
8
		loc.set(emitter.x,emitter.y);	 
9
	}		 
10
}

Hier haben wir den Code in das with (this) eingeschlossen, das sich auf das aktuelle Partikelobjekt bezieht.

  • particle.rotate() wird verwendet, um das Objekt zufällig zwischen 0 und 360 Grad zu drehen. In diesem Fall spielt es keine Rolle, da wir ein rundes Objekt verwenden. Bei anderen Objekten wie Sternen spielt es jedoch eine Rolle, da es seltsam aussieht, dass alle Partikel die gleichen geometrischen Winkel haben.
  • Wir werden die anfängliche Beschleunigung auf 0,0,5 einstellen, weil wir veranschaulichen wollen, wie die Teilchen an die Schwerkraft gebunden sind; Deshalb haben wir die y-Koordinate initialisiert. Wenn wir den Wert der Beschleunigung erhöhen, steigt die Geschwindigkeit der schnelleren Teilchen.
  • Hier bezieht sich vel auf die Ausbreitung der Partikel auf der Bühne - das heißt, Math.random() * 4 -2 erzeugt Zahlen im Bereich von -2 bis 2.
  • loc nimmt die Anfangswerte des Partikels.

Einige Punkte sollten beachtet werden:

  1. Bedingung für die Beschleunigung
    • Positive Werte erhöhen die Beschleunigung.
    • Für eine schwerkraftfreie Stufe ist die Beschleunigung = 0.
    • Für die inverse Schwerkraft sollten negative Werte verwendet werden.
  2. Bedingungen für vel
    • Um den Spread zu erhöhen, verwenden wir einen größeren Wert des von Math.random() generierten Bereichs.
    • Für die Emission von Partikeln auf einer bestimmten Seite können wir dies entweder durch Multiplikation mit der maximalen positiven oder negativen Zahl erreichen.


Schritt 10

Wir werden nun eine Funktion erstellen, um die Werte des Partikels an seine neue Position zu aktualisieren.

1
 
2
this.update = function(){ 
3
	with(this) 
4
	{ 
5
		vel.add(acc); 
6
		loc.add(vel); 
7
		lifespan -= 1; 
8
		particle.animate({x:loc.x,y:loc.y},39); 
9
	}	 
10
}

Hier wird bei jedem Aufruf der Aktualisierungsfunktion dem Vel eine Beschleunigung hinzugefügt, die dem Ort hinzugefügt wird. Zuletzt wird das Partikel an seinen neuen Ort aktualisiert. Wenn eine konstante Beschleunigung hinzugefügt wird, entsteht der Eindruck, dass das Teilchen einer gewissen Kraft ausgesetzt ist, da es pro Zeiteinheit eine größere Entfernung zurücklegen muss. Wenn ein Update aufgerufen wird, verringert sich die Lebensdauer um 1.


Schritt 11

Schließlich erstellen wir für die Partikelklasse eine Funktion, um zu überprüfen, ob die Lebensdauer eines Partikels abgelaufen ist oder nicht.

1
 
2
this.dead = function() 
3
	{ 
4
		if(this.lifespan<0) 
5
		{ 
6
			return true; 
7
		} 
8
		else  
9
		{ 
10
			return false; 
11
		} 
12
	}

Schritt 12

Unsere Partikelklasse sieht so aus:

1
 
2
function Particle() 
3
{ 
4
	 
5
	this.size = Math.random() * 10 + 15;  
6
	this.particle =  r.image("particle_img.png",emitter.x,emitter.y,this.size,this.size); 
7
	this.loc = new Vector(); 
8
    this.vel = new Vector(); 
9
    this.acc = new Vector(); 
10
    this.lifespan = Math.random() * 250; 
11
    this.init = function(){ 
12
		with(this) 
13
		{ 
14
			particle.rotate(Math.random()*360); 
15
			acc.set(0,0.05); 
16
			vel.set(Math.random() * 4 -2,Math.random() * 3 -1); 
17
			loc.set(emitter.x,emitter.y); 
18
			 
19
		} 
20
		 
21
		} 
22
	this.update = function(){ 
23
		with(this) 
24
		{ 
25
			vel.add(acc); 
26
			loc.add(vel); 
27
			lifespan -= 1; 
28
			particle.animate({x:loc.x,y:loc.y},39); 
29
		} 
30
		 
31
		} 
32
		 
33
	this.dead = function() 
34
	{ 
35
		if(this.lifespan<0) 
36
		{ 
37
			return true; 
38
		} 
39
		else  
40
		{ 
41
			return false; 
42
		} 
43
	} 
44
	 
45
}

Schritt 13

Jetzt erstellen wir eine Partikelsystemklasse. Beginnen wir mit der Deklaration der Mitgliedsvariablen.

1
 
2
this.particles = new Array();

Hier ist Partikel ein Array der Partikelobjekte, die wir bald erstellen werden.


Schritt 14

Jetzt müssen wir die Funktionen zum Initialisieren und Ausführen unseres Partikelsystems erstellen. Also beginnen wir mit der Erstellung unserer Init-Funktion.

1
 
2
this.init = function(num) 
3
	{ 
4
		 for (var i = 0; i < num; i++)  
5
		 { 
6
          this.particles[i] = new Particle(); 
7
		  this.particles[i].init(); 
8
		 } 
9
		 
10
	}

Zunächst nehmen wir die Anzahl der zu erstellenden Partikel als Funktionsparameter. Anschließend erstellen wir mithilfe der for-Schleife die Partikelobjekte und initialisieren sie durch Aufrufen ihrer init-Funktion.


Schritt 15

Jetzt erstellen wir eine Lauffunktion, mit der unser Partikelsystem ausgeführt wird.

1
 
2
this.run = function(){ 
3
		with(this){ 
4
					timer = setInterval(function(){ 
5
					for (i=particles.length -1; i>=0; i--)  
6
					{ 
7
 		      			if(particles[i].dead()) { 
8
        					particles[particles.length -1].particle.remove(); 
9
							particles.pop(); 
10
							var temp = new Particle(); 
11
				 			temp.init(); 
12
				 			particles.unshift(temp);  
13
							} 
14
						particles[i].update(); 
15
			   		} 
16
				 },40); 
17
	 
18
			} 
19
	   
20
		}

Hier ist unser Code in den with (this) -Block eingeschlossen, der sich auf das aktuelle Partikelsystemobjekt bezieht. Da unsere Partikel nun ständig an der nächsten Stelle aktualisiert werden müssen, rufen wir die update() -Funktion des Partikels innerhalb einer setInterval() -Funktion auf, die die Funktion in einem definierten Zeitintervall ausführt. Wir aktualisieren die Positionierung aller Partikel, indem wir das Partikelarray durchlaufen.

Jetzt wollen wir auch prüfen, ob das Partikel tot ist oder nicht. Wir erfüllen diese Aufgabe, indem wir die Funktion dead() des Partikels aufrufen. Wenn ein Teilchen tot ist, machen wir Folgendes:

  • Entfernen Sie es aus unserem Array.
  • Verschieben Sie die Elemente um eins zurück, beginnend mit der Position nach dem Index des toten Partikels.
  • Schieben Sie ein neues Partikel an das Ende des Arrays.
1
 
2
var p = particles[i]; 
3
	for(var j=i;j<particles.length-1;j++) 
4
	{ 
5
 		particles[j] = particles[j+1]; 
6
	} 
7
p.particle.remove(); 
8
var temp = new Particle(); 
9
temp.init(); 
10
particles.push(temp);

Der obige Code ist die optimale Lösung, aber wenn wir das in der JavasSript-Welt implementieren, ist die Emission so spontan, dass die Motoren hängen bleiben. Aus diesem Grund haben wir den alternativen Code verwendet, um de Komplexität zu erhöhen und eine flüssigere Animation zu rendern. Sie können es selbst ausprobieren ;).

Da der Zeitraum in der Größenordnung von Millisekunden liegt, erhalten wir trotz Verwendung eines komplexeren Algorithmus eine spontane Emission.


Schritt 16

Zu diesem Zeitpunkt sieht unsere ParticleSystem-Klasse so aus.

1
 
2
function ParticleSystem() 
3
{ 
4
	this.particles = new Array(); 
5
	this.init = function(num) 
6
	{ 
7
		 
8
		 
9
		 for (var i = 0; i < num; i++)  
10
		 { 
11
          this.particles[i] = new Particle(); 
12
		  this.particles[i].init(); 
13
		 } 
14
		  
15
		 
16
	} 
17
	 
18
 
19
	this.run = function(){ 
20
		with(this){ 
21
	timer = setInterval(function(){ 
22
				for (i=particles.length -1; i>=0; i--)  
23
			{ 
24
 		      if(particles[i].dead()) { 
25
        		 
26
				particles[particles.length -1].particle.remove(); 
27
				 particles.pop(); 
28
				var temp = new Particle(); 
29
				 temp.init(); 
30
				 particles.unshift(temp);  
31
							 
32
			} 
33
			 
34
			particles[i].update(); 
35
			 
36
    		} 
37
				 },40); 
38
	 
39
		} 
40
	   
41
		}		 
42
}

Schritt 17

Jetzt deklarieren wir unsere Funktion startSystem(), die das Partikelsystem initiiert.

1
 
2
startSystem = function(){ 
3
W = 800; H = 400; 
4
canvas = Raphael("pane", W, H); 
5
var ps = new ParticleSystem(); 
6
var iniVec = new Vector(); 
7
iniVec.set(emitter.x,emitter.y); 
8
ps.init(20,iniVec); 
9
 ps.run(); 
10
}

Wir initialisieren unser Raphael-Objekt mit Stage ID, Breite und Höhe. Dann erstellen wir unser Partikelsystemobjekt und erstellen ein Vektorobjekt mit den Ursprungskoordinaten. Dann initialisieren wir unser Partikelsystem, indem wir init aufrufen, was wiederum die Partikel initialisiert. Wir geben auch 20 als Anzahl der Partikel in den Parametern an.

Die Anzahl der Partikel muss zwischen 20 und 30 liegen, um einen reibungslosen Animationseffekt zu erzielen. Wenn Sie eine höhere Nummer angeben, stürzt der Browser ab oder hängt ihn auf!


Schritt 18

So sieht der Code unserer sps.js-Datei an dieser Stelle aus.

1
 
2
 
3
function Vector() 
4
{ 
5
	this.x =0; 
6
	this.y =0; 
7
    //this.z =0;    

8
	this.set = function(X,Y) 
9
	{ 
10
		with(this) 
11
		{ 
12
			x = X; 
13
			y =Y; 
14
			//z = Z; 

15
		 
16
		} 
17
	} 
18
	this.add = function(vector2) 
19
	{ 
20
		 
21
		 
22
		 
23
		this.x = this.x + vector2.x; 
24
		this.y = this.y + vector2.y; 
25
		//this.z = this.z + vector2.z; 

26
		 
27
		 
28
	} 
29
} 
30
 
31
 
32
var canvas;  // our raphael object 

33
var timer;  
34
var emitter = new Vector(); 
35
emitter.set(400,200); 
36
 
37
function Particle() 
38
{ 
39
	 
40
	this.size = Math.random() * 10 + 15;  
41
	this.particle =  canvas.image("img1.png",emitter.x,emitter.y,this.size,this.size); 
42
	this.loc = new Vector(); 
43
    this.vel = new Vector(); 
44
    this.acc = new Vector(); 
45
    this.lifespan = Math.random() * 250; 
46
    this.init = function(){ 
47
		with(this) 
48
		{ 
49
			particle.rotate(Math.random()*360); 
50
			acc.set(0,0.05); 
51
			vel.set(Math.random() * 4 -2,Math.random() * 3 -1); 
52
			loc.set(emitter.x,emitter.y); 
53
			 
54
		} 
55
		 
56
		} 
57
	this.update = function(){ 
58
		with(this) 
59
		{ 
60
			vel.add(acc); 
61
			loc.add(vel); 
62
			lifespan -= 1; 
63
			particle.animate({x:loc.x,y:loc.y},39); 
64
		} 
65
		 
66
		} 
67
		 
68
	this.dead = function() 
69
	{ 
70
		if(this.lifespan<0) 
71
		{ 
72
			return true; 
73
		} 
74
		else  
75
		{ 
76
			return false; 
77
		} 
78
	} 
79
	 
80
} 
81
 
82
 
83
function ParticleSystem() 
84
{ 
85
	this.particles = new Array(); 
86
	this.init = function(num) 
87
	{ 
88
		 
89
		 
90
		 for (var i = 0; i<num; i++)  
91
		 { 
92
          this.particles[i] = new Particle(); 
93
		  this.particles[i].init(); 
94
		 } 
95
		  
96
		 
97
	} 
98
	 
99
 
100
	this.run = function(){ 
101
		with(this){ 
102
	timer = setInterval(function(){ 
103
				for (i=particles.length -1; i>=0; i--)  
104
			{ 
105
 		      if(particles[i].dead()) { 
106
        		 
107
				particles[particles.length -1].particle.remove(); 
108
				 particles.pop(); 
109
				var temp = new Particle(); 
110
				 temp.init(); 
111
				 particles.unshift(temp);  
112
							 
113
			} 
114
			 
115
			particles[i].update(); 
116
			 
117
    		} 
118
				 },40); 
119
	 
120
		} 
121
	   
122
		} 
123
				 
124
} 
125
 
126
startSystem = function(){ 
127
W = 800; H = 400; 
128
  canvas = Raphael("pane", W, H); 
129
  var ps = new ParticleSystem(); 
130
	ps.init(20); 
131
	 ps.run(); 
132
       
133
}

Endlich sind wir fertig. Dieses kleine Projekt ist mit allen Browsern kompatibel, auch in Internet Explorer, obwohl IE6 einige Transparenzprobleme aufweist. Dieses Partikelsystem kann praktisch überall verwendet werden, einschließlich Hintergründen, Explosionseffekten, Logo- und Header-Intros usw. Ich habe drei Demos erstellt, die modifizierte Versionen des obigen Codes sind. Eines davon implementiert verschiedene Partikelsysteme wie Rauch, Staub und das Bokeh-Partikelsystem. Viel Spaß und danke fürs Lesen!