Advertisement

Unit design question

Started by September 23, 2002 10:53 AM
44 comments, last by Dauntless 22 years, 3 months ago
quote: Original post by Doolwind
This class would never be instantiated (you would never call CUnit myUnit = new CUnit() as it is a base class.

Minor correction: You can call new on a base class; you can''t call new on an abstract class, and you make a class abstract by declaring at least one of its methods pure virtual like so:
class X{  virtual void doSomething( /* params */ ) = 0;  ...}; 
quote: Original post by coderx75
Yes, I realize we are in the wrong forum. =b



No, not that. just that you are obviously a designer first and programer second if you want to get your storyline and content done, and then worry about your game engine afterwards.

¬_¬
Advertisement
quote: Flarelocke
Personally, I'd use a tree. In other words, you're the commander-in-chief, so you have pointers to all the top groups(battalions?) underneath you (not necessary for them to know who their peers are because they can just link to you. Perhaps they have a pointer to the commander-in-chief, perhaps not). Those groups underneath the player have pointers to their members, and so on, until they have as members individual units.

Running with this, we first observe that the military is a hierarchical structure. Unless peers are explicitly grouped together, their instructions come only from "above".

Since each commanding unit may have a variable number of subordinate units under it, you want to have an N-ary tree of hierarchy, where N varies at each node. Solution? (Linked) list.
class CommandingUnit : public Unit{public:  ... private:  std::list< Unit * > subordinates;  ...};  


This eliminates the need to program explicit "unit holder" and "unit holder-holder" classes, as well as allows for infinite hierarchy with variable with (leaf count) at the nodes, meaning completely configurable organizational structure.

quote: Dauntless
As for [coderx75's] suggestions, on question #3, I was sort of thinking of your idea of containing all the units into one container class, but I had two problems. One was that I wasn't quite sure how to group together units that belonged to the same Organizational Unit (actually I borrowed this term from M$ terminology for creating active directory objects...you have forests, trees, organizational units, etc in which to group units based on a common theme). I didn't really think of the Unit ID thing though. But I like your idea of linked lists better....like you say, it should cut down on search time. The only trouble there is....can you make linked lists grow? I know arrays are of fixed size, and I couldn't remember if you could insert nodes into linked lists...the reason that would be necessary is in case you decide to reinforce an Organized Unit, and of course by adding units during the game.

Choice of data structures is normally predicated by access and insert times. Access time is how long it takes you to get to a particular element. For a (singly- or doubly-) linked list, the access time is a function of the offset of the desired node from the current location (usually assumed to be the top or head of the list), and is therefore a function of the number of objects in the list, n. We therefore classify list access as being of O(n) (Big-O is an upper bound on running time in terms of number of discrete operations). Access time for an array is constant, since all you need is the array element index. We denote constant time operations as O(1).

Insert time is how long it takes to add a new element to the data structure at an arbitrary but known location. For a linked list, insertion is O(1) (set the exisiting "next" node as the "next" node of the node to be inserted, and the "previous" node of the "next" node - if doubly-linked - to be the new node as well; then set the "previous" node of the new node to be the current node, and the "next" node of the current node to be the new node) as the same number of steps are always performed irrespective of node position. For an array, insertion requires the allocation of new memory large enough to hold the grown array (in practice this cost is mitigated for dynamic array structures by maintaining some "growing room"), copying over of data up to the location of the element to be inserted, insertion of the new element, and then the copying over of elements from the insertion position in the original array on to the end of the original array. It is clear that the number of operations required is a function of the number of elements in the array, thus making array insertion a O(n) operation.

The C++ STL provides std::list and std::vector among many other facilities, and both are dynamic structures that can be grown and shrunk at runtime (meaning you can insert data into vectors as well as lists, but be aware of the costs and factor them into your algorithms). Basically, all this background is to reinforce the position that linked lists are ideal for your Organizational Units because you can rapidly insert and remove nodes (units) while maintaining decent search times. If search happens very frequently, you can set up a vector of pointers to specific nodes that is refreshed whenever the list changes (so list element access becomes O(1) rather than O(n), but that's an optimzation topic.

quote: Dauntless
As for question #2, why would a scripting engine be diffucult?

A true scripting engine isn't trivial. However, a solution that you can use immediately is custom initialization files. Essentially, your users/designers can specify and tweak unit attributes in simple text files (as coderx75 mentioned earlier) and those values are loaded into the game to define all objects. You could also allow them to define organizational structure and object aliases in these configuration files, sorta like so:

    # interpret lines starting with hashes as comments, skip over them in code #example type definition; Platoon is type label# syntax is "object count id_0, id_1, ... id_count" where count is optional (default count is 1)[type Platoon]Tank RockerInfantry 20 TroopsRadio 2 Comms1, Comms2[end type] [type Company]Platoon 2 A, B[end type] [type Brigade]Company 4 Alpha Company, Beta Company, Charlie Company, Delta Company[end type]    

My military teminology is obviously shot, but suffices to illustrate the point. This way you can tweak and play balance without having to recompile the engine unless there are structural defects. I think this was exactly what coderx75 was espousing earlier on.

Pause for digestion, and to peruse other comments at even greater length.

[Edit: scripting syntax error]

[edited by - Oluseyi on September 25, 2002 4:12:09 PM]
I'd probably use a vector, rather than a list. Access times are shorter, and, depending on the mechanics of your game, you'll most likely access the hierarchy(think of the AI) much more than adding or removing units. Oluseyi has more experience than I do, though, so listen to him. I haven't even finished my first game yet.

The problem, Oluseyi, is that Unit* can't typesafely point to another container, unless you're using a different terminology than me. So I'd have:
class subordinate{  protected:    int id; //0 means container, 1 means unit};class unit : public subordinate{// ...};class container : public subordinate{  vector<subordinate*> subordinates;};unit::unit(){  id = 1;}container::container(){  id = 0;}  


As far as unit, unit-holder, and unit-holder-holder, I was just walking Dauntless through the thought processes to the above class hierarchy.

I still don't really see the need for a scripting engine at the moment, but you could always embed Python into your game.

[Edit: Use '&lt;' to represent '<' when writing template code between [code] tags. The forum inteprets it as invalid HTML otherwise.]

[edited by - Oluseyi on September 25, 2002 4:45:40 PM]
---New infokeeps brain running;must gas up!
quote: Original post by Flarelocke
The problem, Oluseyi, is that Unit* can''t typesafely point to another container, unless you''re using a different terminology than me.

I''m not using different terminology; the difference is that my CommandUnit (container) class derives from Unit, meaning that a pointer to Unit can also be a pointer to CommandUnit. So a std::list<Unit *> can contain pointers to actual Unit objects (if the Unit class is concrete (non-abstract)) or any of its derivatives, including CommandUnit.
quote: Original post by Dauntless
I''d just like to thank everyone for all their help and comments, I really appreciate it. So to Oluseyi, Flarelocke, Coderx75, Doolwind, Sandman, RolandofGilead and anyone else, thanks for all the help.

Your welcome! =)
quote: Original post by Oluseyi
This way you can tweak and play balance without having to recompile the engine unless there are structural defects. I think this was exactly what coderx75 was espousing earlier on.

Yes, I avoid hardcoding any game data. Once the data is loaded, I usually provide a means to change the data on-the-fly. Balancing is probably the most crucial part of designing a game (IMO). Whatever tools you can create to assist in this aspect of development, are worth the effort. I can''t stress this enough.

---------

I was thinking about Dauntless'' hierarchical structure and came up with an idea for a binary tree that would allow for an unlimited command hierarchy.

Each unit could hold two pointers. One points to the first of the units they command. We''ll call this pCommand. The second, points to the next unit that is being command by the same unit. We''ll call this one pCommandNext. To make this clearer, if one unit commands 10 other units, his pCommand points to the first of his units. The first units'' pCommandNext points to the next one that the commanding unit commands, and so on until we have a list of all ten units. Now, if I put unit #3 in charge of 5 units of his own, #3''s pCommand will point to the first of the 5. There are an unlimited number of units that each unit can command and there are unlimited levels of command.

- Jay

There''s an old saying in Tennessee... well, it''s in Texas but probably in Tennessee too. It say''s, "Fool me once, shame on... shame on you... uh... ya fooled meh uh can''t get fooled again."
- George W. Bush


Get Tranced!
Quit screwin' around! - Brock Samson

This topic is closed to new replies.

Advertisement