Collision Detection

A collision is considered as the occurrence of overlapping between two sprites to different extents. The engine itself does not provide sophisticated means for collision detection nor does it include a physics engine. It is the developer's responsibility to handle collision checks. Collision in the sense of user interactions is covered in the section Input & Touch Events.

However, the engine provides some essential functionality for testing 2D collisions between two sprites, namely, point-in-rectangle, rectangle intersection and rectangle containment. They might be not the best choice if costly computation accumulates.

To develop a more performant approach, objects should be collected into different groups. Objects that are obstacles can be aggregated into a group and environmental ones into a different one.

Moreover, the color map approach for collision detection can be used as well which is described below.

More sophisticated methods exist like using a different data structure - a quad tree, for example. Quad trees provide a more efficient collision detection: Actual collision checks are only performed on objects where the player is located. That means, a query can be executed on the player's position, and just nearby objects are returned. This decreases computation time since collision checks are not performed on all objects in every frame. After the objects have been queried and returned, the implemented collision check methods of a sprite can be called. The demo app provides an example on that.

Some general tips

  • Put all relevant code in the updateLogicHook() method or override the default behavior of the updateLogic() method of a sprite.
  • Use different collections (i.e., sprite groups) where only "obstacle-like" sprites are inserted and used for collision checks. The engine provides a marker interface called IObstacleSprite.
  • Use the SpriteQuadtreeGroup as root node in a State as a more sophisticated data structure when many sprites should be evaluated.

Naïve Approach

A sprite is equipped with simple methods to check for collision between them. Therefore, a bounding box in form of a rectangle is created for every sprite. The size of this rectangle (i.e., bounding box) is drawn from the texture's size and can be accessed via the AbstractSprite#getsRectangle() method. A android.graphics.Rect is returned.

The following methods exist for collision checks:

  • checkColWithPoint(PointF): This method evaluates if a given point is contained within the bounding box of the sprite.
  • intersectWithRect(RectF): Checks if the extent of a given sprite's rectangle intersects with the bounding box of the sprite calling this method.
  • containsRect(RectF): Same as above with the exception that the passed rectangle must be fully contained in the sprite's bounding box so that the method is returning true.

Furthermore, the engine provides a marker interface called IObstacleSprite which can be used to distinguished between environmental sprites and obstacles, for example.

Color Map

Regarding this approach, two images are incorporated: one is the real world background and one the collision map. Each color on the collision map indicates parts of the real world map where an obstacle exists.

Example of a Color Map

level1 level1_colmapThe image shows an actual level and the collision map below. Only the level image is drawn onto the canvas whereas the collision map is used to obtain the color at the current player's position, for instance, to check for collisions. (Source of the tile set used in the image: https://opengameart.org/content/platformer-art-deluxe)

This approach is not too slow and only uses more memory for storing an additional bitmap. Generally, the collision map has a lower resolution and is loaded into the memory. Only, the real world bitmap is drawn onto the canvas. This kind of collision detection method employs color similarity comparisons which might be slow when executed in every frame.

This effectively achieves a separation of the level graphics and corresponding meta information about the game logic (e.g., collisions, properties of surfaces) by encoding this information in another bitmap. Then, this additional information can be read out and evaluated. Meaning, that every pixel value of the color map can be decoded and thus relates to a specific action or property.

Color Maps in combination with a scrollable Layer

In this example, a side-scrolling background is created which uses additional color coding for static background obstacle checks. You can load two textures into this layer, one represents the collision map of the level, and the other is the original background image.

Therefore, the engine provides a special background layer which can be "scrolled" - the FixedScrollableLayer.

First, we create the appropriate background layer and assign a level bitmap to it (see image above). Then, we load the color map bitmap:

1
2
3
4
5
bgLayer = new FixedScrollableLayer(BG_LEVEL_1, 500);
bgLevel1Colmap = BG_LEVEL_1_COLMAP;
float scaleWidth = ((float) RetroEngine.W) / 500;
float scaleHeight = (float) Math.ceil((float) RetroEngine.H / (float) bgLevel1Colmap.getHeight());
bgLevel1Colmap = scaleToFit(bgLevel1Colmap, scaleWidth, scaleHeight);

The first sets how much pixels of the level should fill up the screen's width. Furthermore, we must scale the color map accordingly. The background layer can be easily added through the method State#addBackgroundLayer(BackgroundLayer).

Within the update method we can check for colors representing an obstacle:

1
2
3
4
5
6
7
int pixel = bgLevel1Colmap.getPixel((int) player.getPosition().x, (int) player.getPosition().y);
bool collisionDetected = ColorTools.closeMatch(Color.argb(1, 255, 0, 195), pixel, 25);
if (collisionDetected) {
    // collision detected
} else {
    // no collision detected
}

Info

This will change in the next releases. The scrollable layer will support this feature and provide appropriate methods for this kind of usage as described above.

Using other Libraries

Box2D

Box2D is a 2D physics engine. A Java port JBox2D exists in this GitHub Repository. An example on how to integrate Box2D physics on Android can be found in this blog entry.