A quick breakdown on datablocks, objects, %this and %obj
by RedOctopus · 05/31/2012 (6:46 pm) · 3 comments
So, today, whilst rewriting my AI code in order to make it more modular, I had to get a much better grasp on the difference between datablocks and objects when it comes to calling functions. In this context, I was getting confused between AIPlayer and, we'll say, DemoPlayer, and why calling functions between them wasn't working as expected.
Well, the way I now remember it, when writing functions that I want to be attached to a datablock, and thus more easily overloaded, is that a datablock function, typically uses %obj, a reference variable to the object the datablock is assigned to. In my AI example, my AIPlayer object has a datablock, DemoPlayer, assigned to it, but if I wanted a different type of AI, I'd assign it a different datablock, say TestPlayer.
So, here's the situation broken down: AIPlayer has functions that are used by all my AI types. One AI type will use a datablock named DemoPlayer and another AI type will use a datablock named TestPlayer. Both of these AIs will be able to make a melee attack, but one of them has twice the range. Below is how I would set up the script:
The above code makes a new AIPlayer with either the DemoPlayer datablock or the TestPlayer datablock, depending on whether you call the pickData function with either a 1 or a 2. Then, the mainloop is called and the doMelee function is called depending on whether the AI uses a DemoPlayer or TestPlayer datablock. Then the echo function prints a string that starts with the handle of the object that that datablock is assigned to, which is passed as the %obj variable.
While I'm at it, I'll try to describe the %this variable. It's pretty simple, really. When a function gets called, the handle of the calling object gets sent along with the function call. In this case, when we call %player.mainloop(), the AIPlayer object's handle is passed along with the call for the mainloop function. In the mainloop function, when we call %this.mainloop(), what we're really saying is (AIPlayer object handle).mainloop().
And that's about it. I don't know if this was very clear or not, but I know I regularly get confused about it, so I figured I'd write a blog about it.
Well, the way I now remember it, when writing functions that I want to be attached to a datablock, and thus more easily overloaded, is that a datablock function, typically uses %obj, a reference variable to the object the datablock is assigned to. In my AI example, my AIPlayer object has a datablock, DemoPlayer, assigned to it, but if I wanted a different type of AI, I'd assign it a different datablock, say TestPlayer.
So, here's the situation broken down: AIPlayer has functions that are used by all my AI types. One AI type will use a datablock named DemoPlayer and another AI type will use a datablock named TestPlayer. Both of these AIs will be able to make a melee attack, but one of them has twice the range. Below is how I would set up the script:
pickData(%this, %num)
{
switch(%num)
{
case 1:
AIPlayer::spawnAI("DemoPlayer");
case 2:
AIPlayer::spawnAI("TestPlayer");
}
}
AIPlayer::spawnAI(%this, %datablock)
{
%player= new AIPlayer() //create a new AIPlayer object and give it the DemoPlayer datablock
{
datablock = %datablock;
}
%player.mainloop();
}
AIPlayer::mainloop(%this)
{
%this.getDatablock().doMelee(%this);
%this.mainloop();
}
DemoPlayer::doMelee(%this, %obj)
{
echo(%obj @ " does short range melee attack");
}
TestPlayer::doMelee(%this, %obj)
{
echo(%obj @ " does long range melee attack");
}The above code makes a new AIPlayer with either the DemoPlayer datablock or the TestPlayer datablock, depending on whether you call the pickData function with either a 1 or a 2. Then, the mainloop is called and the doMelee function is called depending on whether the AI uses a DemoPlayer or TestPlayer datablock. Then the echo function prints a string that starts with the handle of the object that that datablock is assigned to, which is passed as the %obj variable.
While I'm at it, I'll try to describe the %this variable. It's pretty simple, really. When a function gets called, the handle of the calling object gets sent along with the function call. In this case, when we call %player.mainloop(), the AIPlayer object's handle is passed along with the call for the mainloop function. In the mainloop function, when we call %this.mainloop(), what we're really saying is (AIPlayer object handle).mainloop().
And that's about it. I don't know if this was very clear or not, but I know I regularly get confused about it, so I figured I'd write a blog about it.
#2
06/10/2012 (2:07 pm)
So many ways to "skin the cat" ... seems like just setting a variable on the objects when they spawn to control the range would work too.AIPlayer::spawnAI(%this, %datablock, %meleeRange)
{
%player= new AIPlayer() //create a new AIPlayer object and give it the DemoPlayer datablock
{
datablock = %datablock;
}
%player.meleeRange = %meleeRange;
%player.mainloop();
}
...
AIPlayer::doMelee(%this, %obj)
{
if (%obj.meleeRange $= "2")
{
echo(%obj @ " does long range melee attack");
}
else
{
// default
echo(%obj @ " does short range melee attack");
}
}
#3
06/10/2012 (3:26 pm)
Here is how I would go about this, using some variables.$enemy::isSet["Enemy1"] = true;
$enemy::health["Enemy1"] = 100;
$enemy::meleeRange["Enemy1"] = 10;
$enemy::datablock["Enemy1"] = someDataBlock;
function spawnAi(%name)
{
if($enemy::isSet[%name])
{
%health = $enemy::health[%name];
%meleeRange = $enemy::meleeRange[%name];
%datablock = $enemy::dataBlock[%name];
%player= new AIPlayer() //create a new AIPlayer object and give it the DemoPlayer datablock
{
datablock = %datablock;
health = %health;
meleeRange = %meleeRange;
};
%player.mainloop();
}
}
function AIPlayer::mainloop(%this)
{
if(isEventPending(%this.mainLoop))
cancel(%this.mainLoop);
%this.getDatablock().doMelee(%this);
%this.mainLoop = %this.schedule(1000,mainloop);
}
function aiPlayer::doMelee(%this)
{
%meleeRange = %this.meleeRange;
//do stuff with the range
} 
Torque Owner Kevin Mitchell
12 CatBlack Studios
Also add the schedule handle to the AI create so you can disable a dead AI or cancel the schedule if needed for any reason.