Войти
ПрограммированиеФорумОбщее

Организация поведений объектов

#0
22:06, 17 окт 2009

Привет всем!
Есть такая иерархия классов(это уже почти игра):

// Абстрактный класс поведения
class Behaviour
{
public:
   ...
   virtual void Do(GameObject* pObject) = 0;
   ...
};

// Абстрактный класс для игрового объекта
class GameObject
{
public:
   ...
   virtual void Update() = 0;
   ...

protected:
   Behaviour* m_pBehaviour;
};

// Допустим, есть класс Ниндзя :)
class Ninja: public GameObject ...

// А также классы поведений для разных "ниньзь" :)
class RedNinjaBehaviour: public Behaviour ...
class WhiteNinjaBehaviour: public Behaviour ...
class BlackNinjaBehaviour: public Behaviour ...

Каждый раз, переопределяя метод Do(), я пишу следующее:

void Do(GameObject* pObject)
{
   Ninja* pNinja = (Ninja*)pObject; // Провожу преобразование (!!!)

   // а дальше что-то делаем
   ...
}

Мне офигенно не нравится такая идеология из-за того, что приходится каждый раз приводить преобразование в нужный класс. Но это лучшее, что я смог придумать. Вопрос: как можно организовать это все иначе; или (на крайняк) избавиться от преобразования?

Спасибо за осиливание многабукаф

#1
22:23, 17 окт 2009

GameObject владеет Behaviour или нет? Если владеет, то вот такой вариант:
Просто убрать параметр у Do, а GameObject передавать в констукторе Behaviour.

// этот класс определяет какое-то общее не специфичное поведение
class SomeGenericGameObjectBehaviour : public Behaviour
{
protected:
  GameObject* m_gameObject;
public:
  SomeGenericGameObjectBehaviour(GameObject* );
};

// этому поведению обучены только красные ниндзи
class RedNinjaBehaviour : public Behaviour
{
protected:
   Ninja* m_ninja;
public:
   RedNinjaBehaviour(Ninja* );
   
  void Do()
  {
    m_ninja->...
  }
};

потом Ninja сможет управлятся либо RedNinjaBehaviour либо SomeGenericGameObjectBehaviour.

#2
22:43, 17 окт 2009

gexogen
Ух ты, как просто! И переделывать ничего особо не нужно. Спасибо большое :)

#3
23:04, 17 окт 2009

gexogen
Рано обрадовался.
Получается, что я не смогу поиметь две красные ниндзи с одним поведением, поскольку поведение хранит указатель на одного из них. (Или нужно создать два одинаковых поведения, а это как-то не очень...)
Проблема остается...

#4
1:24, 18 окт 2009

but-cher
> Каждый раз, переопределяя метод Do(), я пишу следующее:
> void Do(GameObject* pObject)
> {
> Ninja* pNinja = (Ninja*)pObject; // Провожу преобразование (!!!)
>
> // а дальше что-то делаем
> ...
> }
В паскале можно примерно так, может и в C такое подобное есть:

procedure Do(pObject: GameObject);
var Obj: Ninja absolute pObject;
begin
// а дальше что-то делаем с Obj как с переменной pObject, но уже типа Ninja
end;

Я так понимаю это почти решает твою проблемму, т.е. надо написать всего одну дополнительную строчку, это уже терпимо.

#5
1:26, 18 окт 2009

but-cher
> Получается, что я не смогу поиметь две красные ниндзи с одним поведением

Ninja  n1 , n2;
RedNinjaBehaviour  rnb1(n1) , rnb2(n2);

Нэ?

#6
10:48, 18 окт 2009

louken
Я подозреваю, что в паскале происходит тоже преобразование типов. Если это не так, и это решает проблему в паскале, то, насколько я знаю, в C++ такого нет (кроме уже предложенного).
А написать дополнительную строчку вообще не проблема, лишь бы эта дополнительная строчка не обрабатывалась каждый цикл рендера по несколько сотен раз. Есть мнение, что это экономия на спичках :)

Merrewend
Лучше когда одно поведение на много ниндзей, чем много поведений на много ниндзей... Ты же не загружаешь каждый раз одну и ту же текстуру для новой модели из-за кривой архитектуры?


класс Ninja - это данные; класс Behaviour - это то, что меняет данные заданным образом (вообще все задумывалось для того, чтобы не лезть в потроха каждый раз для добавления нового поведения). Похоже сама парадигма гнилая и нужно думать в другую сторону.

#7
11:56, 18 окт 2009

С-каст дальше static cast не пойдет. да и pNinja если и вообще создастся,то как DWORD в стеке. Не вижу смысла это оптимизировать дальше

#8
12:17, 18 окт 2009

but-cher
> Лучше когда одно поведение на много ниндзей, чем много поведений на много
> ниндзей... Ты же не загружаешь каждый раз одну и ту же текстуру для новой
> модели из-за кривой архитектуры?
Я, если честно, вообще не понимаю чем плох вариант 0-го поста. Даункаст, конечно, не есть гуд, но и не трагедия мирового масштаба. В крайнем случае используй dynamic_cast в дебаге.

ПрограммированиеФорумОбщее

Тема в архиве.