ВЕЛИКИЙ стрибуни: двомірний ГРА, НАПИСАНА З ДОПОМОГОЮ OPENGL ES – РОЗРОБКА ІГОР ДЛЯ ОС ANDROID

&nbsp

Прийшов час використовувати все, що ви дізналися, для того, щоб написати гру

Однак для нашої наступної гри я вирішив вибрати що-небудь більш просте Ми реалізуємо гру в жанрі стрибунець (jump-em-up), подібну іграм Abduction або Doodle Jump Як і у випадку з грою Містер Ном, ми почнемо з визначення ігрової механіки

ОСНОВНА ігрова механіка

Я пропоную вам встановити гру Abduction на ваш телефон з ОС Android або переглянути відеоролики про цю гру в Інтернеті З цього прикладу ми можемо почерпнути основну ігрову механіку нашої гри, яка називатиметься Великий стрибун Ось деякі деталі

Персонаж постійно стрибає вгору, пересуваючись з платформи на платформу Ігровий світ простягається по вертикалі на безліч екранів

Горизонтальним пересуванням персонажа можна управляти, нахиляючи телефон вліво або вправо

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

Платформи можуть бути як нерухомі, так і переміщаються по горизонталі

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

На своєму шляху персонаж може збирати предмети для того, щоб заробляти очки

Крім монет персонажу можуть зустрітися пружини або платформи, що дозволяють йому стрибати вище

Ігровий світ також населяють і негативні персонажі, які пересуваються по горизонталі Якщо персонаж зачепить одного з них, то він помре і гра закінчиться

Гра також закінчується, коли персонаж падає за нижню межу екрану

На вершині рівня знаходиться яка-небудь мета Коли персонаж досягає її, починається новий рівень

Хоча цей список і довше, ніж той, який ми створили для гри Містер Ном, він не здається більш складним На рис 91 показаний початковий макет ігрових принципів Цього разу для створення макета я використовував програму PaintNET Давайте тепер придумаємо сюжет для гри

Рис 91 Вихідний макет, який містить ігрові механіки на ньому показані персонаж, платформи, монети, негативні персонажі і мета, розташована у верхній частині рівня

ПЕРЕДІСТОРІЯ І СТИЛЬ

Ми збираємося використовувати всю нашу креативність і створити унікальний сюжет для гри

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

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

Така історія є класичною для відеоігор, і для її оформлення відмінно підійде восьмібітного графіка, зразки якої можна зустріти в оригінальній грі Супер Маріо Макет, зображений на рис 91, містить підсумковий варіант графіки всіх елементів гри Боб, монети, білки і розсипаються платформи, звичайно ж, будуть анімованими Ми також використовуємо музику і звукові ефекти, які підходять нашому графічного стилю

ЕКРАНИ І ПЕРЕХОДИ

Тепер ми можемо визначити екрани гри і переходи між ними Опишемо їх тим же способом, який використовувався для екранів гри Містер Ном

У нас буде основний екран з логотипом пункти меню PLAY (Грати), HIGHSCORES (Рекорди), і HELP (Допомога) а також кнопка, що дозволяє включити або виключити звук

Крім того, у нас буде основний екран гри, в якому користувачеві буде здаватися питання про те, чи готовий він грати, а також, відповідно, обробляти стану виконання гри, паузи, закінчення гри і переходу на новий рівень Відмінність від гри Містер Ном тільки одне – стан переходу на новий рівень, в яке перемикається гра в момент, коли Боб потрапляє в замок У цьому випадку генерується новий рівень, і Боб знову починає свій шлях з самого низу світу, при цьому зберігаючи набрані очки

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

Нарешті, в грі буде також екран допомоги, на якому буде розміщена інформація про ігрові механіках і мети гри Крім того, ми розмістимо там опис способу управління персонажем Сучасні діти не стикаються зі складнощами, з якими стикалися в 1980-х і ранніх 1990-х роках ми, коли гри не підказували гравцям про те, як в них грати

Цей список більш-менш схожий на той, який ми створили для гри Містер Ном На рис 92 показані всі екрани гри, а також переходи між ними Зверніть увагу, на основному екрані гри і його подекранах немає ніяких кнопок, крім кнопки Пауза Користувачі будуть інтуїтивно чіпати екран, коли їм поставлять запитання про їх готовність почати гру

Рис 92 Всі екрани ігри Великий стрибун і переходи між ними

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

ВИЗНАЧЕННЯ ІГРОВОГО СВІТУ

Ми знову зіткнулися з класичною проблемою що було раніше, курка чи яйце. З попередньої глави ви дізналися, що існує відповідність між одиницями вимірювання ігрового світу (наприклад, метрами) і пікселями Обєкти фізично визначені в просторі світу Обмежують їх фігури і позиції використовують як одиниці виміру метри, швидкості вимірюються в метрах в секунду Графічне представлення обєктів визначається в пікселах, тому нам доведеться встановити деякий відповідність між ними і метрами Цю проблему можливо обійти, якщо спочатку визначити дозвіл використовуваних графічних ресурсів Як і у випадку з грою Містер Ном, ми використовуємо дозвіл 320 х 480 пікселів (співвідношення сторін дорівнює 1,5) Далі необхідно встановити відповідність між пікселями і метрами нашого світу Макет, зображений на рис 91, дозволяє отримати уявлення про те, скільки місця займають різні обєкти, а також їх пропорції відносно один одного Зазвичай для двомірних ігор я використовую наступний масштаб – 32 пікселя на один метр Давайте тепер накладемо на екран, чиї розміри складають 320 х 480 пікселів, сітку, кожна клітина якої має розміри 32 х 32 пікселя На рис 93 показаний макет з накладеною сіткою

Рис 93 Макет, на який накладено сітка кожна клітина має розмір 32 х 32 пікселя і відповідає площі ігрового світу розміром 1 х 1 м

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

Отже, що можна дізнатися з рис 93 Насамперед стало можливо безпосередньо визначити розміри кожного обєкта ігрового світу в метрах Наступні значення можна використовувати для створення обмежують прямокутників ігрових обєктів

Боб має розміри 0,8 х 0,8 м він не займає цілу клітку

Платформа має розміри 2 х 0,5 м, займаючи дві клітини по горизонталі і половину клітини по вертикалі

Монета має розміри 0,8 х 0,5 м Вона займає практично цілу клітину по вертикалі і половину клітини по горизонталі

Пружина має розміри 0,5 х 0,5 метра, займаючи половину клітини в кожному напрямку Насправді висота пружини дещо більше її ширини Її форма обмежена квадратом для того, щоб було простіше провести тестування зіткнень

Білка має розміри 1 х 0,8 м

Замок – 0,8 х 0,8 м

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

З рис 93 можна також визначити розміри вікна перегляду Гравець зможе побачити область ігрового світу площею 10 х 15 м

Єдине, що залишилося визначити, – це швидкості і прискорення, які будуть використані в грі Це зробить значний вплив на ігровий процес Зазвичай слід провести декілька експериментів для того, щоб визначити їх вірні значення Розглянемо ті значення, до яких я прийшов після декількох етапів тестування

Вектор прискорення, створюваний гравітацією, дорівнює (0, -13) м/с2, що дещо більше, ніж гравітація на планеті Земля, а також значення, використаного нами в прикладі з гарматою

Вихідний вектор швидкості стрибка Боба дорівнює (0,11) м / с Зверніть увагу на те, що цей вектор впливає лише на пересування по вертикалі Горизонтальне пересування визначатиметься згідно з даними, отриманим від акселерометра

Вектор швидкості стрибка Боба буде збільшуватися в 1,5 рази, коли він зачепить пружину Він буде дорівнює (0 16,5) м / с Знову ж, це значення отримано лише експериментальним шляхом

Швидкість пересування Боба по горизонталі дорівнює 20 м / с Зверніть увагу на те, що вона не має напрямку, тобто не є вектором Далі я поясню, як саме використовувати дані, отримані від акселерометра

Білки патрулюватимуть простір зліва направо і навпаки У них буде постійна швидкість пересування, рівна 3 м / с Якщо виразити її вектором, то вона дорівнюватиме (-3,0) м / с, коли білка рухається вліво, і (3,0) м / с, коли білка рухається вправо

Так як же Боб буде переміщатися по горизонталі Швидкість пересування по горизонталі, яку ми визначили раніше, насправді є максимальною швидкістю пересування по горизонталі Залежно від того, наскільки гравець похилить свій телефон, швидкість переміщення Боба по горизонталі буде змінюватися від 0 (немає нахилу) до 20 м / с (максимальний нахил телефону в одну сторону)

Ми будемо використовувати нахил акселерометра по осі х, оскільки гра буде працювати в портретній орієнтації У той час, коли телефон не нахиляючись, вісь повідомить про прискорення, рівному 0 м/с2 Коли ж телефон максимально нахилений вліво, при цьому виявившись в альбомному режимі, вісь повідомить про прискорення, рівному приблизно -10 м/с2 У разі коли телефон максимально нахилений вправо, вісь повідомить про прискорення, рівному приблизно 10 м/с2 Нам потрібно нормалізувати показання акселерометра, розділивши їх на максимальне абсолютне значення (10), а потім помноживши їх на максимальну швидкість переміщення Боба по горизонталі Тому Боб пересуватиметься вліво або вправо зі швидкістю 20 м / с, коли телефон максимально нахилений в одну зі сторін Швидкість буде зменшуватися зі зменшенням кута нахилу телефону Боб може двічі за секунду перетнути екран, коли телефон максимально нахилений

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

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

Тепер розглянемо ресурси, які нам знадобляться для створення гри

СТВОРЕННЯ РЕСУРСІВ

Наша нова гра буде мати два типи графічних ресурсів: елементи призначеного для користувача інтерфейсу і безпосередньо ігрові елементи (елементи ігрового світу) Почнемо з опису елементів користувальницького інтерфейсу

Елементи користувальницького інтерфейсу

Перше, на що слід звернути увагу, – елементи призначеного для користувача інтерфейсу (кнопки, логотипи і т д) не залежать від перетворення одиниць вимірювання з пікселів в метри, яке було визначено раніше Як і у випадку з грою Містер Ном, слід розробити їх так, щоб вони відповідали конкретному вирішенню – у нашому випадку 320 х 480 пікселів Поглянувши на рис 92 можна визначити, які саме елементи призначеного для користувача інтерфейсу матиме гра

У першу чергу слід створити кнопки, які можуть знадобитися для різних екранів На рис 94 показані всі кнопки, задіяні в грі

Рис 94 Різні кнопки, кожна з яких має розмір 64 х 64 пікселя

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

Ви можете задатися питанням, чому ні стрілки, що показує вправо Памятайте, що за допомогою нашого чудового класу Spri tebatcher можливо легко перевертати картинки, задаючи їм негативні значення ширини і / або висоти

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

Далі розглянемо елементи, які знадобляться на екрані головного меню На ньому розмістяться логотип, пункти меню і фонова картинка Всі ці елементи показані на рис 95

Рис 95 Фонове зображення, пункти головного меню і логотип

Фонове зображення використовується на всіх екранах, а не тільки на екрані головного меню Його розміри в точності збігаються з розмірами цільового дозволу 320 х 480 пікселів Пункти головного меню мають розмір 300 х 110 пікселів Для них був обраний чорний фон, оскільки біле на білому виглядає зовсім не так добре У реальному зображенні фон, звичайно ж, створений з прозорих пікселів Розміри логотипу складають 274 х 142 пікселя, він має кілька прозорих пікселів по кутах

Далі необхідно створити зображення для екранів допомоги Я полінувався і замість того, щоб складати їх з декількох елементів, намалював їх як повноекранні зображення розміром 320 х 480 Це трохи скоротить розмір коду, отрісовиваємих їх, і не додасть занадто багато обсягу нашій програмі Ви можете побачити всі екрани допомоги на рис 92 Єдиний елемент, який ми додамо на ці зображення, – Кнопка зі стрілкою

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

Екран гри має ще кілька текстових елементів користувальницького інтерфейсу, наприклад мітку READY (Готові), Пункти меню, що зявляється, коли гра припинена (RESUME (Продовжити) і QUIT (Вийти)), а також мітку GAME OVER (Гра закінчена) На рис 96 вони показані у всій красі

Рис 96 Мітки READY (Готові), RESUME (Продовжити), QUIT (Вийти) і GAME OVER (Гра закінчена)

Обробка тексту за допомогою растрових шрифтів

Отже, як же слід малювати інші текстові елементи ігрового екрану Ми будемо використовувати прийом, задіяний при створенні гри Містер Ном для отрисовки результатів В даному випадку нам потрібно застосувати набір не тільки чисел, але і символів Використовуємо атлас зображень, в якому кожне під-зображення буде представляти символ (наприклад, О або а) Такий атлас зображень називається растровим шрифтом На рис 97 показаний растровий шрифт, який ми будемо застосовувати

Рис 97 Растровий шрифт

Чорний фон і сітка, показані на рис 97, звичайно, не є частиною зображень, що входять до складу реєстрового шрифту Використання таких шрифтів – дуже старий прийом відтворення тексту на екрані в грі Зазвичай вони складаються з зображень, створених для набору символів ASCII Один такий символ називається гліфом ASCII – це один з Юнікоду Усього в наборі ASCII 128 символів (табл 91)

Таблиця 91 Символи ASCII і їх десяткове, шістнадцяткове і вісімкове подання

З цих 128 символів друкували є лише 96 (вони мають номери з 32-го по 126-й) Наш растровий шрифт складається виключно з друкованих символів Його перший ряд містить з 32-го по 47-й символи, наступний ряд – з 48-го по 63-й і т д Використання ASCII корисно лише в тому випадку, коли необхідно відобразити на екрані текст, що складається з символів стандартного латинського алфавіту Існує розширений формат ASCII, який має символи з номерами з 128-го по 255-й Ці символи використовуються для кодування найбільш часто зустрічаються символів західних мов, наприклад б або е Більш обємні набори символів (наприклад, для китайського чи арабського мов) представляються за допомогою Юникода і не можуть бути закодовані за допомогою ASCII Для нашої гри буде достатньо набору символів ASCII

Як же відобразити текст з використанням растрового шрифту Виявляється, це дуже просто Спочатку слід створити 96 текстурних регіонів, кожен з яких буде вказувати на гліф реєстрового шрифту Ці регіони можливо зберігати в масиві, наприклад, таким чином:

Рядки в мові Java кодуються за допомогою 16-бітного Юникода На щастя для нас, символи ASCII, використані в нашому растровому шрифті мають однакові номери як в ASCII, так і в Юнікод Щоб отримати регіон для символу рядка на мові Java, необхідно зробити лише наступне:

Так ми отримуємо прямий індекс масиву текстурних регіонів Ми просто забираємо номер символу пробілу (32) від порядкового номера поточного символу рядка Якщо індекс менше нуля або більше 95, то можна визначити, що це символ Юнікод, який не входить до наш растровий шрифт Зазвичай слід просто ігнорувати такий символ

Щоб отрісовать декілька символів в рядку, необхідно знати, як багато простору має розділяти ці символи Растровий шрифт, показаний на рис 97, є так званим моноширінним шрифтом Це означає, що кожен гліф має однакову ширину Гліфи нашого реєстрового шрифту мають розмір 16 х 20 пікселів кожний Для переміщення позиції отрисовки від символу до символу нам слід всього лише додати до неї 20 пікселів Кількість пікселів, на яке переміщається позиція отрисовки від символу до символу, називається зміщенням У нашому растровому шрифті воно фіксоване, але в загальному випадку воно є змінною величиною, яка змінюється в залежності від отрісовиваємих символу Більш складна форма розрахунку зміщення бере до уваги як отрісовиваємих в даний момент символ, так і наступний за ним Такий прийом називається кернингом, ви можете дізнатися про нього більше в Інтернеті Ми будемо використовувати лише моноширинних растрові шрифти, оскільки з ними наше завдання значно спрощується

Отже, як я згенерував цей растровий шрифт ASCII Я використав один з багатьох інструментів для генерації атласів текстур, доступних в Мережі Той, що застосував я, називається Bitmap Font Generator Він випущений компанією Codehead і поширюється безкоштовно Ви можете вибрати файл шрифту, що зберігається на вашому компютері, визначити висоту шрифту, і генератор створить зображення, що містить символи набору ASCII Цей інструмент має також і інші можливості, які я не можу обговорити в рамках цієї та Раджу вам ознайомитися з ними самостійно

Всі інші рядки гри ми намалюємо саме таким способом Далі ви побачите конкретну реалізацію класу реєстрового шрифту Розглянемо і інші ресурси

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

Елементи гри

Тепер розглянемо безпосередньо ігрові елементи Всі вони, як говорилося раніше, відповідають нашій пиксельной одиниці виміру Щоб максимально спростити їх створення, я використовував простий прийом – Починав малювання кожного з них з сітки, чиї клітини були розміром 32 х 32 пікселя Всі обєкти розташовувалися в центрі однієї або більше клітин, тому вони з легкістю могли відповідати своїм фізичним розмірами, які вони мають в нашому світі Почнемо з Боба (рис 98)

Рис 98 Пять анімаційних кадрів, що зображують Боба

На рис 98 зображені два кадри, на яких Боб підстрибує, два кадри, на яких він падає, і один кадр, де він мертвий Повний малюнок має розмір 160 х 32 пікселя, а кожна анімація – 32 х 32 пікселя Піксели фонового зображення прозорі

Боб може перебувати в трьох станах: стрибок, падіння і смерть У нас є анімаційні кадри для кожного з цих станів Два кадру стрибка розрізняються лише тим, що на одному у Боба стирчить чуб Ми створимо екземпляр класу Animation для кожної з цих трьох анімацій Боба і будемо використовувати їх для отрисовки персонажа відповідно його поточному стану У нас не буде дублюючих кадрів на той випадок, коли Боб буде рухатися вліво Як і у випадку з кнопкою, яка зображує стрілку, ми просто поставимо негативну ширину кадру при виклику методу SpriteBatcherdrawSpriteO, що переверне зображення Боба по горизонталі

На рис 99 зображена злісна білка Цього разу у нас два анімаційних кадру – білка буде махати крилами

Рис 99 Анімаційні кадри, що зображують злісну літаючу білку

Зображення на рис 99 має розмір 64 х 32 пікселя, а кожен кадр – 32 х 32 пікселя

Анімація монети, показана на рис 910, буде особливою Замість послідовності кадрів 1, 2,3,1 ми використовуємо 1,2,3,2,1 В іншому випадку монета з повністю повернутого стану, зображеного на кадрі 3, відразу перейде в повністю розгорнуте стан, показане на кадрі 1 Ми можемо зберегти трохи памяті, повторно використавши другий кадр

Рис 910 Анімаційні кадри, що зображують монету

Зображення на рис 910 має розмір 96 х 32 пікселя, кожен його кадр – 32 х 32 пікселя

Про пружині, зображеної на рис 911, можна сказати не так вже багато Вона просто спокійно розташовується в центрі зображення

Рис 911 Пружина зображення має розміри 32 х 32 пікселя

Замок, показаний на рис 912, теж не анімований За розмірами він більше, ніж всі інші обєкти (64 х 64 пікселя)

Рис 912 Замок

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

Рис 913 Анімаційні кадри, що зображують платформу

Атлас текстур поспішає на допомогу

Вище були перераховані всі графічні активи, які будуть присутні в нашій грі Ми вже говорили про те, що текстурам необхідні певні значення ширини і висоти Фонове зображення і все екрани допомоги мають розмір 320 х 480 пікселів Ми будемо зберігати їх як зображення розміром 512×512 пікселів, щоб завантажувати їх як текстури Всього виходить 6 текстур

Чи потрібно створювати окремі текстури для кожного іншого зображення Ні Ми створимо єдиний атлас текстур Всі інші елементи відмінно поміщаються в єдиний атлас розміром 512×512 пікселів, який можна завантажити як єдину текстуру – це має дійсно порадувати GPU, адже в такому випадку у нас буде набагато менше текстур На рис 914 показаний наш атлас текстур

Рис 914 Потужний атлас текстур

Зображення на рис 914 має розміри 512×512 пікселів Сітка і кордони не є частиною зображення, а фонові пікселі прозорі Це також вірно і для чорних фонових пікселів міток користувальницького інтерфейсу і реєстрового шрифту Осередки сітки мають розмір 32 х 32 пікселів кожна

Я помістив всі зображення атласу в точки, чиї координати кратні 32 Це спростить створення текстурних регіонів

Музика та звук

Нам також знадобляться звукові ефекти і музика Оскільки у нашої гри 8-бітний ретростиль, ми можемо використовувати так звані чип-тюни Чип-тюнамі називаються звукові ефекти і музика, згенеровані синтезатором Найбільш відомі чип-тюни були згенеровані приставками NES, SNES і GameBoy фірми Nintendo Для створення звукових ефектів я використовував інструмент sfxr, створений Томасом Петерссона (Є також флеш-версія – as3sfxr) Ви можете знайти його за адресою wwwsuperflashbrosnet/as3sfxr

Я створив звукові ефекти для стрибка, торкання пружини, торкання монети і торкання білки Крім того, я створив звуковий ефект для клацання на елементах інтерфейсу користувача Все, що я робив, – натискав кнопки в лівій частині вікна програми as3sfxr в кожній категорії, поки не знаходив відповідний звуковий ефект

З музикою для ігор зазвичай визначитися трохи складніше В Інтернеті існує всього кілька сайтів, що надають 8-бітові чип-тюни, відповідні для ігор на зразок Великого стрибуна Ми будемо використовувати одну пісню, яка називається NewSong, її написав Геір Тьелта (Geir Tjelta) Її можна знайти на сайті wwwfreemusicarchiveorg Вона знаходиться під ліцензією Creative Commons Atribution-NonCommercial-NoDerivatives (Також відомої як Music Sharing) Це означає, що її можна застосовувати для некомерційних проектів, наприклад таких, як наш Великий стрибун з відкритим вихідним кодом, в тому випадку якщо ми вкажемо, що її написав Геір, і не змінимо оригінальний фрагмент Коли ви будете шукати музику для гри в Інтернеті, завжди стежте за тим, що ви твердо дотримуєтеся цієї ліцензії Люди вкладають багато сил в ці пісні Якщо ліцензія вашому проекту не підходить (наприклад, якщо він комерційний), то ви не зможете використовувати ці пісні

РЕАЛІЗАЦІЯ ВЕЛИКОГО стрибун – РОЗРОБКА ІГОР ДЛЯ ОС ANDROID

Реалізувати Великого стрибуна буде досить легко Ми можемо повторно використовувати весь фреймворк, а на високому рівні будемо слідувати архітектурі, розробленої для гри Містер Ном Це означає, що необхідно створити клас для кожного екрана і всі ці класи будуть реалізовувати логіку і уявлення, які повинен мати даний екран Крім того, необхідно також створити стандартні дії перед початком роботи над проектом – зробити відповідний файл маніфесту, помістити всі активи в каталог assets /, визначити всі необхідні значки програми та т д Почнемо з головного класу – Assets

Клас Assets

У грі Містер Ном у нас заздалегідь був готовий клас Assets, що складався тільки з безлічі посилань на зображення і звуки (Pixmap і Sound), які зберігалися в статичних змінних – членах класу Те ж саме ми зробимо і для Великого стрибуна, але на цей раз ми додамо трохи логіки для їх завантаження У лістингу 91 показаний код класу

Лістинг 91 Клас Assetsjava, в якому зберігаються всі активи, за винятком текстур екранів допомоги

У цьому класі зберігаються посилання на всі екземпляри класів Texture, TextureRegi on, Animati on, Musi с і Sound (текстури, текстурні регіони, анімації, музика і звуки), які знадобляться нам під час гри Єдине, що ми не завантажуємо тут, – зображення для екранів допомоги

Метод load, який буде викликатися лише один раз при запуску гри, відповідає за наповнення всіх статичних членів класу Він завантажує фонове зображення і створює для нього відповідний текстурний регіон (TextureRegi on) Далі він завантажує атлас текстур і створює всі необхідні текстурні регіони та анімації (Animation) Порівняйте код з рис 914 та іншими малюнками попереднього розділу Єдине, на що варто звернути увагу при завантаженні графічних ресурсів, – створення анімації для монети Як ми говорили раніше, ми повторно використовуємо другий кадр наприкінці анімаційної послідовності кадрів Час, через яке кадри змінюють один одного, – 0,2 секунди

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

Крім того, в цьому методі завантажуються музика і звуки (екземпляри класів Music і Sound) Як ви можете бачити, ми знову працюємо з нашим старим добрим другом – класом Setti ngs Ми можемо повторно використовувати його реалізацію, яку ми розробили для гри Містер Ном, внісши лише одну невелику модифікацію, про яку ви дізнаєтеся через хвилину Зверніть увагу, ми зациклюємося відтворення композиції і встановлюємо гучність її звуку рівний 0,5, тому вона буде звучати трохи тихіше, ніж звукові ефекти Музика почне програватися, якщо користувач не відключив попередньо звук Ця інформація буде також зберігатися в класі Setti ngs, як і в грі Містер Ном

Далі розглянемо таємничий метод, який називається reload Необхідно памятати, що контекст OpenGL ES буде губитися всякий раз, коли додаток буде ставитися на паузу При поновленні додатки слід щоразу перезавантажувати текстури – саме цим і займається даний метод Крім того, поновлюється відтворення музики, якщо, звичайно, звук включений

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

Тепер поглянемо на модифікований клас Setti ngs

Клас Settings

У лістингу 92 показаний код кілька зміненого класу Setti ngs

Лістинг 92 Settingsjava, трохи змінений клас Settings, який запозичений у гри Містер Ном

Єдина відмінність від класу Setti ngs гри Містер Ном полягає в тому, що файл налаштувань, за якими здійснюється робота, має розширення немає mrnom, a super jumper

Основна активність

Як головну точку входу в нашу гру слід використовувати Activity Ми назвемо її SuperJumper У лістингу 93 показаний її вихідний код

Лістинг 93 Клас SuperJumperjava, головна точка входу в гру

З класу GIGame ми успадковуємо і реалізуємо метод getStartScreenC, який повертає примірник MainMenuScreen Два інших методу трохи менш очевидні

Перевизначають метод onSurfaceCreate, який викликається кожен раз при черговому створенні контексту OpenGL ES Якщо цей метод викликається в перший раз, ми використовуємо метод Assets 1 oadдля того, щоб завантажити всі активи в перший раз, атакож завантажити налаштування з файлу, розміщеного на карті памяті, якщо він доступний В іншому випадку все, що нам потрібно зробити, – перезавантажити текстури і почати відтворення музики за допомогою методу AssetsreloadO Ми також переопределили метод onPause, щоб призупиняти музику, якщо вона відтворюється

Ми виконуємо обидва ці дії, тому немає необхідності повторювати їх в методах resume і pause () для екранів гри

Перед тим як заглибитися в реалізацію класів екранів, поглянемо на наш новий клас Font

Клас Font

Для отрисовки випадкового тексту у форматі ASCII ми будемо використовувати растрові шрифти Принцип дії на високому рівні вже обговорювалося, тому просто погляньте на код лістингу 94

Лістинг 94 Fontjava, клас отрисовки растрових шрифтів

Цей клас зберігає текстуру, що містить гліфи шрифту, ширину і висоту одного гліфа, а також масив TextureRegi ons – по одному регіону на кожен гліф Перший елемент масиву зберігає регіон для гліфа пробілу, наступний зберігає регіон для гліфа знаку оклику і т д Іншими словами, перший елемент відповідає ASCII-символу з кодом 32, а останній – символу з кодом 127

У конструкторі зберігаємо конфігурацію реєстрового шрифту і генеруємо регіони для гліфів Параметри offset і offsetY визначають верхній лівий кут області текстури, що містить растровий шрифт У створеному нами атласі текстур цей піксель має координати (224 0) Параметр glyphsPerRow говорить про те, скільки гліфів буде в рядку, а параметри glyphWidth і glyphHeight визначають розмір одного гліфа Оскільки ми використовуємо Моноширинний растровий шрифт, цей розмір буде однаковим для всіх гліфів Параметр glyphWidth також є значенням, на яке ми будемо зрушуватися при відображенні декількох гліфів

Метод drawText приймає примірник SpriteBatcher, рядок тексту і позиції х і у, звідки слід починати малювати текст Координати хну визначають центр першого гліфа Ми отримуємо індекс кожного символу рядки, перевіряємо, чи є для нього гліф, і, якщо відповідь позитивна, отрісовиваємих його за допомогою екземпляра класу SpriteBatcher Далі збільшуємо координату хна 3Ha4eHHeglyphWidth Після цього ми готові малювати наступний символ рядка

Ви, можливо, ставите питанням, чому нам не потрібно привязувати текстуру, що містить гліфи Передбачається, що це вже зроблено перед викликом методу drawText Причина полягає в тому, що отрисовка тексту може бути частиною пакета, в цьому випадку текстура повинна бути привязана заздалегідь

Чому необовязково привязувати її знову в методі drawText Памятайте, для OpenGLES набагато краще, якщо стану змінюються лише незначно

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

Екран GL

У прикладах, наведених у двох попередніх розділах, ми завжди отримували посилання на обєкт класу GLGraphics за допомогою перетворення типів Виправимо це за допомогою невеликого допоміжного класу по імені GLScreen, який буде робити за нас всю брудну роботу і зберігати посилання на обєкт GLGraphi cs У лістингу 95 показаний код цього класу

Лістинг 95 Невеликий допоміжний клас GLScreenJava

Ми зберігаємо екземпляри класів GLGraphics і GLGame Звичайно ж, програма видасть помилку, якщо екземпляр класу Game, переданий конструктору, не матиме тип GLGame Але тепер можна бути впевненим, що цього не трапиться

Екран головного меню

Цей екран повертається методом SuperJumper, getStartScreen, користувач побачить його в першу чергу Він отрісовиваєт фонове зображення і елементи інтерфейсу, а потім чекає натискання одного з елементів Грунтуючись на натиснутому елементі ми або змінюємо конфігурацію (включення / вимикання звуку), або переходимо на новий екран У лістингу 96 міститься код цього класу

Лістинг 96 Клас MainMenuScreenjava: екран головного меню

Цей клас успадковує від класу GLScreen, тому ми можемо отримати доступ до примірника класу GLGraphics простіше

У цьому класі є кілька членів Перший – це екземпляр класу Camera2D, який називається gui Cam Нам також знадобиться екземпляр класу Spri teBatcher для отрисовки фонового зображення і елементів користувача інтерфейсу Щоб визначити натискання користувачем одного з елементів інтерфейсу, ми будемо застосовувати прямокутники (Rectangles) Оскільки ми задіємо клас Camera2D, нам також знадобиться екземпляр класу Vector2, щоб перетворити координати натискання в координати ігрового світу

У конструкторі инициализируются всі члени класу Тут є невелика особливість Примірник класу Camera2D дозволяє працювати з нашим цільовим дозволом 320 х 480 пікселів Нам потрібно встановити відповідні значення для ширини і висоти області видимості Останнє OpenGL ES зробить на ходу Однак зверніть увагу на те, що початок координат і раніше знаходиться в лівому нижньому кутку і вісь спрямується вгору Ми будемо використовувати подібну GUI-камеру на всіх екранах, що мають елементи призначеного для користувача інтерфейсу, тому стає можливо вимірювати їх в пікселах, а не в координатах ігрового світу Звичайно, ми трохи шахраювати в разі, якщо дозвіл екрану не відповідає цільовому, але ми вже застосовували цей трюк у грі Містер Ном, і нічого поганого не сталося Тому координати Rectangle, які ми використовуємо для кожного елемента, дано у точках

Далі розглянемо метод updateO У циклі ми проходимо по всіх подіях TouchEvents, які повертає екземпляр класу Input, і перевіряємо їх тип Нам потрібно виявити дотику до екрану Якщо така подія відбулося, насамперед необхідно перетворити координати дотику в координати ігрового світу Оскільки камера встановлена ​​для роботи з цільовим дозволом, суть трансформації полягає лише в простому перетворенні координати по осі у для екрану розміром 320 х 480 пікселів Для менших або великих за розміром екранів слід перетворювати координати дотику для цільового дозволу Як тільки координати дотику отримані, можна звірити їх з координатами розташування прямокутників, що містять елементи призначеного для користувача інтерфейсу Якщо таким чином були обрані пункти меню PLAY (Грати), HIGHSC0RES (Рекорди) або HELP (Допомога), здійснюється перехід на відповідний екран Якщо була натиснута кнопка звуку, змінюються настройки і, відповідно, відтворення музики або починається, або призупиняється Зверніть також увагу на те, що якщо натиснення було вироблено за допомогою методу Assets pi aySound, програється звук клацання

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

Останній метод, який робить що-небудь, – pause Тут ми переконуємося в тому, що всі налаштування після маніпуляцій користувача зі звуком на цьому екрані збережені на SD-карту

Екрани допомоги

Всього в грі пять екранів допомоги, всі вони працюють за одним принципом: завантажують зображення екрану допомоги, малює його та стрілку і чекають натискання цієї кнопки, щоб перейти на наступний екран Єдине, що змінюється, – завантажуване ними зображення, а також екран, на який здійснюється перехід З цієї причини я приведу код тільки перший екрану допомоги, з якого можна перейти на другому Файли, які містять зображення екранів допомоги, називаються help, Png і т д аж до hel р5 png Відповідні класи називаються HelpScreen, Help2Screen і т д Останній екран, Help5Screen, переходить назад до екрану головного меню

У цьому класі також є кілька членів для зберігання екземплярів класу камери, Spri teBatcher, прямокутника кнопки зі стрілкою, вектора точки дотику, Texture і TextureRegion для зображення екрану допомоги

У конструкторі инициализируются всі члени класу Це відбувається приблизно так само, як і в класі Mai nMenuScreen

У методі resume завантажується відповідна текстура екрану допомоги і створюється відповідний TextureRegi on для його відтворення за допомогою Spri teBatcher Завантаження винесена в цей метод, оскільки контекст OpenGL ES може бути загублений Текстури фонового зображення і елементів інтерфейсу користувача, як говорилося раніше, обробляються класами Assets і SuperJumper У роботі з ними на інших екранах немає необхідності Вдобавок ми видаляємо текстуру зображення екрану допомоги в методі pause, щоб очистити память

Далі слід метод update О, в якому виконується проста перевірка натискання кнопки зі стрілкою, при якому відбувається перехід на наступний екран При натисканні також відтворюється звук клацання

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

Як було зазначено раніше, інші екрани допомоги мають аналогічну реалізацію

&nbsp

Екран кращих результатів

Далі в нашому списку слід екран кращих результатів Для його створення будуть використані кілька міток користувача інтерфейсу головного меню (ділянка HIGHSCORES (Рекорди)) Кращі результати, що зберігаються в екземплярі класу Setti ngs, будуть отрісовиваться за допомогою обєкту класу Font, який зберігається в екземплярі класу Assets Звичайно, на цьому екрані також буде кнопка зі стрілкою, за допомогою якої гравець зможе повернутися в головне меню У лістингу 97 показаний код класу цього екрану

Лістинг 97 Клас HighscoresScreenjava: екран кращих результатів

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

У конструкторі ми як завжди инициализируем всі члени класу і обчислюємо значення параметра xOffset Це можна здійснити, оцінивши розмір найдовшою з пяти рядків, створених нами для пяти кращих результатів Оскільки ми використовуємо моноширинний растровий шрифт, можна з легкістю порахувати кількість пікселів, необхідних для одного рядка тексту, помноживши кількість символів на ширину гліфа Такий спосіб, звичайно, не годиться для недрукованих символів або для символів, що знаходяться за межами таблиці ASCII Оскільки ми впевнені, що не будемо використовувати такі символи, можна обійтися подібними простими обчисленнями Потім в останньому рядку конструктора з 160 (горизонтальний центр екрану з цільовим дозволом 320 х 480 пікселів) віднімається половина значення ширини самої довжини рядка і підлаштовується це значення далі шляхом вирахування половини ширини гліфа Це необхідно, оскільки метод Font drawTextC) працює з центром гліфа замість однієї з крайніх точок

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

У цьому класі метод рresent також досить прямолінійний Він очищає екран, встановлює значення матриць, отрісовиваєт фонове зображення і все мітки головного меню, що відносяться в кращих результатів Далі з використанням розрахованого в конструкторі значення xOffset отрісовиваємих пять рядків, що містять кращі результати Тепер ми можемо помітити, чому клас Font не виконує ніяких привязок текстур: ми можемо обєднати пять викликів методу Font drawText Звичайно, необхідно переконатися в тому, що екземпляр класу SpriteBatcher може прийняти необхідне для отрисовки наших текстів кількість спрайтів (Або в нашому випадку – гліфів) Переконатися в цьому можна при його створенні в конструкторі, де в якості максимального значення встановлюється 100 спрайтів (гліфів)

Тепер поглянемо на класи емуляції ігрового світу

Класи емуляції ігрового світу

Перед тим як ми зможемо поринути в ігрові екрани, нам необхідно створити класи емуляції ігрового світу Як і у випадку з грою Містер Ном, в грі буде клас для кожного ігрового обєкта і єднальний їх все суперклас по імені World, який обєднує всі дрібні деталі і оживляє ігровий світ Нам знадобляться класи для наступних обєктів: Боб білки пружини монети платформи

Боб, білки і платформи можуть пересуватися, тому їх класи будуть засновані на класі DynamicGameObject, який ми створили раніше Пружини і монети є статичними, тому вони будуть наслідувати від класу GameObject Наведемо основні завдання для класів емуляції ігрового світу: зберігання позиції, швидкості і фігури, що обмежує обєкт зберігання стану і часу перебування в цьому стані (час стану), якщо це необхідно надання методу update О, який буде змінювати обєкт відповідно в його поведінкою надання методів, змінюють стан обєкта (наприклад, що повідомляють Бобу про те, що він загинув або торкнувся пружини)

Клас World відстежуватиме численні екземпляри цих ігрових обєктів, оновлювати їх кожен кадр, визначати зіткнення між ігровими обєктами і Бобом, а також генерувати наслідки таких зіткнень (наприклад, дозволяти Бобу загинути, підібрати монету і т д) Розглянемо кожен клас: від найпростішого до найскладнішого

Клас пружини

Почнемо з розгляду коду класу пружини, наведеного в лістингу 98 Лістинг 98 Springjava, клас пружини

Клас Spri ng успадковує від класу GameObject: нам необхідно знати тільки позицію і обмежує фігуру пружини, оскільки вона нерухома

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

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

Клас монети

Далі розглянемо клас монети (лістинг 99) Лістинг 99 Coinjava, клас монети

Клас Coin виглядає практично так само, як і клас Spring, він має тільки одна відмінність: необхідно відстежувати тривалість життя монети Ця інформація буде потрібно далі, коли нам знадобиться отрісовать монету, використовуючи екземпляр класу Animation Ми робили те ж саме для печерної людини, героя останнього прикладу Цей прийом ми використовуємо для всіх класів емуляції ігрового світу Грунтуючись на стані і часу, протягом якого обєкт перебуває в цьому стані, ми можемо вибрати анімацію, а також поточний кадр цієї анімації для отрисовки У монети є всього один стан, тому необхідно відслідковувати лише час знаходження в цьому стані Для цього у класу є метод update, що збільшує значення часу стану кожного разу, коли йому передається параметр deltaTime

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

Клас замку

Далі розглянемо клас замку, що знаходиться на вершині нашого ігрового світу (лістинг 910)

Цей клас не дуже складний Нам потрібно зберегти позицію замку і його межі Розмір замка визначається константами CASTLE WIDTH і CASTLEJHEIGHT, для яких використані значення, розглянуті нами раніше

Клас білки

Тепер розглянемо клас Squi rrel (лістинг 911) Лістинг 911 Squirreljava, клас білки

Білки – переміщалися обєкти, тому їх клас успадковує від класу Dynami cGameObject, що дозволить нам задати вектори швидкості і прискорення Перше, що нам необхідно зробити, – задати розміри білки, а також її швидкість Оскільки білки анімовані, необхідно також відстежувати час, який білка перебувала в певному стані У білки є тільки один стан, як і у монети: переміщення по горизонталі Напрям її переміщення може бути визначене за допомогою компоненти вектора швидкості по осі х, тому немає необхідності зберігати час знаходження білки в цьому стані У конструкторі ми, звичайно ж, викликаємо конструктор суперкласу, в який передається вихідна позиція білки Ми також встановлюємо вектор швидкості білки рівним (SQUIRREL VELOCITY 0) Всі білки спочатку будуть пересуватися вправо

Метод update оновлює позицію і обмежує фігуру білки, грунтуючись на швидкості і минулому часі Це стандартний етап інтеграції Ейлера, який ми обговорювали і активно використовували в попередній чолі Необхідно також перевіряти зіткнення білки з лівим або правим краями світу Якщо сто-кновеніе сталося, просто міняємо значення вектора швидкості на протилежний, і білка починає рухатися в іншому напрямку Ширина нашого світу обмежена 10 м, як ми вже говорили раніше Останнє, що нам необхідно зробити, – оновити час стану на значення deltaTime, що дозволить визначити, яку з двох анімацій слід використовувати для отрисовки білки надалі

Клас платформи

Код класу PIatform приведений в лістингу 912 Лістинг 912 Platformjava, клас платформи

Звичайно, платформи – обєкти кілька більш складні, ніж білки Розглянемо константи, визначені в класі Перші дві константи задають ширину і висоту платформи, значення яких ми розглянули раніше У кожної платформи є свій тип, вона може бути нерухомою або рухомою Тип платформи описується константами PLATFORM TYPE STATIC і РLATF0RM TYРЕ М0VING Платформа також може бути в одному з двох станів: або в нормальному стані (тоді вона може бути статичною або пересувається), або вона може розсипатися Ці стани зашифровані в константах PLATFORM STATE NORMAL і PLATFORM STATE PULVERIZING

Розсип платформи – це процес, обмежений в часі Тому необхідно визначити час, необхідний для повного знищення платформи Будемо вважати його рівним 0,8 секунди Це значення можна легко отримати, прийнявши в розрахунок кількість кадрів анімації і тривалість кожного кадру – це одна з невеликих особливостей, що не вписуються в шаблон MVC, які слід враховувати, якщо ви намагаєтеся слідувати цим шаблоном Нарешті, ми задаємо швидкість рухомих платформ рівний 2 м / с, це значення також обговорювалося раніше Пересувається платформа поводиться точно так само, як і білки, – переміщається в одному напрямку до тих пір, поки не торкнеться краю екрану, в цьому випадку вона просто змінює напрямок

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

Метод update переміщує платформу і перевіряє, чи не вийшла вона за межі ігрового світу У цьому випадку метод змінює вектор її прискорення Точно такі ж дії виробляв метод Squi rrel update У кінці цього методу також оновлюється час стану

Останній метод цього класу називається pulverize Він перемикає стан платформи з PLATFORM STATE N0RMAL в Р LATFORM STATE PUL V ERI ZING, а також скидає час стану і швидкість Це означає, що платформа зупиниться Даний метод викликається в тому випадку, якщо клас World визначає зіткнення Боба і платформи і визначає, що платформа повинна розсипатися, грунтуючись на сгенерированном випадковому числі Трохи пізніше ми поговоримо про це більш детально

&nbsp

Клас Боба

Спочатку нам необхідно поговорити про сам Боба Код, який реалізує його клас, наведений у лістингу 913

Лістинг 913 Клас Bobjava

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

Звичайно ж, необхідно також зберігати стан Боба і час, який він у ньому знаходиться

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

Метод update починається з поновлення позиції Боба і обмежує його фігури, грунтуючись на гравітації і його поточної швидкості Зверніть увагу на те, що швидкість вираховується з урахуванням гравітації і пересування Боба як по горизонталі, так і по вертикалі за допомогою стрибків Дві наступні умовні конструкції встановлюють стан Боба рівним або BOBSTATEJUMPING, або BOB STATE FALLING і скидають його час стану Всі ці дії здійснюються на підставі компоненти у його швидкості Якщо вона більше нуля – значить Боб стрибає, якщо менше – падає Проте ці дії виконуються лише в разі, якщо Боб живий, але перебуває в неправильному стані Якби ці дії проводилися завжди, час стану було б дорівнює нулю, що несприятливо позначилося б на анімації Боба надалі Цей метод також переміщує Боба з одного кінця в інший, якщо він покинув межі ігрового світу зліва чи справа Нарешті, в цьому методі знову оновлюється член класу stateTime

Коли ж Боб відокремлює свою швидкість від гравітації Для цього служать інші методи

Метод hitSqui rrel викликається класом World, якщо Боб доторкнеться до білку Якщо цього сталося, Боб перестає пересуватися і входить в стан B0B STATE HIT З цього моменту на Боба діє лише гравітація, гравець більш не може управляти персонажем, а сам Боб не взаємодіє з платформами Подібна поведінка демонструється в грі Супер Маріо: якщо до Маріо доторкнеться ворог, Маріо просто впаде вниз

Метод hitPl atformC також викликається класом World Це робиться в тому випадку, якщо Боб доторкнеться до платформи при падінні вниз Якщо це сталося, швидкість Боба по осі у стає рівною BOBJUMPVELOCITY, а також відповідно встановлюються його стан і час стану З цього моменту Боб рухатиметься вгору, поки гравітація знову не переможе, змусивши його знову падати

Останній метод, hi tSpring, викликається класом World, якщо Боб доторкнеться до пружини Він робить те ж саме, що і метод hi tPl atformO, але з однією відмінністю: швидкість Боба встановлюється рівною значенню BOB JUMP VELOCITY, помноженому на 1,5 Це означає, що Боб при торканні пружини підстрибне трохи вище в порівнянні з результатом торкання платформи

Клас World

Останній клас, який нам необхідно обговорити, – World Він трохи більше за розміром, ніж попередні класи, тому варто розбити його на кілька частин У лістингу 914 показана перша частина його коду

Лістинг 914 Фрагменти KHaccaWorldJava: константи, члени класу і ініціалізація

Перше, що ми визначаємо в цьому класі, – інтерфейс, який називається World Listener Ви запитаєте, для чого він потрібен Він необхідний для вирішення невеликої проблеми, яку ставить перед нами MVC: коли слід програвати звукові ефекти Для вирішення цієї проблеми можна просто викликати метод Assets pi aySound з відповідних класів емуляції, але такий підхід не зовсім коректний з точки зору проектування Замість цього ми дозволимо користувачеві класу World зареєструвати Worl dLi stener, який буде викликатися, коли Боб стрибає з платформи або пружини, стосується білки або підбирає монету Далі зареєструємо слухача, який буде відтворювати відповідні цим подіям звуки, що дозволить звільнити класи емуляції від прямих залежностей, повязаних з отрисовкой і відтворенням аудіо

Після цього необхідно визначити кілька констант Константи WORLD WIDTH і WORLDHEIGHT задають вертикальні і горизонтальні межі ігрового світу Памятайте, що область видимості в нашій грі має площу 10 х 15 м Грунтуючись на константах, представлених тут, ігровий світ буде сягати на 20 областей видимості або екранів по вертикалі Знову ж, до цього значення я прийшов після тестування Ми повернемося до цього моменту, коли будемо обговорювати генерацію рівнів Камера ігрового світу також може бути в трьох станах: переміщатися, очікувати початку рівня або знаходитися в нерухомому стані, якщо гра закінчилася (в цей час Боб падає дуже далеко, за межі області видимості) Тут також визначається як константа вектор гравітаційного прискорення

Тут перераховані всі змінні – члени класу Worl d Цей клас стежить за Бобом, усіма платформами, пружинами, білками, монетами і замком Він також має посилання на інтерфейс Worl dLi stener та примірник класу Random, який буде використовуватися для генерації випадкових чисел для різних потреб Останні три члени відстежують найбільшу координату по осі у, на якій був Боб, стан камери ігрового миру і кількість набраних гравцем очок

У конструкторі инициализируются всі члени класу, а також зберігається екземпляр класу Worl dLi stener, переданий як параметр Боб поміщається по центру осі х трохи вище нульової координати по осі у (в точці (5 1)) Інша частина коду говорить сама за себе, з одним лише винятком: метод generateLe vel не так прозорий

Генерація ігрового світу

Ви могли задатися питанням – як же відбувається створення і розміщення обєктів ігрового світу Для цього використано метод, який називається процедурної генерацією Придумаємо простий алгоритм, що генерує випадковий рівень (лістинг 915)

Лістинг 915 Фрагменти класу WorldJava: метод generateLevel

Опишемо основну ідею алгоритму простими словами

1 Починаємо з нижчої точки ігрового світу у = 0

2 Якщо вершина світу ще не досягнута, виконуємо наступне:

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

2) генеруємо випадкове число між 0 і 1 і, якщо воно більше 0,9 і платформа нерухома, створюємо на цій платформі пружину

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

4) генеруємо випадкове число і, якщо воно більше 0,6, створюємо монету і поміщаємо її з випадковим зміщенням по осі у від позиції платформи

5) збільшуємо у на максимальну висоту нормального стрибка, трохи зменшуємо її (але не настільки, щоб у став менше свого попереднього значення) і переходимо до пункту 2

3 Розміщуємо в останній позиції по осі у замок, розташований посередині осіх

Родзинка цієї процедури – це спосіб збільшення позиції у в пункті 5 кроку 2 Необхідно бути впевненим у тому, що кожна наступна платформа може бути досягнута Бобом після стрибка з поточної платформи Боб може стрибати так високо, як йому може дозволити гравітація Початкова швидкість його стрибка м / с по вертикалі Висоту стрибка Боба можна розрахувати за такою формулою:

Висота = швидкість х швидкість (2 гравітація) = 11

11 / (2 х 13) = 46

Це означає, що якщо між платформами буде відстань, рівну по вертикалі 4,6, Боб все ще зможе до них дострибнути Щоб переконатися, що Боб може досягти будь-якої платформи, використовуємо значення, яке трохи менше максимальної висоти його стрибка Це гарантує, що Боб зможе дострибнути з однієї платформи на іншу Горизонтальне розміщення платформи також випадково Грунтуючись на тому, що швидкість горизонтального переміщення Боба дорівнює 20 м / с, ми можемо бути більш ніж упевнені в тому, що персонаж зможе досягти будь-якої платформи як по вертикалі, так і по горизонталі

Інші обєкти створюються випадково Метод RandomnextFloat повертає випадкове число між 0 і 1 при всіх своїх викликах Кожне число може випасти з однаковою ймовірністю Білки створюються, тільки коли генерується випадкове число більше 0,8 Це означає, що нова білка зявиться з імовірністю 20% (1 – 0,8) Ці слова також вірні і для всіх інших обєктів, що створюються на основі випадкового числа Змінивши ці значення, можна створити в ігровому світі більшу або меншу кількість обєктів

Оновлення ігрового світу

Після генерації ігрового світу ми можемо оновлювати його обєкти і перевіряти наявність зіткнень У лістингу 916 показані методи класу World, використовувані для оновлення ігрового світу

Лістинг 916 Фрагменти класу Worldjava: методи, необхідні для поновлення ігрового світу

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

Метод updateBob відповідає за оновлення стану Боба Перше, що він робить, – перевіряє, чи не чи стосується Боб нижньої межі ігрового світу, в цьому випадку він повинен стрибнути Це означає, що на початку кожного рівня Боб підстрибує від основи ігрового світу Як тільки сама нижня платформа випадає з поля зору, ця перевірка, звичайно ж, більше не спрацьовує Далі оновлюється горизонтальна швидкість Боба, грунтуючись на показаннях акселерометра, які метод отримує в якості аргументу Як ми говорили раніше, показання акселерометра наводяться від виду [-10 10] до виду [-1 1] (від повного нахилу вліво до повного нахилу вправо), а потім множаться на стандартну швидкість горизонтального переміщення Боба Далі цей метод наказує Бобу оновити свій стан за допомогою виклику Bobupdate Останнє, що відбувається в цьому методі, – збереження максимального значення висоти, якого зумів досягти Боб Надалі воно знадобиться для визначення, впав Боб чи ні

Далі оновлюються всі платформи в методі updatePl atforms Ми проходимо за списком платформ і викликаємо для кожної з них метод update, передаючи в нього поточне значення параметра deltaTime Якщо платформа вже розсипається, перевіряємо, як довго проходить цей процес Якщо платформа знаходиться в стані PLATFORM STATE PULVERIZING час, більше, ніж значення PLATFORM PULVERIZE TIME, вона просто видаляється з списку платформ

Метод updateSqui rrel s оновлює кожен екземпляр класу Squi rrel за допомогою його методу updateO, передаючи йому як аргумент час, що минув з останнього виклику методу Те ж саме робиться і для методу updateCoins

Визначення зіткнень і реакція на них

Якщо ви знову поглянете на оригінальний метод WorldupdateO, то побачите, що далі він визначає зіткнення між Бобом і всіма іншими обєктами ігрового світу Це робиться тільки в тому випадку, якщо Боб не в стані BOBSTATEHIT, в якому він просто продовжує летіти вниз під впливом гравітації Погляньмо на код методів, що визначають зіткнення (лістинг 917)

Лістинг 917 Фрагменти loiaccaWorldJava: методи, що визначають зіткнення

Метод checkCol lisions також є суперметодом, який просто викликає інші методи, що визначають зіткнення Боб може доторкнутися до наступних обєктах ігрового світу: платформи, білки, монети, пружини і замок Для кожного типу обєктів існує окремий метод Слід памятати, що цей суперметод викликається після того, як оновилися позиції і обмежують фігури всіх обєктів ігрового світу Таку ситуацію можна розглядати як фотознімок стану ігрового світу в заданий момент Все, що залишається зробити, – переглянути це нерухоме зображення і перевірити, чи не перетинаються якісь обєкти Далі ми можемо почати діяти і переконатися, що перетнувши обєкти відреагують належним чином, змінивши свої стану, позиції, швидкості і т д

Метод checkPl atf ormCol1isions перевіряє перетин Боба з усіма платформами ігрового світу Ми швидко виходимо з цього методу, якщо Боб зараз рухається вгору У цьому випадку Боб може проходити крізь платформи знизу вгору Для Великого стрибуна така поведінка підходить добре в іграх начебто Супер Маріо нам швидше знадобиться, щоб Боб падав вниз при ударі об блок знизу Далі проходимо по всіх платформ в циклі і перевіряємо, чи знаходиться над поточною платформою головний герой Якщо так, перевіряємо, перетинається чи обмежує його прямокутник з обмежуючим прямокутником платформи У цьому випадку ми вказуємо Бобу, що він зачепив платформу, викликом методу Bob hi tPl atform Якщо повернутися назад до даного методу, ми побачимо, що це спровокує стрибок і відповідно змінить стан Боба Далі викликається метод Worl dLi stener jump, що інформує слухача про те, що Боб щойно почав стрибати Це буде використано для того, щоб слухач відтворив відповідний звуковий ефект Останнє, що робить даний метод, – генерація випадкового числа Якщо воно більше 0,5, ми наказуємо платформі розсипатися Вона проіснує ще PLATFORM PULVERI ZE TIME секунд (0,8), а потім буде видалена методом updatePI atf onus, показаним раніше Коли ми будемо малювати цю платформу, використовуємо її час стану для того, щоб визначити, який саме кадр анімації платформи слід відобразити

Метод checkSqui rrel Col1isionsO перевіряє перетин прямокутника, що обмежує Боба, з прямокутниками, які обмежують кожну білку Якщо Боб торкнеться білки, ми накажемо йому перейти в стан BOB STATE HIT, що змусить його впасти, і гравець ніяк не зможе керувати ним Ми також сповіщаємо про це WorldListener, щоб він програв відповідний звуковий ефект

Метод checkltemCollisionsO перевіряє, не зіткнувся Чи Боб з якою-небудь монетою чи пружиною Якщо Боб торкнувся небудь монети, вона видаляється з ігрового світу Далі метод повідомляє слухачеві про те, що була підібрана монета, і збільшує поточну кількість очок гравця на COINSC0RE Якщо Боб падає, ми також здійснюємо перевірку торкання небудь пружини Якщо воно сталося, ми повідомляємо Бобу про це, через що він підстрибне вище, ніж зазвичай Про цю подію також інформується слухач

Останній метод перевіряє зіткнення Боба і замку Якщо Боб стосується замку, стан світу приймає значення WORLDSTATENEXTLEVEL, сигналізуючи всім зовнішнім сутностям (таким як ігровий екран) про те, що слід перейти на наступний рівень, який також представлятиме собою випадково згенерований екземпляр класу World Гра закінчена, друже

Код останнього методу класу World, який викликається в останньому рядку методу Worldupdate, приведений в лістингу 918

Лістинг 918 Закінчення класу Worldjava: метод, перевіряючий, не закінчилася гра

Згадайте, як ми визначили стан закінчення гри: Боб повинен покинути нижню частину області видимості Область видимості, звичайно ж, управляється екземпляром класу Camera2D, який має позицію Координата цієї позиції по осі у завжди дорівнює найбільшою координаті, яку зумів досягти Боб Камера буде слідувати за головним героєм тільки в тому випадку, якщо він буде рухатися вгору Оскільки ми хочемо розділити код отрисовки і емуляції, нам не потрібна посилання на камеру Тому ми лише відстежуємо найбільшу координату по осі у, досягнуту Бобом, в методі updateBob і зберігаємо її значення у змінній heightSoFar Ми знаємо, що область видимості має висоту 15 м Ми також знаємо, що якщо координата Боба по осі у стала менше, ніж значення виразу heightSoFar – 75, то він покинув область видимості знизу і має бути визнаний мертвим Звичайно, цей метод трохи ненадійний, оскільки він заснований на припущенні, що висота області видимості завжди дорівнюватиме 15 м, а камера завжди буде знаходитися у вищій точці, яку зумів досягти Боб Якби ми дозволили масштабування або використовували інший спосіб переміщення камери, такий метод став би невірним Замість того щоб все зайве ускладнювати, давайте просто залишимо все як є Ви будете часто зустрічати подібні рішення при розробці ігор, оскільки дуже важко постійно приймати рішення, прозорі з точки зору інженерії програмного забезпечення (про що свідчить зловживання нами членами класу, що мають тип public або package private)

Можливо, ви зацікавилися, чому до цих пір не був використаний клас Spati al HashGrid Я поясню причину через мить Спочатку закінчимо написання нашої гри, реалізувавши клас GameScreen

Ігровий екран

Ми практично закінчили написання ігри Великий стрибун Останнє, що залишилося реалізувати, – ігровий екран, який дозволить гравцеві побачити ігровий світ і взаємодіяти з ним Ігровий екран складається з пяти подекранов, що показано на рис 92 Мається екран готовності, екран нормальної роботи гри, екран переходу на наступний рівень, екран закінчення гри і екран паузи Ігровий екран гри Містер Ном був схожий на цей, в ньому не було лише екрану переходу на новий рівень, оскільки в грі був всього один рівень Ми будемо використовувати той же підхід, що і для гри Містер Ном: у нас будуть окремі методи оновлення і відображення для кожного подекрана, які оновлюють і малює ігровий світ, а також елементи призначеного для користувача інтерфейсу, що є частиною подекранов Оскільки код класу ігрового екрану дещо більше коду інших класів, розібємо його на кілька лістингів У лістингу 919 показана перша частина коду ігрового екрана

Лістинг 919 Фрагменти класу GameScreenJava: члени класу і конструктор

Клас починається з опису декількох констант, що визначають пять станів, у яких може перебувати екран Далі задані члени класу Є камера для отрисовки елементів користувальницького інтерфейсу, а також вектор, що дозволить перетворювати координати дотику до координат ігрового світу (як і на інших екранах, до області видимості в 320 х 480 одиниць, нашому цільовим дозволу) У класі є також SpriteBatcher, екземпляри класів World і Worl dLi stener Клас Worl dRenderer ми розглянемо трохи пізніше Він просто бере екземпляр класу Worl d і отрісовиваєт його Зверніть увагу на те, що його конструктор приймає посилання на екземпляри класів SpriteBatcher і World в якості параметрів Це означає, що для отрисовки елементів користувальницького інтерфейсу і самого ігрового світу використовуються однакові екземпляри класу SpriteBatcher Решта членів класу – це прямокутники (обєкти класу Rectangles) для різних елементів інтерфейсу користувача (наприклад, для пунктів меню RESUME (Продовжити) і QUIT (Вийти), присутніх на подекране паузи) і два члени, які відстежують поточний результат гравця Ми не хочемо створювати новий рядок кожен кадр, тому спростимо роботу збирачеві сміття

У конструкторі инициализируются всі змінні – члени класу Єдине, що тут становить інтерес, – реалізація Worl dLi stener як анонімного внутрішнього класу Він реєструється екземпляром класу World і відтворює звукові ефекти відповідно відбувається подій

Оновлення ігрового екрана

Далі розглянемо методи оновлення, які дозволять переконатися в тому, що будь-який введення даних користувачем буде коректно оброблений, і при необхідності оновлять екземпляр класу World (лістинг 920)

Лістинг 920 Фрагменти класу GameScreenjava: методи оновлення ігрового екрана

Метод GLScreenupdate також є суперметодом, що викликає інші методи оновлення залежно від поточного стану екрану Зверніть увагу на те, що ми обмежуємо параметр del taTi me значенням, рівним 0,1 секунди Навіщо це робиться

У нашій грі також може виникнути ця проблема, якщо вона буде запущена на пристрої з ОС Android 15 У будь-який момент гра може перерватися складальником сміття на кілька сотень мілісекунд Це відібється і на параметрі del taTi ті, що змусить Боба телепортувати з однієї точки в іншу замість плавного просування Боб проходитиме крізь платформи, навіть не перетинаючись з ними, оскільки буде переміщатися на велику відстань за один кадр Обмеживши цей час чутливим максимальним значенням, рівним 0,1 секунди, ми можемо компенсувати цей ефект

Метод updateReady викликається на подекране паузи Все, що він робить, – очікує дотику до екрану, після чого ігровий екран перейде в стан GAME RUNNING

Спочатку метод updateRunni ng перевіряє, доторкнувся чи користувач до кнопки Пауза в правому верхньому куті екрану Якщо це так, гра переходить у стан GAME PAUSED В іншому випадку екземпляр класу World оновлюється, використовуючи поточне значення параметра deltaTime і показання акселерометра, що відповідають за переміщення Боба по горизонталі Після цього також необхідно перевірити, чи потрібно оновити рядки, містять кількість очок користувача Виконується також перевірка на те, чи досяг Боб замку У цьому випадку переходимо до стану GAME NEXT LEVEL, в якому на екран буде виведено повідомлення, аналогічне показаному на рис 92 Далі екран буде очікувати натискання екрану, щоб згенерувати новий рівень Якщо гра закінчилася, виводимо на екран рядок, що містить кількість очок користувача Вона буде мати вигляд або score: fscore, або new hi ghscore: # score залежно від того, перевершує чи поточну кількість очок результати, показані раніше Далі підсумковий результат гравця додається в налаштування і зберігається на карті памяті На додаток ігровий екран переходить у стан GAME 0VER

У методі updatePaused перевіряється, натиснув користувач пункти меню RESUME (Продовжити) або QUIT (Вийти), а також виконується відповідна реакція

Метод updateLevel End очікує дотику користувача до екрану Якщо воно сталося, створюються нові екземпляри класів World і Worl dRenderer Крім того, в цьому методі екземпляру класу World вказується кількість очок, набраних користувачем впродовж гри Ігровий екран переходить у стан GAME READY, в якому він також очікує дотику гравця до екрану

Метод updateGameOver також очікує натискання екрана Якщо воно сталося, ми просто переходимо до головного меню гри, що показано на рис 92

Отрісовка ігрового екрана

Після всіх цих оновлень ігровий екран повинен отрісовать себе за допомогою виклику методу GameScreen present О Погляньмо на код цього методу, наведений у лістингу 921

Лістинг 921 Фрагменти класу GameScreenjava: метод отрисовки ігрового екрана

Отрісовка ігрового екрана відбувається в два етапи Спочатку отрісовивается ігровий світ за допомогою класу Worl dRenderer, а потім отрісовиваємих всі елементи користувальницького інтерфейсу у верхній частині ігрового світу, грунтуючись на поточному стані ігрового екрана Метод render виконує якраз ці функції Як і для методів оновлення, у нас є окремі методи отрисовки для кожного подекрана

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

Метод presentRunning просто отрісовиваєт кнопку паузи і поточне кількість очок гравця

Метод presentPaused відображає елементи призначеного для користувача інтерфейсу меню паузи і кількість очок гравця

Метод presentLevelEndO отрісовиваєт рядок THE PRINCESS IS .. (Прінцесса .) у верхній частині екрана і рядок IN ANOTHER CASTLE (В іншому замку) У нижній частині екрану, як показано на рис 92 Виконуються також деякі обчислення для того, щоб вирівняти ці рядки по центру

Метод presentGameOver відображає елементи призначеного для користувача інтерфейсу, необхідні на екрані кінця гри, і кількість очок гравця Памятайте, що екран результатів встановлюється методом updateRunn i ng і його рядки мають вигляд або score: score, або new highscore: value

Останні штрихи

Клас ігрового екрана практично готовий Інша частина коду приведена в лістингу 922

Лістинг 922 Закінчення класу GameScreenjava: методи pauseO, resumeO і disposeO

Ми просто переконуємося в тому, що ігровий екран знаходиться в стані паузи, коли користувач вирішує призупинити додаток Останнє, що залишилося реалізувати, – клас WorldRenderer

Клас World Renderer

Цей клас не повинен вас здивувати Він просто використовує екземпляр класу Spri teBatcher, який передається йому в конструктор для того, щоб отрісовать ігровий світ У лістингу 923 приведено початок його коду

Лістинг 923 Фрагменти класу WorldRendererJava: константи, члени класу і конструктор

Як звичайно, починаємо з визначення деяких констант У цьому випадку це ширина і висота області видимості, значення яких ми визначили рівними 10 і 15 м У нас також є кілька інших членів – екземпляри класів GLGraphics, Camera2D, а також посилання на екземпляр класу SpriteBatcher, яку конструктор отримує від класу ігрового екрана

Конструктор в якості параметрів приймає екземпляри класів GLGraphi cs, Spri teBatcher і World Слід відповідно ініціалізувати всі члени класу У лістингу 924 приведений код отрисовки ігрового світу

Лістинг 924 Закінчення класу WorldRendererJava: код отрисовки ігрового світу

Метод render розбиває отрисовку на два пакети: один для фонового зображення, а другий – для всіх обєктів ігрового світу Він також оновлює позицію камери, грунтуючись на поточному координаті Боба по вертикалі Якщо він знаходиться вище координати камери по осі у, камера відповідно зсувається Зверніть увагу на те, що використана камера, яка працює в одиницях виміру ігрового світу Ми тільки одного разу встановлюємо матриці для фонового зображення і для обєктів

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

Метод renderObjects відповідає за отрисовку другого пакета Цього разу ми будемо використовувати змішування, оскільки всі наші обєкти мають прозорі фонові пікселі Всі обєкти отрісовиваємих в одному пакеті Озираючись на конструктор класу GameScreen, можна побачити, що екземпляр класу SpriteBatcher, який ми використовуємо, може працювати з 1000 спрайтів в одному пакеті – цього більш ніж достатньо для ігрового світу Для кожного обєкта існує свій метод, отрісовиваємих його

Метод renderBobC відповідає за отрисовку Боба Грунтуючись на стані Боба і часу стану, ми вибираємо один кадр з пяти (див рис 98) Грунтуючись на компоненті швидкості Боба по осі х, ми також визначаємо, в яку сторону буде повернутий Боб Грунтуючись на цьому, ми повернемо до відповідного текстурний регіон Памятайте, на наявних у нас кадрах Боб повернуть тільки вправо Зверніть також увагу на те, що ми не використовуємо параметри B0B WI DTH або BOB HEIGHT для того, щоб визначити розміри прямокутника, який ми малюємо для Боба Ці параметри призначені для обмежують фігур, вони необовязково знадобляться для прямокутників, які ми малюємо зараз Замість цього ми застосовуємо вибраний масштаб – 1х1мк32х32 пікселя Це ж ми повторимо для всіх спрайтів ми будемо використовувати прямокутник 1×1 (Боб, монети, білки, пружини), прямокутник 2 х 0,5 (платформи) або прямокутник 2×2 (замок)

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

Метод render Items отрісовиваєт пружини і монети Для пружин використовується один текстурний регіон, визначений в активах програми Для монет ми знову вибираємо кадр анімації, грунтуючись на часі стану монети

Метод renderSquirrels отрісовиваєт білок Ми знову отримуємо кадр анімації грунтуючись на часі стану білки, визначаємо напрямок її руху, а також управляємо її шириною при відображенні за допомогою SpriteBatcher Це необхідно, Оскільки в нашому атласі текстур є тільки зображення білки, повернутою вліво

Останній метод називається renderCastle Він просто отрісовиваєт замок використовуючи текстурний регіон, визначений у класі Assets

Це було досить просто, чи не так У нас є тільки два пакети для отрисовки: один для фонового зображення і один для всіх ігрових обєктів Враховуючи все вищеописане, зрозуміло, що ми отрісовиваємих третій пакет для всіх елементів інтерфейсу користувача Всього припадає три рази змінювати текстури і три рази завантажувати нові вершини в GPU Теоретично ми могли б обєднати пакети користувальницького інтерфейсу і ігрових обєктів, але це було б обтяжливо, а код став би Неелегантна У відповідності з нашим керівництвом по оптимізації, нашому додатком слід мати миттєву отрисовку Перевіримо, чи це так

Ми практично закінчили У нашу другу гру – Великий стрибун – вже можна грати

Джерело: 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>

*

*