# Kollisionserkennung mit AABBs und Spielerobjekt



## tdc (11. Jan 2012)

Hi,
bisher habe ich für die Kollisionserkennung für jeden Eckpunkt jeder Fläche des Spielerobjektes überprüft, ob er sich in der Bounding Box des anderen Objektes befindet. Zusätzlich gab es für jeden Punkt auch noch 2 "Referenzpunkte" die auf der Kante der Fläche ein wenig verschoben waren, da an einen Punkt 3 Flächen grenzten. Es hat teilweise funktioniert, war aber total langsam und verbuggt.

Jetzt versuche ich es "einfach" über die x,y,z - Koordinaten und über die Breite, Höhe und Tiefe zu regeln. Meine grobe Kollisionserkennung, die überprüft, ob es überhaupt zu einer Kollision kommt, sieht z.B. so aus:

```
public boolean collisionTest(GameObject a, GameObject b)
	{
		if(b.getX() <= a.getX() + a.getWidth() && b.getX()+b.getWidth() >= a.getX())
		{
			if(b.getZ() <= a.getZ() + a.getDeep() && b.getZ()+b.getDeep() >= a.getZ())
			{
				if(b.getY() <= a.getY() + a.getHeight() && b.getY()+b.getHeight() >= a.getY())
				{
					return true;
				}
			}
		}
		return false;
	}
```

Mein Problem ist es allerdings nun herauszufinden, welche Seite mit dem anderen Objekt kollidiert. Der Code für die genauere Kollisionserkennung sieht zurzeit folgendermaßen aus:

```
boolean top = true;
		boolean bottom = true;
		boolean front = true;
		boolean back = true;
		boolean right = true;
		boolean left = true;
		for(GameObject obj:objects)
    	{
			if(collisiondetector.collisionTest(obj, mainplayer))
			{
				if(obj != mainplayer)
				{
					if(obj.isSolid())
					{
						if(obj.getY() <= mainplayer.getY()+mainplayer.getHeight() && obj.getY() > mainplayer.getY() + mainplayer.getHeight()/3*2)
						{
							if(obj.getX() <= mainplayer.getX() + mainplayer.getWidth() -0.2f && obj.getX()+obj.getWidth() >= mainplayer.getX() +0.2f)
							{
								if(obj.getZ() <= mainplayer.getZ() + mainplayer.getDeep() -0.2f && obj.getZ()+obj.getDeep() >= mainplayer.getZ() +0.2f)
								{
									top = false;
								}
							}
						}
						if(obj.getY()+obj.getHeight() >= mainplayer.getY() && obj.getY() < mainplayer.getY() + mainplayer.getHeight()/3)
						{
							if(obj.getX() <= mainplayer.getX() + mainplayer.getWidth() -0.2f && obj.getX()+obj.getWidth() >= mainplayer.getX() +0.2f)
							{
								if(obj.getZ() <= mainplayer.getZ() + mainplayer.getDeep() -0.2f && obj.getZ()+obj.getDeep() >= mainplayer.getZ() +0.2f)
								{
									//cam.forceSetY(mainplayer.getHeight()+obj.getY()+obj.getHeight());
									bottom = false;
								}
							}
						}
						
						if(	(obj.getY() >= mainplayer.getY() && obj.getY() <= mainplayer.getY() + mainplayer.getHeight()) ||
							(obj.getY() + obj.getHeight() >= mainplayer.getY()+0.15f && obj.getY() + obj.getHeight() <= mainplayer.getY() + mainplayer.getHeight()) ||
							(obj.getY() <= mainplayer.getY() && obj.getY() + obj.getHeight() >= mainplayer.getY() + mainplayer.getHeight()))
						{
							if(obj.getX() < mainplayer.getX() + mainplayer.getWidth()/2)
							{
								right = false;
							}
							if(obj.getX() > mainplayer.getX() + mainplayer.getWidth()/2)
							{
								left = false;
							}
							if(obj.getZ() < mainplayer.getZ() + mainplayer.getDeep()/2)
							{
								back = false;
							}
							if(obj.getZ() > mainplayer.getZ() + mainplayer.getDeep()/2)
							{
								front = false;
							}
						}
					}
					obj.collisionEvent();
				}
			}
    	}
```

An den Booleans in den If-Abfragen könnt ihr ja erkennen, für welche seite die Kollisionserkennung durchgeführt wird.
Ein paar kleine Anmerkungen zum Code:
- die Fläche der oberen und unteren "Kollisionsfläche" habe ich eingeschränkt, da ma ansonsten evtl. in einer Wand hängen bleibt (-> hängt mit meinem Problem zusammen)
- die Kollisionserkennung für die Seiten habe ich auch auf eine bestimmte Mindesthöhe begrenzt, da anonsten seitliche Kollisionen auftreten (hängt letztendlich auch mit dem Problem zusammen)

Das Problem ist, dass sich vor allem an den Seiten die "Kollisionsvolumen" überschneiden. D.h. wenn sich ein Block bewegt, gibt es bei jedem Durchlauf von der einen Position zur nächsten eine gewisse Lücke. Wenn z.B. ein Eckpunkt plötzlich rechts vorne innerhalb eines anderen Blocks ist, befindet er sich von den Koordinaten her an einer Stelle, durch die sowohl right, als auch front auf false gesetzt werden, obwohl sich der Block eigentlich rechts vom Spieler befindet. Dadurch kommt es zu sehr unschönen Hängern und ruckligen Bewegungen, wenn man an einer Wand entlanglaufen will.
Da es sich bei den Boundig Boxes um AABBs (Axis Aligned Boundig Boxes) handelt, darf aber bei einer einfachen Kollision des Spieler(-blocks) mit einem Block nur eine Bewegungsachse betroffen sein, bei meinem Beispiel sind aber fast immer 2 Achsen betroffen. (!= Sliding-Effekt an Wänden)

Wie könnte ich jetzt erkennen, an welcher Seite die Kollisionserkennung wirklich stattfindet?
(ja, ich weiß, dass es parrallel noch einen anderen Kollisionserkennungs-Threat gibt, mein Problem ist allerdings ein wenig spezifischer)




EDIT:
Das mit der Achsen-Bewegung habe ich beim Spieler übrigens ganz einfach so gelöst:

```
public void setX(float x)
	{
		if(x > campos.x)
		{
			if(left)
			{
				campos.x = x;
			}
		}
		else
		{
			if(right)
			{
				campos.x = x;
			}
		}
	}
	
	public void setY(float y)
	{
		if(y > campos.y)
		{
			if(top)
			{
				campos.y = y;
			}
		}
		else
		{
			if(bottom)
			{
				campos.y = y;
			}
		}
	}
	
	public void setZ(float z)
	{
		if(z > campos.z)
		{
			if(front)
			{
				campos.z = z;
			}
		}
		else
		{
			if(back)
			{
				campos.z = z;
			}
		}
	}
```
Nur damit das hoffentlich auch verständlich ist.


----------



## Lulumann6 (11. Jan 2012)

Eine relativ einfache, aber nicht besonders schöne möglichkeit, wäre zuerst die hoch/runter-bewegung durchzuführen, danach kollisionserkennung und dann die seitliche bewegung durchführen und wieder kollisionserkennung. 
es würde mich aber auch interessieren ob es dafür elegantere lösungsmöglichkeiten gibt.


----------



## Marco13 (11. Jan 2012)

Was sollen denn diese willkürlich aussehenden /3*2 und +0.2 dort? Man hat einen Anfangs- und einen Endzustand. Wenn man davon ausgeht, dass Spieler und Objekt immer genau Quaderförmig sind (also wenn der Spieler und das Objekt quasi SELBST die AABBs sind) kann das je nach Bewegung immernoch kompliziert werden, wenn man es kontinulierlich machen will. Aber selbst im einfachsten, diskreten Fall braucht man die Info top/bottom/left/right ja nicht unbedingt, sondern kann die Objekte auf dem kürzesten Weg so verschieben, dass sie sich nicht mehr überschneiden...!?


----------



## tdc (11. Jan 2012)

Lulumann6 hat gesagt.:


> Eine relativ einfache, aber nicht besonders schöne möglichkeit, wäre zuerst die hoch/runter-bewegung durchzuführen, danach kollisionserkennung und dann die seitliche bewegung durchführen und wieder kollisionserkennung.
> es würde mich aber auch interessieren ob es dafür elegantere lösungsmöglichkeiten gibt.



Mein Problem bezieht sich aber derzeit eigentlich nur auf die seitliche Kollisionserkennung. D.h. bei einer Kollision auf der X-Achse kann man sich auch auf der Z-Achse in eine Richtung nicht bewegen.
Ich muss also zurzeit nur herausfinden, auf welcher Seite die Kollision eigentlich stattfindet. Bei meiner Vorgehensweise hatte ich das Problem aufgrund dieser "Bezugspunkte" nicht, jetzt brauche ich eben etwas ähnliches.



Marco13 hat gesagt.:


> Was sollen denn diese willkürlich aussehenden /3*2 und +0.2 dort?


Das ist letztendlich das, was ich damit


tdc hat gesagt.:


> - die Fläche der oberen und unteren "Kollisionsfläche" habe ich eingeschränkt, da ma ansonsten evtl. in einer Wand hängen bleibt (-> hängt mit meinem Problem zusammen)
> - die Kollisionserkennung für die Seiten habe ich auch auf eine bestimmte Mindesthöhe begrenzt, da anonsten seitliche Kollisionen auftreten (hängt letztendlich auch mit dem Problem zusammen)


gemeint habe. Wobei mir gerade auffält, dass mein 2. Stichpunkt gar keinen Sinn macht. Ich meinte, dass bei der Bewegung über den Boden (Kollision unten) auch seitlich Kollisionen auftreten.



Marco13 hat gesagt.:


> Man hat einen Anfangs- und einen Endzustand. Wenn man davon ausgeht, dass Spieler und Objekt immer genau Quaderförmig sind (also wenn der Spieler und das Objekt quasi SELBST die AABBs sind) kann das je nach Bewegung immernoch kompliziert werden, wenn man es kontinulierlich machen will. Aber selbst im einfachsten, diskreten Fall braucht man die Info top/bottom/left/right ja nicht unbedingt, sondern kann die Objekte auf dem kürzesten Weg so verschieben, dass sie sich nicht mehr überschneiden...!?


Ja, bisher sind meine Objekte Quaderförmig. Auf der X- und Z-Achse kann man sich je nach Blickrichtung frei bewegen. Außerdem kann man Springen.
Die Idee mit dem kürzesten Weg hatte ich auch schonmal... irgendwas hatte wohl imo dagegen gesprochen, sodass ich die Idee wieder verworfen hatte, aber jetzt fällt es mir nicht ein. Ich denke nochmal bis morgen drüber nach und versuche es dann evtl. mal umzusetzen.
(Letzendlich hatte ich geahnt, dass mein Problem eigentlich recht einfach ist, vorhin sind mir aber die Ideen dazu ausgegangen  )


----------



## Kr0e (12. Jan 2012)

Vermutlich ist das nicht das, was du hören willst, aber ich sags trotzdem:

Es gibt ja auch Dinge wie jBox2D (eine fertige und auf hohem Niveau arbeitende 2D Physicsengine). Sofern es dir nicht darum geht, die Funktionsweise 100% zu verstehen und selbst zu impl. so könntest du die Probleme outsourcen und auf was zurückgreifen, was sehr gut bereits funktioniert. Und falls es 3D werden soll ist die Bullet-Engine super funktionsfähig.

Und nun ein Vorschlag, für den mich einige bestimmt hauen: Falls es dir ums Spiel ansich geht und nicht darum es mit Java gemacht zu haben, so würde ich dir Unity3D empfehlen. Meiner Meinung nach gibt es für Spiele kaum was besseres/billigeres verlgichen mit den Fähigkeiten. Es gibt die kostenfreie Variante mit der Spiele sogar kommerziell vermarkten darfst, allerdings darfst du im Jahr nich mehr als 100.000$ verdienen und wenn doch, dann musst du dir die Pro Variante für 1500$ Dollar kaufen, was bei 100.000$ pro Jahr dann sicherlich wie ein kleiner Scherz aussieht  Scripten/Programmieren kannst du in Unity3D sogar in C# was ja vom Syntax her Java recht nahe kommt.

Ist aber nur ein dummer Vorschlag vermutlcih, da du ja alles bereits in Java gemacht hast und sicherlich dabei bleiben willst 

Gruß,
Chris


----------

