LoginSignup
5
4

More than 5 years have passed since last update.

JokerScriptでLive2Dモデルをマウスドラッグの方向に向かせる

Posted at

需要がありそうなのでやり方をメモしておきます。

開発環境

・Live2D_SDK_Unity_2.1.00_1_jp
・Unity5.2.0f3
・jokerscript_v041
・live2d_for_joker_plugin_031

マウスドラッグのやり方

Live2D Unity SDKのDemoプロジェクトで一番シンプルなマウスドラッグができます。
要するにこれをJokerScriptに組み込めばOKですっ!
JokerScriptの方もLive2Dのスクリプトは、SimpleModel.csと同名のファイルになっています。

1)L2DTargetPoint.csをインポート
JokerScriptの方にマウスドラッグ用のスクリプトをインポートします
UnityInspector.png

2)SimpleModel.csにマウスドラッグ処理を追加

SimpleModel.cs
using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using live2d.framework;
using live2d;


public class SimpleModel : MonoBehaviour
{
    public TextAsset modelJson;                             // JSONファイル
    private TextAsset mocFile;                              // Mocファイル
    private Texture2D[] textures;                           // テクスチャファイル
    private TextAsset[] mtnFiles;                           // モーションファイル
    private string[] mtnFilenms;                            // モーションファイル名
    private int[] mtnFadeines;                              // フェードイン
    private int[] mtnFadeoutes;                             // フェードアウト
    private AudioClip[] soundFiles;                         // 音声ファイル
    private TextAsset poseFile;                             // ポーズファイル 
    private TextAsset physicsFile;                          // 物理演算ファイル 
    private Live2DModelUnity live2DModel;
    private Live2DMotion motion;                            // モーションクラス
    private MotionQueueManager motionManager;               // モーション管理クラス
    private L2DPose pose;                                   // パーツ切り替えクラス
    private L2DPhysics physics;                             // 物理演算クラス
    private Matrix4x4 live2DCanvasPos;                      // 表示位置
    private int motioncnt = 0;                              // ファイル項番
    private EyeBlinkMotion eyeBlink = new EyeBlinkMotion();
    private L2DTargetPoint dragMgr = new L2DTargetPoint();


    /// <summary>
    /// 初期化処理
    /// </summary>
    void Start()
    {
        // JSONを読込
        Json_Read();
        // Live2D初期化
        Live2D.init();
        // モーション管理クラスのインスタンス
        motionManager = new MotionQueueManager();
        // モーションのインスタンス
        motion = Live2DMotion.loadMotion(mtnFiles[0].bytes);
        // モーションの再生
        motionManager.startMotion(motion, false);
        // 表示位置
        float modelWidth = live2DModel.getCanvasWidth();
        live2DCanvasPos = Matrix4x4.Ortho(0, modelWidth, modelWidth, 0, -50.0f, 50.0f);
    }


    /// <summary>
    /// 更新処理
    /// </summary>
    void Update()
    {
        // 再生中のモーションからモデルパラメータを更新
        if(motionManager != null )
        {
            motionManager.updateParam(live2DModel);
        }
        // ポーズの設定
        if (pose != null) pose.updateParam(live2DModel);
        // 物理演算の設定
        if (physics != null) physics.updateParam(live2DModel);

        // モーション再生が終了した場合
        if (motionManager != null && motionManager.isFinished())
        {
            // モーションをロードする
            motion = Live2DMotion.loadMotion(mtnFiles[motioncnt].bytes);
            // フェードインの設定
            motion.setFadeIn(mtnFadeines[motioncnt]);
            // フェードアウトの設定
            motion.setFadeOut(mtnFadeoutes[motioncnt]);
            // モーション再生
            motionManager.startMotion(motion, false);
            // 音声再生
            if (soundFiles[motioncnt] != null)
            {
                GetComponent<AudioSource>().clip = soundFiles[motioncnt];
                GetComponent<AudioSource>().Play();
            }
        }
        var pos = Input.mousePosition;
        if (Input.GetMouseButtonDown(0))
        {
            //
        }
        else if (Input.GetMouseButton(0))
        {
            dragMgr.Set(pos.x / Screen.width * 2 - 1, pos.y / Screen.height * 2 - 1);
        }
        else if (Input.GetMouseButtonUp(0))
        {
            dragMgr.Set(0, 0);
        }


        dragMgr.update();
        live2DModel.setParamFloat("PARAM_ANGLE_X", dragMgr.getX() * 30);
        live2DModel.setParamFloat("PARAM_ANGLE_Y", dragMgr.getY() * 30);

        live2DModel.setParamFloat("PARAM_BODY_ANGLE_X", dragMgr.getX() * 10);

        live2DModel.setParamFloat("PARAM_EYE_BALL_X", -dragMgr.getX());
        live2DModel.setParamFloat("PARAM_EYE_BALL_Y", -dragMgr.getY());

        double timeSec = UtSystem.getUserTimeMSec() / 1000.0;
        double t = timeSec * 2 * Math.PI;
        live2DModel.setParamFloat("PARAM_BREATH", (float)(0.5f + 0.5f * Math.Sin(t / 3.0)));

        eyeBlink.setParam(live2DModel);
        // 頂点の更新
        live2DModel.update();
    }


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


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


        // モデルを読み込む
        mocFile = new TextAsset();
        mocFile = (Resources.Load(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(json.get("textures").get(i).toString(), ".png$", "");
            textures[i] = (Resources.Load(texturenm, typeof(Texture2D)) as Texture2D);
            live2DModel.setTexture(i, textures[i]);
        }

        // モーションの配下のキーを取得
        Dictionary<string, Value> motion_keys = json.get("motions").getMap(null);
        int mtn_tag = 0;
        int mtn_num = 0;
        string[] motion_tags = new string[motion_keys.Count];

        // 読込モーションファイル数カウント用
        foreach (var mtnkey in motion_keys)
        {
            // motions配下のキーを取得
            motion_tags[mtn_tag] = mtnkey.Key.ToString();
            // 読み込むモーションファイル数を取得
            mtn_num += json.get("motions").get(motion_tags[mtn_tag]).getVector(null).Count;
            mtn_tag++;
        }
        // インスタンス化
        mtnFiles = new TextAsset[mtn_num];
        soundFiles = new AudioClip[mtn_num];
        mtnFadeines = new int[mtn_num];
        mtnFadeoutes = new int[mtn_num];

        mtn_tag = 0;
        mtn_num = 0;
        // モーションファイル数分JSON読込
        foreach (var mtnkey in motion_keys)
        {
            // モーションとサウンドを読み込む(motions配下のタグを読み込む)
            Value motionPaths = json.get("motions").get(motion_tags[mtn_tag]);
            int motionNum = motionPaths.getVector(null).Count;

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

        // ポーズファイルを読み込む
        if (json.getMap(null).ContainsKey("pose"))
        {
            Value posepath = json.get("pose");
            poseFile = new TextAsset();
            poseFile = (Resources.Load(posepath.toString(), typeof(TextAsset)) as TextAsset);
            // pose.jsonを読み込む
            char[] posebuf = poseFile.text.ToCharArray();
            // パーツ切り替えクラスへ渡す
            pose = L2DPose.load(posebuf);
        }

        // 物理演算ファイルを読み込む
        if (json.getMap(null).ContainsKey("physics"))
        {
            Value physicpath = json.get("physics");
            physicsFile = new TextAsset();
            physicsFile = (Resources.Load(physicpath.toString(), typeof(TextAsset)) as TextAsset);
            // physics.jsonを読み込む
            char[] physicsbuf = physicsFile.text.ToCharArray();
            // 物理演算クラスへ渡す
            physics = L2DPhysics.load(physicsbuf);
        }
    }


    /// <summary>
    /// モーションのチェンジ
    /// </summary>
    /// <param name="storage">モーションファイル名</param>
    /// <param name="idle">アイドリング有無</param>
    public void Motion_change(string storage, string idle)
    {
        int cnt = 0;
        for (int m = 0; m < mtnFiles.Length; m++)
        {
            if (mtnFiles[m].name == storage)
            {
                break;
            }
            cnt++;
        }

        // アイドルフラグがONなら、指定したモーションをアイドリングさせる
        if (idle != "")
        {
            motioncnt = cnt;
        }

        /*
        int cnt = 0;
        string filenm = Regex.Replace (storage, ".bytes$","");
        // モーションファイル名を検索
        foreach (string mtnNm in mtnFilenms)
        {
            if(mtnNm == filenm)
            {
                break;
            }
            cnt++;
        }
        */

        // モーションのロードをする
        motion = Live2DMotion.loadMotion(mtnFiles[cnt].bytes);
        // フェードインの設定
        motion.setFadeIn(mtnFadeines[cnt]);
        // フェードアウトの設定
        motion.setFadeOut(mtnFadeoutes[cnt]);
        // モーション再生
        motionManager.startMotion(motion, false);
        // サウンドがあればボイス再生

        if (soundFiles[cnt] != null)
        {
            GetComponent<AudioSource>().clip = soundFiles[cnt];
            GetComponent<AudioSource>().Play();
        }
    }
}

はい、これで完成しました!
JokerScriptにはLive2Dのソースは結構わかりやすい形だと思うので、自由にカスタムしちゃって下さい。
001.gif

5
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4