Создавая игру на движке cocos2d-x, мне понадобился инструмент для создания физических тел из произвольных изображений. Изначально поиск меня привёл к коммерческому инструменту PhysicsEditor, но взглянув на его цену, решил найти что-нибудь дешевле. Пришлось потратить довольно-таки много времени, прежде чем я наткнулся на видео-уроки, которые оказались для меня полезными.
В данной статье будет описано, как создавать физические тела для изображений в бесплатном, кроссплатформенном редакторе Physics Body Editor и интегрировать их в cocos2d-x-сцену.
Для урока нам потребуется изображение с прозрачным фоном. Если у Вас под рукой нет подходящего, то можете использовать вот это.
Скачаем Physics Body Editor по этой ссылке.
Распакуем его и кликнув два раза по physics-body-editor.jar запустим. У Вас в системе должно быть установлено программное обеспечение Java, иначе редактор не запуститься.
После запуска Physics Body Editor, должно появиться такое окно.
Кликаем New proect
Вверху выбираем папку, где будет храниться файл с физическим телом. Внизу пишем имя этого файла. Я назвал его pampkin.json. Жмём Ок.
Теперь кликаем New
В появившемся окне вводим имя создаваемого тела, я поставил имя pampkin. После чего кликаем кнопку Create body from image.
Выбираем файл с изображением и жмём Ок.
В редакторе появилась наше изображение, а также меню сцены. Объясню что означают эти флаги меню.
При установленном флаге Creation, каждый клик ЛКМ по сцене создаёт точку для нашего тела до тех пор, пока не получится замкнутый контур. Я создал контур из 5 точек. Если кликнуть по флагу Creation, то режим сцены поменяется на Edition.
В режиме Edition, мы можем редактировать созданные точки. Просто наведите курсор мыши на точку, зажмите левую клавишу мыши и не отпуская перетащите точку на позицию, которая Вам покажется более правильной. В этом режиме можно также удалять выделенные точки, нажав Remove points. Кликнув мышкой по флагу Edition, мы перейдём в режим тестирования тела Test.
В режиме Test, зажав левую клавишу мыши и направив прицел в сторону нашего тела, мы можем запустить в него шарик, который от него отскочит. Кликнув по флагу Test, мы снова попадём в режим Creation.
Тело у нас получилось совсем не таким, какое нужно. Поэтому удаляем все точки нажав Clear all points.
Создавать точки вручную не очень удобно, благо в Physics Body Editor, этот процесс можно автоматизировать. Нажмём Auto-trace, в появившемся окне оставляем всё по умолчанию и нажимаем Ок.
И получилось у нас такое вот тело.
Редактируем, если что-то не нравится, тестируем, и сохраняем нажав Save.
Физическое тело для изображения готово.
Далее будем работать с cocos2d-x.
Для начала перекинем файлы с физическим телом и изображением в папку с ресурсами Resources.
Создадим новый проект в cocos2d-x.
Для загрузки нашего json-файла, в котором находится физическое тело, нам потребуется скачать специальный класс. Скачайте его и закиньте в папку Classes.
Далее откроем файл CMakeLists.txt и добавим туда пути к файлам MyBodyParser.h и MyBodyParser.cpp. Это должно выглядеть так.
set(GAME_SRC
Classes/AppDelegate.cpp
Classes/HelloWorldScene.cpp
Classes/MyBodyParser.cpp
${PLATFORM_SPECIFIC_SRC}
)
set(GAME_HEADERS
Classes/AppDelegate.h
Classes/HelloWorldScene.h
Classes/MyBodyParser.h
${PLATFORM_SPECIFIC_HEADERS}
)
Если вы компилируете код для Андройд, то откройте файл Android.mk и добавьте путь к классу MyBodyParser.
LOCAL_SRC_FILES := hellocpp/main.cpp
../../../Classes/AppDelegate.cpp
../../../Classes/MyBodyParser.cpp
../../../Classes/HelloWorld.cpp
Откроем файл HelloWorld.h и удалим от-туда такой код.
// a selector callback
void menuCloseCallback(cocos2d::Ref* pSender);
Добавим класс MyBodyParser
#include "MyBodyParser.h"
и такой код внутри класса HelloWorld.
private:
// Данный класс будет отвечать за физику в нашей сцене
cocos2d::PhysicsWorld *sceneWorld;
void SetPhysicsWorld( cocos2d::PhysicsWorld *world ) { sceneWorld = world; };
Код требующий пояснений будет содержать комментарии.
Открываем HelloWorld.cpp и удаляем не нужную нам функцию menuCloseCallback(Ref* pSender).
Заменяем код из функции createScene() на такой.
Scene* HelloWorld::createScene()
{
// Создаём сцену с физикой
auto scene = Scene::createWithPhysics();
// Устанавливаем DEBUGDRAW_ALL, чтобы границы всех физических объектов обводились красной линией
scene->getPhysicsWorld()->setDebugDrawMask( PhysicsWorld::DEBUGDRAW_ALL );
// Создаём слой
auto layer = HelloWorld::create();
// и передаём в него указатель на физический мир
layer->SetPhysicsWorld( scene->getPhysicsWorld() );
// Добавляем созданный слой
scene->addChild( layer );
return scene;
}
Заменяем содержимое функции bool HelloWorld::init() на вот это.
bool HelloWorld::init()
{
//////////////////////////////
// 1. super init first
if ( !Scene::init() )
{
return false;
}
// Данная структура хранит расширение нашего экрана
auto visibleSize = Director::getInstance()->getVisibleSize();
//Создаём рамку размером visibleSize, то есть во весь экран, с физическим материалом по умолчанию и толщиной рамки 3 пикселя
auto edgeBody = PhysicsBody::createEdgeBox( visibleSize, PHYSICSBODY_MATERIAL_DEFAULT, 3 );
// Создаём новый узел, то есть объект сцены
auto edgeNode = Node::create();
// Устанавливаем на позицию по центру экрана
edgeNode->setPosition( visibleSize.width / 2, visibleSize.height / 2 );
// Добавляем к узлу физическое тело
edgeNode->setPhysicsBody( edgeBody );
//Добавляем узел к нашей сцене
this->addChild( edgeNode );
// Создаём спрайт
auto sprite = Sprite::create( "pampkin.png" );
// Проверяем - существует ли json-файл
if( MyBodyParser::getInstance()->parseJsonFile( "pampkin.json" ) )
{
// Создаём физическое тело. Второй параметр - имя тела(не путать с именем файла), третий параметр - материал, с которым вы можете поиграться устанавливая различные значения.
auto spriteBody = MyBodyParser::getInstance()->bodyFormJson( sprite, "pampkin", PhysicsMaterial( 1.0f, 0.0f, 1.0f ) );
if( spriteBody != nullptr )
{
// Устанавливаем тело для спрайта
sprite->setPhysicsBody( spriteBody );
}
else
{
CCLOG( "Object.cpp spriteBody is nullptr" );
}
}
else
{
CCLOG( "JSON file not found" );
}
// Установим спрайт в центре экрана
sprite->setPosition( Vec2( visibleSize.width / 2, visibleSize.height / 2 ) );
this->addChild( sprite );
return true;
}
Компилируем, запускаем и получаем такой результат.
Ну, и для того, чтобы более наглядно увидеть работу физики, можно заставить нашу тыкву вращаться.
sprite->getPhysicsBody()->setAngularVelocity( -10 );
Кому лень создавать тело в редакторе и вставлять куски кода приведённого выше в свой проект, могут скачать готовые папки с файлами Classes и Resources по этой ссылке.
Только не забудьте добавить всё необходимое в makefile. Надеюсь данная публикация, поможет новичкам быстрее освоиться с физикой в cocos2d-x.
Автор: EvilGoth