Багато андроїд-ігор навіть не мають достатньо великих розмірів, щоб виправдати збереження / завантаження або параметри / уподобання, не маючи на увазі користувальницьких персонажів і тому подібне, просто тому, що вони граються назовні протягом 10 хвилин у поїзді додому.
Не помиляйтесь, що я взявся за щось із великим розмахом для першої гри на Android. Складіть купу менших ігор, а потім займіться чимось більшим
Специфікація для Android мудра:
Структура:
Я б рекомендував проводити майже всю гру в одному класі занять. Android працює над ідеєю, що кожне заняття схоже на міні-додаток, напівнезалежне від інших дій у додатку. Додаток, по суті, є сукупністю заходів, і користувач бачить, що коли-небудь знаходиться на вершині.
Коли ви вискочите один з верху, він, як правило, руйнується і буде відтворений наступного разу, коли користувач розпочне нову діяльність (старт активність). Це ускладнює підтримку станів між діяльністю та призводить до єдиної архітектури діяльності
Можливо, вам потрібно буде виконати діяльність на головному екрані з меню "Нова гра / Завантажити гру / Параметри" і зробити це запуском. Однак у вас буде ігрове меню, як і в ігровій діяльності, яка буде мати в ньому більшість однакових функцій
У власному додатку я зробив "MenuActivity", який має функції, які запускають нову гру, зберігають, завантажують, змінюють параметри. Тоді мій HomeActivity розширює це, як і мій GameActivity.
Оскільки все знаходиться в одному класі активності, я рекомендував би скласти герархію класів діяльності та використовувати приватні, захищені та за замовчуванням ділянки сфери. Роблячи це таким чином, ви принаймні можете розділити речі на різні файли, щоб не мати одного керованого файла активності. Наприклад, для мого власного додатка:
GraphicsEngine extends MenuActivity
.
PhysicsEngine extends GraphicsEngine
.
GameLogicActivity extends PhysicsEngine
.
UIActivity extends GameLogicActivity
.
Оскільки в моєму додатку є 3D opengl-es, багато чого, що я роблю, не працює перехресними видами діяльності, тому все відбувається в одній і тій же діяльності, тому, можливо, я налаштований на використання однієї архітектури діяльності
-
Нитки
Для ігрової діяльності у вас є дві нитки (або 3, якщо ви займаєтеся 3D-відкриттям). Один потік - це UI / main thread. Це нитка діяльності, яка починається і запускається, і надається вам Android.
Цей потік інтерфейсу є єдиним, у якому можна оновити елементи інтерфейсу (представлення, макети тощо). Це також той, де будуть працювати будь-які слухачі для введення користувача. Ви не бачите жодної механіки потоку інтерфейсу, лише де він працює в циклі на задньому плані.
Другий потік ви самі зробите (я б рекомендував використовувати AsyncTask , незважаючи на всі його недоліки). Це робить усе те, що не використовується у звичайному інтерфейсі, у звичайному ігровому циклі, наприклад, оновлення руху, обчислення зіткнень, бойових розрахунків тощо.
Ви робите цей потік / клас AsyncTask як внутрішній клас своєї діяльності. Таким чином, у вас можуть бути об'єкти з широкою сферою діяльності ( Vector<Spaceship>
), до яких можна отримати доступ як за допомогою потоку інтерфейсу користувача, так і для потоку циклу гри.
Оскільки логіка гри відбувається в потоці циклу гри, це єдиний потік, якому потрібно буде фактично змінити значення змінних (оновити швидкість танка, зменшити HP Player). Потік інтерфейсу просто зчитує значення, тому виникають мінімальні проблеми одночасності.
Складний біт - це отримання потоку користувальницького інтерфейсу для оновлення на вимогу потоку циклу гри. Є кілька способів зробити це. Якщо ви читаєте документацію AsyncTask, вона має методpubProgress () / onProgressUpdate (). Це фактично додавання матеріалів до черги потоку інтерфейсу користувача, щоб зробити наступний цикл.
Обробник робить саме те саме, де ви реалізуєте метод handleMessage (), і цей метод фактично виконується наступним циклом інтерфейсу користувача.
Нарешті, будь-який вхід користувача, перебуваючи в потоці користувальницького інтерфейсу, ви можете оновлювати елементи інтерфейсу безпосередньо з нього (тобто всередині реалізації будь-яких слухачів onClick / onTouch). Якщо вам потрібно оновити ігрові об’єкти, ви можете або використати такі речі, як синхронізація, або ви можете реалізувати власну чергу оновлень у AsyncTask, яка подобається потоку інтерфейсу, вона перейде наступного разу при виконанні ігрового циклу.
Посібник з потоку Android .
-
UI
Що стосується фактичної структури інтерфейсу користувача в межах однієї діяльності, я рекомендую мати базовий макет кадру. Дочірні елементи в макеті кадру працюють як черга. Перший елемент малюється першим, другий малюється зверху першого, третій зверху другим.
Таким чином, ви можете мати декілька файлів макета XML, а керуючи дітьми макета кадру, ви можете легко поміняти набори переглядів в і вийти.
Якщо ви завжди маєте SurfaceView внизу (перша дочірка в макеті кадру), то ви можете використовувати всі звичні перегляди / віджети Android (кнопки, текстові подання, подання прокрутки) тощо у верхній частині подання поверхні, що просто робить графічна частина гри.
Наприклад, якщо щось завантажується, ви можете призупинити цикл гри / просто змусити її пропустити все, додати непрозорий екран "завантаження" як останнього дочірнього до макета кадру, і користувач побачить, що на екрані з'явиться "завантаження". , зовсім не знаючи, що за цим стоять інші погляди. Таким чином, вам не потрібно видаляти представлення даних, які потребують тривалого часу, щоб налаштувати або викликати ускладнення кожного разу, коли вони додаються / видаляються.
Я б також рекомендував використовувати лоти View.setVisibility. Наприклад, ви можете додати цілий макет "інвентар" до базового макета кадру, а потім просто встановити на ньому VisVibility (View.Visible), коли користувач натискає, щоб переглянути свій інвентар, і встановити VisVibility (View.Gone), коли він знову закриє його. Таким чином, ви навіть не керуєте дітьми макета кадру настільки, як просто додавати все і робити речі видимими / невидимими, як і коли користувач робить різні речі
Це допомагає повторно нанизувати різьбу; Коли користувач натискає, щоб відкрити свій інвентар, onCLickListener обробляється у потоці користувальницького інтерфейсу, інвентар стає видимим у ньому, і метод виклику updateInventory знову викликається з потоку користувальницького інтерфейсу.
Ось діаграма, яку я склав для попереднього запитання щодо ідеї макета однієї активності / кадру: