Tag 14 – Einfache Kollisionen

veröffentlicht am: 14. Dezember 2012

day14Heute wollen wir einfache Kollisionen durchführen, indem wir unsere Spielfiguren als Rechtecke betrachten und diese miteinander schneiden lassen.

Dafür habe ich mir ein paar freie Graphiken von lostgarden.com geholt:

http://www.lostgarden.com/2007/04/free-game-graphics-tyrian-ships-and.html
http://lunar.lostgarden.com/game_HardVacuum.htm

Als erstes habe ich eine Unterklasse von Image (ein Actor) für unser Schiff erstellt:

package de.bitowl.libgdxtest;

import com.badlogic.gdx.math.Rectangle;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input.Keys;
import com.badlogic.gdx.graphics.g2d.TextureAtlas.AtlasRegion;
import com.badlogic.gdx.scenes.scene2d.ui.Image;
public class Ship extends Image{
	int SPEED=70;
	Rectangle bounds;
	public Ship(AtlasRegion findRegion) {
		super(findRegion);
		bounds=new Rectangle((int)getX(), (int)getY(), (int)getWidth(), (int)getHeight());
	}

	public Rectangle getBounds(){
		return bounds;
	}
	
	private void setXY(float pX,float pY){
		setPosition(pX, pY);
		bounds.setX((int)pX);
		bounds.setY((int)pY);
	}
	@Override
	public void act(float delta) {
		// move ship
		if(Gdx.input.isKeyPressed(Keys.RIGHT)){
			setXY(getX()+delta*SPEED,getY());
		}else if(Gdx.input.isKeyPressed(Keys.LEFT)){
			setXY(getX()-delta*SPEED,getY());
		}
		
		if(Gdx.input.isKeyPressed(Keys.UP)){
			setXY(getX(),getY()+delta*SPEED);
		}else if(Gdx.input.isKeyPressed(Keys.DOWN)){
			setXY(getX(),getY()-delta*SPEED);
		}
	}
}

Das meiste ist alter Code, damit das Schiff auf die Pfeiltasten reagiert.

Heute wollen wir allerdings nur sehr einfache Kollisionen besprechen, die auf Basis von Rechtecken basieren.

rectangles

Dafür nutzen für jedes kollisionsfähige Objekt in unserem Spiel ein Rechteck-Objekt (com.badlogic.gdx.math.Rectangle), dass die Umrandung unseres Schiffs darstellt.
Immer, wenn wir die Position unseres Schiffes verändern, müssen wir somit auch die Position des Rechteckes verändern. (die setXY()-Methode).

Die Enemy-Klasse sieht fast genauso aus, nur dass das gegnerische Schiff momentan in act() seine Y-Position um 30*delta verringert. (ein Schuss genauso, der vergrößert seine y-Position allerdings um 80*delta).

Die Rectangle-Klasse bietet uns direkt eine schnelle Methode, um die Kollision zwischen zwei Rechtecken zu prüfen:

if(enemy.getBounds().overlaps(ship.getBounds())){
	ship.remove();
	quitGame();
}

Nun wollen wir aber mehrere Schiffe und mehrere Schüsse auf dem Bildschirm kollidieren lassen.

Bisher habe ich mir dafür immer ArrayListen angelegt und mir Methoden geschrieben, die neue Objekte hinzufügen:

Ship ship;
ArrayList enemies;
ArrayList shots;

enemies=new ArrayList();
shots=new ArrayList();

public void spawnEnemy(int pX,int pY){
	Enemy enemy=new Enemy(atlas.findRegion("enemy"));
	enemy.setPosition(pX,pY);
	enemies.add(enemy);
	stage.addActor(enemy);
}

public void spawnShot(){
	Shot shot=new Shot(atlas.findRegion("shot"));
	// spawn shot before the ship
	shot.setXY(ship.getX()+ship.getWidth()/2,ship.getY()+ship.getHeight());
	shots.add(shot); 
	stage.addActor(shot);
	
	// play shot sound
	long id=shotSnd.play();
	shotSnd.setPitch(id, (float) Math.random()*0.6f+0.7f);
}

Bei der Kollisionsabfrage gehe ich über alle feindlichen Schiffe und prüfe auf Kollision mit dem Schiff und über alle Schüsse und überprüfe diese mit dem aktuellen Gegner.

Iterator enIterator=enemies.iterator();
while(enIterator.hasNext()){
	Enemy enemy=enIterator.next();
	
	// enemy vs. ship
	if(enemy.getBounds().overlaps(ship.getBounds())){
		
		// create explosion animation
		createExplosion(ship.getX()+ship.getWidth()/2, ship.getY()+ship
				.getHeight()/2);
		
		ship.remove();
		quitGame();
	}
	
	// enemy vs. shot
	Iterator shotIterator=shots.iterator();
	while(shotIterator.hasNext()){
		Shot shot=shotIterator.next();
		if(enemy.getBounds().overlaps(shot.getBounds())){
			// create explosion animation
			createExplosion(enemy.getX()+enemy.getWidth()/2, enemy.getY()+enemy.getHeight()/2);
			
			enemy.remove();
			enIterator.remove();
			shot.remove();
			shotIterator.remove();
		}
	}
}

Es läuft zwar auch mit vielen Schiffen und vielen Schüssen noch gut, aber irgendwie ist es nicht so toll, jedes Schiff mit jedem zu testen… Kennst du eine bessere Möglichkeit?

spacegame

geposted in libgdx

2 Antworten zu “Tag 14 – Einfache Kollisionen”

  1. crypto sagt:

    Hello, is the whole source code for this accessible?

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.