Чи повинен об’єкт у 2D грі представляти себе?


16

Я роблю 2D вуличну винищувальну гру, яка не заснована на плитці. Зазвичай люди рекомендують, щоб сутності були надані рендерінгу, який робить їх, а не вони самі, але здається, що обернено краще,

Чому один кращий за іншого?

Спасибі


Чому ви вважаєте, що зворотне краще?

1
@Martin, тому що об'єкт натякає, який растровий файл використовувати будь-коли, то чому б просто не зробити object-> render ();
jmasterx

Відповіді:


11

Кілька міркувань:

  • як ви вже згадували, кожен спрайт повинен був би "натякати" про те, яку растрову карту використовувати, але якщо суб'єкт повинен виводити себе. Що це за натяк? Якщо це посилання на інший растровий малюнок, аркуш спрайт тощо тощо для кожного спрайту, ви можете в кінцевому рахунку використовувати більше пам'яті, ніж потрібно, або мати проблеми з керуванням цією пам'яттю. Перевагою окремого рендерінга є те, що у вас є лише один клас, відповідальний за будь-яке управління активами. Однак, у бойовій грі, схожій на SF2, у вас можуть бути лише два спрайти;)

  • як уже згадувалося в іншому місці, коли ви хочете змінити свій графічний API, ви повинні змінити код для всіх своїх спрайтів.

  • візуалізація рідко робиться без посилання на якийсь графічний контекст. Отже, або існує глобальна змінна, яка представляє цю концепцію, або кожен спрайт має інтерфейс з візуалізацією (GraphicalContext ctx). Це поєднує графічний API та логіку вашої гри (яку деякі люди вважають неелегантною) і може спричинити проблеми з компіляцією.

  • Я особисто вважаю, що відокремлення візуалізації від окремих сутностей є цікавим першим кроком у напрямку перегляду вашої гри як системи, яка зовсім не обов'язково потребує графіки. Я маю на увазі те, що коли ви виводите рендерінг, ви усвідомлюєте, що багато ігрових процесів відбувається в "не графічному світі", де важливі координати сутностей, їх внутрішні стани тощо. Це відкриває двері до автоматизованого тестування, більш відокремленої системи тощо ...

Загалом, я, як правило, віддаю перевагу системам, де рендерінг здійснюється окремим класом. Це не означає, що у ваших спрайтів не може бути атрибутів, "графічно пов'язаних" (назва анімації, анімаційний кадр, висота x ширина, ідентифікатор спрайт тощо), якщо це полегшує запис або більш ефективний рендерінг.

І я не знаю, чи застосовуватиметься це до 3D (де поняття сіток та змінної координат, яке ви використовуєте, можливо, буде пов'язане з вашим 3D API; тоді як x, y, h, w майже не залежать від будь-якого 2D API).

Сподіватися, що це допомагає.


11

Ви хочете, щоб система візуалізації контролювала те, що отримується, коли. Якщо замість цього спрайти контролюють рендерінг, ви втрачаєте велику ефективність та гнучкість. Я вважаю, що використання системи візуалізації в контролі призводить до отримання більш чистого коду.

Деякі переваги централізованої візуалізації:

  • z-ordering:
    Якщо самі об’єкти гри відповідають за візуалізацію, вам доведеться передзвонити їх у правильному порядку. В іншому випадку фонові об'єкти можуть бути намальовані над об'єктами переднього плану.
    Коли система візуалізації керує, вона може вибрати сортування всіх об'єктів візуалізації, виявляти перекриття під час візуалізації та просто рендерувати їх, або просто відмовитись від замовлення всіх разом. Справа в тому, що рішення зараз можна легко прийняти.
  • дозування:
    Інша очевидна перевага в тому, щоб система управління візуалізацією була під контролем, - це дозування. Тут знову система візуалізації має можливість вибору пакетного спрайту. Він може використовувати трикутне нарізання, щоб рендерувати все одним закликом. Можливо, це зможе кешувати деякі розрахунки візуалізації. Або це може просто зробити кожен спрайт по черзі з жодним із цих вигадливих речей. (Зауважте: можлива партія, коли кожен об'єкт видає себе, але проблема є менш ефективною та складнішою).

Те, як я реалізую це в своїх іграх, щоб ігрові об’єкти реєстрували потрібні спрайти в системі візуалізації. Коли об’єкт більше не хоче, щоб об'єкт намальовано, він реєструє спрайт або позначає його неактивним.

Все, що говорили. Якщо ваші ігрові об’єкти простіше зробити, всі способи роблять це так. Набагато важливіше досягти прогресу і отримати щось / що-небудь намальоване, ніж це мати досконалу архітектуру.


Про z-упорядкування, якщо об'єкти малюють самі, не може система вирішити питання про порядок викликати їх метод малювання? Я маю на увазі, що централізоване порівняно з нецентралізованим, здається, не має ніякого значення щодо замовлення z.
GorillaApe

3

Відмова: Ваше запитання не містить багато деталей, тому я відповідаю загальним принципом. Вибачте, будь ласка, якщо я неправильно зрозумів ваше використання чи «візуалізацію».

Як правило, я використовую зовнішній об'єкт для відображення різних акторів на сцені як спосіб інкапсуляції властивостей і методів рівня сцени поза окремими "акторськими об'єктами". Об'єкти в сцені повинні містити лише внутрішні методи та властивості; вони повинні знати лише про те, що вони самі є і що роблять. Імовірно, на них впливатимуть інші об’єкти в грі, а також введення користувачів. Це вплине на те, як / чи відображаються вони на екрані. Наприклад, "об’єкт режисера" може, наприклад, перекласти клавішу "w", щоб перейти, а потім сказати об'єкту актора .jump (). Така логіка режисерського рівня також може підказати акторам повністю вийти на сцену або вийти з неї.

Ура, Давид


Але в цьому сенсі режисер не міг просто сказати acton-> setVisible (false); ?
jmasterx

Навіть у випадку setVisible (false) це зовнішня сутність, яка робить рендерінг, перевіряючи видиму змінну актора та надаючи її лише у тому випадку, якщо це правда.
Nav

Просто зробити актора невидимим не знімає його зі сцени. Він також повинен припинити участь у зіткненнях тощо
finnw

3

Що робити, якщо колись ви захочете перенести гру в іншу роздільну здатність (наприклад, iPhone та друзів). Таким чином, глобальна властивість щодо надання змін, як ви легко оновлюєте свій код?


3

Я використовував дизайн, заснований на спостерігачах. Коли я створив екземпляр класу, який хотів рендерувати, тоді вказівник на нього зберігався в центральному класі Renderer. Коли ви телефонуєте RenderFrame(), тоді рендерінг вже має всі існуючі об'єкти, які йому потрібні для візуалізації, і доступ до їх властивостей отримав для цього. Самі заняття не мали поняття, що їх взагалі збирають робити. Цей API був приємним, чистим та простим у використанні.


1
+1 Цікаво. Я використовував цей підхід для звуку, використовуючи шаблон відвідувачів для графіки. Я вважав, що це має більше сенсу для звуку, оскільки, коли графіка та AI працюють на одному годиннику, звуковий мікшер працює на іншому, тому модель події легша. Також не критично, якщо подія руху (що спричиняє зміну пан / реверберації аудіоканалу) наступає на кілька мілісекунд, але це критично, якщо спрайт намальований у неправильному стані.
finnw

2

Загалом, завжди про те, як легко підтримувати і розширювати код. Завтра ви зрозумієте, що графічний API, який ви використовуєте зараз, вам не подобається, і хочете переключитися. Чи доведеться вам зараз пройти всі ваші класи об’єктів і все змінити, чи вам все одно просто потрібно змінити код в одній центральній точці проекту?

Це залежить від того, що справді роблять ваші об'єкти, коли ви викликаєте render (). Поки вони просто обмотують виклики методу навколо вашого графічного движка, це абсолютно добре, оскільки логіка <-> графіки все одно буде надана.

Наприклад, якщо ваші методи render () в основному є зручними методами і виглядають приблизно так:

void MyClass::render(const Graphics &g)
{
    g.draw(this);
}

або

void MyClass::render()
{
   mySprite->render();
}

або

void MyClass::render()
{
    mySprite->UseShader(thatshader);
    mySprite->render();
}

або близько до цього, я не думаю, що це взагалі проблема.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.