概要

このドキュメントでは、Cocos2d-xランタイムの使用方法について説明します。ランタイムの言語はC++です。書き出したJSONファイルを読み込んで、シーン内で再生する方法の例を説明します。

ランタイムを取得する

ランタイムをCreatureのGame Runtimesウィンドウから直接ダウンロードするか、リポジトリ(こちら)から取得することができます。

コンパイルに必要なライブラリ

コアランタイムファイルに加えて、以下のライブラリも含まれています:

  • gason (ヘッダーを含み、単一のgason.cppのソースもコンパイルします)

  • glm (ヘッダーのみでインクルードパスが設定されていることを確認してください)

これら2つのライブラリをプロジェクトのソース形式に含んでいるのを確認してください。

ヘッダインクルード

以下のヘッダーを含める必要があります:

#include "MeshBone.h"
#include "CreatureRenderer.h"

読み込みと初期化

dragonTest.jsonと呼ばれるエクスポートされたドラゴンのアニメーションファイルがあるとしましょう。character-dragon.pngと呼ばれる対応するテクスチャアトラスもあると仮定します。 最初にファイルアセットを読み込むことから始めます:

auto filename = CCFileUtils::getInstance()->fullPathForFilename("dragonTest.json");
auto texture_filename = CCFileUtils::getInstance()->fullPathForFilename("character-dragon.png");

CreatureModule::CreatureLoadDataPacket json_data;
CreatureModule::LoadCreatureJSONData(filename, json_data);

上のコードはJSONデータをディスクからメモリに読み込みます。次に、これらの読み込まれたアセットを利用できる実際のオブジェクトを作成しましょう:

auto cur_creature = std::shared_ptr<CreatureModule::Creature>(new CreatureModule::Creature(json_data));

creature_manager = new CreatureModule::CreatureManager(cur_creature);
creature_manager->CreateAnimation(json_data, "default");
creature_manager->CreateAnimation(json_data, "second");    

上記の例では、JSONファイルに2つのアニメーションクリップがあります: defaultsecondです。従って、creature_managerオブジェクトから2つのアニメーションを作成して再生できるようにする必要があります。

読み込みが完了したら、再生用のアクティブなアニメーションを設定できます:

creature_manager->SetActiveAnimationName("default");

これにより、現在アクティブなアニメーションとしてdefaultが設定されます。 キャラクターアニメーションをレンダリングするオブジェクトを作成します:

auto creature_renderer = CreatureRenderer::Renderer::create(
	creature_manager,CCTextureCache::getInstance()->addImage("character-dragon.png"));

これにより、テクスチャアトラス画像ファイルを持つCreature Rendererが作成されます。これが完了したら、いくつかの再生プロパティとレンダリングプロパティを設定できます:

creature_manager->SetIsPlaying(true);
creature_manager->SetShouldLoop(true);
creature_manager->SetMirrorY(true);
creature_renderer->setColor(cocos2d::Color3B(255, 255, 255));

Size visibleSize = Director::getInstance()->getVisibleSize();
Vec2 origin = Director::getInstance()->getVisibleOrigin();
creature_renderer->setScale(30.0);
creature_renderer->setPosition(Vec2(visibleSize.width/2 + origin.x, visibleSize.height/2 + origin.y));

最後に、シーンにオブジェクトを追加します:

this->addChild(creature_renderer, 1);

これで、あなたのキャラクターをCocos2dXに統合する基本的な手順が完了しました!

完全なコードサンプル

以下は完全なコードレイアウトです。ほとんどのコードは、デフォルトのCocos2dXプロジェクトスターターテンプレートから生成されています。ほとんどの作業を行う loadModel() メソッドに注意してください。

#include "HelloWorldScene.h"
#include "MeshBone.h"
#include "CreatureRenderer.h"

USING_NS_CC;

Scene* HelloWorld::createScene()
{
	 // 'scene' is an autorelease object
    auto scene = Scene::create();

    // 'layer' is an autorelease object
    auto layer = HelloWorld::create();

	 // add layer as a child to scene
    scene->addChild(layer);

    // return the scene
	 return scene;
}

void HelloWorld::loadModel()
{
	// The actual code that loads the character animation data
    auto filename = CCFileUtils::getInstance()->fullPathForFilename("dragonTest.json");
    auto texture_filename = CCFileUtils::getInstance()->fullPathForFilename("character-dragon.png");

    CreatureModule::CreatureLoadDataPacket json_data;
    CreatureModule::LoadCreatureJSONData(filename, json_data);

    auto cur_creature = std::shared_ptr<CreatureModule::Creature>(new CreatureModule::Creature(json_data));

    creature_manager = new CreatureModule::CreatureManager(cur_creature);
    creature_manager->CreateAnimation(json_data, "default");
	creature_manager->CreateAnimation(json_data, "second");

    creature_manager->SetActiveAnimationName("default");

    auto creature_renderer = CreatureRenderer::Renderer::create(creature_manager,                                                             			 CCTextureCache::getInstance()->addImage("character-dragon.png"));
    creature_manager->SetIsPlaying(true);
    creature_manager->SetShouldLoop(true);
    creature_manager->SetMirrorY(true);
    creature_renderer->setColor(cocos2d::Color3B(255, 255, 255));
    creature_renderer->SetDebugDraw(false);


    Size visibleSize = Director::getInstance()->getVisibleSize();
    Vec2 origin = Director::getInstance()->getVisibleOrigin();
    creature_renderer->setScale(30.0);
    creature_renderer->setPosition(Vec2(visibleSize.width/2 + origin.x, visibleSize.height/2 + origin.y));

    this->addChild(creature_renderer, 1);
	scheduleUpdate();
}

	// on "init" you need to initialize your instance
	bool HelloWorld::init()
	{
	    //////////////////////////////
	    // 1. super init first
	    if ( !Layer::init() )
   		 {
   	   	  return false;
	    }

	    Size visibleSize = Director::getInstance()->getVisibleSize();
   		 Vec2 origin = Director::getInstance()->getVisibleOrigin();

	    /////////////////////////////
		 // 2. add a menu item with "X" image, which is clicked to quit the program
   		 //    you may modify it.

	    // add a "close" icon to exit the progress. it's an autorelease object
	    auto closeItem = MenuItemImage::create(
                                       "CloseNormal.png",
                                       "CloseSelected.png",
                                       CC_CALLBACK_1(HelloWorld::menuCloseCallback, this));

		closeItem->setPosition(Vec2(origin.x + visibleSize.width - closeItem-	>getContentSize().width/2 ,
                            origin.y + closeItem->getContentSize().height/2));

	    // create menu, it's an autorelease object
	    auto menu = Menu::create(closeItem, NULL);
	    menu->setPosition(Vec2::ZERO);
	    this->addChild(menu, 1);

	    /////////////////////////////
	    // 3. add your codes below...

	    // add a label shows "Hello World"
	    // create and initialize a label

	    auto label = LabelTTF::create("Hello World", "Arial", 24);

	    // position the label on the center of the screen
	    label->setPosition(Vec2(origin.x + visibleSize.width/2,
                        origin.y + visibleSize.height - label->getContentSize().height));

	    // add the label as a child to this layer
	    this->addChild(label, 1);

	    // add "HelloWorld" splash screen"
	    auto sprite = Sprite::create("HelloWorld.png");

	    // position the sprite on the center of the screen
	    sprite->setPosition(Vec2(visibleSize.width/2 + origin.x, visibleSize.height/2 + origin.y));

	    // add the sprite as a child to this layer
	    this->addChild(sprite, 0);

		// Load your character
	    loadModel();

   		return true;
	}

void HelloWorld::menuCloseCallback(Ref* pSender)
{
    Director::getInstance()->end();
}

カスタム時間/フレーム範囲

現在アクティブなアニメーションに対してカスタム時間/フレーム範囲を設定できます。再生範囲を10〜20のフレーム範囲に制限したい場合は、次の操作を行います:

creature_manager->SetUseCustomTimeRange(true);
creature_manager->SetCustomTimeRange(10, 20);

アニメーションブレンディング

2つのアニメーションクリップをブレンドするには、次の手順を実行します:

creature_manager->SetBlending(true);
creature_manager->SetBlendingAnimations("default", "second");
creature_manager->SetBlendingFactor(0.5); // 0 to 1 blends between the 2 clips

自動ブレンドによるスムーズなトランジション

あるアニメーション状態から次のアニメーション状態にスムーズに移行したい場合、ランタイムでオートブレンディング機能を使用できます。

オートブレンディングを有効にするには、まず次の操作を行います:

creature_manager->SetAutoBlending(true);

すべてのアニメーションをあなたのCreature Manager Objectに追加した後、

自動ブレンディングを使用するには:

creature_manager->AutoBlendTo(NEW_ANIMATION_NAME, 0.1f);

上記のコードで、キャラクターがNEW_ANIMATION_NAMEというターゲットアニメーションにスムーズに移行します。2番目のパラメータは、遷移のデルタタイムを決定します。範囲は0.0〜1.0です。

ボーンの位置を変更する

場合によっては、キャラクターのボーンの位置を直接変更する必要があります。例えば、ボーンの位置をラグドール物理のスプリング/ジョイントに接続されたいくつかの剛体に従わせることができます。独自のカスタム要件に合わせてボーンの位置を設定する必要がある場合、次の操作を行う必要があります。まず、カスタムボーンオーバーライドメソッドを記述します。下記はy軸においてボーンを一定量動かした例です:

// This is an example of how you can use a callback function to modify the position of the bones
// on your character. In this example, we will displace all the bones by a fixed amount in y.
void
HelloWorld::bonesModifyCallback(std::unordered_map<std::string, meshBone *>& bones_map)
{
    for(auto& bone_data : bones_map)
    {
        auto cur_bone = bone_data.second;
        auto cur_start_pos = cur_bone->getWorldStartPt();
        auto cur_end_pos = cur_bone->getWorldEndPt();
    
        cur_start_pos.y -= 5;
        cur_end_pos.y -= 5;
    
        cur_bone->setWorldStartPt(cur_start_pos);
        cur_bone->setWorldEndPt(cur_end_pos);
    }
}

また、CreatureManagerにカスタムボーン修正コールバックを使用するために次のように伝える必要があります:

// Example of how to register a callback function to modify the bones
std::function<void (std::unordered_map<std::string, meshBone *>&) > cur_callback =
    std::bind(&HelloWorld::bonesModifyCallback, this, std::placeholders::_1);
creature_manager_2->SetBonesOverrideCallback(cur_callback);

キャラクターのインスタンス化とメモリ

キャラクターの複数コピー(例:2体のドラゴン)をインスタンス化する必要がある場合は、以下のようにアニメーションを作成する必要があります:

// Create and load the animations
auto new_animation_1 = std::shared_ptr<CreatureModule::CreatureAnimation>(
                                                                        new CreatureModule::CreatureAnimation(json_data,
                                                                                              "default"));

auto new_animation_2 = std::shared_ptr<CreatureModule::CreatureAnimation>(
                                                                          new CreatureModule::CreatureAnimation(json_data,
                                                                                                                "pose2"));

その後、新しいCreatureオブジェクト、新しいCreatureManagerオブジェクト、および新しいCreatureRendererオブジェクトを作成する必要があります。作成したアニメーションを、新しく作成したCreatureManagerオブジェクトに次のように追加します:

// Second creature instancing example. This shows you how to load a second creature.
// Because both the first and second creature share animation data, you end up
// saving memory.
auto creature_2 = std::shared_ptr<CreatureModule::Creature>(new CreatureModule::Creature(json_data));

CreatureModule::CreatureManager * creature_manager_2 = new CreatureModule::CreatureManager(creature_2);
creature_manager_2->AddAnimation(new_animation_1);
creature_manager_2->AddAnimation(new_animation_2);
creature_manager_2->SetActiveAnimationName("pose2");
creature_manager_2->SetIsPlaying(true);
creature_manager_2->SetUseCustomTimeRange(true);
creature_manager_2->SetCustomTimeRange(10, 60);

auto creature_renderer_2 = CreatureRenderer::Renderer::create(creature_manager_2,
                                                             CCTextureCache::getInstance()->addImage("character-dragon.png"));
creature_renderer_2->setColor(cocos2d::Color3B(255, 255, 255));
creature_renderer_2->setScale(30.0);
creature_renderer_2->setPosition(Vec2(visibleSize.width/2 + origin.x, visibleSize.height/2 + origin.y - 200));

this->addChild(creature_renderer_2, 1);

この例と前の例との違いは、最初にアニメーションが作成され、それぞれのCreatureManagersに追加されることです。これは、アニメーションに割り当てられたメモリ(最もエクスペンシブなもの)が標準の場所に格納されていることを意味します。複数のCreatureManagerオブジェクトは、CreatureAnimationオブジェクトの共有プールからアニメーションを追加します。

ポイントキャッシュによる再生パフォーマンスの高速化

ポーズエンジンのコストを支払わずにアニメーション再生のスピードを上げたい場合は、特定のアニメーションでポイントキャッシュを有効にすることができます。

ポイントキャッシングは本質的にアニメーションの頂点を保存し、再生がポーズエンジンをバイパスできるようにします。非常に複雑なスケルトンと変形を伴うキャラクタリグは、ポイントキャッシングによって大きな利益を得ます。

特定のアニメーションでポイントキャッシングを有効にするには、次のようにします:

my_creature_manager->MakePointCache("myAnimationName");

これがキャッシュの作成に必要なすべてです。キャッシュはキャラクターではなく、アニメーションに固有のものであることに注意してください。つまり、複数のキャラクターをインスタンス化した場合、そのアニメーションの単一キャッシュのコストのみを支払うことになります。これにより、メモリ節約と再生パフォーマンスの高速化を実現できます