Основи Cocos2d-x

Статті про розробку ігор за допомогою Cocos2d-x

Анімація з Dragon Bones

Posted at — Apr 15, 2020

Існує багато різних засобів для створення скелетної анімації, але більшість з них платні, а тому недоступні для вивчення. У цій статті мова піде про Dragon Bones — доступний, але трохи своєрідний варіант.

Основною перевагою Dragon Bones є те, що ця програма має достатню функціональність і при цьому є безкоштовною. Точніше, редактор є безкоштовним з закритим кодом, а код для інтеграції з Cocos2d розповсюджується за ліцензією MIT.

Основний недолік — китайське походження, і в даному випадку це не просто географічна характеристика. Скажімо, прямо зараз вам наврядчи вдастся скачати редактор з офіційної сторінки завантаження, там виникли якісь проблеми з нововведеннями у сучасних браузерах. Код інтеграції, що знаходиться в офіційному репозиторії, вже трохи застарів, тому я б радив брати за основу для своєї розробки ось цей репозиторій, там внесені усі зміни, необхідні для Cocos2d V4.

Хай там як, після подолання початкових проблем Dragon Bones працює стабільно і з ним можна робити досить круті штуки. Наприклад, такі:

Приклад CoreElementGame з офіційного репозиторію

Ясно, що це просто малюнок, тут цього робота можна побачити розібраним на запчастини.

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

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

Результатом експорту з Dragon Bones до Cocos2d є три файли: два json, що описують модель, та одне зображення-ресурс.

Імпорт моделі до програми виглядає схожим на завантаження plist-файлів:

#include "dragonBones/cocos2dx/CCDragonBonesHeaders.h"

dragonBones::CCFactory* factory = dragonBones::CCFactory::getFactory();
factory->loadDragonBonesData("db_export/BlueWizard_ske.json", "BlueWizard");
factory->loadTextureAtlasData("db_export/BlueWizard_tex.json", "BlueWizard");

dragonBones::CCArmatureDisplay* wizard = factory->buildArmatureDisplay("WizardArmature", "BlueWizard");

wizard->setAnchorPoint(Vec2(0.5,0.5));
wizard->setScale(0.33);
wizard->setPosition(160,140);
addChild(wizard, 10);

CCArmatureDisplay — клас для об'єктів, з якими ви працюєте на сцені. Він є нащадком Node, тому з ним можна робити всі тіж самі речі, що й з іншими об'єктами Cocos2d.

“BlueWizard” — це щось типу тегу, який відрізняє дану завантажену модель від усіх інших. У документації цей параметр згадується як displayName.

“WizardArmature” — назва скелету (armatureName), яка вказується у редакторі, ось тут:

Програвання анімації викликається ось так:

wizard->getAnimation()->play("idle01", 1);//1 to play animation once

Виглядатиме це так:

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

По-перше, редактор дозволяє в одному слоті зберегти кілька варіантів зображень. Наприкад, тут у слоті “Gun” їх три:

В такому випадку перемикання з одного зображення на інше виконується простим вказуванням індексу:

int currentWeaponIndex;
<....>
wizard->getArmature()->getSlot("Gun")->setDisplayIndex(currentWeaponIndex);

По-друге, можна створити окрему модель, у якій будуть лише змінювані зображення. Тоді завантаження і використання виглядатиме складніше:

dragonBones::CCFactory* factory = dragonBones::CCFactory::getFactory();
factory->loadDragonBonesData("db_export/MagentaKnight_ske.json", "MagentaKnight");
factory->loadTextureAtlasData("db_export/MagentaKnight_tex.json", "MagentaKnight");

factory->loadDragonBonesData("db_export/WeaponPack_ske.json", "WeaponPackMK");
factory->loadTextureAtlasData("db_export/WeaponPack_tex.json", "WeaponPackMK");

knight = factory->buildArmatureDisplay("KnightArmature", "MagentaKnight");

<..пізніше..>
factory->replaceSlotDisplay("WeaponPackMK", "WeaponPackArmature", "OneHandWeaponSlot",
                            "morning_star", knight->getArmature()->getSlot("Weapon"));

Тут “WeaponPackArmature” та “OneHandWeaponSlot” — ідентифікатори скелету та слоту, вказані у редакторі:

В обох випадках результат виглядатиме однаково: