Ам Ням з Cut the Rope 2 переселявся на Amazon Fire Phone

Недавно компанія Amazon випустила новий смартфон Fire Phone, і ZeptoLab надійшла пропозиція модифікувати для нього гру Cut the Rope 2. Ми додали туди підтримку нововведень смартфона, і гра увійшла в список встановлених додатків.

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




Головна особливість першого смартфона від Amazon — чотири фронтальних камери, які стежать за очима користувача і передають дані про їх стан в програми. Це створює помилковий 3D-ефект: можна злегка повертати зображення на екрані поглядом, «оживляючи» іконки і всі інші елементи інтерфейсу. Особливо сильне враження справляє перегляд карт: будівлі набувають обсяг, і їх можна розглянути з будь-якої сторони, просто пересуваючи погляд по екрану.

Іншою особливістю телефону є Hero Icon Hero Widget. Fire Phone Fire працює на OS, модифікації Android, і в ньому замість звичайного домашнього екрану присутні екрани Carousel і App Grid.



App Grid — це звична «сітка» встановлених додатків, а Carousel — набір останніх програм з горизонтальною прокруткою. Для кожного додатка екран ділиться на дві частини: у верхній відображається тривимірна іконка Hero Icon, а в нижній — набір елементів Hero Widget. В віджеті міститься набір рядків для виведення даних з додатка без необхідності запускати його; ці елементи можуть виконувати дії для швидкого доступу до частин програми, навіть якщо воно закрито або згорнуто.

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

Для модифікації Cut the Rope 2 під Fire Phone нам потрібно було зробити тривимірну іконку, навчити гру створювати віджет і додати в неї підтримку команд цього віджета.

Створення Hero Icon

У Fire Phone за промовчанням для всіх додатків створюється тривимірна Hero Icon — плоский об'єкт з накладеною текстурою звичайної 2D іконки.



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

Від Amazon нам дістався toolset, інструкція по створенню іконки в Autodesk Maya і готовий sample.

У точності повторюючи всі зазначені в інструкції пункти, ми зробили перший варіант іконки:



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

Ми почали робити іконку паралельно з розробкою елемента керування, і не мали можливості перевірити, як саме вона буде виглядати на екрані смартфона. Після першого ж експорту моделі в формат .vbl, зроблений Amazon для HeroIcon, ми з'ясували, що альфа-канал відображається некоректно. Тому ми перейшли до другого варіанту і зробили просту іконку на основі 2D-версії, яка нам дуже сподобалася.



І коли здавалося, що всі проблеми вже позаду, почалося найцікавіше.

По-перше, помилки при експорті моделі в формат vbl:

1. [ERROR]: Skeleton: No bind pose specified for node AnimatedNode1 in scene ic_myappname_appsgrid that has node animation, create a «bind» animation with keys on animated objects.

Рішення проблеми знайшлося на forums.developer.amazon.com: виявляється, треба було додати ще одну порожню анімацію з назвою «bind». В офіційній інструкції такої інформації немає.

2. [ERROR]: StateMachine: Detected self looping state with transitions that consists of empty sequence(s) resulting in infinite loops.

Лікується ця помилка досить просто: потрібно перейти в Tools Euclid, який ви встановлюєте в Maya згідно інструкції, зайти в редагування StateMachine, натиснути правою кнопкою миші на «State» і вибрати «Remove Self Connection».

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

Приміром, наша іконка ніяк не хотіла відображатися лицьовою стороною за потрібною осі: як би ми її не повертали — по осі Y, Z або X — у будь-якому випадку на пристрої відображався вид збоку.

Оскільки вирішити проблему в рамках зробленої по інструкції сцени ми не змогли, ми взяли готові семпли від Amazon і імпортували нашу іконку в сцену з іконкою-шаблоном. До нашої радості, експорт пройшов без помилок, і на девайсі красувалася 3D-іконка Cut the Rope 2 в потрібному нам вигляді. І це незважаючи на те, що в sample-сцені не було, наприклад, описаної в інструкції анімації.

По-друге, вилізла ось така помилка:

[ERROR]: MaterialExporter: Unable to open material template «MaterialApplication.app.template»

Ця помилка продовжувала рандомно повторюватися і в sample-сцені, кожен раз, коли ми проводили будь-яких маніпуляцій над моделлю. Щоб позбавитися від неї, ми брали чистий семпл, повторювали імпорт готової моделі в сцену і експортували її ще раз.

Розробка команд для віджета

На цьому наша робота над іконкою закінчилася, але ще потрібно було придумати, що виводити в віджет. Якщо програма не встановлює свій власний віджет в систему, на його місце виводиться стандартний список товарів в Amazon, близьких по тематиці до даного додатка. Для Cut the Rope 2 смартфон виводив в список декілька ігор Amazon Appstore. Замінюючи поведінку, ми налаштували в віджеті відображення ігрової інформації — кількість зібраних зірочок, отриманих медалей і нещодавно використаних елементів, на зразок телепорт або підказок. Ці рядки віджета також дозволяють переходити на карту рівнів гри, на екран досягнень Amazon GameCircle і в кілька розділів внутріігрового магазину.



В якості довідкових матеріалів у нас були три навчальних документа від Amazon за Home Screen, Hero Icon Hero Widget. Також в нашому розпорядженні був SDK для роботи з новим пристроєм і невеликий довідковий матеріал по його установці і настройці.

З установки SDK для Fire Phone ми і почали. Проблемою виявилося те, що SDK працює тільки з Android API не вище 17, і нам довелося вручну понижувати версію середовища розробки (зробити це автоматизовано не вдалося). Для цього треба було видалити папки з Android SDK і завантажити старі версії компонентів (SDK Tools 22.6.3, SDK Build-tools 19.0.1, API 17 Platform tools) по знайденим в інтернеті посиланнях. Після цього установка SDK від Amazon не становить великих проблем.

Далі треба було додати рядок підключення бібліотеки в AndroidManifest:
<uses-library android:name="com.amazon.device.home" />

Самі елементи віджета створюються з тексту програми. Після створення, їх потрібно поміщати в списки і групи, а потім ініціалізувати ними віджет. Таким чином елементи віджета отримують стиль, основний, другорядний та третинний текст, а також іконку і intent.
final ListEntry listEntry = new ListEntry(context)
.setContentIntent(heroIntent)
.setVisualStyle(SHOPPING)
.setPrimaryText(primaryText)
.setPrimaryIcon(imageUri);
listEntry.setSecondaryText(secondaryText);
listEntry.setTertiaryText(tritaryText);
...
listEntries.add(listEntry);
group.setListEntries(listEntries);
groups.add(group);
...
mWidget.setGroups(groups);

Интент для віджета створюється через спеціальний клас:
heroIntent = new HeroWidgetActivityStarterIntent("com.zeptolab.ctr2.CTR2Activity");

Потім потрібно отримати запит від віджета. Ми вирішили зробити код проекту розширюваним для роботи з можливими схожими віджетами або интентами. На рівні фреймворку ZFramework, який використовується нашими проектами, змісту надходять у програму интентов відловлюються в onCreate() і onNewIntent(). Ми використовуємо віртуальний обробник интентов IntentInterpreter у фреймворку, а на рівні даного проекту — віджета від Amazon — конкретний клас WidgetIntentInterpreter для обробки интентов віджета.

Нам також треба було врахувати, що на відміну від стандартних Android Intents, у випадку з віджетом від Amazon в якості додаткових даних з интентом можна передавати тільки рядки. Тому абстрактний клас розбору подій у нас отримав методи перекладу між рядками і ID подій:
public abstract class AbstractIntentInterpreter {
public abstract int processIntent(Intent intent);
public abstract int getIdForString(String stringData);
public abstract String getStringForId(int Id);
}

Він використовується приблизно так:
int viewRequested = intentInterpreter.processIntent(intent);
view.addEvent(viewRequested);

Проектний код з допомогою WidgetIntentInterpreter бере повідомлення з интента і переводить її в запитуваний ID:
String extra = intent.getStringExtra(HeroWidgetActivityStarterIntent.extra_hero_widget_data);
result = getIdForString(extra);

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

На рівні фреймворку клас View зберігає ID запиту в клас EventDispatcher, який надає інтерфейс для додавання, зчитування ID подій і їх стирання:
public class ZEventDispatcher {
...
public ZEventDispatcher(android.content.Context context) ...
public void clearEvent() ...
public int getNextEvent(boolean clearAfterRead) ...
}

Цей код незалежний від конкретного проекту, він може працювати для розбору подій від інших віджетів або інших подій.

Далі залишалося тільки рахувати в проекті ID події, використовуючи JNI. Наприклад, ось так:
int getIntentEvent(bool clearAfterRead)
{
JNIEnv* env = JNI::getEnv();
jclass cls = env->GetObjectClass(JNI::eventDispatcher);
jmethodID meth = env->GetMethodID(cls, "getNextEvent", "(Z)I");
jint jEventId = static_cast<jint>(env->CallIntMethod(JNI::eventDispatcher, meth, clearAfterRead));
env->DeleteLocalRef(cls);
int result = jEventId;
return result;
}

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

Алгоритм обробки запиту віджета при запуску програми приблизно наступний:

  1. Подія onCreate Java-класу додатки обробляє intent, отримуючи ID запиту;
  2. Отриманий ID зберігається в разборщике подій EventDispatcher;
  3. При створенні екрану початковій завантаження ID запиту зчитується класом RootView;
  4. Екран завантаження отримує в якості параметра ID запиту і, в залежності від нього, вибирає набір ресурсів для підвантаження;
  5. При завершенні екрану завантаження в залежності від ID запиту показується певний екран програми.


Невелика складність виникла у нас з правильним отриманням интента на розгортання згорнутого програми. Спочатку цей интент ловився методом onResume, однак ця подія відновлює початковий intent, яким додаток було початково запущено. Нам же потрібно було отримувати новий intent при кожному новому розгортанні. Рішенням стало додавання в додаток властивості

<activity ... 
android:launchMode="singleTop">

Воно дозволило отримувати нові intents в методі onNewIntent(). У підсумку, при розгортанні додаток стало отримувати свій унікальний набір параметрів.

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

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

Майбутні перспективи

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

Говорячи про варіанти розвитку віджета, слід також відзначити, що після додавання підтримки Amazon Hero Widget у Cut the Rope 2 у нас з'явився код, який можна буде при бажанні легко адаптувати під інші віджети на Android або iOS.

Це була розповідь про створення модифікації Cut the Rope 2 під Amazon Fire Phone. Сподіваємося, що наш досвід буде вам корисний.



Ну, а що стосується експериментів з новими технологіями — у нас в ZeptoLab це часта практика, і в зв'язку з цим нам доводиться час від часу переглядати вимоги для знову приходять на технічні завдання людей. Зокрема, у нас оновився тестове завдання на позицію C++ розробника, і, щоб не вводити хабражителей в оману застарілими, викочуємо його найсвіжішу версію.

Необхідно написати просту версію класичної гри Asteroids:
  • Ведемо космічний корабель через астероидное поле, управління на ваш розсуд;
  • Завдання — протриматися максимальну час, уникаючи астероїдів або стріляючи по них. Коли снаряд потрапляє в астероїд, він розлітається на осколки поменше, а осколки, в свою чергу, повністю знищуються при попаданні;
  • Астероїди повинні представляти собою випадково створені багатокутники.


Вимоги до прототипу:
  • Гра пишеться під iOS або Android-платформу (строго);
  • Отрисовка повинна бути реалізована за допомогою OpenGL ES версії 2.0 або вище (можна обмежитися геометричними фігурами з ліній);
  • Якщо пишете під Android, гра повинна бути написана з використанням NDK (С++) — програма повинна бути цілком на С++, Java може бути тільки обв'язка коду;
  • Якщо пишете під iOS, гра повинна бути написана на С++. На Objective-C допускається тільки обв'язка коду;
  • Гра повинна бути написана без застосування яких-небудь сторонніх бібліотек начебто Cocos2D або GLKit.


На адресу job@zeptolab.com ми як і раніше приймаємо ваші тестові цілодобово.
Про те, як ми їх перевіряємо, ми вже раніше писали. А в трохи раніше ми трохи розповіли про систему навчання розробників, яку ми ввели в цьому році — і далі будемо її тільки розвивати, не пропустіть.

Найближчим часом сподіваємося порадувати вас новими цікавинками, що відбуваються в Zepto-просторі.

Завжди ваш,
ZeptoTeam

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.