КЛАСИ емуляції DROID INVADERS

&nbsp

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

Управління здійснюється всезнаючим класом World Як ви бачили при поданні обєктів немає особливої ​​різниці між 2D і 3D Замість класів GameObject і DynamicObject ми тепер будемо використовувати класи Game0bject3D і Dynamic0bject3D Єдина відмінність полягає в тому, що ми тепер для зберігання позицій, швидкостей і прискорень застосовуємо екземпляри класу Vector3 замість екземплярів класу Vector2, а форму обєктів представляють обмежують сфери замість обмежують прямокутників Все, що нам залишилося зробити, – реалізувати поведінку різних обєктів нашого світу

Клас Shield

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

Лістинг 126 Клас Shieldjava, що представляє блок щита

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

Клас Shot

Клас пострілу також досить простий Він успадковує від класу Dynami cGameOb ject3D, оскільки він насправді переміщається Код класу Shot міститься в лістингу 127

Лістинг 127 Клас Shotjava, що представляє постріл

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

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

&nbsp

Клас Ship

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

На додаток корабель буде відстежувати кількість життів і пропонувати нам спосіб повідомляти йому про те, що він був убитий Код класу корабля міститься в лістингу 128

Лістинг 128 Клас ShipJava, що представляє корабель

Ми починаємо з опису декількох констант, що визначають максимальну швидкість корабля, два стани (цілий та вибухає), час, необхідний кораблю для того, щоб повністю вибухнути, а також радіус обмежує сфери Цей клас також успадковує від класу Dynami cGameOb ject3D, оскільки у нього є позиція, що обмежує сфера і швидкість Вектор прискорення, що зберігається в класі DynamicGame0bject3D, знову не використовується

Далі йдуть дві змінні типу int, необхідні для відстеження кількості життів і стану корабля (або SHIP ALIVE, або SHIP EXPL0DING) Останній член класу відстежує кількість секунд, яке корабель провів у поточному стані

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

Метод update досить простий Він приймає проміжок часу, а також показання акселерометра по осі у (памятаєте, гра працює в пейзажному режимі, тому вісь у акселерометра є нашою віссю х) Якщо корабель цілий, ми встановлюємо його швидкість відповідно до показань акселерометра (які будуть лежати в проміжку від -10 до +10) так само, як ми поступали і у випадку з грою Великий стрибун На додаток оновлюємо позицію корабля, грунтуючись на його поточній швидкості Далі перевіряємо, чи покинув корабель межі ігрового поля, використовуючи дві константи, які визначимо далі в класі World Коли позиція корабля встановлена, ми, нарешті, можемо оновити позицію обмежує сфери корабля

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

Нарешті, оновлюємо параметр stateTime, грунтуючись на заданому проміжку часу

Останній метод ki11 може бути викликаний класом World, якщо він визначить, що сталося і зіткнення між кораблем і пострілом або загарбником Він встановить стан вибухає, скине час стану, а також переконається, що поточна швидкість корабля дорівнює нулю по всіх осях (ми ніколи не встановлюємо у-і z-компоненти вектора швидкості, оскільки корабель переміщається тільки по осі х)

Клас Invader

Згідно шаблону, певному раніше, загарбники просто парять в космосі Цей шаблон наведено на рис 1211

Рис 1211 Пересування загарбників: вліво, вниз, вправо, вниз, вліво, вниз, вправо, вниз ..

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

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

Рис 1211 ілюструє пересування лівого верхнього загарбника Відстань, на яку він переміститься вліво в перший раз, менше, ніж те, на яке він буде рухатися в сторони кожний наступний раз Відстань, на яку загарбник переміщається по горизонталі, дорівнює половині ігрового поля, в нашому випадку – 14 одиниць При першому переміщенні по горизонталі загарбник переміститься на половину цієї відстані – 7 одиниць

Нам потрібно відслідковувати напрямок переміщення загарбника, а також те, наскільки він вже перемістився в цьому напрямку Якщо він пересувається на максимальну відстань (14 одиниць для гбрізонтального переміщення, 1 одиниця для вертикального переміщення), він переходить у наступний режим переміщення Відстань, на яку пересуваються всі загарбники, дорівнює половині ігрового поля Погляньте знову на рис 1211, щоб переконатися, чому це працює В результаті загарбники будуть відскакувати від лівої і правої меж ігрового поля

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

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

Лістинг 129 Клас Invaderjava, що представляє загарбника

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

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

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

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

Ми починаємо з розрахунку того, на скільки одиниць загарбник переміститься в цьому оновленні, і відповідно збільшуємо значення змінної movedDi stance Якщо він переміщається вліво, ми оновлюємо позицію, віднімаючи швидкість з координати по осі х, помножену на зміну часу і множник швидкості Якщо загарбник перемістився досить далеко, ми вказуємо йому переміститися по вертикалі, встановлюючи значення змінної move рівним M0VE D0WN Ми також встановлюємо значення змінної wasLastStateLeft рівним true для того, щоб знати, що при наступному переміщенні по горизонталі необхідно буде рухатися вправо

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

Якщо загарбник переміщається вниз, ми працюємо з z-координатою його позиції і знову ж перевіряємо, як далеко він вже пересунувся Якщо він перемістився на максимальну відстань, ми перемикаємо стан на M0VE LEFT або MOVE RIGHT залежно від напряму останнього переміщення по горизонталі, що зберігається у змінній wasLastStateLeft Як тільки ми оновили позиції загарбників, ми можемо встановити позицію обмежує сфери так само, як ми робили це для корабля Нарешті, оновлюємо поточний час стану і вважаємо, що оновлення завершено

Метод ki11 потрібен для того ж, для чого служить однойменний метод класу Ship Він дозволяє повідомити загарбникові, що він повинен почати вмирати Ми встановлюємо його стан рівним INVADER DEAD і скидаємо час стану Загарбник більше не буде переміщатися і буде тільки оновлювати свій стан, грунтуючись на поточному зміну часу

Клас World

Клас World є найголовнішим класом Він зберігає екземпляри класів корабля, загарбників і пострілів, а також відповідає за їх оновлення і перевірку зіткнень Він робить те ж саме, що й у грі Великий стрибун, з невеликими відмінностями Початкове розміщення блоків щита і загарбників – це також обовязок цього класу Ми також створюємо екземпляр класу World Listener для того, щоб інформувати всіх слухачів про події, що відбулися всередині світу, таких як постріл або вибух Він буде відтворювати звукові ефекти, як і в грі Великий стрибун Розглянемо кожен метод цього класу докладніше Код міститься в лістингу 1210

Лістинг 1210 Клас WorldJava, що представляє собою ігровий світ Він повязує все воєдино

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

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

Цей клас відстежує безліч речей У ньому є слухач, який буде викликатися всякий раз, коли відбувається вибух або постріл Він також відстежує, скільки хвиль прибульців гравець вже знищив Мінлива score відповідає за поточний рахунок, а параметр speed Multipiiег дозволяє прискорити рух загарбників (згадайте метод Invadersupdate) Крім того, тут зберігаються списки пострілів, загарбників і блоків щита, які в даний момент існують в ігровому світі Нарешті, тут є екземпляр класу Ship, а також час, в який був проведений останній постріл Це час видається в наносекундах, оскільки метод SystemnanoTime повертає час в такому форматі, і зберігається в змінної типу long Примірник класу Random знадобиться, коли нам знадобиться визначити, вистрілить Чи загарбник

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

Метод generatelnvaders просто створює сітку розміром 8×4, яка складається з прибульців, вибудуваних так, як показує рис 1211

Метод generateShields виконує ті ж самі завдання – він створює 3 щита, кожен з яких складається з 5 блоків, вибудуваних так, як показано на рис 122

У класі World є також метод, що встановлює слухача

Метод update дивно простий Він приймає поточну зміну часу, а також дані з акселерометра по осі у, які ми передаємо методу Ship, update Як тільки оновиться корабель, викликаються методи update Invaders і updateShots, які відповідальні за оновлення загарбників і пострілів Після того як всі обєкти світу оновилися, ми можемо почати перевірку того, чи відбулося зіткнення Метод checkShotCol1ision перевірить на зіткнення всі постріли, корабель і загарбників Нарешті, ми перевіряємо, знищені чи все загарбники Якщо так, то генерується їх нова хвиля На радість збирача сміття ми могли б повторно використовувати старі екземпляри класу Invader, наприклад за допомогою екземпляра класу Pool Однак для простоти ми створюємо нові екземпляри класу Invader До речі, те ж саме вірно і для пострілів Оскільки за одну гру може бути створено не так вже багато обєктів, складальник сміття не матиме часто запускатися Але якщо ви хочете запобігти всі можливі проблеми, просто використовуйте клас Pool, щоб повторно застосовувати загиблих загарбників і постріли Зверніть також увагу на те, що в цьому методі ми збільшуємо множник швидкості

У методу update Invaders Про є кілька обовязків Він в циклі проходить по всіх загарбникам і викликає їх методи update Як тільки екземпляр класу Invader оновився, ми перевіряємо, чи живий він до цього моменту Якщо так, то генерується випадкове число, що представляє собою шанс на постріл Якщо воно менше 0,001, то загарбник робить постріл Це означає, що кожен загарбник має 0,1% шансу на постріл кожен кадр Якщо шанс спрацьовує, створюється новий екземпляр класу Shot, його швидкість встановлюється таким чином, що він починає переміщатися уздовж позитивної частини осі р Про цю подію інформується слухач Якщо загарбник вмирає і закінчує вибухати, ми просто видаляємо його зі списку загарбників

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

У методі checkInvaderCol1isions відбувається перевірка того, зіткнувся чи який-небудь загарбник з кораблем Це досить просто, оскільки все, що потрібно зробити, – пройти в циклі по всім загарбникам і перевірити, перетинається чи їх обмежує сфера з обмежує сферою корабля Відповідно до ігровою механікою, коли це відбувається, гра закінчується Тому ми встановлюємо кількість життів корабля рівним 1 перед тим, як викликати метод Ship klllO Після цього виклику параметр 1ive корабля встановлюється рівним 0, що буде використано в іншому методі для перевірки настання стану кінця гри

Метод checkShotCol1isions кілька більш складний Він проходить у циклі за всіма примірниками класу Shot і перевіряє їх перетин з блоком щита, загарбником або кораблем Блоки щита можуть бути зачеплені як у разі пострілу загарбника, так і у випадку пострілу корабля Загарбник може бути збитий тільки пострілом корабля, а корабель – тільки пострілом загарбника Щоб визначити, хто саме стріляв, необхідно лише подивитися z-компоненту швидкості стріляв Якщо вона позитивна, то постріл зробив загарбник, в іншому випадку – корабель

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

Нарешті, розглянемо метод shoot Він буде викликатися ззовні всякий раз, коли буде натискатися кнопка пострілу У розділі опису ігрової механіки ми говорили, що корабель може стріляти кожну секунду або якщо на ігровому полі немає пострілу корабля Звичайно ж, корабель не зможе стріляти, якщо він вибухає, тому спочатку виконуємо саме цю перевірку Далі проходимо в циклі по всім пострілам і перевіряємо, є хоча б один з них пострілом корабля Якщо такого не знаходиться, корабель може миттєво вистрілити В іншому випадку перевіряється останній постріл, зроблений кораблем Якщо з часу його появи пройшло більше секунди, корабель може вистрілити знову Цього разу ми встановлюємо значення швидкості рівним-Shot SH0T VEL0CITY, що змусить постріл переміщатися уздовж негативній частині осі z, у бік загарбників Як звичайно, ми інформуємо про цю подію слухача

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

Droid Invaders – це, звичайно, дуже проста гра, тому ми можемо використовувати найпростіші рішення начебто застосування як обмежують фігур сфер Це все, що потрібно, для багатьох простих 3D-nrp Перейдемо до розгляду двох заключних фрагментів нашої гри, класам GameScreen і WorldRenderer

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

*

*