Today we want to test for collision very simple by seing our gameobjects as rectangles.
Therefore I got some cool free graphics from lostgarden.com:
http://www.lostgarden.com/2007/04/free-game-graphics-tyrian-ships-and.html
http://lunar.lostgarden.com/game_HardVacuum.htm
http://www.lostgarden.com/2007/04/free-game-graphics-tyrian-ships-and.html
http://lunar.lostgarden.com/game_HardVacuum.htm
Then I created a subclass of Image (an Actor) for our ship:
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);
}
}
}
Most of the code is known and lets the ship react to the arrow-keys.
For every collision-able object in our game we have an rectangle-object(com.badlogic.gdx.math.Rectangle) that represents the bounds of our ship.
Everytime we change the position of our ship, we have to correct the position of our bounds-rectangle. (this is done in the setXY()-method).
Everytime we change the position of our ship, we have to correct the position of our bounds-rectangle. (this is done in the setXY()-method).
The enemy-class and the shot-class are the same. The enemy-ship changes his position in every act() by -30*delta and the shot by 80*delta.
The rectangle-class has a fast and simple method to check for collision between two rectangles.
if(enemy.getBounds().overlaps(ship.getBounds())){
ship.remove();
quitGame();
}
But we want to let more than one ship and one enemy collide.
My common practise is to create ArrayLists and some methods that create new objects:
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);
}
My collision code is to check every enemy ship with the playership and then test every shot with every enemy ship:
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();
}
}
}
It does run pretty well with many enemies and many shots, but it kind of feels wrong to test everything with everything… Do you know a better solution?
No comments:
Post a Comment