Game Development Community

dev|Pro Game Development Curriculum

T3D Newb Learning Log #2

by Ron Barbosa · 06/07/2011 (3:58 pm) · 15 comments

As I continue my travels through learning T3D, I'm noticing that everything I'm reading in the tutorials seems to lean towards things I can make my character/avatar do as a direct response to some input from the player.

There doesn't seem to be much documentation or tutelage in the way of autonomous function. In other words, what does my player character do on his own, and what can I make AI/NPC characters do on their own?

I hate to beat the Torque X horse, but it had a great component system. I've heard that this is similar to the Torque 2D Behavior system, but I've not enough experience with T2D to say that for certain.

Components in TX were cool, because they provided a code module that represented an access point to a series of properties and methods related to one particular aspect of a game object's capabilities. So weapon control could be made into a component and everything related to weapon control could be encapsulated in the weapon control component. The component could then be added to a game object and that object magically had weapon control features.

A path-following component could be written to allow an AI or NPC to patrol a path and break the path and pursue an enemy when the enemy is within a certain range.

Add the path-following component and the weapon component to a single scene object and you magically have an autonomous patrolling NPC that can fire on enemies as he chases them away from his patrol region.

Components could be made to expose a "ProcessTick" method that basically allowed you to perform per frame processing associated with that component. My weapons component had an "overheat" cycle which leveraged tick processing to track a running weapon temperature and disable its firing functionality if it reached a critical point. The firing features would remain disabled until the weapon cooled (weapon cooling was also handled on a per tick basis), but my overall game never needed knowledge of this functionality. It was just attached to a component and that component had a heartbeat (ProcessTick) that told it what to do each frame. If I wanted to eliminate the overheating portion of the code, it was simply a matter of changing the "overheat temperature" property to 0.0 (which my code interpreted as...never overheat).

The lovely thing about the component model is in the elegance of it all. It's very rare that your components ever need knowledge of one another. I had no idea when I wrote my first components how they would later act as glue to pull together all kinds of great gameplay features several months later.

I have read that TorqueScript should be home to my game-specific logic, but I've also heard that (for performance reasons) TorqueScript does not have a game loop of its own. This leads me to believe that whatever functionality I want to occur and/or be evaluated each frame needs to be either [A.] written in the engine or [B.] done using a callback from the engine into TorqueScript.

I've read (from the T2D behavior documentation) that script callbacks that get called on update (which I'm guessing is per tick) are dissuaded because of performance reasons, so I'm not quite sure what mechanisms exist for me to get the functionality that I'm familiar with in the 3D engine.

The reason this is so important to me is because games evolve during the build. Modular components can come together in very satisfying ways without having any knowledge of each other's implementation. I get the feeling that in Torque 3D I'd have to make a "Knight" module to handle all of the things that a Knight can do. However, my mind (in the interest of being pragmatic as a programmer) would rather create a "SwordWielder" module and a "ShieldBearer" module and just add those 2 modules (and any other normalized knight-like behavior modules) to a scene object.

TX was very different in this regard, because the engine is written in C# and the components are also written in C#. This all gets compiled and executed as a single game project, so there is little change in performance between core engine functionality and script/component functionality.

Game development let's us create things that have a sort of life of their own (even Tetris blocks). Life has instincts and reflexes. Voluntary movements and involuntary movements. Life thinks and plans and reacts...but it doesn't all happen in one place. It's a collection of independent behaviors that makes it all interesting.

Again...these are newb learnings. These are probably not accurate, but this is where I am swimming about in the sea of learning T3D.

If anyone in the know would care to respond and provide some guidance...here's something that would interest me as an exercise; Assume I'm using the blank game project template. I would like to take 2 game objects (let's keep it simple...2 cubes) and make one chase and the other evade with some randomness to the direction. That strikes me as something that would have to be managed per frame. Each frame, the evader could be made to check to see that he's some minimum distance from the chaser and move in a direction that is reasonably opposite (with some slight angular variations) of the chaser's approach vector. The chaser should always just move in the direction of the evader. What are the mechanisms I should leverage to bring this all together? Keep in mind that next week I will want to add some other functionality to either or both of the aforementioned scene objects without touching the chase/evade code.

I have my stethoscope out...but I can't find T3D's heartbeat. I am reading tons of tutorials that tell me how I can give my player the opportunity to do things...but I still don't know how to make things do themselves.

Undaunted and still learning...
--RB

#1
06/07/2011 (4:29 pm)
Well, this doesn't give you a component system -- but it does let you start to create a heartbeat:

schedule()

http://docs.garagegames.com/tge/official/content/documentation/Reference/Console%20Functions/TorqueScript_Console_Functions_10.html

You can call it outright, in which case you might have to supply an object ID, or you can call schedule ON an object:

%obj.schedule(500, "memberFunction")

This is where you might also start to get warnings about WHERE to put scripts. Such as "it isn't a good idea to build the NPC AI into the client, put it in the server".

Anyhow, schedule() returns a little handle. If there's even the remove chance you might need to suppress that event (such as telling an AI to stop running amok), save the return value. You can call cancel(%scheduleHandle) later to abort it.

This is meant to solve exactly the problem you're describing -- how to give the scripter a way to keep things moving WITHOUT giving them access to the main event loop.

Behaviors and components... That's a nod to Aspect Oriented Programming. Good methodology, weird in that it can ride shotgun with nearly every other programming methodology out there. Not widespread in the wild yet by any means. I'm trying to think about scripting AI myself quite a bit this week. If I can think of a good model for making a TorqueScript library that modularizes AI behavior I'll speak up -- there may be some stray resources out there. There's also the coupl'a add-on tools in the shop for AI. They're both FPS/TPS/RTS oriented, and good. I'll try to think of something more generic if I can.
#2
06/07/2011 (4:42 pm)
@random...thanks for the insight. I will try to learn what can be gained using schedule() as relates to meeting my goal.

I've seen tons of tools in the shop as far as add-ons go...and they are no doubt great and worth the coin.

Unfortunately, I'm a builder at heart. That being said...I don't have to (or even want to) build everything...but I do have to understand how it does what it does.

Like many people here...I started off writing my own game engine. But once you've done a few thousand matrix transformations and done the quaternion math on paper (just to make sure the math books weren't lying), you can begin to appreciate what does into a full featured game engine and accept the fact that you could probably do it on your own (given limitless time and resources), but you don't have to because someone has invested that time and made the fruits of their labor available to you at a reasonable fee.

If my English teacher could only read that last run-on-sentence-slash-paragraph. :)

It may come down to me purchasing AI kits for the various features I want to implement, but I don't like to borrow what I don't understand. Even if my understanding is cursory (and in some cases flawed), I feel more comfortable than if I'm taking it wholesale and letting it work on faith. At least then I can use my understanding to fix bugs and/or extend features.
#3
06/07/2011 (5:18 pm)
Sadly, no components or behaviors in Torque 3D (someday...)

This might help you to get your feet wet with AI:

Using Basic AI Commands
#4
06/07/2011 (6:18 pm)
Behavior-like scripting...

What we need is to create are objects which can borrow the context of other objects.  Every object has its %this pointer in TS. We have a very similar situation, but need to retain %this for the behavior-class itself. Nor are we going to rewrite the engine. It could be a pretty lightweight class template.

So within each of these classes we'd need to read from the bot and write to the bot.

Probably this requires eval().

If we say, by convention, use %this.activeObject in a behavior object.

Then you can read variables in that context:

%this.behaviorInput = (%this.activeObject @ ".dynamicField");

You can write variables back this way:

eval(%this.activeObject @ ".dynamicField =" SPC %this.behaviorOutput");

We'd also probably be better off using a consistent function name that the attached object triggers. Say, "go()". It should at least do this:

function myAbberantBehavior::go(%this, %activeObject)
{
    %this.activeObject = %activeObject;
    // do work here
}

function myAbberantBehavior::onAdd(%this)
{
    %this.behaviorName = "myAbbereantBehavior"; //I'll need this in a sec.
}

Now your bots need a conventional way to add these, maybe:

function SimObject::AddBehavior(%this, %behavior)
{
    if (%this.hasBehaviors == "")
    {
        %this.hasBehaviors = true;
        %this.behaviors = new SimSet();
    }
    %this.behaviors.addObject(%behavior);
}

function SimObject::RunBehaviors()
{
    %n = %this.behaviors.getCount();
    for (%i = 0; %i < %n; %i++)
    {
        if (%this.behaviorsEnabled[%this.behaviors.getObject(%i).behaviorName])
        {
            %this.behaviors.getObject(%i).go(%this);
        }
    }
}


Caveats-- I typed this out on an iPad, and am away from anywhere I can syntax-check and/or smoke-test this. I _believe_ it will work. It may incur too much performance drain, depending on the context. You may also wish to attach further down the inheritance tree than SimObject, this just lets you add behaviors to all manner of things.

I'm guessing T2D's behaviors are more robust yet, but this is a conceptual launching point. If it works, it'd be something you can use until GG gets behaviors implemented in the 3D engine.


You should also definitely check out the bit Matt pointed to. Wish I'd seen that page YEARS ago. :-)
#5
06/07/2011 (6:23 pm)
PS -- Strange... Copying from Evernote, where I composed that, into Safari, where I pasted it, made some very creative translations of what should be plain vanilla spaces. Hopefully there's an easy way to replace them back the way they should be on your end. I tried editing it on my end but that might take two hours given iOS's lack of simple arrow-key movements.

PPS -- GG website won't let me edit it anyways, claiming it's oversize. There's an "eval" I see missing from how I describe reading a variable. :-( Guess it's at least pseudo-code...
#6
06/07/2011 (6:47 pm)
@random...thanks for the inspiration. As I mentioned in my last blog...my weekdays are pretty lean on spare time, so I won't likely get to do any coding until the weekend.

Nothing stops me from reading and digesting, though...so keep the ideas coming. :)

@Matt...very interesting link. I'm going to dig into AIPlayer and see what that's about...I am also curious about the trigger that makes the crossbow fire and how those things tie together. Not to mention...the thought hadn't really occurred to me to add TDN (including samples and docs from the older engines) to my list of go-to places.

I am certain that everything I want to do is "in there" I just haven't quite crystallized the concepts of getting all to go.
#7
06/07/2011 (7:11 pm)
@Ron

It's all good. I quite empathize how time can get to be a premium commodity.

I did it to help us both: that code will actually, if it works, dovetail nicely with something else I was conceptualizing. I won't be able to test any of it myself until Sunday, either, simply because of where I am and what I couldn't bring along -- just [happily] architecting in advance. Hope it actually _does_ help you out, even if just as inspiration for later.
#8
06/09/2011 (3:38 am)
Are you looking for ideas for AI charcter sets? Like a hobo AI that walks around the city doing funny hobo things?
#9
06/09/2011 (3:40 am)
Further Explanation:

Guard AIs
Wondering NPC AIs
AI's that hate you so throw rocks at you when angry?

Things like that?
#10
06/09/2011 (5:15 am)
@Kevin...not really. Those all sound like things that already exist and are prepackaged.

What I want to know is how those types of things get implemented within Torque 3D/TorqueScript.

I understand that all of these things are possible...and even already exist and can be purchased or used freely, but I don't have a clear understanding of how several behaviors come together to become an AI.

I find myself often using words like Behavior or Component, but really that's more out of a desire to encapsulate individual and related functionalities into a single module.

Also, I don't want to get too hung up on AI. That's my example that I'm going to try implementing this weekend, but really any "activity" that can be attached to a character, including the player character.

I just can't shake this feeling that T3D is going to require me to create a class that contains all of my player functionality...rather than allow me to create a bunch of individual modules of functionality and attach them and detach them at will.

Can anyone from GG speak to this? What are the recommended ways to normalize related functionality and then apply it to characters (player and NPC alike)? Or am I correct in thinking that the functionality needs to be approached from a more global perspective...as in...this is my player character and his functionality is all in here.

Would really like to know what the acceptable implementation approach is.
#11
06/09/2011 (8:59 am)
@Ron

Correct me if I'm wrong here...

@Kevin

Just to tie your examples together with what Ron's looking for (it is a feature in certain other versions of Torque), Ron wants a way to layer individual behaviors as a way of (a) making AI development easier and more modular and (b) also making more complex behaviors out of simpler behaviors.

So say you have a behavior for "distractible" which causes the bot to notice random environmental objects at intervals and study them. And another that is a basic "miander" behavior which causes the bot to move in a random direction, turn a bit, continue, turn a bit, continue, and handles some basic collision/redirect. Also perhaps "miander" can be given a restricted range. Another behavior called "antics" which selects from a grab-bag of animations, perhaps restrictable so that you can differentiate NPC personalities. Still another behavior which identifies foes within a certain range called "IFF". Another which attacks a foe called, blandly, "attack". Yet another which causes the bot to communicate to other bots the location of a foe called "alarm". And another yet that follows a basic pre-set path, called "patrol". You can even add a behavior called "irate" which cases the NPC to slowly regard the player as more of an enemy the longer the player is within a certain distance.

Then you can arrive at NPCs that are the sum of several behaviors.

Generic street person = miander.
Odd street person = miander + distractible.
Very odd street person = miander + distractible + antics.
Street performer = patrol + antics.
Mob person = miander + irate + attack.
Posted sentry = IFF + alert.
Attack/solo sentry = IFF + attack.
Patrol guard = patrol and/or miander + IFF + attack.
Suspicious guard = miander + distractible + IFF + attack.
Panicky guard = miander + distractible + IFF + alert.
Lazy guard (no IFF, only treats you as enemy if another alerts it) = miander + attack + antics.
Half-asleep guard = attack.

Ron's after not the modules per-se, but the means to the "=" and the "+" in all the above. Or, short of that, what GG recommends as best practice given existing support in T3D 1.1. Hope that illustrates why you'd want to go about it that way: you can arrive at a very diverse, rich set of behaviors with a lot less work than coding the AI for each actor distinctly.




#12
06/09/2011 (11:19 am)
@random...that nails precisely what I'm after. I either want to know what the mechanisms are for combining various behaviors into one character, or I want to know that T3D "just doesn't work that way."

Either way...I think we all agree that characters are a combination of several different functionalities all of which may be context sensitive (chasing people away but ONLY when they approach your patrol zone) or constant (ALWAYS show idle animation when not moving).

Whether these equate to a series of behaviors/components that are tacked onto a character or they equate to a full-blown per actor implementation is what I haven't been able to put my finger on.
#13
06/13/2011 (5:56 am)
So...life caught up with me this weekend. I didn't get much game-development time.

I did get PLENTY of fixing-sprinkler-heads-on-my-lawn time. Much more of that than I wanted.

So...still not a ton of progress. This effort might have to wait. I would like to release another game this year, and it's almost half over. I think I'm going to focus my efforts on another Xbox LIVE Indie Game using Torque X and come back to T3D later.

Sorry for the false start and thanks for the suggestions. It just seems like the entire paradigm is different for T3D. Realistically speaking, I don't have the funding for the assets to make a quality 3D game, so this was really more of a learning exercise for me. But if I focus on the 2D engine that I already own and am comfortable with...then I might actually be able to deploy another title by the end of this year.

Will continue to monitor the blog for new posts, just the same.

Thanks,
--RB

#14
06/13/2011 (6:11 am)
Rats.

Well, I understand, though.

I guess if I start a newb-B learning log here it'd be solo. I'm OK with sticking my neck out and looking foolish if it results in me understanding more and a better GG product, though.

Thanks, at least, for two good posts and a great idea. :-)
#15
06/13/2011 (6:37 am)
@random...you definitely won't be blogging solo. If you post a blog...I will certainly follow it and contribute whatever brain droppings might be worth expressing. :)

This weekend was just a big reality check for me. With the paradigm shift from what I'm accustomed to (Torque X) to T3D being so large...the weekends just won't be enough to cover it. Especially when I take into account that "stuff happens" and I might not get to contribute any time at all on a given weekend.

With Torque X, I'm quite comfortable. I sit down after dinner for 1 hour and I can whip up a completely new gameplay mechanic and spend 30-60 minutes each night tweaking and refining it. With T3D...an hour yields next to nothing for me...and that means there's nothing to spend 30-60 minutes each night tweaking or refining.

This year, my goal is not to learn a new game engine, it's to release another game. If I clog up my game development time making minimal progress learning a new engine, then I will not reach my goal this year.

So I've decided to expand upon a TX project that I've been cultivating for a while and complete it. That will maximize my available time and will get me to my goal.

I had originally hoped that this series of blog posts would get more concrete attention from GG. Some folks "dropped in," but I didn't see much (anything?) in the way of direction or even someone coming out authoritatively and saying, "Ron...your thought process is wrong...look at it this way and you will make better progress."

I still don't know if I'm correct when I stated my feeling that in order to build a knight...I'd have to build "a knight" and not combine a series of knight-like behaviors.

I think this was a good opportunity for someone from GG to take a guiding a role and make this a community-educating series, but instead they seem to be sitting back and watching to see where it goes. That's not necessarily a bad thing...sometimes it's best to observe and not interfere, but it just doesn't fit into my time budget and my game-delivery goals for me to completely flub my way through the learning process without authoritative guidance.

@random...thanks for entertaining my thought process and coming up with some suggestions. I will keep an eye out for your blog.

@GG...you guys should also keep an eye out for random's blog. If he has the time to commit to learning T3D, and it doesn't conflict with any of his other goals (personal or game development related), then you should do what you can to guide him (or anyone else in the community) through the process. An intelligent and knowledgeable community is a huge asset.

No knocks to anyone at GG...this is my decision to delay this process. It's more important to me to deploy a new title this year than it is to learn a new engine.