1

For example, I have a game, it has 5 enemies which attack once sequentially at each round:

class Enemy{
};

class Game{
public:
    Enemy enemys[5];
};

I want something to indicate which enemy has attacked and which has not, now I have 2 solutions:

1.add a counter "enemyIndex" to indicate which enemy is attacking, after each enemy attacked, the "enemyIndex" counter automatically +1:

class Enemy{
};

class Game{
public:
    int enemyIndex;
    Enemy enemys[5];
};

2.each Enemy object adds a flag "isAttacked", after the enemy attacked, its "isAttacked" flag marked from false to true:

class Enemy{
public:
    bool isAttacked;
};

class Game{
public:
    Enemy enemys[5];
};

which one is more reasonable in terms of design pattern?

1
  • I think this is less about design patterns. The question is more if the simple iteration will work or if for some reason the order of attacking is somewhat random. With the flag you would have still to iterate over them some way and then additionally check for the flag. Which somehow only makes sense if you iterate multiple times? At least one time to reset the flags before you start attacking?. (Also the name 'isAttacked' seems to indicate the the enemy was attacked by somebody else instead of having attacked itself). Basically a simple loop would suffice here unless you left out some info. Oct 2, 2015 at 8:20

4 Answers 4

1

A good approach could be using linked list. It is easy to keep the order, you can add or remove any item (creature) in any place in the linked list.

A demo:

              Last attacked
                |
c1 --> c2  --> c3 --> c4 --> c5 -
 ^                              |
 |------------------------------

Player hits c3 and killed it

c1 --> c2  --x c3 --x c4 --> c5
^                      ^     |
|       | -------------|     |
|----------------------------

Check how is next() after c3

           Current turn
               |
c1 --> c2 --> c4 --> c5
 ^                    |
 |--------------------|

You can also keep extra data in the nodes beyond the link data. You can just follow the next() link to get the next node. Remove or add node any time you want.

1

You're confusing Enemy class, focus of performing anything and everything related to that particular enemy with its representation in the Game class.

The Enemy class should know what it means to attack, but it should not care about effects in other classes if it is not a direct effect of the attack. In other words, an Enemy might need to perform some operation on its target, but it wouldn't need to retain state information related to whether or not it has attacked already.

The caller should know this and should keep track of this, and I assume the caller is the Game class itself. If that is the case, then the solution is simple. Your Game class should hold two lists: one with a list of enemies which have not attacked and another with a list of enemies which have. Create a private method in your Game class that performs the "attack" call for a particular enemy. After the call, you remove it from the list of enemies that have not attacked and you add it to the list of enemies that have attacked.

Operations performed on all enemies would simply require two passes, one for each list.

If Game class doesn't call attack of Enemy, then Enemy will have to require a simple event handling system that allows other objects to listen. Game will then subscribe to the attack event of all its enemy instances. When an attack occurs, it will keep track of which enemies have attacked and which have not using the list system mentioned above.

Consider using the event bus pattern to centralize all events in your program if you feel the need to use many events like this. Have an instance which allows a caller to listen or trigger an event by name. Then you create a name "enemy.attacked" to indicate an event specific to an enemy attacking. Similarly you can do the same for other events.

I hope this helps!

1

You could encapsulate the iteration logic in a Iterator. Then you would call the iterator in the game class, or create a list of enemies that return this iterator.

Game::getAttackIterator() or EnemiesList::getAttackIterator()

This allows you to encapsulate the iteration logic for the attack, for example if you want enemies to be attacked twice sequentially instead of just once, you would simply change the implementation of the iterator.

0

Only enemyIndex fulfills the "which attack once sequentially" criteria.

However, presumably you'll want to vary the attack pattern at some stage. To make this easy to do, I would add unique Ids to each enemy and pass a list of them to an AI class which would contain the attack order logic, creating an order from the Ids, keeping track of who has attacked and causing each to attack in turn.

Try to avoid baking the logic into your data structures.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.