Як поводитися з довільно великими зображеннями у 2D іграх?


13

Питання

Коли у вас є двовимірна гра, яка використовує дійсно великі зображення (більші, ніж може підтримувати ваше обладнання), що ви робите? Можливо, є якесь цікаве рішення цієї проблеми, яке раніше у мене не виникало.

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

Контекст

Добре відомо, що графічні картки встановлюють набір обмежень щодо розміру текстур, якими вони можуть користуватися. Наприклад, працюючи з XNA, ви обмежуєте максимальний розмір текстури 2048 або 4096 пікселів, залежно від того, який профіль ви вибрали.

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

Але подумайте про кілька класичних графічних пригодницьких ігор (наприклад, Monkey Island). Кімнати в графічних пригодницьких іграх зазвичай розроблені в цілому, з невеликими або відсутніми повторюваними ділянками, як художник, що працює над пейзажем. Або, можливо, така гра, як Final Fantasy 7, яка використовує великі попередньо надані фони.

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

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

Якщо ви працюєте з API високого рівня, чи не варто, можливо, бути готовим розібратися з цією ситуацією та зробити розбивання та збірку текстур внутрішньо (як попередній процес, наприклад, контент конвеєра XNA, або під час виконання)?

Редагувати

Ось що я думав, з точки зору впровадження XNA.

Мій 2D двигун вимагає лише дуже невеликого набору функціональності Texture2D. Я фактично можу зменшити його до цього інтерфейсу:

public interface ITexture
{
    int Height { get; }
    int Width { get; }
    void Draw(SpriteBatch spriteBatch, Vector2 position, Rectangle? source, Color  color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects effects, float layerDepth);
}

Єдиний зовнішній метод, який я використовую на Texture2D, це SpriteBatch.Draw (), щоб я міг створити міст між ними, додавши метод розширення:

    public static void Draw(this SpriteBatch spriteBatch, ITexture texture, Vector2 position, Rectangle? sourceRectangle, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects effects, float layerDepth)
    {
        texture.Draw(spriteBatch, position, sourceRectangle, color, rotation, origin, scale, effects, layerDepth);
    }

Це дозволить мені використовувати ITexture незмінно, коли я раніше використовував Texture2D.

Тоді я міг би створити дві різні реалізації ITexture, наприклад, RegularTexture та LargeTexture, де RegularTexture просто оберне звичайний Texture2D.

З іншого боку, LargeTexture зберігатиме список Texture2D, кожен з яких відповідає одному з розбитих фрагментів повного зображення. Найважливіша частина полягає в тому, що викликаючи Draw () на LargeTexture, слід мати змогу застосувати всі перетворення та намалювати всі фрагменти так, ніби вони були лише одним суміжним зображенням.

Нарешті, щоб зробити весь процес прозорим, я створив би уніфікований клас завантажувача текстур, який би виступав як заводський метод. Потрібно взяти шлях текстури як параметр і повернути ITexture, який би був або RegularTexture, або LargeTexture, залежно від розміру зображення, що перевищує обмеження чи ні. Але користувачеві не потрібно було знати, хто це.

Трохи перенасичені чи це звучить нормально?


1
Добре, якщо ви хочете розпочати розбиття зображення, продовжте контент конвеєра, щоб це зробити програмно. Існує не вся функціональність, щоб охопити кожен окремий сценарій, і в якийсь момент вам доведеться розширити його самостійно. Особисте розбиття звучить як найпростіше рішення, оскільки ви можете потім обробляти зображення, схожі на карти плитки, на яких є численні ресурси.
DMan

Робити це на контентному конвеєрі - це найбільш розумний підхід. Але в моєму випадку мені потрібно було завантажувати свої зображення під час виконання, і я вже встиг придумати рішення для виконання (саме тому я вчора задав це питання ). Але справжня краса походить від того, щоб взяти цю «плиткову карту» і змусити її вести себе як нормальну текстуру. Тобто ви все ще можете передати його до spritebatch для малювання, і ви все ще можете вказати положення, обертання, масштаб, src / dest прямокутники і т. Д. Я вже зараз на півдорозі :)
David Gouveia

Але, правду кажучи, я вже в момент, коли мені цікаво, чи все, що насправді того варте, чи я повинен просто показати попередження користувачеві, який каже йому, що максимальний підтримуваний розмір зображення - 2048x2048 і робити це з ним.
Девід Гувейя

Це дуже залежить від дизайну. Якщо ви закінчите проект і не можете прокручувати між кімнатами, то краще буде не готовий редактор, який дозволяє прокручувати великі текстури: D
Aleks

Сховати його в API звучить як приємний спосіб полегшити життя авторів ігор. Я, мабуть, реалізував би це у класах Polygon (спрайт) та Texture, а не в особливих випадках для менших зображень, а просто зробив би їх плиткою розміром 1х1. Тож клас текстури - це група текстур, що описує всі плитки та скільки рядків / стовпців. Потім клас "Полігон" переглядає цю інформацію, щоб розбитись і намалювати кожну плитку відповідною текстурою. Таким чином, він є той же клас. Бонусні бали, якщо ваш клас спрайтів малює лише видимі плитки, а групи текстур не завантажують текстури до необхідності.
uliwitness

Відповіді:


5

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

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

Якщо ви хочете, щоб ці шари мали ефект паралаксації, тоді, коли ви розбиваєте плитку, просто пропустіть один раз все напівпрозоре. Тут потрібно подумати про розмір плитки. Менша плитка додасть керування накладними та зворотними дзвінками, але буде менше даних, коли більші плитки будуть більш сприятливими для GPU, але матимуть велику прозорість.

Якщо у вас немає ефекту паралаксування, то замість того, щоб покривати всю сцену 2-4 гігантськими зображеннями з глибиною 32 біт, ви можете створити лише одну глибину 32 біти. А у вас може бути шар трафарету або глибини, який буде лише 8 біт на піксель.

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

Про те, як це робили класичні ігри. Я не впевнений, що вони, ймовірно, робили схожі трюки, але ви повинні пам’ятати, що на той час на екрані було 320х240 ігри були з 16 кольорами, що при використанні піднебінних текстур дозволяє кодувати 2 пікселі в одному байті. Але так не працює нинішня архітектура: D

Щасти


Дякую, тут дуже багато цікавих ідей! Я фактично бачив техніку шару трафарету, яку раніше застосовували в студії Adventure Game. Щодо моєї заявки, я роблю речі дещо інакше. У номерах не обов'язково є одне фонове зображення. Натомість є палітра зображень, які імпортував користувач, і фон / передній план. Користувач вільний перетягувати шматочки в приміщення, щоб створити його. Тож якби він хотів, він міг би складати його і з менших творів, не створюючи неінтерактивних ігрових об'єктів. Немає жодного паралакса, оскільки є лише ці два шари.
Девід Гувейя

І я переглянув файли даних для Monkey Island Special Edition (рімейк HQ). Кожен фон розділений рівно на 1024x1024 штуки (навіть якщо велика частина зображення не використовується). У будь-якому разі, перевірте мою редакцію на те, що на увазі, щоб зробити весь процес прозорим.
Девід Гувейя

Я б, напевно, вибрав щось більш розумне, наприклад 256x256. Таким чином я не витрачаю ресурси і, якщо згодом вирішуватимуть реалізувати потокове передавання, він завантажує більш розумні шматки. Можливо, я не пояснив це досить добре, але я припустив, що ви можете випікати всі ці маленькі статичні об’єкти гри у велику текстуру. Що ви заощадите, це якщо у вас велика фонова текстура, усі пікселі, покриті статичними об’єктами зверху.
Алекс

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

Мені подобається трафаретний підхід, але якщо я роблю редактор пригодницьких ігор, я, мабуть, не став би його використовувати ... Можливо, тому що, якщо будую такий інструмент, я призначений для розробників ігор. Ну, це є плюси і мінуси. Наприклад, ви можете використовувати інше зображення, на якому біти можуть визначати тригери на піксель, або якщо у вас є анімована вода, ви можете легко їх викреслити. Примітка. Одне дивне незв'язане пропозиція загляньте в діаграми стану / активності UML для вашого сценарію.
Алекс

2

Виріжте їх, щоб вони більше не були довільно великими, як ви кажете. Магії немає. Ці старі 2D ігри або зробили це, або вони були надані в програмному забезпеченні, і в цьому випадку не було апаратних обмежень, що перевищують розмір оперативної пам'яті. Зазначимо, що багато з цих 2D-ігор насправді не мали величезного фону, вони просто прокручували повільно, щоб вони відчували себе величезними.

Що ви хочете зробити у своєму графічному виробнику пригодницьких ігор - це попередньо обробити великі зображення під час певного кроку "складання" чи "інтеграції" перед тим, як гра буде упакована до запуску.

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

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


Робити це в час збирання було б ідеально ... Але мій редактор також використовує XNA для візуалізації, це не лише двигун. Це означає, що після того, як користувач імпортує зображення та перетягне його у приміщення, XNA вже має змогу його відтворити. Отже, моя велика дилема - чи робити розбиття в пам'яті під час завантаження вмісту, чи на диск при імпорті вмісту. Крім того, фізично розділити зображення на кілька файлів означало б, що мені знадобиться спосіб їх зберігання по-різному, тоді як робити це в пам'яті під час виконання не вимагає жодних змін у файлах даних гри.
Девід Гувейя

1

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

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

Час завантаження / виконання: Шлях, який я б пішов про завантаження, просто розрізав його на шматки пропорційного розміру. Отримайте один піксель у правій частині шрифту, якщо це непарна кількість пікселів, хоча ніхто не любить вирізати їх зображення, особливо недосвідчені користувачі, які можуть просто не знати, що це не повністю їм. Зробіть їх наполовину ширини АБО наполовину висоти (або 3др., 4-й, що завгодно), причина не в квадрати чи 4 розділи (2 ряди 2 стовпчики) полягає в тому, що це зробить об'єм пам’яті плиткою менше, оскільки ви не будете турбуватися про х і у в той же час (і залежно від того, скільки зображень настільки великі, це може бути досить важливо)

Перед рукою / Автоматично: У цьому випадку мені подобається ідея дати користувачеві можливість зберігати його в одному зображенні або зберігати його як окремі фрагменти (одне зображення має бути за замовчуванням). Збереження зображення у форматі .gif спрацювало б чудово. Зображення було б в одному файлі, і замість того, щоб кожен кадр був анімацією, він був би більше схожий на стислий архів все того ж зображення (що, по суті, є .gif у будь-якому випадку). Це дозволило б легко перенести фізичний файл, простоту завантаження:

  1. Це єдиний файл
  2. Усі файли мали б майже однакове форматування
  3. Ви можете легко вибрати, коли І, якщо розрізати його на окремі текстури
  4. Доступ до окремих зображень може бути простішим, якщо вони вже є в одному завантаженому файлі .gif, оскільки це не вимагатиме стільки безладу файлів зображень у пам'яті

О, і якщо ви використовуєте .gif метод, ви повинні змінити розширення файлу на щось інше (.gif -> .kittens) задля меншої плутанини, коли ваш .gif анімує, як би зламаний файл. (не турбуйтеся про законність цього, .gif - це відкритий формат)


Привіт і дякую за Ваш коментар! Вибачте, якщо я неправильно зрозумів, але чи не те, що ви написали, стосується в основному стиснення та зберігання? У цьому випадку мене дуже хвилює те, що користувач моєї програми може імпортувати будь-які зображення, а двигун (у XNA) може завантажувати та показувати будь-яке зображення під час виконання . Мені вдалося вирішити це просто, використовуючи GDI для читання різних розділів зображення в окремі XNA Textures і загортання їх у клас, який веде себе як звичайна текстура (тобто підтримує малювання та перетворення в цілому).
Девід Гувейя

Але з цікавості ви могли б детальніше розглянути, за якими критеріями ви використовували для вибору, яка область зображення входила до кожного розділу?
Девід Гувейя

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

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

Роджере, я розібрався з частиною використання фреймів GIF в якості архіву. Але мені також цікаво, чи не GIF - індексований формат з обмеженою палітрою кольорів? Чи можу я просто зберігати цілі Rbb-зображення 32bpp у кожному кадрі? І я думаю, що процес його завантаження закінчується ще складніше, оскільки XNA нічого з цього не підтримує.
Девід Гувейя

0

Це буде здаватися очевидним, але, чому б просто не розділити свою кімнату на більш дрібні шматки? Виберіть довільний розмір, який не нахилить голови проти будь-яких відеокарт (наприклад, 1024x1024 або, можливо, більше) і просто розбийте свої кімнати на кілька частин.

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


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

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