Edited at

Live2DのUnity版でシンプル実装

More than 3 years have passed since last update.

Live2DのSampleApp1プロジェクトは全部入りですが、複雑で難しいです。

最も簡単なSimpleプロジェクトをカスタムしてモーション・音声が再生できるシンプル実装してみました。


Live2Dで音声・モーション付きのシンプル実装

でき上がりは、UGUIボタン操作でモーション再生するかんじ

2015-02-18_21h27_36.png

InspectorはこんなかんじでスクリプトとAudio Sourceだけ。

PathにはResources配下のフォルダ名をセットしてます。

2015-02-18_21h27_25.png

フォルダ構成はResourcesの下にLive2Dモデルをいれておきます。

ここにあるmodel.jsonをInspectorにセットしています。model.jsonはLive2D Cubism Modelerから出力できます。

2015-02-18_21h29_43.png


ソースコード

モーションボタンが押されない限り、配列0番目のモーションがループ再生される仕様です。

配列0番目のモーションはmodel.json上で指定します(model.jsonもソースコードの下に書きました!)

2015/09/17追記

Live2D Unity SDK2.1からクリッピングマスク使用モデルの場合はlive2DModel.updateのタイミングが変更


SimpleModel.cs

using UnityEngine;

using System;
using System.Collections;
using System.Text.RegularExpressions;
using live2d;

[ExecuteInEditMode]
public class SimpleModel : MonoBehaviour
{
public string path; // モデルパス
public TextAsset modelJson; // model.json
private string modelpath; // モデルパス
private TextAsset mocFile; // モデルファイル
private Texture2D[] textures; // テクスチャファイル
private TextAsset[] mtnFiles; // モーションファイル
private int[] mtnFadeines; // フェードイン
private int[] mtnFadeoutes; // フェードアウト
private AudioClip[] soundFiles; // 音声ファイル
private Live2DModelUnity live2DModel;
private Live2DMotion motion; // モーションクラス
private MotionQueueManager motionManager; // モーション管理クラス
private Matrix4x4 live2DCanvasPos;
private int motioncnt = 0; // モーション番号

/// <summary>
/// 初期処理
/// </summary>
void Start ()
{
// Live2D初期化
Live2D.init();
// model.jsonを読み込む
Json_Read();
// モーション管理クラスのインスタンス作成
motionManager = new MotionQueueManager();
// モーションのインスタンス作成
motion = Live2DMotion.loadMotion(mtnFiles[motioncnt].bytes);
// モーションの再生
motionManager.startMotion(motion, false);

// Live2Dモデルの表示位置計算
float modelWidth = live2DModel.getCanvasWidth();
live2DCanvasPos = Matrix4x4.Ortho(0, modelWidth, modelWidth, 0, -50.0f, 50.0f);
}

/// <summary>
/// model.jsonを読み込む
/// </summary>
void Json_Read()
{
// model.jsonを読み込む
char[] buf = modelJson.text.ToCharArray();
Value json = Json.parseFromBytes(buf);

modelpath = path + "/";

// モデルを読み込む
mocFile = new TextAsset();
mocFile = (Resources.Load(modelpath + json.get("model").toString(), typeof(TextAsset)) as TextAsset);
live2DModel = Live2DModelUnity.loadModel(mocFile.bytes);

// テクスチャを読み込む
int texture_num = json.get("textures").getVector(null).Count;
textures = new Texture2D[texture_num];

for (int i = 0; i < texture_num; i++)
{
// 不要な拡張子を削除
string texturenm = Regex.Replace(modelpath + json.get("textures").get(i).toString(), ".png$", "");
textures[i] = (Resources.Load(texturenm, typeof(Texture2D)) as Texture2D);
live2DModel.setTexture(i, textures[i]);
}

// モーションとサウンドを読み込む(motions配下のタグを読み込む)
Value mtnpath = json.get("motions").get("null");
int mtn_num = mtnpath.getVector(null).Count;
mtnFiles = new TextAsset[mtn_num];
soundFiles = new AudioClip[mtn_num];
mtnFadeines = new int[mtn_num];
mtnFadeoutes = new int[mtn_num];

for (int n = 0; n < mtn_num; n++)
{
mtnFiles[n] = (Resources.Load(modelpath + mtnpath.get(n).get("file").toString()) as TextAsset);
// サウンドファイルがあれば入れる
if (mtnpath.get(n).getMap(null).ContainsKey("sound"))
{
// 不要な拡張子を削除
string soundnm = Regex.Replace(Regex.Replace(modelpath + mtnpath.get(n).get("sound").toString(), ".mp3$", ""), ".wav$", "");
soundFiles[n] = (Resources.Load(soundnm, typeof(AudioClip)) as AudioClip);
}
//フェードイン
if (mtnpath.get(n).getMap(null).ContainsKey("fade_in"))
{
mtnFadeines[n] = int.Parse(mtnpath.get(n).get("fade_in").toString());
}
//フェードアウト
if (mtnpath.get(n).getMap(null).ContainsKey("fade_out"))
{
mtnFadeoutes[n] = int.Parse(mtnpath.get(n).get("fade_out").toString());
}
}
}

/// <summary>
/// 更新処理
/// </summary>
void Update()
{
// モーション再生が終了した場合
if (motionManager != null && motionManager.isFinished())
{
motioncnt = 0;
// モーションをロードする
motion = Live2DMotion.loadMotion(mtnFiles[motioncnt].bytes);
// フェードインの設定
if (mtnFadeines[motioncnt] != null) motion.setFadeIn(mtnFadeines[motioncnt]);
// フェードアウトの設定
if (mtnFadeoutes[motioncnt] != null) motion.setFadeOut(mtnFadeoutes[motioncnt]);
// モーション再生
motionManager.startMotion(motion, false);
}
}

/// <summary>
/// カメラシーンにレンダリング時呼ばれる
/// </summary>
void OnRenderObject()
{
if (live2DModel == null) return;
live2DModel.setMatrix(transform.localToWorldMatrix * live2DCanvasPos);
// アプリが終了していた場合
if (!Application.isPlaying)
{
live2DModel.update();
live2DModel.draw();
return;
}

// 再生中のモーションからモデルパラメータを更新
motionManager.updateParam(live2DModel);
// 頂点の更新
live2DModel.update();
// モデルの描画
live2DModel.draw();
}

/// <summary>
/// モーションチェンジ
/// </summary>
/// <param name="filenm"></param>
void Motion_change(string filenm)
{
int cnt = 0;
for (int m = 0; m < mtnFiles.Length; m++)
{
if (mtnFiles[m].name == filenm)
{
break;
}
cnt++;
}
// モーションのロードをする
motion = Live2DMotion.loadMotion(mtnFiles[cnt].bytes);
// フェードインの設定
if (mtnFadeines[cnt] != null) motion.setFadeIn(mtnFadeines[cnt]);
// フェードアウトの設定
if (mtnFadeoutes[cnt] != null) motion.setFadeOut(mtnFadeoutes[cnt]);
// モーション再生
motionManager.startMotion(motion, false);
// 音声再生
if (soundFiles[cnt] != null)
{
audio.clip = soundFiles[cnt];
audio.Play();
}
}

// UGUIから呼び出す処理1
public void Motion_idle1()
{
Motion_change("tetudau.mtn");
}

// UGUIから呼び出す処理2
public void Motion_idle2()
{
Motion_change("nurupo.mtn");
}
}


model.jsonはこんなかんじでmoitons-null配下の1行目をアイドルモーションとしてます


model.json

{

"version":"Sample 1.0.0",
"model":"model/model.moc",
"textures":[
"model/model.1024/texture_00.png"
],
"motions":{
"null":[
{"file":"motions/idle.mtn"},
{"file":"motions/chotto.mtn","sound":"sounds/kei_voice_020_1.mp3","fade_in":100,"fade_out":100},
{"file":"motions/nurupo.mtn","sound":"sounds/kei_voice_035_1.mp3","fade_in":100,"fade_out":100},
{"file":"motions/otukare.mtn","sound":"sounds/kei_voice_017_2.mp3","fade_in":100,"fade_out":100},
{"file":"motions/tetudau.mtn","sound":"sounds/kei_voice_023_2.mp3","fade_in":100,"fade_out":100}
],
"idle":[
{"file":"motions/idle.mtn"}
]
},
"physics":"embed://Sample Physics.json"
}
code

HierarchyウィンドウでCreateボタンでUI-Buttonして、

UGUIボタンからOnClick()イベントを呼べばモーションと音声再生できるシンプル実装の出来上がりです!

2015-02-18_21h34_14.png

あと以前MiniJSON使ったものをブログに書いたけど、Live2DのライブラリにはJson解析コードが含まれていて、外部のものを使う必要ありませんでした~。

参考URL:Live2DでJSON対応のUnityコード書いた