Hier werden die Unterschiede zwischen zwei Versionen gezeigt.
Beide Seiten der vorigen Revision Vorhergehende Überarbeitung Nächste Überarbeitung | Vorhergehende Überarbeitung | ||
ws2425:lebewesenverhalten [2025/03/06 17:12] R.Arndt |
ws2425:lebewesenverhalten [2025/05/05 19:41] (aktuell) stefanborn [Unser Code:] |
||
---|---|---|---|
Zeile 22: | Zeile 22: | ||
====Projektplanung (Stand: Projektbeginn):==== | ====Projektplanung (Stand: Projektbeginn):==== | ||
Da wir zu zweit arbeiten, ist es für uns am sinnvollsten die Dateien in einer gemeinsamen tubCloud zu sammeln. Dort laden wir die neuen Dateien hoch. Wir planen, jede Woche einen Ordner für den jeweiligen Donnerstagstermin zu erstellen und dort die neuesten Dateien hineinzufügen. Wären wir in einer größeren Gruppe wäre eine andere Herangehensweise, wie zum Beispiel über gitlab, sinnvoller. Für uns reicht aber vermutlich das Cloud System. | Da wir zu zweit arbeiten, ist es für uns am sinnvollsten die Dateien in einer gemeinsamen tubCloud zu sammeln. Dort laden wir die neuen Dateien hoch. Wir planen, jede Woche einen Ordner für den jeweiligen Donnerstagstermin zu erstellen und dort die neuesten Dateien hineinzufügen. Wären wir in einer größeren Gruppe wäre eine andere Herangehensweise, wie zum Beispiel über gitlab, sinnvoller. Für uns reicht aber vermutlich das Cloud System. | ||
- | (Hier muss noch Link zur Cloud hin) | ||
Zeile 64: | Zeile 63: | ||
===4. Projekttag (12.12.2024)=== | ===4. Projekttag (12.12.2024)=== | ||
- | Am 12.12.2024 haben wir versucht arbeitsteilig unterschiedliche Dinge zu implementieren. Wir wollten den Tieren eine "health" geben und sie beim erreichen von health = 0 sterben lassen. Das sterben lassen ging voran aber hat noch nicht final funktioniert. Außerdem haben wir die 360 Grad Bewegung hinzugefügt, sowie zufällige Startrichtungen. Temporär haben wir hinzugefügt, dass Tiere bei Kollision mit der "Wand" oder einem anderen Tier sich umdrehen. Final haben wir entschlossen, dass sich Tiere nicht erst bei Zusammenstößen umdrehen, sondern vor und zum Teil um sich schauen können und bei Detektion sich bereits umdrehen, um Kollisionen zu vermeiden. | + | Am 12.12.2024 haben wir versucht arbeitsteilig unterschiedliche Dinge zu implementieren. Wir wollten den Tieren eine "health" geben und sie beim Erreichen von health = 0 sterben lassen. Das sterben lassen ging voran aber hat noch nicht final funktioniert. Außerdem haben wir die 360 Grad Bewegung hinzugefügt, sowie zufällige Startrichtungen. Temporär haben wir hinzugefügt, dass Tiere bei Kollision mit der "Wand" oder einem anderen Tier sich umdrehen. Final haben wir entschlossen, dass sich Tiere nicht erst bei Zusammenstößen umdrehen, sondern vor und zum Teil um sich schauen können und bei Detektion sich bereits umdrehen, um Kollisionen zu vermeiden. |
===5. Projekttag (19.12.2024)=== | ===5. Projekttag (19.12.2024)=== | ||
- | Am letzten Tag vor den Weihnachtsferien haben wir uns darum gekümmert, dass wir die Visualisierung im Vollbildmodus auf dem gesamten Bildschirm anzeigen lassen. So wollen wir später auch die finale Modellierung anzeigen lassen. Durch den Vollbildmodus konnte man die Visualisierung nurnoch extern schließen und nicht mehr über den klassischen Weg. Dafür haben wir hinzugefügt, dass man mit dem Drücken der Escape-Taste den Vollbildmodus beendet. Dies funktioniert. Wir haben die Tiere nun Pflanzenfresser genannt und hinzugefügt, dass ihre "Sichtchecks" auf verschiedenen Distanzen durchgeführt werden. Wir haben verbessert, dass Tiere die sich nah kommen, die RIchtung ihrer Bewegung stärker ändern. Anschließend an die letzte Woche, wo Pflanzenfresser eine "Lebensanzahl" erhalten haben, haben wir heute implementiert, dass sie konstant Leben verlieren und bei weniger als 0 Leben aus der Liste gelöscht werden und damit sterben. Fleischfresser haben wir nun auch und diese laufen fürs erste zufällig durch den Canvas. Wir haben Funktionen, die für verschiedene Tierklassen benutzt werden in eine Elternklasse, namens Tiere, ausgelagert. | + | Am letzten Tag vor den Weihnachtsferien haben wir uns darum gekümmert, dass wir die Visualisierung im Vollbildmodus auf dem gesamten Bildschirm anzeigen lassen. So wollen wir später auch die finale Modellierung anzeigen lassen. Durch den Vollbildmodus konnte man die Visualisierung nurnoch extern schließen und nicht mehr über den klassischen Weg. Dafür haben wir hinzugefügt, dass man mit dem Drücken der Escape-Taste den Vollbildmodus beendet. Dies funktioniert. Wir haben die Tiere nun Pflanzenfresser genannt und hinzugefügt, dass ihre "Sichtchecks" auf verschiedenen Distanzen durchgeführt werden. Wir haben verbessert, dass Tiere die sich nah kommen, die Richtung ihrer Bewegung stärker ändern. Anschließend an die letzte Woche, wo Pflanzenfresser eine "Lebensanzahl" erhalten haben, haben wir heute implementiert, dass sie konstant Leben verlieren und bei weniger als 0 Leben aus der Liste gelöscht werden und damit sterben. Fleischfresser haben wir nun auch und diese laufen fürs erste zufällig durch den Canvas. Wir haben Funktionen, die für verschiedene Tierklassen benutzt werden in eine Elternklasse, namens Tiere, ausgelagert. |
Zeile 93: | Zeile 92: | ||
===12. Projekttag - Zusatztag 1 (04.03.2025)=== | ===12. Projekttag - Zusatztag 1 (04.03.2025)=== | ||
- | Heute war der erste Tag vom Labor Block in den Ferien. Wir haben uns für das implementieren eines simpleren Sichtsystems entschieden. Dabei haben wir auf die Autonomie der Tiere und auf die Vermeidung von Kollisionen von Tieren der gleichen Art verzichtet. Mit Matplotlib haben wir auch weitergearbeitet. An diesem Tag sind wir etwas frher gegangen und hatten weniger Zeit. | + | Heute war der erste Tag vom Labor Block in den Ferien. Wir haben uns für das implementieren eines simpleren Sichtsystems entschieden. Dabei haben wir auf die Autonomie der Tiere und auf die Vermeidung von Kollisionen von Tieren der gleichen Art verzichtet. Mit Matplotlib haben wir auch weitergearbeitet. An diesem Tag sind wir etwas früher gegangen und hatten weniger Zeit. |
===13. Projekttag - Zusatztage 2 (05.03.2025)=== | ===13. Projekttag - Zusatztage 2 (05.03.2025)=== | ||
Zeile 113: | Zeile 112: | ||
- | Wir haben uns vorgestellt, dass wir ein Ökosystem erschaffen, in welchem verschiedene Arten von Dinos leben und interagieren. Wir wollten herausfinden, wie sich die verschiedenen Arten verhalten jenachdem, wie viele man von welcher Sorte hineinfügt. Wir hätten uns gerne bei der Erstellung der Arten auf Eigenschaften der Dinos bezogen, die sie damals in ihrem echten Leben auch hatten. | + | Wir haben uns vorgestellt, dass wir ein Ökosystem erschaffen, in welchem verschiedene Arten von Dinos leben und interagieren. Wir wollten herausfinden, wie sich die verschiedenen Arten verhalten, jenachdem, wie viele man von welcher Sorte hineinfügt. Wir hätten uns gerne bei der Erstellung der Arten auf Eigenschaften der Dinos bezogen, die sie damals in ihrem echten Leben auch hatten. |
- | In Wirklichkeit kamen wir nicht dazu mehr als 2 Klassen an Dinos zu erstellen und konnten dabei nicht viele Eigenschaften hinzufügen. Dafür fehlte etwas die Zeit, da einige DInge länger dauerten, als wir erwarteten. Trotzdem haben wir es geschafft, Tiere miteinander interagieren zu lassen. Außerdem haben wir es geschafft die Verhalten statistisch zu beobachten und können nun die Parameter der Anzahlen ändern und anpassen. Also haben wir trotzdem einiges geschafft. | + | In Wirklichkeit kamen wir nicht dazu mehr als 2 Klassen an Dinos zu erstellen und konnten dabei nicht viele Eigenschaften hinzufügen. Dafür fehlte etwas die Zeit, da einige Dinge länger dauerten, als wir erwarteten. Trotzdem haben wir es geschafft, Tiere miteinander interagieren zu lassen. Außerdem haben wir es geschafft die Verhalten statistisch zu beobachten und können nun die Parameter der Anzahlen ändern und anpassen. Also haben wir trotzdem einiges geschafft. |
Zeile 123: | Zeile 122: | ||
Beim nächsten Mal würden wir uns von Anfang an etwas weniger vornehmen und versuchen auf die perfekten Bewegungsverhalten eher zu verzichten und zumindest zum Anfang eher auf gröbere Bewegung zu setzen. Die Arbeitsweise mit der Cloud und den wöchentlichen Dokumentationen war aber sehr gut und hat gut geklappt. | Beim nächsten Mal würden wir uns von Anfang an etwas weniger vornehmen und versuchen auf die perfekten Bewegungsverhalten eher zu verzichten und zumindest zum Anfang eher auf gröbere Bewegung zu setzen. Die Arbeitsweise mit der Cloud und den wöchentlichen Dokumentationen war aber sehr gut und hat gut geklappt. | ||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | ====Unser Code:==== | ||
+ | |||
+ | <code python>import tkinter as tk | ||
+ | import random as r | ||
+ | import math as m | ||
+ | import numba | ||
+ | import matplotlib.pyplot as plt | ||
+ | from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg | ||
+ | |||
+ | fenster = tk.Tk() | ||
+ | fenster.title("Lebewesenverhalten") | ||
+ | |||
+ | """ | ||
+ | fenster.attributes("-fullscreen", True) | ||
+ | def beenden(event=None): | ||
+ | fenster.attributes("-fullscreen", False) | ||
+ | exit() | ||
+ | fenster.bind("<Escape>", beenden) | ||
+ | |||
+ | width = fenster.winfo_screenwidth() | ||
+ | hight = fenster.winfo_screenheight() | ||
+ | """ | ||
+ | |||
+ | fenster.geometry("1000x600") | ||
+ | |||
+ | width = 1000 | ||
+ | hight = 600 | ||
+ | |||
+ | |||
+ | canvas = tk.Canvas(fenster, bg="pink") | ||
+ | canvas.pack(fill="both",expand=True) | ||
+ | |||
+ | def end_simulation(event): | ||
+ | fenster.destroy() | ||
+ | fenste = tk.Tk() | ||
+ | fenste.title("Statistik") | ||
+ | fenste.geometry("1000x600") | ||
+ | fig, ax = plt.subplots(figsize=(6,4)) | ||
+ | ax.plot(x_werte, plant_values) | ||
+ | ax.plot(x_werte, meat_values) | ||
+ | canvas = FigureCanvasTkAgg(fig, master=fenste) | ||
+ | canvas.draw() | ||
+ | canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True) | ||
+ | |||
+ | fenster.bind("<Return>", end_simulation) | ||
+ | |||
+ | start_pflanzenfresser = 50 | ||
+ | start_fleischfresser = 5 | ||
+ | anzahl_seen = 1 | ||
+ | lines = [] | ||
+ | dis = 100 | ||
+ | time = 0 | ||
+ | pflanzenfresser = [] | ||
+ | new_pflanzenfresser = [] | ||
+ | fleischfresser = [] | ||
+ | new_fleischfresser = [] | ||
+ | seen = [] | ||
+ | x_werte = [] | ||
+ | plant_values = [] | ||
+ | meat_values = [] | ||
+ | |||
+ | def update(event = None): | ||
+ | global time | ||
+ | if time % 50 == 0: | ||
+ | x_werte.append(time) | ||
+ | plant_values.append(len(pflanzenfresser)) | ||
+ | for tier in pflanzenfresser: | ||
+ | if not tier.alive: | ||
+ | plant_values[-1] -= 1 | ||
+ | meat_values.append(len(fleischfresser)) | ||
+ | for tier in fleischfresser: | ||
+ | if not tier.alive: | ||
+ | meat_values[-1] -= 1 | ||
+ | #for z in range(len(lines)): | ||
+ | # canvas.delete(lines[z]) | ||
+ | global new_pflanzenfresser | ||
+ | global new_fleischfresser | ||
+ | for baby in new_pflanzenfresser: | ||
+ | pflanzenfresser.append(baby) | ||
+ | baby.show() | ||
+ | new_pflanzenfresser = [] | ||
+ | for baby in new_fleischfresser: | ||
+ | fleischfresser.append(baby) | ||
+ | baby.show() | ||
+ | new_fleischfresser = [] | ||
+ | |||
+ | for pflanzenfresse in pflanzenfresser: | ||
+ | if pflanzenfresse.alive: | ||
+ | if time % 5 == 2: | ||
+ | pflanzenfresse.sight() | ||
+ | pflanzenfresse.check_grazing() | ||
+ | pflanzenfresse.change_food(-5*pflanzenfresse.speed) | ||
+ | if pflanzenfresse.mating_cooldown > 0: | ||
+ | pflanzenfresse.mating_cooldown -= 5 | ||
+ | pflanzenfresse.move() | ||
+ | |||
+ | for fleischfresse in fleischfresser: | ||
+ | if fleischfresse.alive: | ||
+ | if time % 5 == 0: | ||
+ | fleischfresse.sight() | ||
+ | fleischfresse.change_food(-5*fleischfresse.speed) | ||
+ | if fleischfresse.mating_cooldown > 0: | ||
+ | fleischfresse.mating_cooldown -= 5 | ||
+ | fleischfresse.move() | ||
+ | time += 1 | ||
+ | #fenster.bind("<space>", update) | ||
+ | canvas.after(20, update) | ||
+ | |||
+ | def det(alpha, beta): | ||
+ | return m.sin(m.radians(beta-alpha)) | ||
+ | |||
+ | #Distanz zwischen zwei Punkten | ||
+ | def distance(x1, x2, y1, y2): | ||
+ | return m.sqrt((x1 - x2)**2 + (y1 - y2)**2) | ||
+ | |||
+ | #Quadrat des Abstandes zweier Punkte (für schnelle Berechnungen) | ||
+ | def squared_distance(x1, x2, y1, y2): | ||
+ | return (x1 - x2)**2 + (y1 - y2)**2 | ||
+ | |||
+ | class Objekt: | ||
+ | def __init__(self, x, y): | ||
+ | self.x = x | ||
+ | self.y = y | ||
+ | |||
+ | class Tiere(Objekt): | ||
+ | def __init__(self, x, y , direction, health = 1000, food = 10000, a = 40, b = 180, color = "black", status = "wandering"): | ||
+ | #Eigenschaften | ||
+ | super().__init__(x, y) | ||
+ | self.direction = direction | ||
+ | self.direction_offset = 0 | ||
+ | self.health = health | ||
+ | self.food = food | ||
+ | self.color = color | ||
+ | self.mating_cooldown = 0 | ||
+ | #Sicht | ||
+ | self.sichtweite = a | ||
+ | self.sichtkegelwinkel = b | ||
+ | #Eigenschaften, von denen das Handeln abhängt | ||
+ | self.alive = True | ||
+ | self.status = "wandering" | ||
+ | self.threat = None | ||
+ | self.target = None | ||
+ | self.avoiding = None | ||
+ | |||
+ | def change_food(self, change): | ||
+ | if self.food > 0 or change > 0: | ||
+ | self.food += change | ||
+ | elif self.food <= 0: | ||
+ | self.change_health(-10) | ||
+ | |||
+ | #tiere verlieren teile ihrer Gesundheit | ||
+ | def change_health(self, change): | ||
+ | self.health += change | ||
+ | if self.health <= 0: | ||
+ | self.die() | ||
+ | |||
+ | #Änderung der Richtung | ||
+ | def change_direction(self, type, change): | ||
+ | if type == "set": | ||
+ | self.direction = change | ||
+ | elif type == "add": | ||
+ | self.direction += change | ||
+ | self.direction %= 360 | ||
+ | |||
+ | #tiere werden wenn sie keine Lebenspunkte mehr haben aus der update-schleife genommen | ||
+ | def die(self): | ||
+ | self.alive = False | ||
+ | if isinstance(self, Fleischfresser): | ||
+ | print(self.id) | ||
+ | self.hide() | ||
+ | |||
+ | #bewegt ein Tier vorwärts abhängig von "speed" und "direction" | ||
+ | def forward(self): | ||
+ | self.x += self.speed*m.cos(m.radians(self.direction+self.direction_offset)) | ||
+ | self.y += self.speed*m.sin(m.radians(self.direction+self.direction_offset)) | ||
+ | self.hide() | ||
+ | self.show() | ||
+ | |||
+ | #beschreibt das Verhalten eines Tieres während seines sogenannten Zuges basierend auf dem Status | ||
+ | def move(self): | ||
+ | if self.status == "wandering": | ||
+ | self.change_direction("add", r.randint(-5,5)) | ||
+ | self.forward() | ||
+ | |||
+ | elif self.status == "fleeing": | ||
+ | if squared_distance(self.x, self.threat.x, self.y, self.threat.y) >= 90000 and self.threat.target != self: | ||
+ | self.status = "wandering" | ||
+ | self.threat = None | ||
+ | self.speed = self.walking_speed | ||
+ | self.forward() | ||
+ | |||
+ | elif self.status == "hunting": | ||
+ | self.change_direction("set", m.degrees(m.atan2((self.target.y-self.y),(self.target.x-self.x)))) | ||
+ | if (self.x-self.target.x)**2+(self.y-self.target.y)**2 <= (self.radius+self.target.radius)**2: | ||
+ | self.collision() | ||
+ | self.forward() | ||
+ | |||
+ | #Visualisierung der Tiere | ||
+ | def show(self): | ||
+ | self.id = canvas.create_oval(self.x-self.radius, self.y-self.radius, self.x+self.radius, self.y+self.radius, fill=self.color) | ||
+ | |||
+ | def hide(self): | ||
+ | canvas.delete(self.id) | ||
+ | |||
+ | |||
+ | #def det(alpha, beta): | ||
+ | # return m.sin(m.radians(beta-alpha)) | ||
+ | #Überprüft ob die Richtung des Hindernisses im Wahrnehmungsbereich des Tieres liegt | ||
+ | def in_sight(self, avoid): | ||
+ | direction_left_edge = (self.direction + self.direction_offset) + (self.sichtkegelwinkel / 2) #in der Visualiesierung sind die Seiten vertauscht, weil y-Achse auch gespiegelt ist | ||
+ | direction_right_edge = (self.direction + self.direction_offset) - (self.sichtkegelwinkel / 2) #in der Visualiesierung sind die Seiten vertauscht, weil y-Achse auch gespiegelt ist | ||
+ | return det(direction_left_edge, avoid) < 0 and det(avoid, direction_right_edge) < 0 | ||
+ | |||
+ | #Wahrnehmung der Umwelt mithilfe von Stichpunktartigen Zustandschecks entlang der sightrichtung ("direction") | ||
+ | def sight(self): | ||
+ | self.avoiding = None | ||
+ | |||
+ | potential_targets = [] | ||
+ | potential_threats = [] | ||
+ | |||
+ | #debug: | ||
+ | #lines.append(canvas.create_line(self.x, self.y, self.x+dis*m.cos(m.radians((self.direction + self.direction_offset) + (self.sichtkegelwinkel / 2))), self.y+dis*m.sin(m.radians((self.direction + self.direction_offset) + (self.sichtkegelwinkel / 2))), fill = "orange")) | ||
+ | #lines.append(canvas.create_line(self.x, self.y, self.x+dis*m.cos(m.radians(self.direction+self.direction_offset)), self.y+dis*m.sin(m.radians(self.direction+self.direction_offset)), fill = "orange")) | ||
+ | #lines.append(canvas.create_line(self.x, self.y, self.x+dis*m.cos(m.radians((self.direction + self.direction_offset) - (self.sichtkegelwinkel / 2))), self.y+dis*m.sin(m.radians((self.direction + self.direction_offset) - (self.sichtkegelwinkel / 2))), fill = "orange")) | ||
+ | |||
+ | |||
+ | #Kollision mit der Ecke links oben verhindern | ||
+ | if m.sin(m.radians(self.direction+self.direction_offset)) <= 0 and m.cos(m.radians(self.direction+self.direction_offset)) <= 0: | ||
+ | if self.x > dis and self.y <= dis: | ||
+ | self.avoiding = 270 | ||
+ | elif self.x <= dis and self.y > dis: | ||
+ | self.avoiding = 180 | ||
+ | elif self.x <= dis and self.y <= dis: | ||
+ | if self.avoiding == None: | ||
+ | self.avoiding = 180 | ||
+ | |||
+ | #Kollision mit der Ecke rechts oben verhindern | ||
+ | elif m.sin(m.radians(self.direction+self.direction_offset)) <= 0 and m.cos(m.radians(self.direction+self.direction_offset)) > 0: | ||
+ | if self.x <= width-dis and self.y <= dis: | ||
+ | self.avoiding = 270 | ||
+ | elif self.x > width-dis and self.y > dis: | ||
+ | self.avoiding = 0 | ||
+ | elif self.x > width-dis and self.y <= dis: | ||
+ | if self.avoiding == None: | ||
+ | self.avoiding = 0 | ||
+ | |||
+ | #Kollision mit der Ecke links unten verhindern | ||
+ | elif m.sin(m.radians(self.direction+self.direction_offset)) > 0 and m.cos(m.radians(self.direction+self.direction_offset)) <= 0: | ||
+ | if self.x > dis and self.y > hight-dis: | ||
+ | self.avoiding = 90 | ||
+ | elif self.x <= dis and self.y <= hight-dis: | ||
+ | self.avoiding = 180 | ||
+ | elif self.x <= dis and self.y > hight-dis: | ||
+ | if self.avoiding == None: | ||
+ | self.avoiding = 180 | ||
+ | |||
+ | #Kollision mit der Ecke rechts unten verhindern | ||
+ | elif m.sin(m.radians(self.direction+self.direction_offset)) > 0 and m.cos(m.radians(self.direction+self.direction_offset)) > 0: | ||
+ | if self.x <= width-dis and self.y > hight-dis: | ||
+ | self.avoiding = 90 | ||
+ | elif self.x > width-dis and self.y <= hight-dis: | ||
+ | self.avoiding = 0 | ||
+ | elif self.x > width-dis and self.y > hight-dis: | ||
+ | if self.avoiding == None: | ||
+ | self.avoiding = 0 | ||
+ | if self.avoiding != None: | ||
+ | self.avoid(self.avoiding) | ||
+ | |||
+ | |||
+ | for k in range(len(pflanzenfresser)): | ||
+ | if pflanzenfresser[k].alive and not ((isinstance(self, Pflanzenfresser) and k == self.number)): | ||
+ | direction_animal = m.degrees(m.atan2((pflanzenfresser[k].y-self.y),(pflanzenfresser[k].x-self.x))) | ||
+ | if self.in_sight(direction_animal): | ||
+ | self.react_to_pflanzenfresser(k, potential_targets) | ||
+ | |||
+ | for k in range(len(fleischfresser)): | ||
+ | if fleischfresser[k].alive and not (isinstance(self, Fleischfresser) and k == self.number): | ||
+ | direction_animal = m.degrees(m.atan2((fleischfresser[k].y-self.y),(fleischfresser[k].x-self.x))) | ||
+ | if self.in_sight(direction_animal): | ||
+ | self.react_to_fleischfresser(k, potential_threats) | ||
+ | |||
+ | if len(potential_targets) > 0: | ||
+ | self.set_target(self.find_animal(potential_targets)) | ||
+ | if len(potential_threats) > 0: | ||
+ | self.set_threat(self.find_animal(potential_threats)) | ||
+ | |||
+ | if self.avoiding == None: | ||
+ | self.change_direction("add", self.direction_offset) | ||
+ | self.direction_offset = 0 | ||
+ | |||
+ | #Ändert die Richtung, mithilfe einer Offset variable | ||
+ | def avoid(self, direction_avoid): | ||
+ | determinante = det(self.direction+self.direction_offset, direction_avoid) | ||
+ | if determinante < 0: | ||
+ | self.direction_offset += 10 | ||
+ | else: | ||
+ | self.direction_offset -= 10 | ||
+ | |||
+ | def find_animal(self, animals): | ||
+ | if len(animals) > 0: | ||
+ | nearest_animal = animals[0] | ||
+ | for i in range(1, len(animals)): | ||
+ | if squared_distance(self.x, animals[i].x, self.y, animals[i].y) < squared_distance(self.x, nearest_animal.x, self.y, nearest_animal.y): | ||
+ | nearstest_animal = animals[i] | ||
+ | return nearest_animal | ||
+ | |||
+ | #setzt den status auf "fleeing" | ||
+ | def set_threat(self, threat): | ||
+ | self.status = "fleeing" | ||
+ | self.threat = threat | ||
+ | self.speed = self.running_speed | ||
+ | self.change_direction("set", m.degrees(m.atan2((self.threat.y-self.y),(self.threat.x-self.x))) + 180) | ||
+ | |||
+ | #setzt den status auf "hunting" | ||
+ | def set_target(self, target): | ||
+ | self.status = "hunting" | ||
+ | self.target = target | ||
+ | self.color = "red" | ||
+ | self.speed = self.running_speed | ||
+ | |||
+ | #Wenn ein Fleischfresser einen Pflanzenfresser gefangen hat verliert der Pflanzenfresser leben bis er stirbt. Dann wird der Status des Fleischfressers wieder zurückgesetzt | ||
+ | def collision(self): | ||
+ | self.target.change_health(-100) | ||
+ | if self.target.alive == False: | ||
+ | self.change_food(500) | ||
+ | self.status = "wandering" | ||
+ | self.color = "blue" | ||
+ | self.speed = self.walking_speed | ||
+ | |||
+ | class Pflanzenfresser(Tiere): | ||
+ | radius = 5 | ||
+ | def __init__(self, i, x, y, direction): | ||
+ | self.number = i | ||
+ | self.grazing_speed = 0.1 | ||
+ | self.walking_speed = 0.5 | ||
+ | self.running_speed = 2.5 | ||
+ | self.speed = self.walking_speed | ||
+ | super().__init__(x, y, direction, 1000, 1000, 40, 180, "green") | ||
+ | |||
+ | def check_grazing(self): | ||
+ | if self.food < 900: | ||
+ | self.speed = self.grazing_speed | ||
+ | elif self.food >= 1000: | ||
+ | self.speed = self.walking_speed | ||
+ | if self.speed == self.grazing_speed: | ||
+ | self.change_food(1) | ||
+ | |||
+ | def react_to_pflanzenfresser(self, k, potential_threats): | ||
+ | if self.status == "wandering" and pflanzenfresser[k].status == "wandering": | ||
+ | if squared_distance(self.x, pflanzenfresser[k].x, self.y, pflanzenfresser[k].y) < 4*self.radius**2: | ||
+ | if self.mating_cooldown == 0 and pflanzenfresser[k].mating_cooldown == 0: | ||
+ | if self.food >= 500 and pflanzenfresser[k].food >= 500: | ||
+ | if len(pflanzenfresser) <= 400: | ||
+ | global new_pflanzenfresser | ||
+ | random_direction = r.randint(0,359) | ||
+ | new_pflanzenfresser.append(Pflanzenfresser(len(pflanzenfresser)+len(new_pflanzenfresser), self.x, self.y, random_direction)) | ||
+ | self.mating_cooldown = 1000 | ||
+ | pflanzenfresser[k].mating_cooldown = 1000 | ||
+ | elif squared_distance(self.x, pflanzenfresser[k].x, self.y, pflanzenfresser[k].y) < 10000: | ||
+ | if self.mating_cooldown == 0: | ||
+ | self.change_direction("set", m.degrees(m.atan2((pflanzenfresser[k].y-self.y),(pflanzenfresser[k].x-self.x)))) | ||
+ | |||
+ | def react_to_fleischfresser(self, k, potential_threats): | ||
+ | quadratischeDistanz = squared_distance(self.x, fleischfresser[k].x, self.y, fleischfresser[k].y) | ||
+ | if quadratischeDistanz <= dis**2: | ||
+ | potential_threats.append(fleischfresser[k]) | ||
+ | |||
+ | class Fleischfresser(Tiere): | ||
+ | radius = 8 | ||
+ | def __init__(self, i, x, y, direction): | ||
+ | self.number = i | ||
+ | self.walking_speed = 0.8 | ||
+ | self.running_speed = 2 | ||
+ | self.speed = self.walking_speed | ||
+ | super().__init__(x, y, direction, 1000, 1000, 100, 120, "blue") | ||
+ | |||
+ | def react_to_pflanzenfresser(self, k, potential_targets): | ||
+ | quadratischeDistanz = squared_distance(self.x, pflanzenfresser[k].x, self.y, pflanzenfresser[k].y) | ||
+ | if quadratischeDistanz <= 200**2: | ||
+ | if self.food < 500: | ||
+ | if self.status == "wandering": | ||
+ | potential_targets.append(pflanzenfresser[k]) | ||
+ | elif self.status == "hunting": | ||
+ | if quadratischeDistanz < squared_distance(self.x, self.target.x, self.y, self.target.y): | ||
+ | potential_targets.append(pflanzenfresser[k]) | ||
+ | |||
+ | def react_to_fleischfresser(self, k, potential_targets): | ||
+ | if self.status == "wandering" and fleischfresser[k].status == "wandering": | ||
+ | if squared_distance(self.x, pflanzenfresser[k].x, self.y, pflanzenfresser[k].y) < 4*self.radius**2: | ||
+ | if self.mating_cooldown == 0 and fleischfresser[k].mating_cooldown == 0: | ||
+ | if self.food >= 500 and fleischfresser[k].food >= 500: | ||
+ | global new_fleischfresser | ||
+ | random_direction = r.randint(0,359) | ||
+ | new_fleischfresser.append(Fleischfresser(len(fleischfresser)+len(new_fleischfresser), self.x, self.y, random_direction)) | ||
+ | self.mating_cooldown = 1000 | ||
+ | fleischfresser[k].mating_cooldown = 1000 | ||
+ | elif squared_distance(self.x, fleischfresser[k].x, self.y, fleischfresser[k].y) < 40000: | ||
+ | if self.mating_cooldown == 0: | ||
+ | self.change_direction("set", m.degrees(m.atan2((fleischfresser[k].y-self.y),(fleischfresser[k].x-self.x)))) | ||
+ | |||
+ | class See(Objekt): | ||
+ | radius = 50 | ||
+ | def __init__(self, number, x = 50, y = 50): | ||
+ | self.number = number | ||
+ | self.radius = radius | ||
+ | self.x = x | ||
+ | self.y = y | ||
+ | self.color = "blue" | ||
+ | super().__init__(x, y) | ||
+ | |||
+ | #Simulationsaufbau | ||
+ | for i in range(start_pflanzenfresser): | ||
+ | random_x = r.randint(Pflanzenfresser.radius, width - Pflanzenfresser.radius) | ||
+ | random_y = r.randint(Pflanzenfresser.radius, hight - Pflanzenfresser.radius) | ||
+ | random_direction = r.randint(0,359) | ||
+ | pflanzenfresser.append(Pflanzenfresser(i, random_x, random_y , random_direction)) | ||
+ | pflanzenfresser[i].show() | ||
+ | |||
+ | for i in range(start_fleischfresser): | ||
+ | random_x = r.randint(Fleischfresser.radius, width - Fleischfresser.radius) | ||
+ | random_y = r.randint(Fleischfresser.radius, hight - Fleischfresser.radius) | ||
+ | random_direction = r.randint(0,359) | ||
+ | fleischfresser.append(Fleischfresser(i, random_x, random_y, random_direction)) | ||
+ | fleischfresser[i].show() | ||
+ | |||
+ | |||
+ | for i in range(anzahl_seen): ###hiermit habe ich den See und Strand gezeichnet | ||
+ | | ||
+ | id = canvas.create_rectangle(0, 70, 100, 0, fill= "yellow", outline = "yellow") # Das ist die Füllung vom Loch oben links | ||
+ | | ||
+ | id = canvas.create_rectangle(0, 200, 100, 0, fill= "yellow", outline = "yellow") | ||
+ | | ||
+ | id = canvas.create_oval(0, 250, 100, 0, fill= "yellow", outline = "yellow") | ||
+ | |||
+ | id = canvas.create_oval(0, 245, 50, 150, fill= "yellow", outline = "yellow") | ||
+ | |||
+ | id = canvas.create_oval(0, 255, 70, 150, fill= "yellow", outline = "yellow") | ||
+ | |||
+ | id = canvas.create_oval(-50, 255, 30, 100, fill= "yellow", outline = "yellow") | ||
+ | |||
+ | id = canvas.create_oval(-100, 260, 100, 100, fill= "yellow", outline = "yellow") | ||
+ | |||
+ | id = canvas.create_oval(-100, 260, 200, 100, fill= "yellow", outline = "yellow") | ||
+ | |||
+ | |||
+ | |||
+ | | ||
+ | | ||
+ | | ||
+ | id = canvas.create_oval(0, 150, 100, 0, fill= "blue", outline = "blue") | ||
+ | |||
+ | id = canvas.create_oval(300, 150, 170, 0, fill= "blue", outline = "blue") | ||
+ | |||
+ | id = canvas.create_oval(50, 100, 240, 200, fill= "blue", outline = "blue") | ||
+ | |||
+ | id = canvas.create_rectangle(50, 0, 220, 150, fill= "blue", outline = "blue") | ||
+ | |||
+ | id = canvas.create_oval(250, 140, 220, 157, fill= "blue", outline = "blue") | ||
+ | |||
+ | id = canvas.create_oval(16, 50, 220, 190, fill= "blue", outline = "blue") | ||
+ | update() | ||
+ | </code> | ||
+ | |||
+ | |||
+ | |||
+ |