2012-03-07 2 views
0

Как я могу преломлять следующее, чтобы перенести мои функции рисования из h-файла в класс GraphicsManager?Код рефакторинга для компонентов игровых компонентов

//drawingFunctions.h 
void drawTexturedQuad(Texture texture, Vector2 pos, Vector2 dim) { 
    // bind texture... 
    glBegin(...); // draw 
    //... 
    glEnd(...); 
} 

//class file 
#include "drawingFunctions.h" 
class Player { 
    void drawPlayer(){ drawTexturedQuad(texture, pos, dim) } 
}; 
class Enemy { 
    void drawEnemy(){ drawTexturedQuad(texture, pos, dim) } 
}; 
class Item { 
    void drawItem(){ drawTexturedQuad(texture, pos, dim) } 
}; 
// and so on for the other components 

//gameloop file 
// instantiate components objects 
while (true) { 
    // input, logic 
    Player.drawPlayer(); 
    Enemy.drawEnemy(); 
    Item.drawItem(); 
    // and so on 
} 

(код явно упрощена, я просто спрашиваю о розыгрыше здесь)

Должен ли я ...

  • передать указатель на GraphicsManager для каждого вызова drawPlayer, drawEnemy и т. д. изнутри gameloop
  • У игрока, Enemy и т. д. есть указатель на GraphicsManger в качестве члена данных
  • есть игрок, враг и т.д. leGameComponent, который имеет указатель на GraphicsManager в качестве члена данных
  • что-то еще?
+0

Было несколько обсуждений по этой теме на http://gamedev.stackexchange.com. Возможно, стоит посмотреть. – Bart

ответ

1

Это звучит как идеальный вариант использования для наследования:

class Drawable 
{ 
public: 
    void draw() 
    { 
     // gl stuff 
    } 

protected: 
    Texture _texture; 
    Vector2 _pos; 
    Vector2 _dim; 
}; 


class Player : Drawable 
{ 
public: 
    // should modify _texture _pos and _dim somewhere.  
}; 

// same thing for the other objects. 
+0

Что делать, если вы хотите использовать * cough * Direct X или SDL или тестовый рендерер для устранения регрессий? –

+0

@PeterWood: ну, я думаю, это не вопрос. Я не упоминал конструктора в «Drawable», если вам нужно выполнить некоторую инициализацию, вам нечего мешать добавлять. –

+0

@PeterWood Ну, в 'draw()', вероятно, было бы лучше вызвать соответствующий метод рендеринга, а не напрямую придерживаться кода OpenGL. – Ben

0

Я хотел бы пойти на первой же возможности: передавая указатель на GraphicsManager в вызове. Несмотря на то, что это кажется немного переполненным, знание того, какой GraphicsManager используется, поддерживается на более высоком уровне и может быть изменено позже.

Сказав это, я все равно унаследовал бы от интерфейса Drawable и поместил бы элементы, которые нужно нарисовать в контейнере, чтобы вы могли просто прокручивать его, чтобы отображать элементы с помощью виртуальной функции drawItem(). Как и (C++ 03, не тестировался):

std::vector<Drawable*> Items; 
Items.push_back(&player); 
Items.push_back(&enemy); 
... 
for (std::vector<Drawable*>::iterator it = Items.begin(); it != Items.end(): ++it) 
{ 
    (*it)->drawItem(&graphMgr); 
} 
+0

Не могли бы вы более подробно объяснить вторую часть своего ответа, пожалуйста?Я понимаю, что это «виртуальная» часть, в которой я предоставляю (абстрактному) «Drawable» классу 'virtual' member function' drawItem() '. Что я не понимаю, это часть контейнера, или, по крайней мере, как эти два связаны? – Ben

+0

Thx для редактирования. Я думаю, что это отдельный вопрос. На данный момент я фактически использую классы-менеджеры (EnemyManager, ItemManager) для поддержки списков компонентов, а затем итерации по методам рисования элемента списка, когда дело доходит до рендеринга. – Ben

+0

@Ben: Вот почему я написал «Сказав это». Он рассмотрел последовательный вызов различных не виртуальных функций в вашем примере. С примером кода он теперь доминирует над реальным ответом. – stefaanv

1

я передам рендерер к модели, и попросите его нарисовать себя.

class Player 
{ 
public: 
    void draw(Renderer& renderer); 
}; 

class Enemy 
{ 
public: 
    void draw(Renderer& renderer); 
}; 

Примечание Вы не должны назвать функцию drawPlayer или drawEnemy, потому что вы уже знаете, что это Player или Enemy типом класса. Это единое соглашение о вызовах идеально подходит для извлечения в общий интерфейс:

class Model 
{ 
public: 
    virtual void draw(Renderer& renderer) = 0; 

    virtual ~Model() {} 
}; 

Тогда вы можете иметь каждый из ваших моделей наследуют от Model, и каждый реализации draw.

Как я уже упоминал в комментарии к ответу @ J.N., вы также можете быть рендерером абстрактного класса. Например, я работал над проектом, который использовал OpenGL, GDI +, а также для создания распечаток схем.

class Renderer 
{ 
public: 
    virtual render(const Triangle& triangle, const Texture& texture) = 0; 

    virtual ~Renderer() {} 
}; 
+0

Чтобы убедиться, что я правильно понял, ваш 'draw (renderer)' затем будет вызывать 'render (...)', правильно? Кроме того: почему я предпочитаю передавать ссылку на средство визуализации при каждом вызове 'draw (...)' только после того, как он был членом данных в Модели и передал его в конструктор компонентов, полученных из Model? – Ben

+0

Ну, вы можете изменить его во время выполнения, я думаю. Я имел в виду, что «Renderer» будет иметь множество функций для визуализации различных объектов, таких как текст, треугольники, круги, растровые изображения и т. Д. Таким образом, каждая модель будет использовать визуализатор по-разному. Но, снова взглянув на ваш пример, который, по-видимому, ошибочно предполагал, был упрощен, вы вызываете 'drawTexturedQuad' точно так же, как и для каждого из них. Таким образом, нет никакого различия в коде чертежа, как позволяет мой, и, возможно, ответ @ J.N - это все, что вам нужно. –

+0

Вполне возможно, что будет вариант. Так почему ссылка на renderer вместо передачи указателя на конструктор компонента? Я до сих пор не вижу причины? – Ben

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