Game Development Community

Ok, some n00b questions

by Chris Sullivan · in Torque Game Engine Advanced · 08/27/2009 (4:09 pm) · 2 replies

I posted this in the wrong forum on the wrong account. This is apparently the correct place to discuss things like learning the code. You can close the other thread if it's inappropriate (http://www.garagegames.com/community/forums/viewthread/100531 ).

Anyway, I'm a novice C++ programmer. I can read the code and more or less know what it means. Complex hacks and obscure shorthand still throw me for a loop.

As I mentioned in the other thread, my team has assigned me to "figure out the TGEA engine so you can make it do what we want."

No small task.

I learn best when I assign myself small challenges and figure out how to overcome them. Frequently they turn out to be larger challenges than I thought, and I end up learning far more than a few small, simple things when I really dig deep and understand what I've set out to do.

So my first order of business is to figure out the Stronghold Demo. I know how to use the GUI to edit terrain, to import models, paint textures, and so forth. GUIs are easy. So here was my list of Things To Figure Out from the other thread:

Quote:
I see an orc running around the demo, and I see his path, but where's the script telling him to follow that particular path?

I feel like I'm on the verge of understanding this, but I need some hints and pointers (<-pun!).

I suppose you'll be able to help better if I give some specific questions... they aren't necessarily related to my end goal, but will help me know where to look to change certain categories of things.

Where would I find the information on how high my character can jump and how fast he moves? I thought I found it in player.cpp (the block with maxForwardSpeed = 10.0f;), but changing the numbers didn't do anything, even when I changed them to 1.0f.

Where would I find the camera location/angle? It should be a simple matter to project the camera to be looking over the character's shoulder, for instance, or to allow zoom in-out functionality, but I can't find it.

Where is the information for interpreting input devices? If I wanted to re-code different default controls, or add new controls attached to my own functions, where would I do it?

When the player runs over ammo, it knows to add ammo. There is obviously some sort of script attached to the ammo object so when it detects a collision with the player it runs the appropriate functions, makes the object vanish, and adds ammo to the player. Where is that script and how do I access it?

To which people responded by directing me to the scripts directory. That was a fun place -- it's fairly easy to do things like make my character Super Jump at tremendous speeds and so forth. I'm sure somewhere in there is the script for the sad little Kork Orc, running in his endless circle.

So now I know where the scripts are, but I don't really know how the engine loads and interacts with them. So I picked a single variable that I can change in the script, maxForwardSpeed, and am trying to trace it through the engine to figure out where it's defined, what is done with it, where it is read from the script, and so forth.

I had gotten about this far:

Quote:
It appears that when I edit the data in the script it propogates into the game without requiring any sort of recompile. That means somewhere in the program it's being told to read data from this script, but that the script itself is not part of the solution. OK.

I see that maxForwardSpeed is part of the struct PlayerData. (player.h)

It is defined as a F32 data type, which means a 32-bit float. (player.h)

It is assigned a value of 10.0f in the constructor for PlayerData. (player.cpp)

There is a static initPersisFields function in the struct PlayerData. This function calls something called AddField, which passes maxForwardSpeed as an argument to a function of the ConsoleObject class...
When I decided I just might need to draw a flowchart to figure it out in a real, concrete way.


OK. Now I've gotten all the stuff I was talking about moved over to the appropriate forum.

I see that maxForwardSpeed is passed in this line of player.cpp as shown:

addField("maxForwardSpeed", TypeF32, Offset(maxForwardSpeed, PlayerData));

OK. what follows is more of an ongoing thought process than an actual question. If you somehow have the patience to read through my thoughts, and also somehow have an opinion or helpful suggestion, go ahead and share it. But mostly I want this down so I can go back and read through what I'm doing.


I dissect things like this fairly methodically. I can see it's all being passed to addField, but first I want to understand the data types we're actually passing. Then I'll go look at addField and see what it's doing.

"maxForwardSpeed" is a string, or char*. simple enough.

TypeF32 is declared some sort of "Console Type":
DefineConsoleType( TypeF32, F32 )

It seems to be in some way letting the addField function know that maxForwardSpeed is of the F32 data type.

But what is a console type? Apparently it's defined thusly:

#define DefineConsoleType( type, nativeType ) 
   extern S32 type; 
   extern const char *castConsoleTypeToString( nativeType arg ); 
   extern bool castConsoleTypeFromString( nativeType &arg, const char *str );
Where it loses me a bit. I'm not sure what exactly it's being defined as. I always seem to get a bit lost in the complex #defines.

Back to the stuff we're passing to addField. We just did TypeF32. Next is an Offset function, where the maxForwardSpeed I'm tracking is actually sent.

So I look up the Offset function... and find another obscure #define.

#define Offset(x, cls) ((dsize_t)((const char *)&(((cls*)0)->x)-(const char *)0))

And here's where it loses me for the second time in this little rabbit hole I'm exploring. What exactly IS Offset being defined as? I can assume with a name like "offset" it's somehow determining an offset, that is to say, some sort of difference in position. I see a subtraction operation, so maybe I'm on the right track there. More study required.

At any rate I now have SOME notion of what's being passed to the addField function, or at least, I'm aware of where my understanding fails me, which helps. It's good to know the limits of my own ignorance so I can learn.

On to addField. addField is a member function of the ConsoleObject class. I do not know what ConsoleObject's job is supposed to be, but maybe I can figure out this one function.

addField looks like it's expecting to be passed 6 things (of types char*, U32, dsize_t, U32, EnumTable, and char*), and from what I've seen it's only being passed 3 things (of the types char*, S32, and whatever Offset returns). This is a discrepancy I need to figure out.


WHEW. I see that addField is doing some things that look fairly complex as well, calling more member functions I don't recognize. Maybe it's time for a little break.

About the author

Recent Threads


#1
08/27/2009 (4:38 pm)
The kork orc on the path is defined in aiPlayer.cs in your server/scripts/ directory.

At the top, you'll find the explination of what's covered in this script:
// AIPlayer callbacks
// The AIPlayer class implements the following callbacks:
//
//    PlayerData::onStuck(%this,%obj)
//    PlayerData::onUnStuck(%this,%obj)
//    PlayerData::onStop(%this,%obj)
//    PlayerData::onMove(%this,%obj)
//    PlayerData::onReachDestination(%this,%obj)
//    PlayerData::onTargetEnterLOS(%this,%obj)
//    PlayerData::onTargetExitLOS(%this,%obj)
//    PlayerData::onAdd(%this,%obj)
//
// Since the AIPlayer doesn't implement it's own datablock, these callbacks
// all take place in the PlayerData namespace.
Now, to find out how kork finds the right path, look in your mission editor (play game/press F11) the path and look at how it's named.
Then, look in aiPlayer.cs and you will find all the code that makes it work.

#2
08/28/2009 (1:48 am)
Quote:And here's where it loses me for the second time in this little rabbit hole I'm exploring. What exactly IS Offset being defined as?
...and that's where I get off ;P. I really admire your approach to the engine - it's very methodical and it seems to be working well for you. But on this one point, I'll advise you that you don't need to go any further down the rabbit hole. Unless you're going to significantly alter Torque's scripting languge/interface, you don't need to look any further than the syntax of addField. Suffice to say, you've figured out that by calling addField, the engine can get values from a script (player.cs) into a C++ object. I'd now focus on broadening your understanding of different classes specifically, rather than trying to understand the very root and core of the engine code. Frankly, that level of understanding is unnecessary as long as you know how to use the engine.

I know it doesn't sound like a healthy outlook - I'm all for understanding what I'm using. But you want to make a game, and you've licenced an engine - so use it! In this case it's just not a profitable use of your time to try to understand these low-level concepts, when you could be focusing on understanding the things that make your game work at a higher level.

That said - I do respect what you're doing! I wish I could understand the engine at some deeper level. But I've found I can get by, making enough changes to implement the type of game I want (a shooter, which makes it easier) without needing that knowledge.