ФРАГМЕНТИ текстура, Спрайт І ПАКЕТИ: приховувала OPENGL ES – РОЗРОБКА ІГОР ДЛЯ ОС ANDROID

&nbsp

До теперішнього часу наш код для прикладу з гарматою включав в себе шаблони, без деяких з них можна обійтися Зокрема, це стосується визначення екземплярів класу Vertices Втомливо постійно писати сім рядків коду тільки для того, щоб визначити один текстурований прямокутник Ще одна область, в якій можна попрацювати, – ручне обчислення текстурних координат для зображень в атласах текстур І нарешті, дуже багато зайвого і повторюваного коду вживається для відображення наших 20-прямокутників Я також згадував про зручний способі відображення декількох обєктів замість виконання отрисовки для кожного обєкта окремо Ми можемо вирішити всі ці проблеми, для чого застосуємо кілька нових концепцій

Фрагменти текстур Ми вже працювали з фрагментами текстур в останньому прикладі Частковий текстури (texture region) – це прямокутна область з одного текстурою (наприклад, область в нашому атласі, що містить гармату) Ми хочемо, щоб у нас був клас, що інкапсулює всі незручні підрахунки перетворення піксельних координат в текстурні

Спрайт Спрайт дуже схожий на будь-який з наших ігрових обєктів У нього є позиція (а також іноді орієнтація і масштаб) і графічні рамки Ми відображаємо спрайт за допомогою прямокутника, так само як і Боба або гармату По суті, графічні представлення Боба та інших обєктів можуть і повинні вважатися спрайтами Спрайт також асоціюється з певним фрагментом в текстурі Ось тут і починається робота з фрагментами текстур Досить спокусливо скомбінувати спрайт безпосередньо з грою, але ми тримаємо їх окремо відповідно до патерном Модель – уявлення – контролер

Це чіткий поділ між графікою і кодом моделі потрібно для краси конструкції

Сортувальники (бетчери) спрайтів Сортувальник спрайтів відповідає за одночасне відображення декількох спрайтів Для цього бетчер спрайтів повинен знати позицію, розмір і фрагмент текстури для кожного спрайту Саме за допомогою бетчера спрайтів ми чарівним чином позбудемося численних викликів отрисовки і матричних операцій для одного обєкта

Ці концепції тісно взаємоповязані переходимо до їх обговорення

Клас TextureRegion

Оскільки ми вже працювали з фрагментами текстур, буде нескладно зясувати, що нам потрібно Ми знаємо, як перетворювати піксельні координати в текстурні Ми хочемо створити клас, де ми будемо визначати піксельні координати зображення в атласі текстур і який буде зберігати текстурні координати для фрагмента атласу для подальших операцій (наприклад, коли ми будемо відображати спрайт) У лістингу 816 показаний клас TextureRegion

Лістинг 816 TextureRegionJava: перетворення піксельних координат в текстурні координати

Клас TextureRegion зберігає текстурні координати верхнього лівого кута (ul vl) і нижнього правого кута (u2 v2) фрагмента в текстурних координатах Конструктор приймає Texture і верхній лівий кут, а також ширину і довжину фрагмента в піксельних координатах Щоб побудувати фрагмент текстури для Cannon, нам треба зробити наступне:

Таким же чином ми можемо побудувати фрагмент для Боба:

Ну і т д Ми можемо використовувати це в коді прикладу, який ми створили, і застосувати члени класу ul, vl, u2, v2 для визначення текстурних координат вершин наших прямокутників Але ми не зробимо цього, поки не позбудемося всіх громіздких визначень Ось для чого ми будемо використовувати бетчери спрайтів

Клас SpriteBatcher

Як ми вже говорили, спрайт легко визначається його позицією, розміром і фрагментом текстури (а також опциональнимі параметрами: орієнтацією і масштабом) Це просто графічний прямокутник в просторі нашого світу Для простоти будемо дотримуватися позначень позиції як центру спрайту й прямокутника, побудованого навколо цього центру Тепер ми можемо отримати клас Sprite і застосувати його таким чином:

Код будуватиме новий спрайт з центром в точці (20 20) в світі з відстанню 0,25 м від центру в кожну сторону, використовуючи bobRegion TextureRegion Але замість цього ми можемо зробити так:

Так вже набагато краще Нам вже не потрібно будувати інший обєкт для представлення графічної боку нашого обєкта Замість цього ми зображуємо копію Боба на вимогу Ми можемо також використовувати такий перевантажений метод:

Він буде малювати гармату, обертову під кутом Як же нам реалізувати бетчер спрайтів І де представники класу Vertices. Давайте подумаємо, як можуть працювати бетчери

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

Бетчер має буфер, який спочатку порожній (або стає порожнім, коли ми сигналізуємо про необхідність очищення) У буфері міститимуться вершини У нашому випадку це буде просто масив змінних типу f1oat – чисел з плаваючою крапкою

Кожен раз, коли ми викликаємо метод SpriteBatcher drawSprite, ми додаємо чотири вершини в буфер, виходячи з положення, розміру, орієнтації і фрагмента текстури, які задаються як аргументи Це також означає, що ми повинні будемо вручну міняти і переводити координати вершин без допомоги OpenGL ES Однак у цьому немає нічого страшного, бо тут нам на допомогу прийде код з нашого класу Vector2 Це ключ до усунення всіх викликів отрисовки

Коли ми визначили всі спрайт, які хочемо відобразити, даємо вказівку нашому бетчеру спрайтів завантажити вершини всіх прямокутників спрайтів в графічний процесор за один раз, а потім викликаємо сам метод малювання OpenGL ES для зображення всіх прямокутників Для цього ми перетворимо вміст масиву з змінними float в екземпляр класу Vertices і використовуємо його для відображення прямокутників

ПРИМІТКА

Ми можемо використовувати тільки спрайт, що знаходяться в одній і тій же текстурі Однак це не велика проблема, оскільки ми будемо застосовувати атласи текстур

Звичайна схема використання бетчера спрайтів виглядає так:

Виклик Spri teBatcher begi nBatch дозволяє повідомити сортувальника дві речі: він повинен очистити буфер і використовувати текстуру, яку ми йому передали Для зручності звяжемо текстуру з цим методом

Далі відображаємо стільки спрайтів, що відносяться до фрагментів в даній текстурі, скільки нам потрібно Це заповнить буфер, оскільки будуть додаватися чотири вершини для кожного спрайту

Виклик SpriteBatcherendBatch повідомить сортувальника спрайтів, що ми вже закінчили відображення групи спрайтів (пакета) і що він повинен завантажити вершини в графічний процесор власне для відображення Ми збираємося використовувати индексированное відображення з екземпляром класу Verti ces, тому нам буде потрібно визначити індекси на додаток до вершин в f1oat-масиві буфера Однак, оскільки ми завжди відображаємо прямокутники, ми можемо один раз заздалегідь згенерувати індекси в конструкторі SpriteBatcher Для цього нам потрібно знати, яку максимальну кількість спрайтів сортувальник може намалювати за один раз Наклавши суворі обмеження на кількість спрайтів, яке можна відображати для однієї групи, ми зможемо уникнути нарощування масивів в інших буферах ми можемо просто один раз розподілити ці масиви і буфери в конструкторі

Базовий механізм досить простий Метод SpriteBatcherdrawSpriteO може здатися дивним, але насправді він досить простий (поки ми не включаємо обертання і масштабування) Нам необхідно розрахувати координати вершин і текстурні координати відповідно з параметрами У попередніх прикладах ми вже робили це вручну, наприклад, коли визначали прямокутники для гармати, ядра і Боба Ми виконаємо приблизно те ж саме в методі SpriteBatcher dravySprite, але тільки автоматично, виходячи з параметрів в методі У лістингу 817 показаний код SpriteBatcher

Лістинг 817 Фрагмент з SpriteBatcherJava без обертання і масштабування

Спочатку розглянемо члени класу Член класу verti cesBuffer є тимчасовим float-масивом, в якому ми зберігаємо вершини спрайтів поточного пакета Член bufferlndex вказує, з якого місця float-масиву ми повинні починати записувати наступні вершини Член verti ces – це екземпляр Vertices, який використовується для відображення пакета Він також зберігає індекси, які ми зараз визначимо Член numSpri tes містить кількість вже намальованих спрайтів в поточному пакеті

Переходячи до конструктора, ми бачимо, що у нас є дві змінні: екземпляр класу GLGraphics, який нам потрібен для створення екземпляра класу Vertices, і максимальна кількість спрайтів, які сортувальник може відображати в одному пакеті Перше, що ми робимо в конструкторі, – створюємо масив змінних f1oat У нас є чотири вершини для кожного спрайту, кожна вершина займає (2 для х-і у-координати і 2 для текстурних координат) Максимум у нас може бути кількість спрайтів, рівне maxSprites, тому для буфера нам знадобиться 4 х 4 х maxSprites float Далі створюємо екземпляр класу Vertices Він потрібен нам для зберігання не більше maxSprites х 4 вершин і maxSprites х 6 індексів Ми також повідомляємо екземпляру класу Vertices, що у нас є не тільки атрибути становища, а й текстурні координати для кожної вершини Далі присвоюємо членам bufferlndex і numSprites значення 0 Потім створюємо індекси для нашого екземпляра класу Vertices Нам потрібно буде зробити це тільки один раз, тому що індекси не змінюватимуться Перший спрайт в групі завжди матиме індекси 0,1, 2, 2,3,0 наступний – 4, 5,6, 6, 7,4 і т д Ми можемо попередньо обчислити їх і зберегти в екземплярі класу Vertices Таким чином ми зможемо встановити їх тільки один раз, замість того, щоб робити це для кожного спрайту

Далі слід метод begi nBatch Він привязує текстуру і повертає в початковий стан члени numSpri tes і bufferlndex, так що вершини першого спрайта будуть вставлені в початок масиву float verti cesBuf fer

Наступний метод – endBatch Ми викликаємо його, щоб фіналізувати і отрісовать поточний пакет Метод спочатку переносить визначені для цього пакета вершини з масиву f 1 oat в екземпляр класу Verti ces Залишилося привязати екземпляр класу Vertices, намалювати numSprites х 2 трикутника і знову відвязати екземпляр класу Vertices Оскільки ми використовуємо индексированное відображення, ми визначаємо кількість застосовуваних індексів, яке дорівнює шести індексам для спрайту, помноженим на numSprites Отже, залишається саме відображення

Наступний метод можна назвати робочою конячкою класу SpriteBatcher Він приймає х-і г /-координати центру спрайта, його ширину і довжину і TextureRegi on, до якого він належить Метод додає чотири вершини в масив змінних f 1 oat, починаючи з поточного buf ferlndex Ці чотири вершини формують текстурний прямокутник Ми підраховуємо позицію нижнього лівого (xl yl) і верхнього правого кутів (х2 у2) і використовуємо ці чотири змінні разом з текстурними координатами з TextureRegi on для побудови вершин Вершини додаються проти годинникової стрілки, починаючи з нижньої лівої вершини Коли вони додані в масив float, збільшуємо лічильник mSprites і чекаємо додавання наступного спрайта або завершення пакета

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

Залишається реалізувати ще метод SpriteBatcherdrawSpriteO, який може малювати обертовий спрайт Потрібно побудувати чотири кутові вершини без додавання позиції, повернути їх навколо початку координат, додати позицію спрайту, щоб вершини були розташовані в просторі ігрового світу, а потім продовжити так, як у попередньому методі отрисовки Ми можемо використовувати для цього Vector2rotate, але тоді виникнуть деякі функціональні витрати Ми, таким чином, відтворюємо код з Vector2 rotate і оптимізуємо його, де це можливо Останній метод SpriteBatcher показаний в лістингу 818

Лістинг 818 Закінчення методу SpriteBatcherjava: малювання обертового спрайта

Ми робимо те ж саме, що і в більш простому методі отрисовки Крім того, будуємо всі чотири кутові вершини замість тільки двох протилежних Це потрібно для обертання Все інше таке ж, як і раніше

А що щодо масштабування Нам явно не потрібен окремий метод, оскільки для масштабування спрайта потрібно отмасштабовані тільки його ширину і довжину Ми можемо зробити це всередині двох методів отрисовки, тому немає потреби створювати ще кілька методів для цього

Отже, це і є той самий великий секрет про те, як відбувається блискавичне відображення спрайтів за допомогою OpenGL ES

Джерело: Mario Zechner / Маріо Цехнер, «Програмування ігор під Android», пров Єгор Сидорович, Євген зазноби, Видавництво «Пітер»

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*