Torque 3D 3.7
SimObject Class
class SimObject : public ConsoleObject;

Base class for objects involved in the simulation. 

@section simobject_intro Introduction 

SimObject is a base class for most of the classes you'll encounter working in Torque. It provides fundamental services allowing "smart" object referencing, creation, destruction, organization, and location. Along with SimEvent, it gives you a flexible event-scheduling system, as well as laying the foundation for the in-game editors, GUI system, and other vital subsystems. 

@section simobject_subclassing Subclassing 

You will spend a lot of your time in Torque subclassing, or working with subclasses of, SimObject. SimObject is designed to be easy to subclass. 

You should not need to override anything in a subclass except:


Of course, if you know what you're doing, go nuts! But in most cases, you shouldn't need to touch things not on that list. 

When you subclass, you should define a typedef in the class, called Parent, that references the class you're inheriting from

@code class mySubClass : public SimObject { typedef SimObject Parent; ... @endcode 

Then, when you override a method, put in: 

@code bool mySubClass::onAdd() { if(!Parent::onAdd()) return false; 

// ... do other things ... } @endcode 

Of course, you want to replace onAdd with the appropriate method call. 

@section simobject_lifecycle A SimObject's Life Cycle 

SimObjects do not live apart. One of the primary benefits of using a SimObject is that you can uniquely identify it and easily find it (using its ID). Torque does this by keeping a global hierarchy of SimGroups - a tree - containing every registered SimObject. You can then query for a given object using Sim::findObject() (or SimSet::findObject() if you want to search only a specific set). 

@code // Three examples of registering an object. 

// Method 1: AIClient *aiPlayer = new AIClient(); aiPlayer->registerObject(); 

// Method 2: ActionMap* globalMap = new ActionMap; globalMap->registerObject("GlobalActionMap"); 

// Method 3: bool reg = mObj->registerObject(id); @endcode 

Registering a SimObject performs these tasks:

  • Marks the object as not cleared and not removed.
  • Assigns the object a unique SimObjectID if it does not have one already.
  • Adds the object to the global name and ID dictionaries so it can be found again.
  • Calls the object's onAdd() method. Note: SimObject::onAdd() performs some important initialization steps. See @ref simobject_subclassing "here for details" on how to properly subclass SimObject.
  • If onAdd() fails (returns false), it calls unregisterObject().
  • Checks to make sure that the SimObject was properly initialized (and asserts if not).

Calling registerObject() and passing an ID or a name will cause the object to be assigned that name and/or ID before it is registered. 

Congratulations, you have now registered your object! What now? 

Well, hopefully, the SimObject will have a long, useful life. But eventually, it must die. 

There are a two ways a SimObject can die.

  • First, the game can be shut down. This causes the root SimGroup to be unregistered and deleted. When a SimGroup is unregistered, it unregisters all of its member SimObjects; this results in everything that has been registered with Sim being unregistered, as everything registered with Sim is in the root group.
  • Second, you can manually kill it off, either by calling unregisterObject() or by calling deleteObject().

When you unregister a SimObject, the following tasks are performed:

  • The object is flagged as removed.
  • Notifications are cleaned up.
  • If the object is in a group, then it removes itself from the group.
  • Delete notifications are sent out.
  • Finally, the object removes itself from the Sim globals, and tells Sim to get rid of any pending events for it.

If you call deleteObject(), all of the above tasks are performed, in addition to some sanity checking to make sure the object was previously added properly, and isn't in the process of being deleted. After the object is unregistered, it deallocates itself. 

@section simobject_editor Torque Editors 

SimObjects are one of the building blocks for the in-game editors. They provide a basic interface for the editor to be able to list the fields of the object, update them safely and reliably, and inform the object things have changed. 

This interface is implemented in the following areas:

  • onNameChange() is called when the object is renamed.
  • onStaticModified() is called whenever a static field is modified.
  • inspectPreApply() is called before the object's fields are updated, when changes are being applied.
  • inspectPostApply() is called after the object's fields are updated.
  • onEditorEnable() is called whenever an editor is enabled (for instance, when you hit F11 to bring up the world editor).
  • onEditorDisable() is called whenever the editor is disabled (for instance, when you hit F11 again to close the world editor).

(Note: you can check the variable gEditingMission to see if the mission editor is running; if so, you may want to render special indicators. For instance, the fxFoliageReplicator renders inner and outer radii when the mission editor is runnning.) 

@section simobject_console The Console 

SimObject extends ConsoleObject by allowing you to to set arbitrary dynamic fields on the object, as well as statically defined fields. This is done through two methods, setDataField and getDataField, which deal with the complexities of allowing access to two different types of object fields. 

Static fields take priority over dynamic fields. This is to be expected, as the role of dynamic fields is to allow data to be stored in addition to the predefined fields. 

The fields in a SimObject are like properties (or fields) in a class. 

Some fields may be arrays, which is what the array parameter is for; if it's non-null, then it is parsed with dAtoI and used as an index into the array. If you access something as an array which isn't, then you get an empty string. 

You don't need to read any further than this. Right now, set/getDataField are called a total of 6 times through the entire Torque codebase. Therefore, you probably don't need to be familiar with the details of accessing them. You may want to look at Con::setData instead. Most of the time you will probably be accessing fields directly, or using the scripting language, which in either case means you don't need to do anything special. 

The functions to get/set these fields are very straightforward: 

@code setDataField(StringTable->insert("locked", false), NULL, b ? "true" : "false" ); curObject->setDataField(curField, curFieldArray, STR.getStringValue()); setDataField(slotName, array, value); @endcode 

For advanced users: There are two flags which control the behavior of these functions. The first is ModStaticFields, which controls whether or not the DataField functions look through the static fields (defined with addField; see ConsoleObject for details) of the class. The second is ModDynamicFields, which controls dynamically defined fields. They are set automatically by the console constructor code. 


Copyright (c) 2015. All rights reserved.
What do you think about this topic? Send feedback!