Sign in to follow this  
Zarion

Selecting targets for actions in an RTS

Recommended Posts

Note that an RTS certainly isn't the only type of game where this question is relevant, however, it seems to me to be the clearest example of where this takes place frequently. Maybe it's just me, but requesting targets for actions seems to be a hard issue on which to cleanly seperate GUI and game logic code. Say, for example, in an RTS, you have a cleric selected, and you want to command it to cast Heal on a damaged unit. You click on the Heal button, and then click on the desired target, and then the unit proceedes to cast the spell. Pseudocode something like the following seems intuitive at first glance, but very tricky once you get into it: Button_Heal { CastSpell(Heal, GetTarget(creature) ); } Obviously, the spell needs a target upon which it is to be cast, and once you click on the button you are prompted to select this target. Though this seems like the most straightforward method as far as the button's spellcasting code is concerned, how would you really extract a target as the return value of a function while still continuing to process the rendering and updating of game entities as normal? I suppose its possible that the GetTarget routine could contain its own version of the main game event loop, and could intercept mouse events. If it determined that a valid target was clicked on, it could return this target, and if it detected a cancel command (like pressing escape or something) it could return -1, and cause the whole casting routine to bail. However, this complicates one's ability to click on other command buttons after clicking on the spell button. Even if we could see that this is an invalid target an bail, we'd still lose the click event, thus requiring the user to click on a button twice if they'd previously selected another action. There are ways around this, of course, but they seem to become increasingly messy and contrived as time goes on. Another method involves the heal button setting some sort of global 'cursor mode' which determines how the cursor is interpreted by the objects it clicks on. Then, whenever you click on the map or a creature, the game interface checks the current cursor mode, and performs the appropriate action according to it. In this case, it could switch to 'spell targetting' mode, but in order to know which spell to cast when you click, it would also need to store additional information, like a spell ID code. Plus, to properly inform the player about a target being somehow invalid when you click on it, the GUI code would seem to need to grow uncomfortably coupled with the underlying game mechanics. Even worse would seem to be routines requiring multiple different types of targets within the same action. (Say, for a random example since nothing better comes to mind at the moment, a spell that exchanged control of two creatures) Clicking on a creature in 'spell targetting' mode could no longer simply cast the spell on the creature you click on. In this case, it would have to somehow store the previous target (presumably in some global 'spell target' variable), then switch to another targetting mode to obtain the second target. Then, this cursor mode would call the spell with one target being what it just clicked on, and the other target that was previously stored in the global spell_target variable. This is beginning to seem almost spagetti-like, with the required componants of spellcasting being seperated among multiple different, seemingly unrelated areas of the GUI. Is there no clean way to organize this all within the spell's own code? Say: Spell_SoulTransfer() { creature1 = GetTarget(creature); creature2 = GetTarget(creature); swap(creature1.owner, creature2.owner); } How have some of you dealt with this issue? Any helpful hints? Am I totally looking at this the wrong way? (PS. I'd rather avoid threading, if possible, since that brings its own set of headaches)

Share this post


Link to post
Share on other sites
Finite state machines. You start in an Idle state, then clicking that button moves you to the Heal-Targeting state. Clicking Cancel returns you to the Idle state, clicking on a Creature moves you to the Casting state, etc. You don't duplicate any loops or do any threading. Just keep track of what state you're in at all times and act accordingly. You may need several parallel state machines to do this, or a hierarchical model.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this