Game Development Community

Advice/sharing on developing OO framework

by Phil Shenk · in Torque Game Builder · 07/01/2005 (5:14 pm) · 28 replies

I'm starting to move away from the "nest" of just hacking experiments together, which has me starting to think about how to organize my code. I've done some OOP in C++, so I know the theory, but I'm still pretty new at it. I'm wondering if anyone out there has some concrete advice or examples on how they've approached this.

Specifically, what I'm looking to do is create a large variety of entities that can do a large variety of things. I'd like them to have inventory, or at least modifiable properties, RPG style (i.e. + 2 to armor, +25% to damage, etc). I like the idea of having different unit types have different movement styles. For example, some might move by thrusting and applying incements to velocities (like flying, drifting), others might explicityly move location to location (like walking).

That's what I'm looking at for a unit class, at least. Beyond that though, I'm interested in talking about how AI interacts with the units, how people handle unit and game states, how unit interaction is handled, etc. I'm wondering about the big picture, not stuff like, "store unit refs in an array" type things.

Like what about events? Are people scheduling individual unit actions, or putting active units and actions in a queue that gets get called on a regular tick? What do people's main loops look like?

Someone on these forums linked to an article on OO game framework that set everything up with action and state objects that were contained inside of unit objects (can't find the link right now). That theory intrigued me, moving the actions outside of the unit class methods and into a seperate class that acts directly on units. I'd be curious to hear if anyone experimented with anything like this.

I guess, generally, I think it would be cool to share methodologies for how we are setting up our game structure. Start drilling down to what specifically we're doing, and what rewards/problems we're encountering. I think it could be a potentially interesting topic.
Page «Previous 1 2
#1
07/01/2005 (5:23 pm)
In this thread I have some source scripts linked from a GID RTS... only a 12-14 hour game, but some very script on how I made the enemies interact with the player... nothing much, but a quick and rough setup that worked
#2
07/01/2005 (9:19 pm)
Here's a nice article on what you're referring to (however, it's examples are in c# and not in c++/torquescript):

www.devmaster.net/articles/oo-game-design/

I would like to work on building some classes/logic that follow this methodology in torquescript. However, i need to get a mastery of the language first.
#3
07/01/2005 (10:11 pm)
@Ty - Yes, that's the article I was thinking about. It's very abstract, but it got me thinking a lot. I looked at his event class (very briefly)... it's kind of interesting. Off hand, it looks like a *lot* of actions. It also looks like he's got the unit "states" genericized to some degree, although this is hard to tell. I think you'd want to keep the states simple, so an action that was acting on a unit didn't have to test crazy amounts of states to see what's valid or not.

Like I said, though, there are a lot of actions. Does this make sense? Would you ever want to call action "AllStop", or "BuildTargetSet" or "Evade" on like a button or a level? Maybe it's fine to use the member function route, where a set of functions only really works with the class it's designed for. If it was a good idea to do the generic action class thing, it seems like these could be abstracted and have an AI class figure out how to implement actions in a more efficient fasion.

For instance, an AI could probably figure out how to use action Accelerate to get to a target, and not need an AccelToDest class. Again, this is just first reaction, since I don't really know the full extent of the code. I guess maybe he's building his AI out of these actions... ANyone have any more insight on this?

@ Matt - Thanks man, I saw that earlier while cruising. I'll check it out. Are you doing any OO stuff in your projects?
#4
07/01/2005 (10:23 pm)
@phil.

In regards to actions not seeming applicable to certain entity types: I believe he has each entity tied to a specific set of actions they are capable of. Then, his event scheduler checks if the action exists for that entity before trying to schedule it on that entity.

It is cool in theory. I imagine you'd have to follow a chart of standard naming conventions for actions. Then you as a developer, and i as a developer would both know that to create a universally compatible entity, we must name our movement action 'move' (instead of walk, etc....). If this was done right, it is theoretically possible to drop a 'standardized' entity in another compatible game and have it perform correctly (to some degree) right off the bat.
#5
07/02/2005 (6:08 am)
Stock TorqueScript does not provide function inheritance to create true OO code. So unless you modify it or use Bryan Edds' resource, you can't do any of this.
#6
07/02/2005 (7:00 am)
I'll definately use OO in my team's main game... the Diablo Style RPG. I either will implement Bryan Edds' resource or will only do it on the C++ end. Probably won't be anything special, something like this

Player class...


Enemy class
Ghost sub class
zombie sub class

etc... that way all the general move and attach functions can take place in the enemy class, then the class specific actions can be in the sub classes... I might go one more level down in sub classes
#7
07/02/2005 (7:16 am)
I use that ScriptObject stuff for my RTS's OO. Works well.
#8
07/02/2005 (7:33 am)
@Jason / @Matt

From what i've seen, while t2d it isn't 'true' OO code, it can come close to mimicking OO code via namespaces and cleverly coded 'handles' to other parent/child objects. The conclusion i came to was that you can do 3 levels of single inheritance relying on namespaces. I know with Bryan's mods, you can get unlimited levels of inheritance, and the last thing i saw was he was going to implement multiple inheritance. If my conclusions are wrong here, please let me know. I don't have as much experience with tscript as you guys, and maybe my conclusions are based on my limited test cases.

@Matt

Can you explain the advantages you'd gain from doing your 2-3 levels of inheritance thru Bryan's system versus just using standard ScriptObject inheritance.

Thanks!
#9
07/02/2005 (7:41 am)
Heh, I feel guilty for not submitting the MI code yet... Between a full time job, college and Puzzle Gaiden... it's tough :)

Sounds like the original author needs to check out design patters. Two good books, in order of suggested reading are -

"Design Patterns Explained"

and

"Design Patterns"

Check 'em out. There's also "Refactoring to Patterns" which is EXTREMELY useful down the road, though you may want to get "Refactoring" first.

Go OO!
#10
07/02/2005 (9:16 am)
@Ty: Namespaces do not inherit function calls, from my testing. I would have happily used it, because I like flat hierarchies anyway, so I don't need more than 1 or 2 inheritance levels. But it only inherits data fields, not functions. If you do get this working without Bryan's resource, please let us know how you did it.
#11
07/02/2005 (10:14 am)
@Matt/others

I'm thinking you wouldn't even have to sub-class "enemy", just do it all with data. Have the AI and actions be seperate script objects that act ON the unit objects. The actions and units would have to store refs to each other, for various stuff, but the hierarchy stays really flat. Like totally flat.

This avoids the issue of functions not being inhereted with the namespaces, mostly because it's not even using inheretance. I guess this isn't even really OO, not fully at least. It's not etirely procedural though either since it does use classes to define entities, and provides fields and methods for interacting with each other.

I was going to try to prototype something like this over the weekend... we shall see what kind of mess that produces ;)
#12
07/02/2005 (11:38 am)
@Jason

Try this code out and see if it does what you need:

// TEST
 echo("begin test");
 
 $char = new ScriptObject("GameCharacter"); 
 
 function GameCharacter::announceType(%this) {
        echo("I am a character in your game!");
 }

 echo($char.announceType() );
 
 $wizard = new ScriptObject("Wizard") {
        class = "GameCharacter";
 };

 function Wizard::announceSubType(%this) {
        echo("I am a wizard character in your game!");	
 }
 
 echo($wizard.announceType() );
 echo($wizard.announceSubType() );
 
 
 $evilWizard = new ScriptObject("EvilWizard") {
        class = "Wizard";
        superClass = "GameCharacter";
 };

 function EvilWizard::announceSide(%this) {
        echo("I am an evil wizard from the dark side!");
 }


 echo($evilWizard.announceType() );
 echo($evilWizard.announceSubType() );
 echo($evilWizard.announceSide() );         
         
 
 echo("end test");
 // END TEST



The trick here is that you are allowed 3 namespaces......

1) the namespace in the parentheses of your 'new ScriptObject()' call
2) the namespace defined in the 'class' attr in the scriptobject block
3) the namespace defined in the 'superClass' attr in the scriptobject block

The function calls will crawl these namespaces in order looking for functions named after your call.

For example, on the "$evilWizard.announceType()" call, it traverses.............

EvilWizard --> Wizard --> GameCharacter

......and it indeed finds a 'GameCharacter.announceType()'
#13
07/02/2005 (4:05 pm)
Wow, I didn't realize the "class" dynamic field was another "magic" name. I really wish they wouldn't have designed it this way, but thanks very much for the info! This means a lot of refactoring... :)
#14
07/03/2005 (10:44 am)
@Ty

I could easily be doing something stupid, but when I cut and paste your sample, I get a halt right at the G like:

function ##G##ameCharacter::announceType(%this) { echo("I am a character in your game!");

I'll keep looking into it.

(edit)
nevermind, it was something stupid.
#15
07/03/2005 (1:05 pm)
@Phil

Yeah, i did the same thing at first i think. I pasted the block of code inside another function and it took me awhile to figure out what was going on too.
#16
07/08/2005 (12:56 am)
Just to report in here. I said earlier that I was going to try and implement a object-based system similar to what's described here www.devmaster.net/articles/oo-game-design/
I must say, it's working pretty well so far. It's a slick way of setting things up. What I've got now is a "unit" class based off of scriptObject. It holds properties, some basic functions like onAdd() constructor type things, and a kill() That cleans stuff up. It also has a handle to a sprite. For now, I'm having the sprite store all the stuff that sprites store, like velocity, rotation, position, etc. Since they're already set up to do that.

I subclass unit one level for types of units ("ship", "asteroid", "alien", etc.) This will probably be all the inheretance I do for Unit.

That's pretty standard stuff, I'm sure. The interesting thing, for me at least, is an "action" class, also based on scriptObject. A bunch of things can create an action object, like player input for example. Eventually, an AI object will drive an input object, that will in turn create action objects for NPCs.

Actions add themselves to a global simSet, so I know at any given time how many actions are in the world. They store handles to what Unit object they are acting on, and an update time. They reschedule their Do() function according to their update time. The neat thing is that any action can work on ANY unit. In a lot of ways, they are similar to scheduled functions, but they can more easily store data between Do() calls. Actually, now that I think about it, maybe the same thing could be done with scheduled functions that keep passing their parameters to themselves.

Right now, I've got simple test style actions like "lookAt", "moveTo", "ApplyThrust". It's proving kind of easy to make new action objects that will work with any of the units I have set up.

Oh, a unit that an action object registers itself with the object it's "actioning" on. So that unit object can cancel an action, if it wants. It's also easy to check what all actions are acting on a given unit, or iterate through all the active actions and find what units they are affecting. Most actions can also be exclusive or additive, exclusive meaning that if an action of that type is already registered with that unit, it will update the existing action rather than create a new one. Additive actions will just create a new one, then they both are acting on that unit.

Anyway, so far so good. I'm thinking that actions that are one-off (non repeating, don't need to store or expose data), would just as easily be "action functions". I'm not strictly following that write up I linked (at all!), just using the general idea as a jumping off point. I'm sure all this isn't anything new or unique, but it is for *me*, and that makes it really fun :)
#17
07/08/2005 (6:25 am)
Thanks for getting this thread going Phil. I start my OO class next tuesday.
#18
07/08/2005 (9:34 am)
Its always fun getting "clever" with code :)
#19
07/08/2005 (9:36 am)
@Jesse
Glad you'r liking it. I like talking about this kind of stuff. I kind of feel like T2D is starting to click for me, which is a very cool feeling :) In some other thread, Ben Garney said that Torque script didn't really "want" to be pure OOP or pure procedural, but was sort of a Zen space in between. That description feels pretty right to me at the moment.

Good luck in class! I'd be curious to hear what you learn, and apply back onto T2D :)
#20
07/08/2005 (9:57 am)
That sounds interesting, Phil. If you don't mind, can you post/link source code? I'd be interested to see how it looks.
Page «Previous 1 2