3.x系でもLive2Dのサンプルを動かす

![half.png](https://qiita-image-store.s3.amazonaws.com/0/2490/1f1f6787-b9df-c519-e0af-0ab0620ca4d4.png)

## 概要
[Live2Dとは](http://www.live2d.com/about)
> 当社が独自に開発した「Live2D」は、3Dのような彫刻的アプローチではなく、 「絵」そのものを完全2Dによって動かすことで立体的矛盾も 描き手の思い通りに表現できる、新時代の表現・クリエイティブツールです。

だそうです。

編集するためのツールの他、各種プラットフォーム用のSDKも提供されており、小規模事業者・一般ユーザは無料でSDKを利用することができます。
[Cubism SDK](http://www.live2d.com/products/cubism_sdk)

SDKに付属のCocos2d-x用サンプルが2.x系のものだったので、3.x系でも動かせるようにするための手順を記します。

## ライブラリをリンクする
提供されているSDKにはアーキテクト別にライブラリが入っているのでユニバーサルバイナリにするか、使わないものを削除して`lib`と`include`をプロジェクトに加えます。
![Live2D_SDK_iPhone_ES2_1_0_01_と_live2d_—_Live2DNode_cpp_と_sampleCocos2dx_—_SampleLive2DSprite_cpp.png](https://qiita-image-store.s3.amazonaws.com/0/2490/8373d0a3-5ac0-b34f-75e5-b0d1938d95ba.png)

## リソースをコピーする
サンプルの`sample/cocos2dx/sampleCocos2dx/Resources`からリソースをコピーしてきます。必要なものは.mocとテクスチャです。
![Resources_と_live2d_—_Live2DNode_cpp.png](https://qiita-image-store.s3.amazonaws.com/0/2490/a01f9b8e-2c99-fccb-752c-03e5d502e8f5.png)

## Live2D用クラスを作る
最後に表示用のクラスを作ります。サンプルと同じようにCocos2d-xのNodeを継承した描画用クラスのdrawをオーバライドしますが、3.x系ではレンダリング用のコマンドを積んでいくのでそのように修正します。

```cpp:Live2DNode.h
#ifndef __live2d__Live2DNode__
#define __live2d__Live2DNode__

#include "cocos2d.h"
#include "Live2DModelIPhoneES2.h"

class Live2DNode : public cocos2d::Node
{
public:
    Live2DNode();
    ~Live2DNode();
    virtual bool init();
    virtual void draw(cocos2d::Renderer *renderer, const cocos2d::Mat4 &transform, uint32_t flags);
    CREATE_FUNC(Live2DNode);
private:
    live2d::Live2DModelIPhoneES2* live2DModel;
    cocos2d::Vector<cocos2d::Sprite*> textures;
    cocos2d::CustomCommand live2DCommand;
};

#endif /* defined(__live2d__Live2DNode__) */
```
```cpp:Live2DNode.cpp
#include "Live2DNode.h"
#include "DrawProfileCocos2D.h"
#include "UtSystem.h"

using namespace cocos2d;
using namespace live2d;

Live2DNode::Live2DNode()
:live2DModel(nullptr)
{
}

Live2DNode::~Live2DNode()
{
    delete live2DModel;
    textures.clear();
}

bool Live2DNode::init()
{
    if (!Node::init()) {
        return false;
    }
    
    //Live2D Sample
	const char* MODEL = "haru.moc" ;
	const char* TEXTURES[] ={
		"texture_00.png" ,
		"texture_01.png" ,
		"texture_02.png" ,
		NULL
	} ;
    auto data = FileUtils::getInstance()->getDataFromFile(MODEL);
	unsigned char* buf = data.getBytes();
	unsigned long bufSize = data.getSize();
	
	live2DModel = Live2DModelIPhoneES2::loadModel( buf,bufSize ) ;
	
	for( int i = 0 ; TEXTURES[i] != NULL ; i++ ){
		Sprite* sprite = Sprite::create(TEXTURES[i]);
		
		int glTexNo = sprite->getTexture()->getName() ;
		live2DModel->setTexture( i , glTexNo ) ;//テクスチャとモデルを結びつける
		textures.pushBack(sprite);
	}
	//Live2Dモデルはローカル座標で左上を原点にして(CanvasWidth、CanvasWidth)
	//のサイズになるため、以下のようにして調整してください。
	float w = Director::getInstance()->getWinSize().width;
	float h = Director::getInstance()->getWinSize().height;
	float scx = 2.0 / live2DModel->getCanvasWidth() ;
	float scy = -2.0 / live2DModel->getCanvasWidth() * (w/h);
	float x = -1 ;
	float y = 1 ;
	float matrix []= {
		scx , 0 , 0 , 0 ,
		0 , scy ,0 , 0 ,
		0 , 0 , 1 , 0 ,
		x , y , 0 , 1
	} ;
	live2DModel->setMatrix(matrix) ;//位置を設定
    live2DCommand.func = [&]() {
        //モデルのパラメータを変更。動作確認用です。
        double t = (UtSystem::getUserTimeMSec()/1000.0) * 2 * M_PI ;
        live2DModel->setParamFloat("PARAM_ANGLE_X", (float)(30 * sin( t/3.0 )) );
        
        //Live2Dの描画前と描画後に以下の関数を呼んでください
        //live2d::DrawProfileCocos2D::preDraw() ;
        //live2d::DrawProfileCocos2D::postDraw() ;
        //これはOpenGLの状態をもとに戻すための処理です。
        //これを行わない場合、Cocos2DかLive2Dどちらかで状態の不整合が起こります。
        DrawProfileCocos2D::preDraw();
        
        live2DModel->update() ;
        live2DModel->draw() ;
        
        DrawProfileCocos2D::postDraw() ;
    };
    
    return true;
}

void Live2DNode::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags)
{
    live2DCommand.init(getGlobalZOrder());
    renderer->addCommand(&live2DCommand);
}
```
Nodeを生成し、シーンに追加して首を振る女の子が表示されれば成功です。