# Collision Detection bei Tile Map



## skappler (20. Mrz 2012)

Hallo Leute
Ich arbeite momentan an einem 2D Shooter und brauche Hilfe bei der Kollision zwischen dem Spieler und der Map.
Ich habe meine Map als 2 dimensionales Array aus Tiles gespeichert, wobei jedes Tiles eine boolean Variable hat, ob man über das Tile laufen darf oder nicht. 
Meine Tiles sind 32x32 Pixel und mein Player 32x64. 
Ich arbeite nun schon mehrere Tage daran aber komme zu keinem funktionierenden Ergebnis.

Hat einer einen guten Ansatz für mich?

Gruß,
skappler


----------



## TimoH. (20. Mrz 2012)

überprüfe doch bevor du deinen Spieler bewegst, ob die Tile zu der du laufen würdest begehbar ist, wenn ja, bewege den Spieler und wenn nicht dann halt nicht


----------



## skappler (20. Mrz 2012)

Ja aber ich komme mit den Koordinaten nicht wirklich klar. Dazu kommt, dass mein Player doppelt so hoch wie ein Tile ist und sich flüßig bewegen lässt (also nicht immer genau auf einem Tile liegt, sondern auf mehreren).


----------



## TimoH. (20. Mrz 2012)

Du kannst die Spielerkoordinate doch in die dazugehörige Tile umrechnen.

x = Spieler.x / Tile.Width
y = Spieler.y / Tile.Height


----------



## skappler (20. Mrz 2012)

Ja schon klar. Aber wie gestalte ich dann die abfrage, ohne dass sie sich überschneiden? Zum Beispiel wenn ich nach links will oder nach oben will muss ich ja das linke obere Eck checken. Wenn ich dann zum Beispiel an der Linken Wand stehe kann ich mich nichtmehr nach oben bewegen.


----------



## TimoH. (20. Mrz 2012)

Warum denn, du guckst doch immer nur wo der neue Ankunftspunkt ist, wenn der halt nicht betretbar ist, dann kannst du da halt nicht hin.

Schritte:
- Berechne neue Position
- Wenn Tile an neuer Position betretbar, dann bewege dich, ansonsten nicht

Du musst natürlich in die berechnung eventuell die Größe deines Spieler mit reinnehmen, jenachdem, wie du die Bewegung generell implementiert hast.


----------



## skappler (20. Mrz 2012)

Ja aber wie schon gesagt überschneiden sich die Fälle.


----------



## Fu3L (20. Mrz 2012)

Bewegst du dich nach oben, prüfst du halt 
x = Spieler.x / Tile.Width
y = (Spieler.y+Spieler.height) / Tile.Height 

nach unten halt:

x = Spieler.x / Tile.Width
y = Spieler.y / Tile.Height 

Links und rechts (und auch diagonal) ähnlich.


----------



## Degush (20. Mrz 2012)

Du überprüfst, ob sich im nächsten Frame, in der neue Positionen für den Spieler vorliegen, ein undurchsichtiger Punkt der Spielergrafik und ein undurchsichtiger Punkt eines Tiles, das nicht begehbar ist, überlappen.
Dazu solltest du erst orüfen, ob sich die bounding boxes schneiden


----------



## skappler (20. Mrz 2012)

Degush hat gesagt.:


> Du überprüfst, ob sich im nächsten Frame, in der neue Positionen für den Spieler vorliegen, ein undurchsichtiger Punkt der Spielergrafik und ein undurchsichtiger Punkt eines Tiles, das nicht begehbar ist, überlappen.
> Dazu solltest du erst orüfen, ob sich die bounding boxes schneiden



Mein Player und auch meine Tiles haben eine getBounds() Methode. Aber wie überprüf ich den nächsten Frame?


----------



## www.tonypa (20. Mrz 2012)

Alt, in As2 aber ich verweiße gern drauf:
Tile based games


----------



## mavinatic (21. Mrz 2012)

Es ist doch recht simpel, ich bin momentan etwa an der gleichen Stelle wie du. Ich habe das folgender Maßen aufgebaut:

Ich errechne mir die Tile-Position aus und hole mir das Tile aus meinem Tile-Array und überprüfe ob man auf dem Tile sich bewegen darf oder nicht. Jedoch ist dieser Code-Snippet nicht ganz ausgereift, aber auf alle Fälle mal ein Anfang.

```
@Override
	public void move()
	{	
//		System.out.println("movementData:");
//		System.out.println(this.getPositionX()+"|"+this.getPositionY());
//		System.out.println(this.getMapX()+"|"+this.getMapY());
		if(handler.isKeyForward() && isMovableOnTile('n') && !handler.isKeyMenu())	
			this.setPositionY(this.getPositionY() - this.getEntityMovementSpeed());
		
		if(handler.isKeyBackward() && isMovableOnTile('s') && !handler.isKeyMenu())
			this.setPositionY(this.getPositionY() + this.getEntityMovementSpeed());
		
		if(handler.isKeyLeft() && isMovableOnTile('w') && !handler.isKeyMenu())
			this.setPositionX(this.getPositionX() - this.getEntityMovementSpeed());
		
		if(handler.isKeyRight() && isMovableOnTile('e') && !handler.isKeyMenu())
			this.setPositionX(this.getPositionX() + this.getEntityMovementSpeed());	
	}
	
	/*
	 * CollisionDetectionViaPx
	 */
	public boolean isMovableOnTile(char dir)
	{
		float x = 0;
		float y = 0;
		
		if(dir=='n')
		{
			x = getMapX()/Tile.SIZE;
			y = (getMapY()-this.getEntityMovementSpeed())/Tile.SIZE;
			Tile currentTile = this.getCurrentLevel().getTile((int)x,(int)y);
			return currentTile.isMovable();
		}
		if(dir=='s')
		{
			x = getMapX()/Tile.SIZE;
			y = (getMapY()+this.getEntityMovementSpeed())/Tile.SIZE;
			Tile currentTile = this.getCurrentLevel().getTile((int)x,(int)y);
			return currentTile.isMovable();	
		}
		if(dir=='w')
		{
			x = (getMapX()-this.getEntityMovementSpeed())/Tile.SIZE;
			y = getMapY()/Tile.SIZE;
			Tile currentTile = this.getCurrentLevel().getTile((int)x,(int)y);
			return currentTile.isMovable();
		}
		if(dir=='e')
		{
			x = (getMapX()+this.getEntityMovementSpeed())/Tile.SIZE;
			y = getMapY()/Tile.SIZE;
			Tile currentTile = this.getCurrentLevel().getTile((int)x,(int)y);
			return currentTile.isMovable();	
		}
		return false;
	}
```


----------



## Degush (21. Mrz 2012)

Für die Position gibst du
currentX + currentSpeedInXDirection und currentY + currentSpeedInYDirection an.


----------



## skappler (21. Mrz 2012)

Ich habe jetzt versucht zu prüfen ob sich die Bounds überschneiden, wenn die Koordinaten erhöht sind.

Mein Code lautet:

```
public boolean checkCollision(int dir){
		// up 0, right 1, down 2, left 3
		

		int xx =(int) player.x - offsetx;
		int yy = (int) player.y - offsety;
		
		Rectangle r;
		
		switch(dir){
		case 0: r = new Rectangle(xx, yy-2, 32, 66);
			break;
		case 1: r = new Rectangle(xx, yy, 34, 64);
			break;
		case 2: r = new Rectangle(xx, yy, 32, 66);
			break;
		case 3: r = new Rectangle(xx-2,yy,34,64);
			break;
		default: r = new Rectangle();
		}
		
		for(int x = 0; x< world.width;x++){
			for(int y = 0; y < world.height;y++){
				
					if(world.world[x][y].getBounds().intersects(r) && world.world[x][x].isSolid()){
						return true;
					}
				
			}
		}
				
		return false;
}
```

Ich laufe hier durch die gesamte Map (sehr uneffizient ich weiß, aber auf die schnelle zum testen am einfachsten) und teste ob sich der Player überschneidet und ob das Tile Solid ist, also nicht begehbar.
Allerdings wird aus irgendeinem Grund immer false zurück gegeben.

Was mache ich falsch?


----------



## Fu3L (21. Mrz 2012)

```
if(world.world[x][y].getBounds().intersects(r) && world.world[x][x].isSolid()){
```

Eigentextblindheit.. Das Problem, wenn man zu lange dran arbeitet^^ world[x][x] wird evtl. der Übeltäter sein. Wenn nicht alleine, dann nochmal melden^^


----------



## skappler (21. Mrz 2012)

Oh danke^^
Klappt aber leider immer noch nicht =/


----------



## Fu3L (21. Mrz 2012)

Zeig mal getBounds() und die Methoden, wo das Rectangle initialisiert wird. Außerdem die isSolid() Abfrage.

Das mit den xOffset und yOffset könnte es natürlich auch sein, aber das andere scheint mir gefühlt wahrhscheinlicher.

Außerdem bau mal ein System.out.println(dir); ein. Am besten auch System.out.println(xx + ":" + yy);


----------



## skappler (21. Mrz 2012)

Hat sich gerade erledigt  
Ich bin so doof  Im Konstruktor der Tile Klasse hat this.width = width und this.height = height gefehlt, weshalb die getBounds() Methode immer ein Rectangle mit width und height 0 geliefert hat.
Ich muss mehr auf meine Konstruktoren achten. Das ist schon der dritte Bug der durch fehlende initialisierungen verursacht wurde.

Naja vielen Dank dann mal, ohne deine Frage hät ich das nie gefunden


----------

