Combining objects/datablocks?
by Aaron Moore · in Torque Game Engine · 05/23/2007 (11:53 pm) · 24 replies
I'm not sure if this can be done but I thought I'd try. I've looked but haven't really seen anything about it.
My question is whether or not you can combine different types of objects to be a single entity. For example I have a torch that belongs in my castle...
It consists of a model, a light, and particle effects(fire).
Now I have these set and need to make a couple dozen of these for different parts of my castle. Can I combine these as a single object so I'm dealing with only the Torch object, or do I need to deal with 3 of these every time I go to position one of them (effectively dealing with "a couple dozen" x 3)?
If it's possible, how would I go about it? A single datablock deriving from the other 3 as base classes?
My question is whether or not you can combine different types of objects to be a single entity. For example I have a torch that belongs in my castle...
It consists of a model, a light, and particle effects(fire).
Now I have these set and need to make a couple dozen of these for different parts of my castle. Can I combine these as a single object so I'm dealing with only the Torch object, or do I need to deal with 3 of these every time I go to position one of them (effectively dealing with "a couple dozen" x 3)?
If it's possible, how would I go about it? A single datablock deriving from the other 3 as base classes?
#22
I'm thinking out loud here rather than giving intentions...comments would be much appreciated as I'm not sure how feasible this is with the engine (worth it or not?).
Maybe make a couple new objects that derive from the emitter's class and the light's class. However, instead of using a position variable I'd use a pointer to a position variable, and I'd add a "parent" pointer.
When instantiated:
If a parent was passed in, the position pointer would point to the parent's position.
If a parent was not passed in, the position pointer would have a new position created and go to a default location.
In theory, this would cause the objects' position to move wherever the parent was moved to, but I haven't worked out the implementation yet.
05/27/2007 (3:24 am)
I've been thinking about it more, and I think I may add a couple new objects that might be a cleaner fix.I'm thinking out loud here rather than giving intentions...comments would be much appreciated as I'm not sure how feasible this is with the engine (worth it or not?).
Maybe make a couple new objects that derive from the emitter's class and the light's class. However, instead of using a position variable I'd use a pointer to a position variable, and I'd add a "parent" pointer.
When instantiated:
If a parent was passed in, the position pointer would point to the parent's position.
If a parent was not passed in, the position pointer would have a new position created and go to a default location.
In theory, this would cause the objects' position to move wherever the parent was moved to, but I haven't worked out the implementation yet.
#23
Purpose: Attaching lights & particles to a StaticShape without having to mount them. They will share the same transform as the StaticShape. Perfect for lightsources like torches, lanterns, candles where you need a light and a particle, but dont' want to have to deal with 3 different objects or mounting. The position where you want the particle/light should be the object's center.
in StaticShape.h, add:
We should also initialize our variables in the constructor:
Next, move to the implementation and lets add our functions:
Lets then add the code so that the child moves with our object. It seems to me we should edit the shapes setTransform().
Lets do some cleanup in the onRemove so that our children are deleted along with the parent:
Then we expose our functions to the console:
What Works: Objects added as children move with the parent object.
What Doesn't: Light position doesn't update until you click on it.
What isn't fully tested: Umm...I got it all. It SHOULD be stable, please let me know if you find anything.
Example:
My Script:
My Result:

I'm still planning on making any children's exposed field's show as individual groups under the object's name. I'm also still trying to figure out a way that the light's position will update without having to click on it. Any tips or if you see any problems with my code please let me know. I think I've pasted it all here but I may have missed a step. Any testing is appreciated.
05/29/2007 (8:19 am)
Success!...mostly tested, still could use a little improvement. It's been a while since I've used pointers, I shouldn't have any leaks, if you see any please tell me.Purpose: Attaching lights & particles to a StaticShape without having to mount them. They will share the same transform as the StaticShape. Perfect for lightsources like torches, lanterns, candles where you need a light and a particle, but dont' want to have to deal with 3 different objects or mounting. The position where you want the particle/light should be the object's center.
in StaticShape.h, add:
public:
bool addChild(GameBase* child);
bool deleteChild(GameBase* child);
private:
GameBase* Children[MAXCHILDREN];
int numChildren;Lets also add...#define MAXCHILDREN 3At the top, this can be set to whatever you want, 3 seems a reasonable number for my intended purpose.
We should also initialize our variables in the constructor:
StaticShape::StaticShape()
{
overrideOptions = false;
mTypeMask |= StaticShapeObjectType | StaticObjectType;
mDataBlock = 0;
numChildren = 0;
for( int i = 0; i < MAXCHILDREN; i++ )
{
Children[ i ] = NULL;
}
}Next, move to the implementation and lets add our functions:
bool StaticShape::addChild( GameBase* child )
{
bool childAdded = false;
if( numChildren < MAXCHILDREN )
{
numChildren++;
Children[ numChildren - 1 ] = child;
childAdded = true;
setTransform( getTransform() );
}
return childAdded;
}
bool StaticShape::deleteChild( GameBase* child )
{
int childIndex = 0;
bool childFound = false;
for( int i = 0; i < numChildren && !childFound; i++ )
{
if( Children[ i ] == child )
{
childIndex = i;
childFound = true;
Children[ childIndex ]->deleteObject();
Children[ childIndex ] = NULL;
//Compact the array of children
//Leave the open spaces pointing to NULL
while( childIndex < numChildren - 1 )
{
Children[ childIndex ] = Children[ childIndex + 1 ];
Children[ childIndex + 1 ] = NULL;
childIndex++;
}
numChildren--;
}
}
return childFound;
}Lets then add the code so that the child moves with our object. It seems to me we should edit the shapes setTransform().
void StaticShape::setTransform(const MatrixF& mat)
{
Parent::setTransform(mat);
setMaskBits(PositionMask);
for( int i = 0; i < numChildren; i++ )
{
Children[ i ]->setTransform(mat);
Children[ i ]->setMaskBits( PositionMask );
setMaskBits(PositionMask);
}
}Lets do some cleanup in the onRemove so that our children are deleted along with the parent:
void StaticShape::onRemove()
{
for( int i = 0; i < numChildren; i++ )
{
Children[ i ]->deleteObject();
}
scriptOnRemove();
removeFromScene();
Parent::onRemove();
}Then we expose our functions to the console:
ConsoleMethod( StaticShape, addChild, bool, 3, 3, "obj.addChild(child) - Add a child mimics the parent's transforms, deletes when parent is deleted")
{
GameBase* newChild = dynamic_cast<GameBase*>(Sim::findObject(argv[2]));
if ( !newChild )
{
Con::warnf("obj.addChild(child) - Couldn't find/Invalid object '%s'.", argv[2]);
return false;
}
bool result = object->addChild(newChild);
if( result )
{
Con::printf( "Child sucessfully added." );
}
else
{
Con::printf( "addChild failed, amount of children is at the limit." );
}
return result;
}
ConsoleMethod( StaticShape, deleteChild, bool, 3, 3, "obj.deleteChild(child) - deletes the child object")
{
GameBase* child = dynamic_cast<GameBase*>(Sim::findObject(argv[2]));
if ( !child )
{
Con::warnf("obj.deleteChild(child) - Couldn't find/Invalid object '%s'.", argv[2]);
return false;
}
bool result = object->deleteChild(child);
if( result )
{
Con::printf( "Child sucessfully deleted." );
}
else
{
Con::printf( "deleteChild failed, couldn't find the specified child." );
}
return result;
}What Works: Objects added as children move with the parent object.
What Doesn't: Light position doesn't update until you click on it.
What isn't fully tested: Umm...I got it all. It SHOULD be stable, please let me know if you find anything.
Example:
My Script:
datablock StaticShapeData(TorchShape)
{
category = "LightSources";
className = "Torch";
shapeFile = "~/data/shapes/Torch/Torch.dts";
};
function Torch::onAdd(%this, %obj)
{
%obj.playthread(0, "ambient");
new ParticleEmitterNode(myFire) {
canSaveDynamicFields = "1";
position = "-75 -355.6 6.5";
rotation = "1 0 0 0";
scale = "1 1 1";
dataBlock = "TorchFireEmitterNode";
emitter = "TorchFireEmitter";
velocity = "1";
};
%light = new sgLightObject(myLight) {
dataBlock = "sgTowerFireLightDataBlock";
canSaveDynamicFields = "1";
rotation = "1 0 0 0";
scale = "1 1 1";
dataBlock = "sgTowerFireLightDataBlock";
Enable = "1";
IconSize = "1";
ParticleColorAttenuation = "1";
ParticleEmitterName = "myFire";
};
%obj.addChild(myFire);
%obj.addChild(myLight);
}My Result:

I'm still planning on making any children's exposed field's show as individual groups under the object's name. I'm also still trying to figure out a way that the light's position will update without having to click on it. Any tips or if you see any problems with my code please let me know. I think I've pasted it all here but I may have missed a step. Any testing is appreciated.
#24
Changed my script to the above and added:
After I load in the mission next time, delete the light and the particle effect automatically created by the editor and voila! the torch will have light and fire, and the only thing that will show up is the torch in the editor. Position the torch as needed and not have to deal with 3 items for each torch. Also, the torch and its light and fire are all automatically named with unique names. Each torch has it's own light, fire, and the light reacts to the fire on its appropriate torch!
Only thing I've failed to do is add the light and fire's parameters as a sub-group when you inspect the torch but I couldn't figure out how to do it without making initPersistFields() non-static which doesn't seem like a good idea. If anybody else has a suggestion on how to do it I'd appreciate it.
05/30/2007 (11:11 pm)
Got it:datablock StaticShapeData(TorchShape)
{
category = "LightSources";
className = "Torch";
shapeFile = "~/data/shapes/Torch/Torch.dts";
};
function Torch::onAdd(%this, %obj)
{
%fireName = ("Torch" @ $torchNum @ "Fire");
%lightName = ("Torch" @ $torchNum @ "Light");
$torchNum = $torchNum + 1;
%obj.playthread(0, "ambient");
echo("Makign particle emitter:" + %fireName);
new ParticleEmitterNode(%fireName) {
canSaveDynamicFields = "1";
position = "-75 -355.6 6.5";
rotation = "1 0 0 0";
scale = "1 1 1";
dataBlock = "TorchFireEmitterNode";
emitter = "TorchFireEmitter";
velocity = "1";
};
echo("Makign light:" + %lightName);
%light = new sgLightObject(%lightName) {
dataBlock = "sgTowerFireLightDataBlock";
canSaveDynamicFields = "1";
rotation = "1 0 0 0";
scale = "1 1 1";
dataBlock = "sgTowerFireLightDataBlock";
Enable = "1";
IconSize = "1";
ParticleColorAttenuation = "1";
ParticleEmitterName = %fireName;
};
%obj.addChild(%fireName);
%obj.addChild(%lightName);
%light.attachtoobject(%obj);
}Changed my script to the above and added:
$torchNum = 1;to my init.cs file
After I load in the mission next time, delete the light and the particle effect automatically created by the editor and voila! the torch will have light and fire, and the only thing that will show up is the torch in the editor. Position the torch as needed and not have to deal with 3 items for each torch. Also, the torch and its light and fire are all automatically named with unique names. Each torch has it's own light, fire, and the light reacts to the fire on its appropriate torch!
Only thing I've failed to do is add the light and fire's parameters as a sub-group when you inspect the torch but I couldn't figure out how to do it without making initPersistFields() non-static which doesn't seem like a good idea. If anybody else has a suggestion on how to do it I'd appreciate it.
Torque Owner Aaron Moore
I've edited the following to hide the handlebars....
if(mSelected.size()) { if(mAxisGizmoActive) { if(mSelected.size() > 1 || (mSelected.size() == 0 && (!mSelected[0].hideGizmo))) { renderAxisGizmo(); }This would accomplish what I'm trying to do, however I don't think it'll work (don't currently have a compiler on this computer). The problem with this I think is checking for the variable. I think I'm going to have to find the specific object that "mSelected" is an array of and add a variable the variable to this, and expose it to the editor. I can use the editor as a tool, but I don't have any experience editing the engine yet. I need to become more acquainted with the code.
I think attaching objects to eachother within the editor (instead of appearing as a separate object, I want it to not show up at all, and I want it's variables to show up as a set underneath the object the light is attached to. This is going to take a lot more research. If anybody can point me in the right direction for where the code deals with it, or ideas how the editor might be able to detect if an object is mounted (or in the case of a light, "attached") it'd be appreciated, otherwise I'll start combing through the code.