WoW! Super Erklärung, könnten sich n paar ne Scheibe davon abschneiden
Danke.
Dennoch finde ich es eigentlich übertrieben, dass man diese Variablen zwingend als final deklarieren muss... man könnte ja immerhin mit try - catch arbeiten um das Problem zu umgehen.
Welches Problem?
Das Ändern von Listen ist ein Feature. Wenn die Liste also geändert wird, ist dies doch kein Problem sondern die ganz normale Benutzungsweise.
Davon abgesehen würde dir schlimmstenfalls permanent eine ListDidChangeException um die Ohren fliegen - damit hättest du dann auch nichts gewonnen.
Und wie würdest du darauf reagieren wollen? Einfach von vorn anfangen? Im schlimmsten Fall feuert dein Turm dann schlicht niemals.
Ich persönlich bin übrigens überhaupt kein Freund dieser unsäglichen Threading-Geschichte.
Android besteht beispielsweise darauf, dass Netzwerkaktivität im Hintergrundthread ausgeführt wird. Warum?
Wenn _ich_ zeitintensive Netzwerkaktivität habe, dann, weil sie zum Gebrauch des Programms essentiell notwendig ist. Sprich: bevor das nicht durch ist, kann die Anwendung nicht bedient werden.
Doch dank Androids Vorgaben muss ich im Hintergrund die aktualisierten Daten laden während ich meinen UI-Thread blockieren muss, damit der User nichts kaputtspielt.
Nicht sehr klug gelöst, wenn man mich fragt.
Threads sollen Arbeiten übernehmen, die das UI auf Grund ihrer hohen Ausführungszeit blockieren würden.
Mein UI soll blockieren, also brauche ich den Thread nicht.
Ein Spiele-UI ist von vorn herein blockiert, zumindest aus Sicht des Betriebssystems. Ob es jetzt künstlich blockiert ist oder manuell blockiert wurde macht da doch keinen Unterschied.
Im Prinzip läuft auch so ein TowerDefense eher rundenbasiert ab:
1 Jedes Viech bewegt sich (entsprechend seiner Eigenschaften)
2 Jeder Turm prüft ob er schießen kann (entsprechend seiner Geschwindigkeit)
2.1 Turm schießt (entsprechend seiner Eigenschaften)
2.2 getroffenes Viech prüft, ob es tot ist (entsprechend seiner Gesundheit und des Projektils)
2.2.1 Beute wird dem Spieler zugeschrieben (entsprechend der Beuteeigenschaftes des Viechs und ggf. Boni des Turms)
Fahre fort bei Schritt 1.0
Das heißt, bevor deine Türme schießen können sollten sich die Viecher schon bewegt haben.
(Meinetwegen auch anders herum: du schießt erst und sie bewegen sich dann.)
Dann passiert nichts weiter, die Runde endet erst, wenn alle Türme prüften ob sie schießen konnten.
Das kannst du in die Runnable des Turmes auslagern, solltest du aber nicht tun.
Genau genommen baust du dir gerade gewaltige Code Smells ein.
Du verletzt nicht nur das Paradigma der Kapselung, sondern verdrahtest auch Codeteile miteinander, die nichts miteinander zu tun haben.
Beispiel: dein fünfter Turm KANN gemäß seiner Eigenschaften nur ein einziges Viech angreifen. Wieso sollte er von der Existenz anderer Viecher wissen?
Wenn du dein Spielfeld mit Quadraten aufteilst (Gamefield Array), dann kennst du ja schon den Umkreis des Bereiches, den dein Turm überblicken kann.
Warum gibst du ihm dann nicht einfach eine neue Liste mit allen Viechern in diesem Umkreis mit? Wenn er nur die Eigenschaft 'attackiere schwächstes Wesen' hat, dann gib ihm einfach an Stelle ALLER nur das Viech in seinem Umkreis mit der geringsten Energie mit.
Du kannst schon bei der Erstellung der Listen so viel optimieren, dass du das Auslagern in einen anderen Thread überhaupt nicht benötigst.
Schneller wird es dadurch eh nicht, da der Mainthread auf die Ergebnisse wartet. (a.k.a. wenn du geschossen hast, muss der UI-Thread das Zeichnen und Bewegen des Projektils übernehmen.)
Auf Threading würde ich wirlkich nur dann zurückgreifen, wenn es Performanceengpässe gibt.