Eigentlich hatte ich mir für gestern ja ganz etwas anderes vorgenommen. Aber dann konnte ich es nicht lassen und mußte wie angekündigt mit der neuen Version der NodeBox spielen. Und zwar wollte ich als ein erstes Experiment die Partikelsysteme, die Daniel Shiffman im vierten Kapitel seines wunderbaren Buches »The Nature of Code – Simulating Natural Systems with Processing« in Processing (Java) programmiert hatte, nach Python und in die NodeBox portieren. Dafür brauchte ich natürlich das Modul PVector (hier eine Erweiterung), da Shiffman dieses Modul, das standardmäßig in Processing vorhanden ist, intensiv nutzt, aber genau deswegen hatte ich es ja auch für die NodeBox umgeschrieben.
Zuerst einmal habe ich eine Klasse Particle
angelegt, die so aussieht:
class Particle(object):
def __init__(self, l):
self.acceleration = PVector(0, 0.05)
self.velocity = PVector(random(-1.5, 1.5), random(-2.0, 2.0))
self.location = l.get()
self.lifespan = 255
def run(self):
self.update()
self.display()
def update(self):
self.velocity.add(self.acceleration)
self.location.add(self.velocity)
self.lifespan -= 2
def display(self):
colorrange(255)
stroke(0, 0, 0)
fill(255, 140, 0, self.lifespan)
ellipse(self.location.x, self.location.y, 20, 20)
def isDead(self):
if self.lifespan <= 0:
return True
else:
return False
Sie besitzt drei Vektoren, einmal velocity
für die Richtung, mit der sich die Partikel bewegen sollen, acceleration
für die Geschwindigkeit und dann location
, die den jeweils aktuellen Ort der Partikel angibt. Die location
wird direkt dem Konstruktor übergeben, die velocity
wird in einem gegeben Rahmen zufällig erzeugt. Dann gibt es noch den lifespan
, der die Lebensdauer des Partikels angibt. Da das Partikel im Laufe seines Lebens immer mehr verblassen und das durch den Alpha-Kanal realisiert werden soll, habe ich die Lebensdauer mit 255
initialisiert.
In der update()
-Methode wird die neue Position des Partikels berechnet, in dem zuerst einmal der Vektor acceleration
mit dem Vektor velocity
auf- und dann die neue velocity
der location
zuaddiert wird. Zum Schluß wird dann noch der lifespan
bei jedem Durchlauf erniedrigt.
Die Methode display()
ist für die Darstellung des Partikels zuständig. Hier wird erst einmal der colorrange()
, der ja bei der NodeBox per Default zwischen 0,0 und 1,0 liegt auf die Spanne zwischen 0 und 255 erweitert, weil das mir und vermutlich den meisten anderen von Euch eine vertrautere Art der Farbdarstellung ist. Das Partikel soll als Kreis dargestellt werden, anfangs mit einem feurigen Orange, das mit jeder Verringerung des Alphakanals (lifespan
) immer mehr verblasst, bis es schließlich endgültig verschwindet.
Der Übersichtlichkeit wegen und da ich diese beiden Methoden nicht jedesmal in der Hauptschleife niederschreiben will, gibt es noch die Methode run()
, die schlicht und einfach nur diese beiden Methoden aufruft.
Für das Verschwinden der Partikel ist die boolsche Methode isDead()
zuständig, die True
zurückgibt, wenn der lifespan
kleiner oder gleich Null wird (ansonsten False
).
In dieser Klasse wird schon eigentlich alles geregelt, daher ist das Hauptprogramm mal wieder von erfrischender Kürze:
size(500, 500)
speed(30)
colormode(RGB)
from pvector import PVector
#---------------------Klassendefinitionen ------------------------
#-----------------------------------------------------------------
particles = []
def setup():
global loc
loc = PVector(WIDTH/2, 50)
def draw():
global loc
background("#1f2838")
particles.append(Particle(loc))
for i in range(len(particles) - 1, -1, -1):
particles[i].run()
if particles[i].isDead():
particles.pop(i)
print(len(particles))
Hier werden zuerst die Größe des Fensters und die Geschwindigkeit festgelegt. Die Initialisierung des colormodes auf RGB ist eigentlich nicht notwendig, da dies die Default-Einstellung der NodeBox ist.
Dann wird eine leere Liste particles[]
initialisiert und in der setup()
-Funktion die Startposition aller Partikel auf die Mitte oben festgelegt.
Die draw()
-Funktion zeichnet einen dunkelgrauen Hintergrund und hängt in jedem Durchlauf einen weiteren Partikel an die Liste an.
Die darauffolgende Schleife ist ein wenig tricky. Denn wenn man eine Liste vorwärts durchläuft und dann in der Schleife ein Element aus der Liste entfernt, erhält man – da ja alle Elemente, die weiter oben stehen um eines nach unten rücken – zum einen Elemente, die in diesem Durchlauf nicht abgefragt werden. Das wäre meistens nicht so schlimm, sie würden halt im nächsten Durchlauf wieder abgefragt. Aber ganz sicher erhält man dabei auch den berüchtigten index out of range
-Error, der das Programm gnadenlos zum Absturz bringen würde. Um dies zu vermeiden, zählt man die Liste rückwärts durch. Hierbei ist einmal zu beachten, daß der letzte Index einer Liste len - 1
ist, da ja in Python die Indizes mit Null beginnen, und das der Endwert einer Range-Schleife immer exklusiv ist (mathematisch gesprochen wird das halboffene Intervall [startwert, endwert[) benutzt). Um daher beim rückwärtigen Durchlauf auch den Index [0]
anzusprechen, muß der Endwert um eins kleiner als Null sein, also -1
betragen. Der letzte Parameter ist einfach die Schrittlänge, in diesem Fall natürlich ebenfalls -1
.
Zum Schluß wird einfach nur noch gefragt, ob das entsprechende Partikel denn noch lebt. Wenn nicht, wird es aus der Liste entfernt.
In meiner Konfiguration sind immer etwa 128 Partikel aktiv. Das reicht gerade, daß die Animation auf meinem betagten, neun Jahre alten MacBook Pro noch flüssig abläuft. Für mehr Partikel benötigt man entweder einen leistungsstärkeren Rechner oder einen intelligenteren Algorithmus. 😜
In einem weiteren Tutorial werde ich dieses Partikelsystem noch ein wenig erweitern und dann die Klassen in ein externes Modul auslagern. Still digging!
Über …
Der Schockwellenreiter ist seit dem 24. April 2000 das Weblog digitale Kritzelheft von Jörg Kantel (Neuköllner, EDV-Leiter, Autor, Netzaktivist und Hundesportler — Reihenfolge rein zufällig). Hier steht, was mir gefällt. Wem es nicht gefällt, der braucht ja nicht mitzulesen. Wer aber mitliest, ist herzlich willkommen und eingeladen, mitzudiskutieren!
Alle eigenen Inhalte des Schockwellenreiters stehen unter einer Creative-Commons-Lizenz, jedoch können fremde Inhalte (speziell Videos, Photos und sonstige Bilder) unter einer anderen Lizenz stehen.
Der Besuch dieser Webseite wird aktuell von der Piwik Webanalyse erfaßt. Hier können Sie der Erfassung widersprechen.
Diese Seite verwendet keine Cookies. Warum auch? Was allerdings die iframes
von Amazon, YouTube und Co. machen, entzieht sich meiner Kenntnis.
Werbung