<<Previous Page — Next Page >>
Tutorial 2 - Simple Object with Animation (pg. 2)
Of Mice and Men (or, Hosts and Components)
Objects within a game will usually extend from a class which can host components. To get the most out of The Render Engine, you'll want an object that derives from the HostObject class. This is the beauty of the engine! By using this object, you don't have to create (or copy) the same code, over and over, for drawing to the render context, moving your game object, and interacting with the player. All of that is handled by the magic of components. A HostObject "hosts" components that need to be executed to make your game object do its thing.
The Core of Components
Creating game objects within the engine is based on one premise: No object should be monolithic. What does that mean? Well, it means that an object shouldn't have to know how to move, render, interact with the player, and so forth. This simple premise is the foundation of The Render Engine.
Game objects are typically comprised of many "components" in the engine. Each component is responsible for one task, and one task only. Be it transformations or rendering, only one component will be responsible for it. Your game object will interact with the component which performs the task, but it won't necessarily need to keep state for that task since the component will usually do that.
Components are broken up into five different types: INPUT, TRANSFORM, LOGIC, COLLIDER, and RENDERING. These types encompass many different things, but they are discreet from eachother. A "TRANSFORM" component, for example, is responsible for updating its position, rotation, and scale, whereas an "INPUT" component handles interaction with the player.
The "TRANSFORM" component typically will not need anything from the "INPUT" component directly, and vice versa. In fact, one component cannot directly interact with another component on purpose.
Components - How do they Work?
A component encapsulates functionality at the simplest of levels. It takes input manipulates it, and creates output. All of this processing happens in the execute() method of a component. For each frame that is drawn, a HostObject's components will be called, in order of importance to functionality, to execute. Each component will take its input, perform its function, and manipulate the HostObject in its own special way.
So, what is this level of importance? Good question! Each component has a certain responsibility which must occur before another component is executed. INPUT components need to execute before RENDERING components. This way the player doesn feel as if their actions are being ignored. Some of the components perform an action each frame with strict determination to get their work done, while others accumulate and act with less stringency. But they all affect the HostObject they live within.
In addition to their level of importance, a HostObject can have many components of the same type. So, a priority can be assigned to each component so that one render action occurs before another, or one LOGIC component acts before another since the second depends on the first's result. This allows for a fairly complex object with very little setup, and only some creative planning.
INPUT Components
An INPUT component interacts with the player in some way. It may take input from the keyboard or mouse and provide actionable information to the HostObject's other components. Typically an input component like the KeyboardInputComponent would call event handlers on your HostObject for when a key is pressed and released. This type of component will only call the event handler if it exists, and the handler must have a specific name.
TRANSFORM Components
A TRANSFORM component typically maintains position, rotation, and scale information. Although, it is possible that it might contain velocity, acceleration, and deceleration information too, such as is the case with the Mover2DComponent. That component extends from the Transform2DComponent which actually contains the position, rotation, and scale.
LOGIC Components
A LOGIC component is a little hard to describe since it's kind of a catch-all for components which aren't really one of the other types. But rather than having an infinite number of component types, LOGIC will suffice. Handily, it sits right in the middle of the importance chain so it has a chance to react to input and transformation before collisions or rendering occurs.
Two LOGIC components exist at the time of this writing: the HostComponent (which you can see an example of in Tutorial 4), and the NotifierComponent which uses a subscriber model for its activity.
COLLIDER Components
To make a HostObject truly interactive in its environment, it will need to collide with it. These components will satisfy that need... COLLIDER components utilize a collision model (such as the SpatialGrid) to determine whether or not your game object is in a state of collision with another game object. It's up to your object to determine if the collision is worthy of a reaction, by responding to a special event. Your object's response to that event will determine if the component keeps checking for other collisions within the "potential collision set", or if your object is indeed colliding. One example is the BoxColliderComponent which does simple AABB collision testing.
RENDERING Components
The last components in the chain are the RENDERING components. These bad boys put your game object into the visible world (or take it out). Everything from the Vector2DComponent which draws simple vector shapes, to the SpriteComponent are at your disposal. Every component up to this point has just been fluff!
Which Component to Use?
Not all components will need to be involved in your HostObject. Some game objects won't need to take input, but will render to the context. Others may only perform logic and nothing else. The sky's the limit when you're using components. Remember... components break you out of the monolithic mold!