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 >> Bounced balls

Bounced balls

In this example, bouncing balls are moving in the playfield. For this, we reuse the previous example, and change few things. You can find the complete code in BouncedSprites.java. This example is running in the applet below:

The line we have to analyse is:


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

We introduce a new object MovingWrapper extending SpriteWrapper. The goal of a SpriteWrapper is to make actions on a sprite; we will call it a wrapper. The sprite on which action are done is called the actionSprite. You can notice that a SpriteWrapper is also a sprite, and therefore, we can wrap it with another wrapper and so on. But you have to be careful, when a sprite is wrapped, all action have to be done on the high level wrapper, for this, we recommend to use getFinalWrapper() for all actions. Now, the MovingWrapper will move the AnimatedSprite. The interest, of this architecture, is that you can apply this wrapper, or another which you built, to all sprites without rewriting the code. In our example, here is the complete code of the MovingWrapper:


import com.genuts.gameui.*;

/**
 * SpriteWrapper with the ability to move a sprite with a constant
 * speed.
 */
public class MovingWrapper extends MovingSpriteWrapper {

  /**
   * X speed
   */
  private int xspeed;

  /**
   * Y speed
   */
  private int yspeed;

  /**
   * Initializes the moving sprite with an action sprite
   * and a given speed
   * @param sprite Sprite for visualisation
   * @param vx Speed for X coordinates
   * @param vy Speed for Y coordinates
   */
  public MovingWrapper(Sprite sprite, int vx, int vy) {
    super(sprite);
    xspeed = vx;
    yspeed = vy;
    setBackgroundSprite(true);
  }


  /**
   * Moves the sprite with the current speed
   * @param ticks Number of ticks from the playfield
   */
  public void move(int ticks) {
    getFinalWrapper().setPosition(getX()+xspeed, getY()+yspeed);
  }

  /**
   * Receives the event that this sprite is collision
   * with another sprite
   * @param s Sprite with which the collision is
   */
  public void collisionWith(Sprite s) {
    if (s == null) {
      if ((getX() < 0) || ((getX() + getWidth()) > getParent().getWidth())) {
        xspeed *= -1;
        getFinalWrapper().setPosition(getX() + xspeed, getY());
      }
      if ((getY() < 0) || ((getY() + getHeight()) > getParent().getHeight())) {
        yspeed *= -1;
        getFinalWrapper().setPosition(getX(), getY() + yspeed);
      }
    }
    super.collisionWith(s);
  }
}

Now we will take a look to some details.
The MovingWrapper extends MovingSpriteWrapper, which is an abstract subclass of SpriteWrapper. When we construct the sprite, we need an actionSprite on which actions are done, and the speed of the wrapper.


  public MovingWrapper(Sprite sprite, int vx, int vy) {
    super(sprite);
    xspeed = vx;
    yspeed = vy;
    setBackgroundSprite(true);
  }

You can notice that we set the sprite as a background sprite; we will explain that later in this example.

Now, how the wrapper moves its actionSprite. We have to override the move method:


  public void move(int ticks) {
    getFinalWrapper().setPosition(getX()+xspeed, getY()+yspeed);
  }

This method is call on each tick, and the position of sprite changes. We don't apply directly setPosition to the wrapper or its actionSprite, because this wrapper can be wrapped by another wrapper, and we can break transmission of the information. But we agree, in our example, this is superfluous.
But what happen when a ball reachs a border of the playfield. Here is one the most interesting feature of the Genuts API, collisions detection. To check collisions, the playfield delegates this to a CollisionManager. By default, this is a SpriteCollisionManager, its goal is to check efficiently collision between sprites for the general purpose. It does not consider background sprites which are displayed and they don't have interaction with other sprites. For a particular game, you can create a special CollisionManager for your own needs. We will see in a future course how to do that.

To explain quickly how a SpriteCollisionManager works, you have to know:

  • When bounding boxes of two sprites are intersecting, the method checkCollision(Sprite) of each sprite is called with the other one as argument. By default, only bounding box of the sprite is considered, you can override this method and have a more precise estimation.
  • If one of the collision checking return true, the method collisionWith(Sprite) is called of each sprite.
  • If the bounding box of a sprite is out of the playfield, its method collisionWith(Sprite) is called with null as argument. The sprite has to compute which border is responsible of the collision.

    In all of these cases, the high-level wrapper has in charge to transmit to its actionSprite the message.

    In the present example, we will see only collisions with borders, in the next example, collisions with other sprites will be explained.
    When a collision is detected, we must find the concerned border, then change the speed orientation on the proper axis, and finally set the new position of the sprite.

    
      public void collisionWith(Sprite s) {
        if (s == null) {
          if ((getX() < 0) || ((getX() + getWidth()) >= getParent().getWidth())) {
            xspeed *= -1;
            getFinalWrapper().setPosition(getX() + xspeed, getY());
          }
          if ((getY() < 0) || ((getY() + getHeight()) >= getParent().getHeight())) {
            yspeed *= -1;
            getFinalWrapper().setPosition(getX(), getY() + yspeed);
          }
        }
        super.collisionWith(s);
      }
    

    Note: the first thing to do is to check the argument of the method, if it is null, the collisin is with a border, otherwise, this is with another sprite.

    Note: Don't forget to call the collisionWith(Sprite) of the superclass of this wrapper to be sure that the message is transmitted to the actionSprite.

    That's it, now you have a pretty animation. In the next course, we will check collisions between sprites.

    << Previous Page Next Page >>
    API >> Tutorials >> Fundamentals >> Bounced balls