Sunday, June 22, 2014

[libgdx] day 14 – simple collisions

Today we want to test for collision very simple by seing our gameobjects as rectangles.
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.

rectangles
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).
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?
spacegame

No comments:

Post a Comment

Popular Posts