# 3D-Kollision mit zwei ArrayLists



## spoinkh (13. Dez 2012)

Hallo erstmals!

Es geht, wie es im Titel schon steht, um ein 3D-Spiel für Android. Ich habe sowohl die Zombies als auch die Schüsse in zwei ArrayLists gespeichert. Jetzt muss ich es irgendwie schaffen, dass die Zombies verschwinden, wenn sie vom Schuss getroffen werden. Mein Problem: Die Zombies verschwinden in der Reihenfolge, in der sie erschienen sind und das auch wenn sie nicht vom Schuss getroffen werden. D.h. es ist vollkommen egal, in welche Richtung ich schieße, die Zombies verschwinden einfach.
Ich wäre für ein paar Lösungsvorschläge sehr dankbar. 


Liebe Grüße

Spoinkh


```
for (int j = 0; j < zombieListe.size(); j++) {
					Zombie zombie = (Zombie) zombieListe.get(j);
					zombieX = zombie.getX();
					zombieZ = zombie.getZ();

					for (int i = 0; i < schussListe.size(); i++) {
						Schuss schuss = (Schuss) schussListe.get(i);
						schuss.bewegeSchuss();
						schuss.display(gl, activity);

						GK = (float) (Math.sin(schuss.getWinkel()) * schuss.getPosition());
						AK = (float) (Math.cos(schuss.getWinkel()) * schuss.getPosition());
						
						collisionEntf = (float) (Math.sqrt(Math.pow((AK - zombieX), 2) + Math.pow((GK - zombieZ), 2)));
						
						if (Math.abs(collisionEntf) < 1.5) {
							zombieListe.remove(j);
						}

						if (schuss.fertig()) {
							schussListe.remove(i);
						}
					}
				}
```


----------



## SlaterB (13. Dez 2012)

das scheint alles nur 2D zu sein statt 3D, oder spielt die Höhe auch eine Rolle? 

der genaue Programmablauf ist nicht wirklich ersichtlich, wie lange bleiben die Zombies da, bewegen die sich zwischenzeitlich,
was heißt 'verschwinden in der Reihenfolge', alle bei einem Schuss oder wie oder was genau?

spielst du doch auf das gepostete remove() aus der Zombie-Liste an?
das passiert nur aufgrund einer genauen Bedingung, Schusstreffer, 

> egal, in welche Richtung ich schieße
sollte besser nicht sein, schaue dir doch die Rechnung im Detail an,
was wird für GK, AK berechnet, das sind doch Positionsangaben?
sind die in der Nähe des Zombies? wenn ja und nicht gut dann die Rechnung davor näher beleuchten, was soll der Winkel und die Postion sein, wie sieht die Rechnung aus? kann glaube ich niemand einfach so nachvollziehen

sind GK und AK korrekt, und weit entfernt und springt das if dennoch an, dann diese Bedingung überprüfen,
alles simpelste Schritte wie Schlaufe beim Schuhezubinden, nach Schritt A kommt Schritt B, dann Schritt C..

collisionEntf  als Wurzel dürfte übrigens bereits immer positiv sein


----------



## Marco13 (13. Dez 2012)

Die Listen zu ändern (d.h. elemente zu entfernen) während drüberiteriert wird ist ein bißchen frickelig. Ggf. müßten die Variablen (i,j) beim Enfernen angepasst (d.h. um eins verringert) werden, oder man speichert sich, was entfernt wurde, und entfernt es am Ende in einem Rutsch.


----------



## Dow Jones (13. Dez 2012)

Ein möglicher Fehler könnte hier sein, das du für die Positionen der Schüsse und der Zombies verschiedene Bezugspunkte verwendest. Falls [c]schuss.getPosition()[/c] die Distanz zwischen Schuss und Kanone zurückliefert dann berechnest du in den Zeilen 11+12 die X/Y-Position eines Schusses relativ zur Kanone. Sind die Positionen der Zombies auch in dieser Form gespeichert?

Was aber ganz sicher falsch ist: Du kannst nicht einfach so Elemente aus einer Liste löschen während du gerade über sie iterierst. Angenommen zwei Schüsse treffen den gleichen Zombie - dann würdest du zwei mal [c]zombieListe.remove(j)[/c] aufrufen und dadurch zwei (verschiedene) Zombies entfernen.
Aber selbst wenn nur ein einziger Zombie aus der Liste entfernt würde käme es zum falschen Ergebnis, denn bei solche Konstrukten wie

```
for (int i = 0; i < schussListe.size(); i++) {
        if (schuss.fertig()) {
            schussListe.remove(i);
        }
    }
```
überspringst du einzelne Elemente des Arrays. Siehe auch hier.


----------



## Robokopp (13. Dez 2012)

Marco13 hat gesagt.:


> Die Listen zu ändern (d.h. elemente zu entfernen) während drüberiteriert wird ist ein bißchen frickelig. Ggf. müßten die Variablen (i,j) beim Enfernen angepasst (d.h. um eins verringert) werden, oder man speichert sich, was entfernt wurde, und entfernt es am Ende in einem Rutsch.



Oder man kopiert jedes mal das Array und verwendet die Kopie bspw. zum zeichnen.
Dann kann man über das kopierte Array iterieren, aber aus dem Original löschen und es gibt keine Konflikte


----------



## spoinkh (13. Dez 2012)

SlaterB hat gesagt.:


> das scheint alles nur 2D zu sein statt 3D, oder spielt die Höhe auch eine Rolle?
> 
> der genaue Programmablauf ist nicht wirklich ersichtlich, wie lange bleiben die Zombies da, bewegen die sich zwischenzeitlich,
> was heißt 'verschwinden in der Reihenfolge', alle bei einem Schuss oder wie oder was genau?
> ...



Programmablauf:
- Zombies erscheinen am Rand des Displays
- In der Mitte steht eine Figur; Die Zombies bewegen sich Richtung Figur und bleibt (falls sie nicht getroffen wird) kurz vor der Person stehen
- Bei der Berührung des Displays werden Schüsse abgefeuert
- Trifft ein Schuss einen Zombie, dann soll der getroffene Zombie verschwinden
(Im Anhang ein Screenshot)

Verschwinden in der Reihenfolge heißt: Sie erscheinen in einer bestimmten Reihenfolge und in dieser verschwinden sie dann auch.

Das zombieListe.remove(j) soll nur aufgerufen werden, wenn sich Zombie und Schuss treffen.
Das schussListe.remove(i) wird aufgerufen, wenn die Entfernung des Schusses von der Person in der Mitte einen bestimmten Wert erreicht (wenn die Patrone nicht mehr sichtbar ist soll sie gelöscht werden, um Ressourcen zu sparen)

GK ist die Koordinate vom Schuss (von unten nach oben)
AK ist die Koordinate vom Schuss (von links nach rechts)

zombieZ ist die Koordinate vom Zombie (von oben nach unten)
zombieX ist die Koordinate vom Zombie (von links nach rechts)

Die Variable winkel ist der Winkel von der X-Achse zum Berührungspunkt

getPosition ist eine Methode, die den Abstand vom Schuss zur Figur zurückliefert


----------



## Dow Jones (13. Dez 2012)

spoinkh hat gesagt.:


> GK ist die Koordinate vom Schuss (von unten nach oben)
> AK ist die Koordinate vom Schuss (von links nach rechts)
> 
> zombieZ ist die Koordinate vom Zombie (von oben nach unten)
> ...



Daraus werde ich ehrlich gesagt nicht schlau... Verwendest du für Schuss und Zombie unterschiedliche Koordinatensysteme mit entgegengesetztem Vorzeichen der Achsen? Oder schmeisst du hier 2D und 3D in einen Topf, womöglich noch zusammen mit der Projektion? :bahnhof:

Zeiche doch mal eine Skizze, auf der die Koordinatensysteme für Schuss, Zombie und Winkel eingezeichnet sind, jeweils mit Ursprung und Beschriftung der Achsen. Das würde glaube ich schon einiges an Klarheit bringen, denn die Berechnungen ob ein Zombie getroffen wurde sehen ja durchaus korrekt aus - solange die zugrundeliegenden Werte auch wirklich das sind, was sie sein sollten.

Ansonsten bleibt ja noch die Frage was denn passiert wenn du mal das schon mehrfach genannte Problem des _remove in der Schleife_ behebst. Im einfachsten Fall könnte du das mal so probieren:

```
if (schuss.fertig()) {
                            schussListe.remove(i);
                            i--;
                        }

                        if (Math.abs(collisionEntf) < 1.5) {
                            zombieListe.remove(j);
                            j--;
                            break;
                        }
```
Falls das nicht klappt - versuch mal die Schüsse/Zombies nicht aus den Listen zu entfernen sondern sie nur zu markieren (z.B. einzufärben). Das bringt vielleicht auch etwas Klarheit darüber was deine Methode genau macht.


PS: Auch wenn es "schön" aussieht - das Wurzelziehen etc. würde ich mir sparen und stattdessen 

```
collisionEntf = (float) (  (AK - zombieX)*(AK - zombieX)  +  (GK - zombieZ)*(GK - zombieZ)  );
    if ( collisionEntf < 2.25 )
```
verwenden. Die ganzen allgemeinen mathematischen Operationen kosten nur Rechenzeit, von der man auf einem Android sicherlich auch nicht zuviel hat.


----------



## theodosis (13. Dez 2012)

Hallo,

Angenohmen, daß die Objekte in deinem Spiel in Quader oder/und in Kugeln (oder eine Kombination aus dieser Raumkörper) passen, dann ist die Sache viel einfacher.

Viel einfacher und leichter auch für den ARM prozessor von Android ist nach nicht-Kollision zu prüfen, statt für Kollision.

Ich beschreibe das Verfahren in meinem Artikel und obwohl das ist über 2D Objekte, das kann auch für 3D angewendet werden (da gibt es nur mehrere Fälle für nicht-Collision)


game programming algorithms: Collision detection by detecting ...no-collision

Ich hoffe das wird dir helfen.


----------

