Hier werden die Unterschiede zwischen zwei Versionen gezeigt.
Beide Seiten der vorigen Revision Vorhergehende Überarbeitung Nächste Überarbeitung | Vorhergehende Überarbeitung | ||
ws2122:boids:boids [2022/04/03 11:47] mak.18 [Erzeugung Boids] |
ws2122:boids:boids [2022/04/03 21:09] (aktuell) mak.18 [Grundaufbau] |
||
---|---|---|---|
Zeile 48: | Zeile 48: | ||
5. **Positionen aller Boids updaten.** | 5. **Positionen aller Boids updaten.** | ||
+ | Mithilfe von pygame (2D-Version) bzw. vpython (3D-Version) erfolgt dann die Darstellung der Boids auf dem Bildschirm. | ||
+ | ---- | ||
+ | //Nachfolgend gezeigte Code-Ausschnitte stammen aus der 2D-Version. Die 3D-Version hat jedoch einen ähnlichen Code.// | ||
==== Erzeugung Boids ==== | ==== Erzeugung Boids ==== | ||
Für die erste Erzeugung der Boids bei Start werden Anzahl der Boids, Fressfeinde, Hindernisse sowie für spätere Berechnungen, der Radius festgelgt. | Für die erste Erzeugung der Boids bei Start werden Anzahl der Boids, Fressfeinde, Hindernisse sowie für spätere Berechnungen, der Radius festgelgt. | ||
Zeile 62: | Zeile 65: | ||
self.speed = 60 / self.target_framerate | self.speed = 60 / self.target_framerate | ||
</code> | </code> | ||
- | Eine Liste mit Positionen und Geschwindigkeiten von Boids und Fressfeinden wird zu Beginn durch die Funktion self.generate_agents() erzeugt. | + | Eine Liste mit Positionen und Geschwindigkeiten von Boids und Fressfeinden wird zu Beginn durch die Funktion self.generate_agents() erzeugt. Die Fressfeinde bewegen sich schneller als die Boids. |
<code python> | <code python> | ||
# typ 0: boids / typ 1: predators | # typ 0: boids / typ 1: predators | ||
Zeile 77: | Zeile 80: | ||
==== Target Boids bestimmen ==== | ==== Target Boids bestimmen ==== | ||
Nun werden alle vom aktuellen Boid innerhalb des Radius sichtbare Boids bestimmt. Nur diese spielen später bei der Kräfteberechnung eine Rolle. Die Funktion get_target_mask() gibt ein Array zurück. Dabei wird die Liste aller Positionen der Boids als Grundlage genommen und geschaut, ob der Boid der jeweiligen Position innerhalb oder außerhalb des Radius ist. Befindet er sich im Radius, wird sein Wert auf True gesetzt. Da die Positionen innerhalb der Liste gleich bleiben, kann jeder Boid später auf eine Position zurückverfolgt werden. Hierbei wird unterschieden, ob es sich beim aktuellen Boid um Boid oder Predator handelt. Handelt es sich um einen Predator wird der betrachtete Radius verdreifacht. | Nun werden alle vom aktuellen Boid innerhalb des Radius sichtbare Boids bestimmt. Nur diese spielen später bei der Kräfteberechnung eine Rolle. Die Funktion get_target_mask() gibt ein Array zurück. Dabei wird die Liste aller Positionen der Boids als Grundlage genommen und geschaut, ob der Boid der jeweiligen Position innerhalb oder außerhalb des Radius ist. Befindet er sich im Radius, wird sein Wert auf True gesetzt. Da die Positionen innerhalb der Liste gleich bleiben, kann jeder Boid später auf eine Position zurückverfolgt werden. Hierbei wird unterschieden, ob es sich beim aktuellen Boid um Boid oder Predator handelt. Handelt es sich um einen Predator wird der betrachtete Radius verdreifacht. | ||
+ | <code python> | ||
+ | def get_target_mask(self, current_pos, current_vel = np.zeros(2)): | ||
+ | boid_mask = np.zeros([self.n[0]], dtype=bool) | ||
+ | ... | ||
+ | for i in range(self.n[0]): | ||
+ | if (self.boid_positions[i] != current_pos).all() and np.dot(current_vel, self.boid_positions[i] - current_pos) >= 0: | ||
+ | if current_pos in self.pred_positions: | ||
+ | boid_mask[i] = np.linalg.norm(self.boid_positions[i] - current_pos) < self.radius * 3 | ||
+ | else: | ||
+ | boid_mask[i] = np.linalg.norm(self.boid_positions[i] - current_pos) < self.radius | ||
+ | ... | ||
+ | |||
+ | return (boid_mask, pred_mask, obstacle_mask) | ||
+ | |||
+ | </code> | ||
==== Kräfteberechung ==== | ==== Kräfteberechung ==== | ||
Nachdem alle Boids erzeugt wurden können wir mit der eigentlichen Simulation des Schwarmverhaltens beginnen. Jedes Individuum eines Schwarms folgt immer drei bestimmten Regeln - Separation, Kohäsion und Ausrichtung. Alle drei Kräfte ermöglichen zusammen das typische Schwarmverhalten. Bei uns sind die Kräfte Vektoren, die die neue Richtung des aktuellen Boids anzeigen. | Nachdem alle Boids erzeugt wurden können wir mit der eigentlichen Simulation des Schwarmverhaltens beginnen. Jedes Individuum eines Schwarms folgt immer drei bestimmten Regeln - Separation, Kohäsion und Ausrichtung. Alle drei Kräfte ermöglichen zusammen das typische Schwarmverhalten. Bei uns sind die Kräfte Vektoren, die die neue Richtung des aktuellen Boids anzeigen. | ||
Zeile 128: | Zeile 146: | ||
==== Update ==== | ==== Update ==== | ||
- | Zuerst werden aus der Maske alle Positionen der Target boids bestimmt. Nun werden die Kräfte mithilfe der zuvor bestimmten Funktionen berechnet. Ist im Sichtfeld des aktuellen Boid mind. ein Feind, wird die zehnfache Separation-Kraft angewendet - schließlich will der Boid schneller vom Predator wegschwimmen, sobald er ihn sieht. | + | Zuerst werden aus der Maske alle Positionen der Target boids bestimmt. |
+ | <code python> | ||
+ | def update_velocity(self, current_pos, current_vel): | ||
+ | |||
+ | boid_target_mask, pred_target_mask, obstacle_target_mask = self.get_target_mask(current_pos, current_vel) | ||
+ | |||
+ | # applying target masks | ||
+ | # to get the positions and velocities of visible boids and obstacles | ||
+ | boid_target_pos, boid_target_vel = self.boid_positions[boid_target_mask], self.boid_velocities[boid_target_mask] | ||
+ | pred_target_pos, pred_target_vel = self.pred_positions[pred_target_mask], self.pred_velocities[pred_target_mask] | ||
+ | obstacle_target_pos = self.obstacle_positions[obstacle_target_mask] | ||
+ | ... | ||
+ | </code> | ||
+ | Nun werden die Kräfte mithilfe der zuvor bestimmten Funktionen berechnet. Ist im Sichtfeld des aktuellen Boid mind. ein Feind, wird die zehnfache Separation-Kraft angewendet - schließlich will der Boid schneller vom Predator wegschwimmen, sobald er ihn sieht. | ||
Letztendlich werden die neuen Geschwindigkeiten zu den Positionen hinzuaddiert. | Letztendlich werden die neuen Geschwindigkeiten zu den Positionen hinzuaddiert. | ||
---- | ---- | ||
+ | =====Zusatz: interaktiver Modus in der 2D-Version (debug mode)===== | ||
+ | Der Modus lässt sich durch die Home-Taste (Pos1) starten. Durch das Eingeben einer Zahl von 1-5 wird ein bestimmter Modus ausgewählt. Der interaktive Modus ist dazu da die wirkenden Kräfte auch sehen zu können. | ||
+ | Bei Modus 1-4 wird der Mauszeiger als weiterer Boid behandelt. Mit dem anfangs festgelegten Radius wird ein Kreis um den Mauszeiger dargestellt. Alle weiteren Boids bewegen sich nicht. | ||
+ | Für den Mauszeiger-Boid wird/werden je nach ausgewählten Modus | ||
+ | - die Kohäsionskraft als blaue Linie angezeigt. | ||
+ | - die Alignment-Kraft als blaue Linie angezeigt. | ||
+ | - die Separationskraft als blaue Linie angezeigt. | ||
+ | - alle einzelnen Kräfte (grau) und die insgesamt wirkende Kraft (grün) angezeigt. | ||
+ | Modus 3: Separation {{:ws2122:boids:boids_separation.png?200|Modus 3: Separation}} | ||
+ | {{ :ws2122:boids:boids_alle_kraefte.png?200|Modus 4: alle Kräfte}} | ||
+ | Modus 4: alle Kräfte | ||
+ | |||
+ | In Modus 5 werden die Kräfte wie in Modus 4 dargestellt. Nur diesmal beziehen sie sich nicht auf den Mauszeiger, sondern auf einen Boid. Die Boids bewegen sich in diesem Modus wieder. | ||
+ | ---- | ||
===== Ergebnis ===== | ===== Ergebnis ===== | ||
2D | 2D |