2016-02-16 3 views
4

Я разрабатываю очень маленький и простой игровой движок в C++. У меня есть класс Существа и класс Оружия. Существо должно знать, какое оружие (и) оно имеет, и каждое Оружие должно знать Существо, которое имеет это. Основная причина, по которой я хотел бы, чтобы Оружие знало, что это за Существо, - это предотвратить его уничтожение своего собственного Существа (когда Оружие атакует, обнаружит все Существа, с которыми он сталкивается, и убьет их, кроме Существа, у которого есть Оружие).Два объекта, которые должны ссылаться друг на друга. Плохая идея?

Вот что (упрощенный) класс Существо выглядит следующим образом:

class Creature { 
    private: 
    Weapon* weapon_; 
    public: 
    void SetWeapon(Weapon* w){ 
     // do some other stuff (e.g. remove Weapon from any other Creatures) 
     weapon_ = w; 
     w->creature_ = this; 
    } 
} 

Вот что (упрощенный) класс оружия выглядит следующим образом:

class Weapon{ 
    friend class Creature; // Creature needs access to creature_ pointer 
    private: 
    creature_; 
} 

Как вы можете видеть, я сделал Создайте класс друзей класса Weapon, чтобы метод setWeapon() Существа мог правильно установить указатель частного существа_.

Моих конкретные вопросы:

  1. Я слышал, что два объекта привязка друг к другу плохой дизайн. Но в моем случае, как бы я этого не делал? Я действительно «чувствую», что каждое Существо должно знать, какое Оружие оно имеет, и каждое Оружие должно знать, что есть у этого существа (чтобы оно не повредило это Существо). Есть ли способ достичь того, чего я хочу БЕЗ, если эти два класса свяжутся друг с другом? Я столкнулся с этой ОДНОЙ проблемой снова и снова в своем игровом движке с помощью Map/Entity, Inventory/Item и т. Д. Кажется, что всякий раз, когда у меня есть класс «Container» и класс «Item», эта проблема ссылок снова появляется. Я хочу возложить ответственность за добавление элемента только в ОДИН из классов, но я хочу, чтобы классы BOTH знали друг о друге (т. Е. Я хочу, чтобы Существо узнало свое Оружие и Оружие, чтобы знать его Существо). Есть ли способ достичь этого, если оба пункта ссылаются друг на друга?

  2. Этот дизайн иногда необходим? Или существует общий способ всегда избегать этого, но достичь того же типа функциональности?

  3. Если этот проект действительно необходим для достижения такого типа функциональности, использует класс друга надлежащим образом для его обработки?

Большое вам спасибо. Мне очень интересно узнать, есть ли способ достичь такого типа функциональности, не связывая объекты друг с другом.

+1

Вы считаете, что существа атакуют вместо оружия? Тогда у вас может быть метод attack(), который знает об оружии и существе, поскольку у существа есть оружие, и существо знает о себе. – Knox

+0

@Knox Я подумал об этом, однако я хочу, чтобы поведение атаки лежало в оружии, а не в существе. Когда существу говорят атаковать(), он должен просто делегировать оружие_.attack(). Это позволило бы существу динамически менять оружие. – MeLikeyCode

+0

Тогда, возможно, метод attack() метода существа вызовет _attack оружия (Entity), таким образом вы можете вызвать _attack() для каждого объекта в пределах диапазона оружия (исключая себя). – Knox

ответ

1

Такого рода проблемы случается время от времени, и быть решен по следующей методике:

class Creature { 
public: 
    void SetWeapon(Weapon* w) { 
     weapon_ = w; 
     weapon_->SetCreature(this); 
    } 
private: 
    Weapon* weapon_; 
}; 

class Weapon { 
public: 
    void SetCreature(Creature* _creature) { 
     m_owner = _creature; 
    } 
private: 
    Creature* m_owner; 
}; 

Как насчет вашего общего вопроса - если вы сталкиваетесь с таким родом проблемы довольно часто в одном проекте, я предложите вам пересмотреть свои дизайнерские решения.
Например, ваше предложение об оружии, чтобы знать его существо, является нелогичным и не кажется правильным. Поэтому начните с этого предположения, и я уверен, что вы получите лучший дизайн, где ваше оружие ничего не узнает о своих владельцах (как в реальной жизни!).

+0

Отличное решение, проблема в том, что теперь я не смог бы изменить то, к чему принадлежит Существо. Вероятно, я должен был упомянуть, что в своем вопросе я продолжу и обновляю его. Спасибо! – MeLikeyCode

+0

@MeLikeyCode вы будете, если вы измените 'Существо & _owner' на' Существо * _owner' –

+0

@MeLikeyCode обновил мой ответ –

0
  1. Вы слышали правильно. Это не хорошая практика программирования, чтобы использовать эталонные объекты таким образом, но затем с использованием goto также считается плохим подходом. Для альтернативного решения см. Ниже.

  2. Этот дизайн может быть использован как иногда требуется goto петля. BU не понравился подход многими.

Альтернативное решение: Основываясь на том, что вам требуется, я могу предложить альтернативный подход, надеюсь, что это помогает. Вместо того, чтобы ссылаться друг на друга в своих соответствующих классах, вы можете создать struct, чтобы разместить как объект игрока, так и объект оружия. Таким образом, будет легче манипулировать и вносить изменения в соответствии с желанием. то есть у игрока может быть много оружия (вы можете создать массив в этом случае в struct). У каждого игрока будет экземпляр связанного с ним оружия.

+0

Интересное решение. Однако у меня также есть класс Map. Это очень интуитивно, чтобы добавить Существа на карту, однако добавление CreatureStruct на карту будет очень неудобно для пользователей моего игрового движка. Тем не менее я рад, что вы это поняли, я сразу не подумал об этом. Спасибо! – MeLikeyCode

0

Очень распространено, что объекты обращаются туда и обратно. Общим примером является указатель на родителя. Ваша концепция вполне разумна. Просто убедитесь, что у вас есть деструктор на месте, чтобы указатели объектов были очищены.

В ~Weapon() снимите указатель Creature с оружием, и наоборот.

+0

А, спасибо за этот ответ. Тот факт, что это общий и разумный, заставляет меня чувствовать себя намного лучше. Благодаря! – MeLikeyCode

Смежные вопросы