Game Development Community

dev|Pro Game Development Curriculum

Master Modules Part Three : The Control Object

by Simon Love · 04/26/2016 (2:48 pm) · 1 comments

The purpose of this module is to implement a system which allows developers to route player input to a specific game object, referred to as the Control Object.

This system goes hand-in-hand with the InputMatrix; I suggest getting familiar with the InputMatrix Module before reading through this post.

You can grab the ControlObject Module here.

The Control Object

With this module, any object in the game world can be chosen to be the Control Object.
If you remember in the InputMatrix Module, our process function ends by posting an event (Process_EVT) using the EventManager.

The ControlObject Module simply makes sure that a chosen object subscribes to this event and reacts accordingly when the event is posted. To do so, it installs a new Behavior on the target object which implements the method ::onProcess_EVT.

The onProcess_EVT method does nothing except call its owner object's (the Control Object) ProcessInput Method. This method must be provided by the developer and is described thoroughly later on. Think of onProcess_EVT as a bridge linking the input matrix to an object's game logic.

This makes it extremely simple to implement Player control on various objects without having to manually customize every single object in your scene.

All you need to do is call the following function:
SetControlObject(%target_object);

Code Overview


ControlSet

This time around, the /scripts/Init.cs file executes a single line of code upon module initialization, creating a Simset named ControlSet. The purpose of this Simset is to contain one or more objects which will receive and process Player Input.

Having this object (or objects) in a named Simset allows developers quick access to the object(s) currently being controlled by the player.

This module offers two main functions : SetControlObject and RemoveControlObject

SetControlObject

This function can be called from anywhere in script and does three things.

First, it adds the target object to the ControlSet Simset.
Second, it installs the CtrlObj_BEH behavior on the target object.
Lastly, it subscribes the object to the InputMatrix's Process_EVT event.
The function also makes sure that the InputMatrix object exists, that the target object is a valid object and that only one object is set as the control object at any one time. (more on that later.)

RemoveControlObject

This removes the CtrlObj_BEH behavior from the target object and removes it from the subscribers list of InputMatrix's Process_EVT event. The object will remain in the scene but will no longer be controlled by Player Input.

Developers will rarely need to manually call this function as by default, the SetControlObject function will automatically call RemoveControlObject on objects that might require it.

- Warning -
Removing Control Object functionality from an object that is in movement might yield undesirable results. If the object is moving based on physics impulses, calling RemoveControlObject on it will simply let it decelerate according to its physical properties.

If the object is motivated by the use of SetLinearVelocity however, make sure to stop the object manually (Set its LinearVelocity to 0) or it will keep going at its current speed until the end of time, since its connection to the InputMatrix is severed.

The CtrlObj_BEH Behavior

This behavior implements the ::onProcess_EVT method on our Control Object(s) which in turn calls the Control Object's ProcessInput method.

If the target object does not implement its own ProcessInput method, a warning will be displayed in the console. Once again, bear in mind that this is where YOU come in, as how you wish to act upon the status of the InputMatrix is entirely game-dependent.

The ProcessInput method should be implemented by another behavior or by a class method.

- Script class Example use

Let's imagine that you create a Scene which contains 12 Sprite objects.
You would set these objects to be of class TestClass
new Sprite(){
class = TestClass;
Image = "ToyAssets:Blocks";
Size = "5 5";
};
Then you simply need to define a ProcessInput Method for this class
function TestClass::ProcessInput(%this)
{
...
}

- Behavior-based Example use

Again, we imagine a Scene containing 12 Sprite objects.
This time, however, we would start by creating a new BehaviorTemplate Test_BEH...
new BehaviorTemplate(Test_BEH);

function Test_BEH::ProcessInput(%this)
{
...
}
...and add it to our Sprites!
%sprite = new Sprite();
%BEH = Test_BEH.createInstance();
%sprite.addBehavior(%BEH);

Both examples would ensure that all objects in your Gameworld could potentially be used as Control Objects. I personally prefer the Behavior-based approach as Behaviors can be added and removed to objects on the fly while classes tend to be for more permanent use.

- ProcessInput example

function TestClass::ProcessInput(%this, %data)  
{
switch(InputMatrix.XAXIS)  
{  
case -1 : %this.setLinearVelocity(-5. 0);  
case 0 : %this.setLinearVelocity(0,0);  
case 1 : %this.setLinearVelocity(5.0);  
}
}

Multiple Control Objects

In most games, you usually control one object at a time (e.g. the Player Character).
If this behavior corresponds to your game design, the code ensures by default that only one Control Object can be specified at any one time. Setting a new Control Object will look for previous ones and remove all ControlObject functionality from them.

If you're feeling crazy, simply set the following variable to false. This will allow you to send player input on as many ControlObjects as you want at once.
ControlObject_Module.SingleControlObject = false;
In this case, developers must manually remove objects from the ControlSet Simset as the Simset is not cleared every time a new Control Object is chosen.

Conclusion


As you can see, it becomes extremely easy to switch control from a player character to a vehicle, an enemy, a bullet or a physics-powered contraption using the Control Object system. Switching Control objects can be done as often as you want; experiment, go crazy and share your findings!

Next and Last Issue : Master Modules Part Four : The UI_Base Module

Glossary


- Simset

A Simset is a logical group of SimObjects which can be sorted and modified at will.

I suggest taking a look at SimSet's Consolefunctions if you aren't already familiar with them. Hint : You should use Simsets as often as possible.


- Behaviors

Behaviors are customized bits of code that can be added to any ScriptObject or SceneObject.
If you call a method on an existing object, the code will look through the registered script methods to determine if the method actually exists.

Such a method would normally be defined as follows:
function MyObject::somemethod(%this)
{
...
}
If the method does not exist however, the engine will scan all behaviors which were added to the target object to see if they implement the desired method.

- Script Class

Setting an object's script class is simple
new Sprite(){
class = MyClass;
...
};
This allows you to develop methods which would apply to class MyClass, allowing similar functionality across different objects (Sprites, Particle Players, CompositeSprites, etc.).

Defining a method for a specific class is just like defining a method for any other object or module.
function MyClass::somemethod(%this)
{
...
}
In this scenario, %this would refer to the specific object instance on which the method was called.

Torque2D also allows you to define a superclass, which works in the same way. For example, an object could be of superclass Item and class Medkit; it would respond to methods common to all items but would also implement methods specific to the Medkit class.

About the author

I am here to help. I've worked at every imaginable position in game development, having entered the field originally as an audio guy.


#1
04/27/2016 (6:51 am)
More great code Simon! I would like to second the call to use SimSets. Anytime you use arrays of objects, you should probably be using a SimSet instead. Also, remember that an object can belong to multiple SimSets, but only one SimGroup. There's a lot more on this topic in the generated documentation for these objects and any serious developer should understand how they work.