Introduction By this point, your game engine is capable of implementing games in convenient coordinate systems and presenting and animating objects that are visually appealing. However, there is a lack of abstraction support for the behaviors of objects. You can see the direct result of this shortcoming in the initialize() and update() functions of the MyGame objects in all the previous projects: the initialize() function is often crowded with mundane per-game object settings, while the update() function is often crowded with conditional statements for controlling objects, such as checking for key presses for moving the hero. A well-designed system should hide the initialization and controls of individual objects with proper object-oriented abstractions, or classes.
An abstract GameObject class should be introduced to abstract and hide the specifics of initialization and behaviors. There are two main advantages to this approach. First, the initialize() and update() functions of a game level can focus on managing individual game object and the interactions of these objects without being clustered with details specific to different types of objects. Second, as you have experienced with the Renderable and Shader object hierarchies, proper object-oriented abstraction creates a standardized interface and facilitates code sharing and reuse.
As you transition from working with the mere drawing of objects (in other words, Renderable) to programming with behavior of objects (in other words, GameObject), you will immediately notice that for the game to be entertaining or fun, the objects need to interact. Interesting behaviors of objects, such as facing or evading enemies, often require the knowledge of the relative positions of other relevant objects in the game. In general, resolving relative positions of all objects in a two-dimensional world is nontrivial.
Fortunately, typical video games require the knowledge only of objects that are in close proximity to each other or of detecting objects that are about to collide or have collided. An efficient but somewhat crude approximation to detect collision is to compute, bound, and collide objects with bounding boxes. In the simplest cases, bounding boxes are rectangular boxes with edges that are aligned with the x/y-axes. Because of the axes alignments, it is computationally efficient to detect when two bounding boxes overlap or when www.it-ebooks.info Chapter 6
■ Defining Behaviors and Detecting Collisions 188 collision is about to occur. Most 2D game engines detect the actual collision between two textured objects by comparing the location of pixels from both objects and detecting the situation when at least one of the pixels overlaps. This computationally intensive process is known as per-pixel-accurate collision detection, pixel-accurate collision, or per-pixel collision.
This chapter begins by introducing the GameObject class to provide a platform for abstracting game object behaviors. The GameObject class is then generalized to introduce common behavior attributes including speed, movement direction, and target-locked chasing. The rest of the chapter focuses on deriving an efficient per-pixel accurate collision implementation that supports both textured and animated sprite objects.
Game Objects As mentioned, an abstraction that encapsulates the intrinsic behavior of typical game objects should be introduced to minimize the clustering of code in the initialize() and update() functions of a game level and to facilitate reuse. This section introduces the simple GameObject class to illustrate how the cleaner and unclustered initialize() and update() functions clearly reflect the in-game logic and to demonstrate how the basic platform for abstracting object behaviors facilitates design and code reuse.