Collision Detection bei Tile Map

skappler

Aktives Mitglied
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
 
ü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 🙂
 
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).
 
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.
 
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.
 
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.
 
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
 
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?
 
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.
Java:
	@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;
	}
 
Ich habe jetzt versucht zu prüfen ob sich die Bounds überschneiden, wenn die Koordinaten erhöht sind.

Mein Code lautet:
Java:
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?
 
Java:
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^^
 
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);
 
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 😛
 

Zurück
Oben