見出し画像

動く立ち絵をゲームに実装したい!Unity&Live2d備忘録

Unity内でLive2dモデルを使う上で覚えておきたいことをメモしました。私と同じように初めてこの作業する人にとっても、少しでも参考になればと思い公開します。これで簡単なノベルゲームの立ち絵くらいは作れます。

注意
本番のUnityプロジェクトに読み込む前に、一度新規プロジェクトを作ってそこで一連の流れを予習しておくのが安全だと思われます。また、2dアクションゲーム等になるとまた数段階複雑なアニメーション・イベント制御が必要になると思うのでこの記事を参考にするのはおすすめしません。


0.Live2dモデルを作る。

1.モデルの書き出し

「ファイル→組み込み用ファイル書き出し→moc3ファイル書き出し」でUnityに読み込めるモデルを書き出しておく。4、5個ファイルが出力されるのでモデルの名前をつけたフォルダーにひとまとめにして入れておく(Unityに読み込むとき便利)

2.必要なアニメーションをLive2dで作っておく

・1モーション・表情ごとに1シーン作る
・Idle状態→実際のモーション・表情→Idle状態、で構成しておくとUnity側でのアニメーション制御が便利。
・まばたきと呼吸はUnity側でつけられるのでここでつける必要はない
・喋っている「風」に見せたいだけならここで適当に口の動きをつけておく(音声に対応した口の動きをしなくても問題ない場合のみ)
一通り作れたらファイル→組み込み用ファイル書き出し→モーションファイル書き出し。JSONファイルが書き出されるのでMotionという名前のフォルダーを作ってひとまとめにして入れておく(Unityに読み込むとき便利)

3.Live2dモデルを受け入れるUnity側の下準備

Live2D Cubism SDK | Live2D CubismでLive2D Cubism SDK for UnityをDLして、それをUnityプロジェクトに「Assets→Import Package→Custom Package」からインポートする。Unity再起動。

4.Unityにモデルを読み込む

1手順目で作ったモデルフォルダーをUnityのAssets欄にD&D。無事読み込めたらAsset欄にあるプレハブ(青い箱のアイコン)をHierarchy欄にD&Dする。一度再生ボタンを押すとモデルが正常に表示される。カメラやモデルのサイズ、位置を調整してモデルがしっかりゲーム画面に映るようにする。

5.呼吸とまばたきをつけていく

わかりやすい解説↓

ここには要点を書いておきます。

呼吸
・モデルのルートオブジェクトにCubismHarmonicMotionControllerをつけてBlendModeをOverrideに設定。
・呼吸パラメーターを制御しているオブジェクト(大体ParamBreath)にCubismHarmonicMotionParamterをつける。

まばたき
モデルのルートオブジェクトにCubismEyeBlinkControllerとCubismAutoEyeInputをつける
・目の開閉を制御しているオブジェクト(大体ParamEyeLOpenとParamEyeROpen)にCubismEyeBlinkParamterをつける。

6.アニメーションをつける

ノベルゲームの場合、このシーンやセリフにはこのモーション、というアニメーションの再生の仕方をすると思います。このくらいの処理であればUnityのAnimatorを介さずにできるみたいです。やったぜ。

Aパート
公式ページから出ているやり方:
スクリプトからモーションを再生させる | SDKチュートリアル | Live2D Manuals & Tutorials

上記記事は「ボタンをクリックすると対応するアニメーションが再生される」仕組みの作り方を説明しています。要点を書いておくと

  1. 先ほど作ったMotionフォルダーをAssets欄にD&D。

  2. モデルのルートオブジェクトにCubismMotionControllerをつける。

  3. CubismFadeControllerのCubismFadeMotionListに(モデル名).fadeMotionListを入れる

  4. MotionPlayerというC#スクリプトを作って上記記事からコードをコピペ

  5. MotionPlayerスクリプトをモデルのルートオブジェクトにアタッチ

  6. UIからボタンを作り、OnClick()の二重丸にモデルを入れる。呼び出す関数としてMotionPlayer.PlayMotion()を設定すると新たに設定できるパラメーターが増えるので、そこに「ボタンを押したときに再生してほしいアニメーション(青い三角形のアイコン)」を入れる。

Bパート
上の方法はInspector上で直接アニメーションオブジェクトをセットすることで成り立っている方法です。今度はアニメーションの指定をスクリプト間で完結させたい場合のやり方を書いていきます。書くコードが増えるだけでやり方はほぼ変わりません。

※どんな時に使うの?:例えばノベルゲームならセリフの制御はスクリプトで行うと思います。セリフを管理している関数が「このセリフが表示されているときはこのアニメーションを再生してほしい」という指示を出すには、そのアニメーションオブジェクトにスクリプト内からアクセスする必要があります。

今回は試しに「クリックするとランダムでアニメーションが再生されるボタン」を作っていきます。

(3までは一緒)
4. Assets欄でResourcesという名前のフォルダーを作る。このResourcesフォルダーがないとこれから書くスクリプトが意味を成さない
5. Resourcesフォルダーの中にMotionフォルダーを移す
6. MotionPlayerスクリプトにPlayMotionFromName()という新しい関数を作る。先ほどのPlayMotionと違ってこの関数は引数がstring型になっている。

    public void PlayMotionFromName(string animationName){
    // MotionControllerがみつからなければエラーを吐く
        if (_motionController == null){
            Debug.LogError("Motion controller is null.");
            return;
        }

       // アニメーションをResourcesフォルダーから読み込む
    // Resoucesフォルダーの中にMotionフォルダーが入っているのでパスもきちんと書いてあげる
        AnimationClip animation = Resources.Load<AnimationClip>("Motion/" + animationName);
    
    // アニメーションが見つからなければエラーを吐く
        if (animation == null){
            Debug.LogError($"Animation {animationName} not found in Resources.");
            return;
        }

        _motionController.PlayAnimation(animation, isLoop: false);
    }

7. UIから新たにボタンを作り適当にランダムと名付ける。RandomAnimationというスクリプトを作成。こんなコードを書いて新しいボタンにアタッチする。Inspector上でmodelパラメーターにモデルのオブジェクトをセットする。
ボタンのOnClickで、二重丸にはボタンオブジェクト自身を、呼ぶ関数としてrandomBttnClicked()をセットする。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class RandomAnimation : MonoBehaviour
{
  // モーションを実際に再生するMotionPlayerにアクセスするのに必要
    private MotionPlayer motionPlayer;
    public GameObject model;

    void Start(){
        motionPlayer = model.GetComponent<MotionPlayer>();
    }

    public void randomBttnClicked(){
        // リストにはアニメーションの名前を入れていく
        List<string> animationList = new List<string>{"Confused", "Neutral", "Smile", "Sad"};

        string animationName = animationList[UnityEngine.Random.Range(0, animationList.Count)];
        
        // 再生したいアニメーションの名前をmotionPlayer.PlayMotion()に渡す
        motionPlayer.PlayMotionFomName(animationName);
    }
}

※MotionPlayerスクリプトを変えたことによりAパートで行ったボタンの設定がリセットされています。A-6工程目をもう一度行うと元通り表情・モーションに対応したボタンが動くようになります。

今回はボタンクリックがトリガーとなっていますが、例えばノベルゲームのセリフ送りを担当している関数内でmotionPlayer.PlayMotionFromName(animationName);を呼べばセリフを進めるごとにどんなアニメーションを流すか管理することができます。


全ての工程を順序通りに終えていれば、ゲームを再生したときに
・自動で呼吸とまばたきを行い、
・ボタンをクリックすると対応するアニメーションが再生され、
・ランダムボタンをクリックすればランダムなアニメーションが再生される
立ち絵ができていると思います。

番外編:新規アニメーションをUnityに追加するときに発生するエラー

「新しいアニメーション作ったからUnityに入れよう~」と軽い気持ちでインポートしたらひどい目にあったので解決策(力技なので根本的な解決ではない)を書いておきます。
結論:モデルとMotionフォルダを入れ直してください。

出たエラー:CubismMotionController : Not found motion from CubismFadeMotionList.
詳しいことは分かりませんが、たぶんCubismFadeMotionListに新しく追加したアニメーションのFadeMotionオブジェクトがないのでエラーが吐かれるのだと思います。

FadeMotionListのInspector.元々あったアニメーションが4個、新たに1個追加したのでElement4まであるべきですがここがきちんとアップデートされていないのでエラーが出る

FadeMotionオブジェクトはアニメーションをUnityにD&Dするだけで自動的に作られるし、じゃあ手動でここにIdとモーションオブジェクトを足せばいいじゃないか、と最初は思いました。しかし肝心のインスタンスIdをどう見つければいいのかが分かりませんでした(publicなゲームオブジェクトを作ってInspectorで直に(アニメーション名).fadeをセットし、そのオブジェクトのGetInstanceID()を呼ぼうとしましたが、そもそもInspector上でセットできない)。
正直Idを探し続けるよりもモデルを丸ごと入れ直す方が早いと判断しました。

「Unityに新たなアニメーションを足したときに発生するエラー:CubismMotionController : Not found motion from CubismFadeMotionList.の解決方法」がわかる方がいれば教えていただけると嬉しいです。私はエラー名で検索をかけても解決方法が見つけられませんでした…。無力。

その他参考になるリンク



いいなと思ったら応援しよう!