Game Development Community

Give t2dSceneObjects a user-defined pointer

by Smaug · in Torque Game Builder · 04/18/2005 (2:42 pm) · 7 replies

Basically, there is an issue with scene objects where you may have multiple objects that are all tied in together with a single object. There isn't necessarily a parent-child hierarchial relationship between them, but there is the notion that one object is somehow associated with another. My suggestion is to have all t2dSceneObjects provide the ability to set and retrieve a single void*. This allows the (C++) user to associate scene objects with any arbitrary additional data that the user wants.

I know void*'s aren't the most... well-behaved construct in C++ ;). But, sometimes, it is useful to attach user-defined data directly to objects, rather than deriving a class based on them.

I've already added this functionality to my SceneObjects, but I know it would be handy for others as well.

#1
04/18/2005 (2:45 pm)
This is just a suggestion, but you could release the code to do so as a code snipit or resource.

It's always helpful and if it brings enough attention by people who hadn't realized they needed that yet, maybe they will add it to the engine list.
#2
04/18/2005 (2:56 pm)
I've been playing around with the concept of 'watchers' for a couple of my TGE constructs (which is probably going to be outdated when the component system hits full force), which is very similar I think to what you are talking about:

a 'watcher' is another object, very similar to a 'friend' at the C++ level, or probably even more closely the concept of callbacks, that asks for direct updates whenever the state being watched for happens on the watched object.

Examples:

An AI controlled NPC is "watching" a door for a change in the state of the door (open/close). Instead of having it run a poll look checking every 500 milliseconds or so, it would become purely event driven--when the door opens (based on either game, or player actions), the AI object is informed of the state change, and can handle the message appropriately.

In an party based single player RPG, a healer character could 'watch' the other characters for health bar changes, and be set up to cast an appropriate heal spell automatically. Again, instead of having to script the healer npc to check health values for each party member, it becomes event based.

The primary advantage of this type of messaging system is that the 'watched' object(s) wouldn't have to be what is custom scripted--they wouldn't have to have any pre-game concept of what might be watching them. You would simply implement a list of 'watchers' and state changes they are watching for, and hook in a state reporting system internally to handle the callbacks.

You -may- not have to actually make them void* either--theoretically, all of the objects that used the functionality would have a messaging object of some sort that would be contacted directly by the "watch-ee"...but I may be drifting farther away from what you are talking about here!
#3
04/18/2005 (8:39 pm)
Stephen, for what you're looking for, I think it'd be easier and more flexible to just create a global list of "checks" that happen every frame (effectively a function that returns true or false), and when the check succeeds, it calls a given function. That way, if you find a need to watch something that was not anticipated, then you can do so.

My use for the user-defined parameter is mostly just classification. I want to know if the scene object is part of a larger entity, and I need to be able to get the entity that is responsible for any particular scene object. Obviously, for my needs, I know exactly what the void* is, but for a general-purpose feature, it needs to be an untyped pointer.
#4
04/18/2005 (11:00 pm)
If you considered using "SimObject" as your base and therefore not going typeless, there's a certain set of functionality that you could hook into that makes things a little safer.

Presumably you're not interested in some ellaborated method to enumerate the list of potential children anyway so you could stick a "VectorPtr" into the fxSceneObject2D. You can then use "void SimObject::registerReference(SimObject **obj)" to make it into a smart-pointer. If the child objects are destroyed, the pointers get NULL'd. There are other methods are well like using a SimSet or using the "template class SimObjectPtr" template.

T2D only has the concept of an object being flagged as a child ("fxSceneObject2D::setChild()") so that it is not destroyed by T2D directly but always must be destroyed by the parent (owning) object. The tile-layers are children to the tile-map but don't use an abstracted interface to maintain a list of these children but instead uses its own vector. It would probably be best if this was a common vector, something similar to the above example and so I'll look into that for the next update.

As you hinted, I'd be cautious about using void*'s if I could avoid it at all but I guess that would depend on how bad inheriting from the SimObject would be for people. It is fairly lightweight though.

Thanks for the suggestion. :)

- Melv.
#5
04/19/2005 (3:32 am)
SimObject is lightweight? I just got done looking at the Doxygen docs for it, and it seems to do quite a bit on its own. Plus, in inhierets from ConsoleObject, which makes it scriptable (not a feature to be forced upon many objects). While I would prefer not using void*'s whenever possible, even using SimObject as a base requires a cast operation to convert it into a useful class. As such, I don't exactly see how requiring SimObject as being the base class would help much in terms of type safety.
#6
04/19/2005 (4:17 am)
Quote:Basically, there is an issue with scene objects where you may have multiple objects that are all tied in together with a single object.
The reason why I suggested using SimObject. This is without your definition of what an "object" is.

Quote:As such, I don't exactly see how requiring SimObject as being the base class would help much in terms of type safety.
SimObject comes with "safe" (not type-safe) features as I described above. Features such as when destroying a SimObject having its reference automatically NULL'd if it were referenced in such a child-list. I didn't say you had to, it was only a suggestion. Who knows if you need this functionality or if you want to bake your own. I thought the references would be helpful to you, but it's okay if not.

If you just want to add blocks of data then a vectorPtr<> into fxSceneObject2D could be added.

Quote:SimObject is lightweight?
SimObject takes very little memory, even including registering with the engine, something which you don't have to do. This is non-relevant for data-only allocations but is the base of scene-objects so can be very useful in the situation of referencing "objects" with the existing architecture, even at a small expense.

- Melv.

EDIT: more info
#7
04/19/2005 (9:22 am)
SimObject is pretty lightweight, yeah. Obviously not as lightweight as void* ;) ... but pretty lightweight. This comes down to a design decision for your particular usage, I guess. If the extra load of a SimObject is really going to affect your performance or footprint, then go with void*. Must be a lot of referencing going on if so though!

For the T2D SDK in general, void* wouldn't make as much sense as SimObject. The tradeoff is memory safety tools and fitting in with the Torque's existing idioms for object referencing vs. a small cost in memory. Probably the most common use of this would be for hooking up various scene objects anyway, and these are all SimObjects themselves.

I can see the usefulness in maybe providing out of box support to reference scene objects in a non-parent / child manner, and maybe for general Torque SimObjects. But I don't see providing out of box support for attaching arbitrary C++ data to a scene object. There are more useful patterns for doing such associations.

In any case, I don't know if we'll formally add this to the SDK... there are lots of things we *could* add to sceneobject, but we want to be very careful about doing so. As we all know, cramming tons of stuff into a base class can lead to nasty design and usage decisions down the road. For this change in particular, Torque already provides a lot of functionality for creating and managing object associations, so I lean pretty heavily toward not partially replicating such functionality in sceneobject itself.

Regardless of the official SDK response though, a code snippit using either solution here would be useful to folks, I'm sure. :) Part of the power of this place is that since we all have the source, we can share code with each other. Then, if someone wants to have a void* ref in their sceneobjects, they can just plug in the code snippet and go. :) Not always the best solution, but it's great for potentially useful changes that aren't quite right for the stock SDK.