Day 23: Sprites vs Entities

After a relatively long break, we now start the fourth part of the tutorial series! What we designed over the past 3 parts was a simple graphics framework. However, as we all know, there is more to games than graphics. Other elements of games include physics, controls, etc. Today, we discuss a framework that can accommodate all these features.

Entities

Our sprite-based system does not easily adapt to aforementioned features. For example, imagine we had a 2D game of pool. It is logical to assume we would have a sprite for each ball. To handle the movements, we probably design or use a physics simulator, and then move each sprite according to its calculations. At least that’s the most obvious way of doing at it.

If we go one step away, we realize that pool balls are different from sprites such as score icons: they are more than just sprites. They are physical objects and have some added behavior.

Another example of this nature is menus versus background images. In our system, they would all be represented as sprites. However, menu items are different: they receive actions, such as touch or click, and do something, while backgrounds are only there to render.

We can think of a various other examples. Confirmation or notification dialogues are other examples: they are groups of other sprites that need to be handled atomically. We can even think of combinations of these (e.g. a ball that can be thrown through touch input). So, we can build many kinds of entities that don’t fit our definition of sprites, or anyone’s definition of sprites for that matter. Having dismissed sprite as even a remotely sufficient definition for various kinds of objects we can have in a game, we introduce a better concept called entity, which we define them as follows:

An entity is a component of a game scene that handles part of the scene’s logic.

This definition is broad enough for a simple game engine such as Artenus. Drawing something is also a part of the logic in above definition. Note that an entity doesn’t even have to be renderable. The part of the logic that an entity handles can be as little as defining an area to click on, or it can be as broad as drawing a full set of balls along with the physics simulation involved. The good news is, our whole sprite-based system is a proper subset of the new structure. Sprites are simply entities that handle drawing of a part of a single object.

Solved Problems

Our goal in designing a game engine is to make the creation of games simple, and the entity-based approach pushes us forward in that direction. We will see it clearly during this part of the series. But here are examples of things that get much easier using this approach:

Physics

In order to add physics to the game using the old method, we need to have a physics simulator. For each sprite that we wished to include, we needed to associate a physical body in the simulator. The left part of the figure below shows a schematic of this approach. As you can see, the scene and the simulator are two separate elements, and objects have instances in each of them. What’s worse is that the connection between these objects is not handled automatically since our scene graphics is a complete stranger to the physics engine. So every frame, we would need to update the position of every sprite based on the positions of their corresponding bodies in the simulator.

Sprite-based and Entity-based Charts

The entity-based approach makes it much easier by bringing the simulator into the shadow. Look at the right figure above. We have physical entities that can be added to the scene. The scene still doesn’t know about the simulator, but the good news is, neither do we! A physical entity knows its own position in the world, and those of its fellow physical entities. The sprite that represents the object would automatically be moved around as the game proceeds. The sprite would no longer be in our custody, and everything would be handled by its mother physical entity.

Please note that the same things might happen in the background as with the sprite-based method. But the important improvement is the ease of use and the uniformity of scene contents, regardless of their nature.

Groups of Sprites

Imagine we want to show a dialog on the screen. Normally a dialog involves some text, some images, and a few buttons. Using the sprite-based system, we should add all the involved sprites to the scene, handle the events manually, and when the dialog is dismissed, remember to remove all the sprites and leave nothing behind.

In the previous examples we saw a hierarchical sense in entities. Here it gets more vivid. With the entity-based system, the whole dialog would be a single entity, and all buttons and sprites are part of it (and not part of the scene). So, once we remove the dialog from the scene, there would be no trace of the sub-entities. Touch events would also be handled by the dialog, and not by the stage or the scene.

Scene Layers

Having a group entity like above has another advantage. Remember scene layers? We used them to handle different groups of objects that were logically separate in a scene (such as background, game objects, and HUD). But with the new approach, scene layers would be obsolete, and there would be better ways to solve the said problem. If we are still eager to keep the scene layers, we can just add a group entity for each layer.

User Input

This is one of the useful benefits of the new approach. Some elements of the scene, as we discussed before, accept human interaction. Buttons for example, respond to touch. With the old approach, we would have needed to handle touch events centrally. On any touch event, we would need to check if the location of the touch falls within the boundaries of the sprite corresponding to a button, and trigger an action if that would be the case.

With the new approach, however, a button handles its own touch. We just add a clickable entity to the scene, and we are good to go. Of course, the button sprite still exists somewhere within the entity, but it is no longer our job to give it life.

Implementation

In order to implement entities, we have to decide what methods a core entity has. The broadest possible implementation is one that has nothing useful.

package com.annahid.libs.artenus.entities;

public interface Entity {
    /**
     * Called when this entity is associated with a scene.
     *
     * @param scene The scene that currently contains the entity.
     */
    void onAttach(Scene scene);

    /**
     * Called when this entity is dissociated with a scene.
     *
     * @param scene The scene from which the entity is removed.
     */
    void onDetach(Scene scene);
}

This interface has two methods. onAttach is called when the entity is added to the scene, and onDetach is called when it is removed. Why do we have these methods? This is certainly not meant for sprites. But our definition is so broad that we do not know what it can cover in the future, and some functionality might need initialization or finalization procedures. A sprite simply implements this interface, and possibly other interfaces (transformable, renderable, etc). A benefit of having a simple interface is that we can later introduce limitless kinds of entities using patterns such as decorator, and composite.

I leave an open question here, and that is whether this much simplicity is necessary or even logical. To answer this question, you might ask yourself other questions such as:

  • How broad do we want the entity definition be?
  • Is it okay to assume all entities have positions, scaling, and rotation?
  • Do all our entities have some rendering task?
  • Can all our entities be animated in some way (not necessarily visually)?
  • Is the impact of this abstraction (and what it brings) on performance tolerable?

Keep in mind this famous quote: all problems in computer science can be solved by another level of indirection, except too many levels of indirection.

Next steps

Today’s time (or page space!) was mostly spent on introducing the new approach. Our scenes currently support sprites. Once we are happy with our implementation of entities, we move on to adapting our sprite implementation to the new approach, and later having the scenes accept entities rather than sprites. You may download today’s tiny code here: