Game Development Community

Simple question (flagpole)

by Teromous · in Torque Game Engine · 02/02/2005 (5:37 pm) · 4 replies

Hey I just have a small question about the flagpole scripting tutorial. In the tut it mentions that you need to have:

function StaticShape::onTrigger(%this, %obj, %state)
{
%this.getDatablock().onTrigger(%this, %state);
}

It explains that the reason this script is there, is to loop through all onTrigger scripts. Now, I had a single flagpole in the group and a single onTrigger in that one script. So it seemed reasonable to me, that I could remove this function and the script would still work. I found that by removing this will not trigger the script:

function Flag::onTrigger(%this, %obj, %state)
{
if(%state == 1)
{
%obj.playThread(0);
}
else if(%state == 0)
{
%obj.stopThread(0);
}
}

...unless the previous script was also added. Can anyone explain to me what the first script's job is and what each part does? I thank any response in advance.

#1
02/02/2005 (11:03 pm)
The functionality is global using "StaticShape". This means that ANY static shape that is triggered will run through that function. That function then calls the exact function that is needed by using the "%this.getDataBlock()" function to retrive the proper object name or class to set off any function that is specifically designed for it. In this case it's a flag.

So when the flag is triggered, the engine does not know WHAT has been triggered, but it does know that a StaticShape has been triggered. It then retrieves the correct block (flag) and calls to it.


There are some functions that work exactly the opposite of this as well. Take this for example...


Say you have a function like this...

function Player::doSomeFoo(%this)
{
   // cough up some bad roast beef
}


All player objects will refer to that function when you use "%player.doSomeFoo();". But say you had two different player types such as "Orc" and "Human" and you wanted each to to do something different. In this case lets say you want the human to use the original function above, but you need the orc to do something totally different. By inserting this function into your scripts....


function Orc::doSomeFoo(%this)
{
   // cough up some human flesh
}


it will intercept the original function when the orc is encountered. You would still use the exact same call of "%player.doSomeFoo();", but the engine would recognize that the Orc has it's own function for this action and would refer to the "Orc::doSomeFoo(%this) instead. Same holds true if you added another class of player like a Pixie. If you want the pixie to do something different, you would simply add...

function Pixie::doSomeFoo(%this)
{
   // Scream and fly away from orc
}


And likewise you would call it with the same function of "%player.doSomeFoo();" and the engine would refer it to your new function. If you were to remove the Orc and Pixie functions all three classes would revert back to the original "Player::doSomeFoo()" function for processing. This is one feature about TGE that I flat out LOVE. So to sum it up, depending on the class, and the calls that are coming from the engine, some functions can be intercepted by simply declaring a function for that class. But in the case of the static, it has to be located instead which is why one function handles the traffic for each static type. I believe the reason for this is that most statics are pretty much inactive and usually do not need such functionality attached to them. Just as an observation, my flags are actually Items and not Statics. Not sure why the tutorial chose to use statics but IMO have the flag as an Item makes much more sense and makes the whole CTF game easier to code.

EDIT: To expand on this just a wee bit more, if you also added this function to your scripts....


function Human::doSomeFoo(%this)
{
   // Scream and run away from the Pixie
}

Then each player type would have it's own specific function for the handling of "%player.doSomeFoo();" and thus you would NOT need to have "function Player::doSomeFoo(%this)" function at all because it would never be called by the engine. Which is what you thought you could do on the static. Hope this helps.
#2
02/03/2005 (5:10 am)
@Gonzo
I know you are a Clown :)
But is there a teacher hidden there to ?
Your explanations are really amazing !!
#3
02/04/2005 (4:04 pm)
Thanks for the summary Gonzo. It gets confusing doing tutorials when there is more example than explanation. Your information is helping me (and others I'm sure) understand how torque works.
#4
02/05/2005 (1:47 am)
@ Billy

Thanks dude, much appreciated. :-)

LOL, would you believe I actually hated teachers in school? Well, not really hated them, just didn't care much for them. I have become my own worst nightmare, DOH!!!



@ Teromous

Not a problem, I know exactly how you feel about wading through the tutorials and resources, it's a big job. That's why when someone asks about specific engine functionality I try to give good solid answers. I consider your question to be a "quality" question worth a quality answer. Someone asking "How do I mount the crossbow to the race car?" is not likely to get any answer out of me because that's nothing more than someone who wants a lot of assistance versus someone like you who is trying to learn something. After taking a second look at this thread it occurs to me that there is another very important lesson here that will save you a lot of heartache down the line. You may have already picked up on this but lets examine the original functions a little closer....


The Original:

function StaticShape::onTrigger(%this, %obj, %state)
{
	%this.getDatablock().onTrigger(%this, %state);
}

First off, this function is written badly IMO because it can easily confuse people that are learning. The variable names are not labeled in a fashion that best represents the data that is passing through them. So I've changed the names to better illustrate what you are dealing with and to help you see the reason it is better IMO to write it this way...

function StaticShape::onTrigger(%shape, %trigger, %state)
{
	%shape.getDatablock().onTrigger(%shape, %state);
}

Notice I have changed %this to %shape? The %shape variable represents the ID# of the flag that is being triggered. We know it's a flag, but the engine doesn't. So we ask the engine to get the shapes datablock and perform the "onTrigger()" function on it and then we pass the shapes ID# and the triggers %state to the new function. When the engine gets the shape's datablock it finds "Flag" and calls the second function. Next %this in the first function and %this in the second function are NOT the same thing, and since one function directly calls the other, if they are not the same, they should not be labled the same. And what was named %this the first time shouldn't be passed off as %obj to the next function, no offense to the person that wrote all that, but it's sloppy and confusing. Since it appears in the first function that we are sending the %this variable to the second function twice, it would be very easy for a learning user to assume they are the same and that will be trouble for sure. Also note that %obj is changed to %trigger. That is because this is not some random object, it is a trigger calling this function so it should be labeled appropriately just as %obj was changed to %shape in the second..

function Flag::onTrigger(%data, %shape, %state)
{
	if(%state == 1)
	{
		%shape.playThread(0);
	}
	else if(%state == 0)
	{
		%shape.stopThread(0);
	}
}

Now %this has been replaced with %data because that slot is now filled with the %shapes dataBlock ID# since we performed a namespace function on it in the first function. This shifts %shape into the second slot and %state into the third. Even though we only passed two variables, the third(%data) was passed to the function for us by the engine. And now that you know exactly what variables you have and where they are, you are less likely to make a mistake with your data. IMO this is much easier to follow for novices and experts alike. It makes more sense, it's easier to learn, and it saves everyone who works with your code time because the flow is smooth and harder to mess up due to mixing up arguments. It also makes it much easier to debug when you do make a mistake because it will stand out more obviously than a bunch of %this and %obj variables being passed and shifted all over the place.