The Java Game Framework.

Examples, tutorials, documentation and download of the Genuts Framework.
Games made with the Genuts Frameworks.
General articles around games.
Links covering all needs around game dev.
Who are we?
Terms of Service

API >> Tutorials >> Fundamentals >> Sprite collisions

Sprite collisions

But what about collisions between sprites? We saw in the previous example collisions with borders; here we will make a new wrapper which treats collisions between 2 balls.
What this new wrapper will do: when a ball will touch another one, the animation of these 2 balls will change and when one cycle of this new animation will end, sprites will be removed from the playfield.

To launch this new example, we need to adapt the previous example; the complete code is in CollisionSprites.java. Here's an applet running the CollisionSprites program:

The important line which changes is:


Sprite sprite =
  new MovingWrapper(new ExplosionWrapper(new AnimatedSprite(ballImage,
                                                            4, 3,
                                                            (int) (Math.random()*5)),
                                         explosionImage, 5, 3, 1),
                    1, 1);
sprite.setBackgroundSprite(false);

Of course, a new image is needed for the explosion, here it is:

  5 columns by 3 lines. But you know how it works now.

The new wrapper is inserted between the moving wrapper and the animated sprite. Be careful with the order of wrappers, sometime it is important, especially for collisions. But here, it does not matter.
But what does this new wrapper? Here is the complete code (ExplosionWrapper.java):


import java.awt.*;

import com.genuts.gameui.*;

/**
 * An exploding ball wrapper. <br>
 * Change the animation of an animation, and removes itself from
 * its parent playfield at the end of the second animation sequence.
 */
public class ExplosionWrapper extends SpriteWrapper {
  /**
   * Elements of the second animation.
   */
  private Image anim2;
  private int nbh2, nbv2, fr2;

  /**
   * Initializes the animated sprite with 2 animated sequences.
   */
  public ExplosionWrapper(AnimatedSprite sprite,
			  Image anim2, int nbh2, int nbv2, int fr2) {
    super(sprite);
    this.anim2 = anim2;
    this.nbh2 = nbh2;
    this.nbv2 = nbv2;
    this.fr2 = fr2;
  }

  /**
   * Receives the event that this sprite is collision
   * with another sprite
   * @param s Sprite with which the collision is
   */
  protected void collisionWith(Sprite s) {
    if (s != null) {
      setBackgroundSprite(true);
      int oldWidth = getWidth();
      int oldHeight = getHeight();
      ((AnimatedSprite) getActionSprite()).setSequence(anim2, nbh2, nbv2);
      ((AnimatedSprite) getActionSprite()).setFrequence(fr2);
      ((AnimatedSprite) getActionSprite()).setCurrentPictureNumber(0);
      ((AnimatedSprite) getActionSprite()).setSequenceLoop(false);
      setPosition(getX()+(oldWidth/2 - getWidth()/2),
		  getY()+(oldHeight/2 - getHeight()/2));
    }
    super.collisionWith(s);
  }

  /**
   * Propagations of the tick event to the action event
   * if it is an instance of Tickable. <br>
   * Checks if the actionSprite has ended is sequenceLoop
   * to remove the sprite from its parent playfield.
   */
  public void tick(int ticks) {
    PlayField parent = getParent();
    if ((parent != null) && ((AnimatedSprite) getActionSprite()).isSequenceEnded()) {
      parent.removeSprite(getFinalWrapper());
    }
    super.tick(ticks);
  }
}

This wrapper is specially designed for animated sprites, that's why in the constructor we ask for an AnimatedSprite object. Elements of the new animation, after the collision, are passed as arguments. We save them in variables of the class, and we will use them during the collision.
When a collision of two sprites is detected, like for collisions with the borders, the method collisionWith(Sprite) is called. But this time, the argument is not null, it contains the reference of a sprite with which the collision happened.
Now, during the collision step, we change the sprite to a background sprite, to have no more collision detection with other sprites. Next we change the animation status of the AnimatedSprite to don't loop at the end of the cycle. And finally we move a little bit the sprite to have a pretty transition between animations (they don't have the same size). We don't forget to call collisionWith(Sprite) method of the superclass.

Note: We have to cast the actionSprite because the polymorphism is static, and therefore, it does not know dynamically that the actionSprite is an AnimatedSprite.

Note: The method collisionWith(Sprite) is called for the two concerned sprites. It can be interesting to do different actions if sprites have not the same type; for example a ball and a brick, a ball has to bounce on a brick, and a brick has to disappear when the ball touchs it.

Note: Once again, you can override the method checkCollision(Sprite) and have a more precise estimation of the collision.

Finally, at the end of the new animation, the sprite has to be removed. In the AnimatedSprite, the method isSequenceEnded() tells us if a sequence of pictures has reach the end. We override the method tick(int) and we check this.


  public void tick(int ticks) {
    PlayField parent = getParent();
    if ((parent != null) && ((AnimatedSprite) getActionSprite()).isSequenceEnded()) {
      parent.removeSprite(getFinalWrapper());
    }
    super.tick(ticks);
  }

We use this method because it is called for each tick, and it is the only way for a wrapper to know if an animation ended.

Another solution could be to subclass AnimatedSprite and to override the method sequenceEnded() which is called at the end of the animation. But don't forget that a sprite is only for visual effects, and a wrapper for actions, but if you are an Ugly Duckling, you will mix graphics and actions.

Now it is in your hands, have fun.

<< Previous Page  
API >> Tutorials >> Fundamentals >> Sprite collisions