Ordering system question
After receiving lots of really helpful feedback and tutorials on the unit creation question, I thought I''d tip my hat in another direction.
I want to create an ordering system that is more indepth than the "move, attack, regroup, formation, and set waypoint" that most games have.
In a nutshell, units and their holistic group have to be able to do variety of tasks. I''m wondering if I should design the orders as classes with built in functions, or just as functions themselves. Notice, this is not an exhaustive list. just ideas off the top of my head.
1) Move; (takes a waypoint as a parameter)
-bounding: movement that takes advantage of terrain for cover while units leapfrog each other
-normal: speed at which units can take reasonable terrain cover
-fast: speed is of the essence, defense is not a priority
-covered(stealth): similar to bounding without leapfrogging, more cautious to take advantage of cover
2) Attack; (takes a target as a parameter)
-assault: maximum firepower directed at units, most ammo consumption
-harrasment: fire meant to suppress enemy units, lower ammo consumption, less accuracy
-aimed: ROF is reduced, but accuracy is improved...conserves ammo
3) Maneuvers; (takes different parameters depending on the suborder)
-formation: only available for OU''s (not base units), puts it into a grou formations such as wedge, line, skirmish, etc
**this can be extended for various container classes...ie, a company may have one group of formations, while a brigade may have a different one
-wheel: pivots the OU formation around a central point, good for attacking flanks or protecting them
-feint: combination of attack and move, units fake an attack to provoke a reaction
-bounding guard: Unit will retreat but fall back in order leapfrogging
4)Hold;
-static guard (no pun intended): unit will hunker down and find best possible defensive positions. Unit will
-opportunity hold: Unit is on the lookout and will fire on targets within a designated range/position/threat level etc.
-passive hold: unit is not expecting attack and is resting/refitting. Units in this mode automatically resupply if within range of
5)Organize;
-rally: a rally is an attempt by the leaders to improve the morale of a unit
-regroup: certain terrain conditions or results of attacks can cause units or OU''s to lose their Unit Integrity, or fall out of formation. This will ty to form the group up (may be redundant to -form)
-resupply:
6)Communicate;
-call support: depending on availability, can call for artillery, air support, ortillery, etc.
-evac: call for craft to extract troops
-medevac: call for medical teams to extract wounded
I think there are three methods to do orders. The first is just making different function calls for the orders that take as parameters information the Unit passes to it. The second is you create an Order class that both holds what you want to do (i.e. move, shoot, hold, communicate), and how do to it. When the player selects an officer and tells him which unit to attack, the player is essentially putting data into the order saying: pUnit->Attack(Target* pTarget, pOrder->getAttackVariables)...where the parameters are taken from the players selection of the orders in the GUI and on the map (i.e. the getAttackVariables function returns the attack modifers like how damaging, how much consumables are used, how accurate the attack is, etc.)
The other idea is a bit more tricky. What if instead you did something like define the "roles" the unit is supposed to "play"? For example, I could define a unit as aggressive or stealthy? In other words, one of the objects variables will be temporary definitions of how the unit should behave. The behavior''s could themselves be classes that defined certain characteristics. Now, how I could have behavior''s influence the function calls is beyond me....and is part of the question.
If I can, I''ll try to put up some code later...I''m sure it''ll be all wrong, but at least maybe someone will get the grasp of what I''m trying to do I realize what I''m describing here is pretty diffucult to conceptualize with my poor grasp of programming. So I''ll try to put up some pseudo-code later.
The world has achieved brilliance without wisdom, power without conscience. Ours is a world of nuclear giants and ethical infants. We know more about war than we know about peace, more about killing than we know about living. We have grasped the mystery of the atom and rejected the Sermon on the Mount." - General Omar Bradley
don't get carried away with variety and complexity. Most players prefer simple interfaces with just a few choices per action. At least that's what I heard.
What you describe is good for a turn based strategy game, where player can take lots of time to decide his move so he can afford to examine and choose all the options available for each action.
[edited by - berserk on September 27, 2002 12:35:21 PM]
What you describe is good for a turn based strategy game, where player can take lots of time to decide his move so he can afford to examine and choose all the options available for each action.
[edited by - berserk on September 27, 2002 12:35:21 PM]
September 27, 2002 11:42 AM
forgotten my name/password. anyway
I''d go for a virtual order class that you can subclass individual orders from. I reckon that''d make it easiest to add different orders, and would also surely let you do handy things like pass arrays of Order*s nice and simply. How to carry out the order should be part of the order.
Basically, your second solution. Different types of orders probably shouldn''t be totally unrelated classes, though.
I''d go for a virtual order class that you can subclass individual orders from. I reckon that''d make it easiest to add different orders, and would also surely let you do handy things like pass arrays of Order*s nice and simply. How to carry out the order should be part of the order.
Basically, your second solution. Different types of orders probably shouldn''t be totally unrelated classes, though.
I''d go for making the orders a set of generic algorithms, deducing their template parameter from invocation at compile time. This would allow you to add new types that can receive orders and not have to write a single line of code.
This requires care, however. Templates like I describe depend on their parameters conforming to concepts - abstract definitions of type and interface. For example, many of the C++ STL algorithms require various types of iterators, and some implementations use shorthand like _It (iterator) or _InIt (input iterator) to indicate this in the code. The problem is ensuring that the value used to instantiate a template conforms to the concept - concept checking. STLPort, IIRC, has a number of macros for check concepts, and this has become a pretty hot topic.
Alternatively, you make define an abstract base class that declares an interface (ie, no data members) for all orderable objects and implement the order methods there. The advantage of the generic approach over the inheritance one is that new orders can be added and applied to all Orderable concept-compliant structures easily (you only implement the new order algorithm), while addition of a new virtual function means recompiling all derived classes as well as writing any necessary specializations.
A sample generic approach:
I could take this a step further and define a concept for oder_issuer objects, so the orderable object can prioritize its existing orders (or generate a response) on the basis of rank/importance of the issuer of the order. The orderable object could even flat out refuse to comply, or violate military "seniority" rules on the basis of tactical significance:
deactivate suspends execution of orders, and causes any new orders to be placed on a temporary internal stack.
setOrderSource attempts to inserts a new order object into the priority queue, with the specified source entity indicated in the order. The priority is weighted to ensure this element stays at the top, even though it has no associated actions. If the orderable object is deactivated, this new order goes on the stack. If any pending orders (between deactivate-activate pairs) exist that do not have associated order sources, the source object is assigned to the topmost (most recent) order.
setDestinationCoordinate inserts a new order object into the priority queue with the specified coordinate position (orders only need to maintain a single coordinate, since current position is implicit. multi-stage movement is implemented as a sequence of orders, where the order priority is carefully biased to ensure the orders remain in sequence). If any pending orders (between deactivate-activate pairs) exist that do not have associated coordinate positions, the specified coordinate is assigned to the topmost (most recent) order.
You can probably infer how setDestinationDeadline works.
This requires care, however. Templates like I describe depend on their parameters conforming to concepts - abstract definitions of type and interface. For example, many of the C++ STL algorithms require various types of iterators, and some implementations use shorthand like _It (iterator) or _InIt (input iterator) to indicate this in the code. The problem is ensuring that the value used to instantiate a template conforms to the concept - concept checking. STLPort, IIRC, has a number of macros for check concepts, and this has become a pretty hot topic.
Alternatively, you make define an abstract base class that declares an interface (ie, no data members) for all orderable objects and implement the order methods there. The advantage of the generic approach over the inheritance one is that new orders can be added and applied to all Orderable concept-compliant structures easily (you only implement the new order algorithm), while addition of a new virtual function means recompiling all derived classes as well as writing any necessary specializations.
A sample generic approach:
template < typename orderable >void move( orderable & obj, const coordinate & c, const time_offset & t ){ obj.deactivate(); // suspend execution of any current orders obj.setDestinationCoordinate( c ); obj.setDestinationDeadline( t ); obj.activate(); // resume order execution} // an example orderable classclass Unit{public: void activate( void ); void deactivate( void ); void setDestinationCoordinate( const coordinate & c ); void setDestinationDeadline( const time_offset & t ); // other stuff};
I could take this a step further and define a concept for oder_issuer objects, so the orderable object can prioritize its existing orders (or generate a response) on the basis of rank/importance of the issuer of the order. The orderable object could even flat out refuse to comply, or violate military "seniority" rules on the basis of tactical significance:
// first, modify the move() method to include the originator of the ordertemplate < typename order_issuer, typename orderable >void move( order_issuer & ofc, orderable & inf, const coordinate & c, const time_offset & t ){ inf.deactivate(); // suspend execution of any current orders inf.setOrderSource( ofc ); inf.setDestinationCoordinate( c ); inf.setDestinationDeadline( t ); inf.activate(); // resume order execution} // refine orderable class example#include <queue>// note the implict concretization of setOrderSource() to only accept one type of valid input,// even though the function is accessed generically in move()class Unit{public: void activate( void ); void deactivate( void ); void setDestinationCoordinate( const coordinate & c ); void setDestinationDeadline( const time_offset & t ); void setOrderSource( const Unit & src ); // Unit can only accept order from another unit private: // order_comp is a custom comparator that evaluates which order is most critical // based on several factors std::priority_queue< orders, std::list<orders>, order_comp > // other stuff};
deactivate suspends execution of orders, and causes any new orders to be placed on a temporary internal stack.
setOrderSource attempts to inserts a new order object into the priority queue, with the specified source entity indicated in the order. The priority is weighted to ensure this element stays at the top, even though it has no associated actions. If the orderable object is deactivated, this new order goes on the stack. If any pending orders (between deactivate-activate pairs) exist that do not have associated order sources, the source object is assigned to the topmost (most recent) order.
setDestinationCoordinate inserts a new order object into the priority queue with the specified coordinate position (orders only need to maintain a single coordinate, since current position is implicit. multi-stage movement is implemented as a sequence of orders, where the order priority is carefully biased to ensure the orders remain in sequence). If any pending orders (between deactivate-activate pairs) exist that do not have associated coordinate positions, the specified coordinate is assigned to the topmost (most recent) order.
You can probably infer how setDestinationDeadline works.
Oluseyi-
I''m really going to have to study up on Templates. I started going over them in the two C++ books I have, but so far they aren''t really sinking in. I understand that templates allow you to essentially create functions that work on any data type, but other than that templates are a mystery to me. I''m going to go over them today at work so I can hopefully comment on your suggestion.
I''ve really only had a chance to skim over them though after you suggested templates as a way to go through the container classes to hold my Organized Unit structures. Ohh, and thanks for the tip on the N-ary trees as a way for the officer hierarchy to work. That''s pretty much exactly how I think I envisioned it to work. Now I just gotta think of a "list" algorithm to search through the data to find which leaf the pointer is pointing to.....yuck.
Berserk-
I plan on having the game be both turn based and real time (and probably my next "how-to" question after this one will be on creating the event loop and game flow logic). Since it will be turn based, this will give players lots of time to think of how they want the units to act.
I''m really going to have to study up on Templates. I started going over them in the two C++ books I have, but so far they aren''t really sinking in. I understand that templates allow you to essentially create functions that work on any data type, but other than that templates are a mystery to me. I''m going to go over them today at work so I can hopefully comment on your suggestion.
I''ve really only had a chance to skim over them though after you suggested templates as a way to go through the container classes to hold my Organized Unit structures. Ohh, and thanks for the tip on the N-ary trees as a way for the officer hierarchy to work. That''s pretty much exactly how I think I envisioned it to work. Now I just gotta think of a "list" algorithm to search through the data to find which leaf the pointer is pointing to.....yuck.
Berserk-
I plan on having the game be both turn based and real time (and probably my next "how-to" question after this one will be on creating the event loop and game flow logic). Since it will be turn based, this will give players lots of time to think of how they want the units to act.
The world has achieved brilliance without wisdom, power without conscience. Ours is a world of nuclear giants and ethical infants. We know more about war than we know about peace, more about killing than we know about living. We have grasped the mystery of the atom and rejected the Sermon on the Mount." - General Omar Bradley
quote: Original post by Dauntless
Now I just gotta think of a "list" algorithm to search through the data to find which leaf the pointer is pointing to.....yuck.
Here''s where the STL really shines. In addition to containers and iterators, it also provides algorithms (thus the earlier proposed name of "CIA"). There''s std::find, std::find_if and std::list::find.
I''m in a hurry, so I''ll get back to this later.
Okay, I"ve been reading up a little more on templates, and I think I''m starting to get it. Essentially templates can create an array or container that works on any type....including user-defined types. So if I create something which is an amalgamation of other classes, but the user can define how he wants those classes to be, you can create a template which uses the user-defined types as the parameters themselves.
I''m going to go back and read up a little more, but I think I see where Oluseyi is heading now.
I''m going to go back and read up a little more, but I think I see where Oluseyi is heading now.
The world has achieved brilliance without wisdom, power without conscience. Ours is a world of nuclear giants and ethical infants. We know more about war than we know about peace, more about killing than we know about living. We have grasped the mystery of the atom and rejected the Sermon on the Mount." - General Omar Bradley
I think templates are overkill for this.
You''ll probably be using subclasses from a generic orderable class, so specializing the template for that one class would provide all the functionality you need, so don''t write the template version and just write the specialization instead. Even if you need different orders for different specific units, it wouldn''t be any effort at all to cast that to the derived unit class and do whatever is necessary. (Make sure to check to make sure your unit really is that type, though)
What kind of human-computer interface are you using for this? Is that all at the AI level?
You''ll probably be using subclasses from a generic orderable class, so specializing the template for that one class would provide all the functionality you need, so don''t write the template version and just write the specialization instead. Even if you need different orders for different specific units, it wouldn''t be any effort at all to cast that to the derived unit class and do whatever is necessary. (Make sure to check to make sure your unit really is that type, though)
What kind of human-computer interface are you using for this? Is that all at the AI level?
---New infokeeps brain running;must gas up!
quote: Original post by Flarelocke
I think templates are overkill for this.
Probably. On the other hand, templates can reduce development time and increase development efficiency in that there are fewer locations where code must be reviewed to incorporate a new feature.
Here''s the core argument for templates vs inheritance: if the exact type of the object being operated on is deduced at runtime, then using a template is smarter because it incurs no runtime overhead (polymorphic method invokation is not free). If the type is not known, however, then inheritance becomes the only solution since templates must be concretely instantiated. This only addresses either-or situations, since some problems are better solved using a combination of both techniques.
If we have an object type hierarchy (objects that can receive orders may inherit from one base class Orderable for example), any time we add a new order we need to ensure that all classes are in sync - any necessitated special processing must be added to each class'' override. If we go the template route, we can place all the specializations in one place - inside the template algorithm - which means less maintenance. Of course, careful design could make this easier to achieve using inheritance, for example by providing all the functionality in a derived-type-agnostic fashion in the (abstract) base class.
quote: Of course, careful design could make this easier to achieve using inheritance, for example by providing all the functionality in a derived-type-agnostic fashion in the (abstract) base class.This is the whole point of inheritance in general.
The design need not be that difficult. How hard is it to conceive of a moveable class, or an armed class? They''ll probably end up being in the design anyway.
I don''t think that development time is a consideration here because he doesn''t know templates yet, which is bound to increase development time substantially
I''m a bit confused by the code you posted. By using a priority queue of orders, you seem to indicate that the order is a class, but by the example order(move), you seem to indicate that the order is simply a function call. I think that an order class would be most natural for the use he needs(orders need to be carried around). In which case an order template would be even more unwieldy.
I don''t know anything about the runtime costs of polymorphism, so I can''t downplay their significance
---New infokeeps brain running;must gas up!
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement
Recommended Tutorials
Advertisement