概述

阅读本文档,您可以了解如何使用Cocos2d-x运行库。该运行库使用C++语言。我们将通过一个示例来说明如何加载导出的JSON文件并在场景中进行播放。

获取运行库

您可以直接从Creature游戏运行库窗口下载运行库,或点击 这里从版本库获取运行库。

编译程序库

Cocos2d-x运行库除核心运行库文件外,还包括以下程序库:

  • gason(包含标头文件,并可编译单个gason.cpp源)

  • glm(仅含标头,请确保已为其设置路径)

请确保您的项目中已包含这两个源形式程序库。

所含标头

应包括以下标头:

#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个动画剪辑:默认剪辑和第二剪辑。因此,您需要从Creature管理器对象创建2个动画,使它们可以播放。

至此已完成加载,您可以设置活动状态的动画用于播放:

creature_manager->SetActiveAnimationName("default");

上述操作将默认剪辑设置为当前活动的动画。现在继续创建对象来渲染角色动画:

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

上述操作将创建一个含纹理图谱文件的Creature渲染器。该操作完成后,您可以继续设置一些播放和渲染属性:

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的基本说明!

Complete Code Sample

以下为完整的代码布局。大多数代码是从默认的Cocos2dX项目启动器模板生成的。请注意**loadModel()**方法,该方法执行了大部分工作:

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

USING_NS_CC;

Scene* HelloWorld::createScene()
{
	 // ‘scene’是一个自动释放对象
    auto scene = Scene::create();

    // ‘layer’是一个自动释放对象
    auto layer = HelloWorld::create();

	 // 将图层添加为场景的子级
    scene->addChild(layer);

    // 返回场景
	 return scene;
}

void HelloWorld::loadModel()
{
	// 加载角色动画数据的实际代码
    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();
}

	// 在“init” 需要初始化实例
	bool HelloWorld::init()
	{
	    //////////////////////////////
	    // 1. 优先调用
	    if ( !Layer::init() )
   		 {
   	   	  return false;
	    }

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

	    /////////////////////////////
		 // 2. 添加一个带有“X”图像的菜单项,点击它退出程序
   		 //     可以修改它。

	    // 添加“关闭”图标退出进度。它是一个自动释放对象
	    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));

	    // 创建菜单,它是一个自动释放对象
	    auto menu = Menu::create(closeItem, NULL);
	    menu->setPosition(Vec2::ZERO);
	    this->addChild(menu, 1);

	    /////////////////////////////
	    // 3. 在下面添加代码...

	    // 添加标签显示 "Hello World"
	    // 创建和初始化标签

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

	    // 将标签放在屏幕中心
	    label->setPosition(Vec2(origin.x + visibleSize.width/2,
                        origin.y + visibleSize.height - label->getContentSize().height));

	    // 将标签作为子级添加到此图层
	    this->addChild(label, 1);

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

	    // 将子画面放置在屏幕中心
	    sprite->setPosition(Vec2(visibleSize.width/2 + origin.x, visibleSize.height/2 + origin.y));

	    // 将子画面作为子级添加到此图层
	    this->addChild(sprite, 0);

		// 加载您的角色
	    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到1

使用自动混合进行平滑过渡

如需从一个动画状态平滑地过渡到下一个动画状态,您可以在运行库使用自动混合功能。

要启用自动混合,首先:

creature_manager->SetAutoBlending(true);

将所有动画添加到Creature管理器对象后。

要使用自动混合,只需一次调用:

creature_manager->AutoBlendTo(NEW_ANIMATION_NAME, 0.1f);

上述操作将使角色平滑地过渡到名为NEW_ANIMATION_NAME的目标动画。第二个参数确定过渡的时间增量,范围为0.0到1.0。

覆盖、修改骨骼位置

某些情况下,您需要直接修改角色的骨骼位置。例如,为了添加布娃娃物理效果,您可能希望骨骼位置与若干由弹簧或关节连接在一起的刚体保持一致。在这种情况下,您需要为自己的自定义要求设置骨骼位置,您可以执行以下操作。首先,编写自定义骨骼覆盖方法。在下面的例子中,修改了骨骼y方向上的位置:

// 这是一个如何使用回调函数修改您角色中的骨骼位置的示例。
// 在这个例子中,我们将所有的骨骼在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);
    }
}

您还需要告诉Creature管理器使用您的自定义骨骼修改回调,如下所示:

// 如何注册回调函数来修改骨骼的示例
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条龙),您可以创建这样的动画:

// 创建和加载动画
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对象、一个新的Creature管理器对象和一个新的Creature渲染器对象。您可以添加创建的动画到您新创建的Creature管理器对象中,如下所示:

// 第二个Creature实例示例。这将告诉你如何加载第二个Creature。
// 因为第一和第二个生物共享动画数据,您能够
// 节省内存。
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);

该示例和之前示例的区别在于:先创建动画,后将其添加到各自的Creature管理器中。这就意味着为(最昂贵的)动画分配的内存存储在标准位置。多个Creature管理器对象将从Creature动画对象的公共池添加动画。

使用点缓存提高播放性能

如果您希望提高动画播放速度,也不想占用引擎资源,您可以在特定的动画上启用点缓存。

点缓存实际上直接存储动画的顶点,可以使播放不必占用引擎。在具有非常复杂的骨架和变形的角色绑骨上使用点缓存将非常高效。

要对特定动画启用点缓存,请执行以下操作:

my_creature_manager->MakePointCache("myAnimationName");

上述即为创建缓存的所有操作。请注意:缓存适用于特定的动画,而不是角色。这就意味着如果您实例化了多个角色,也只需使用该动画的单个缓存,即可节省内存并提升播放性能