與二次元老婆邂逅的遊戲的創建過程(三)

上期我們讓老婆進行了一些簡單的動作
但是因爲沒有頭髮擺動顯得不自然
所以今天我們來給老婆加上頭髮的自然搖擺
廢話少說我們開始吧


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using live2d;
using live2d.framework;

public class live2dModel : MonoBehaviour
{
   
   
    public TextAsset modelFile;
    private Live2DModelUnity live2DModel;
    private Matrix4x4 live2DCanvasPos;
    public Texture2D[] textures;

    private L2DMotionManager L2DMotionManager;
    public TextAsset[] motionFiles;
    private Live2DMotion[] motions;
    private MotionQueueManager motionQueueManager;
    public int motionIndex;

    //自動眨眼
    private EyeBlinkMotion eyeBlinkMotion;

    //鼠標拖拽引起動作變化
    private L2DTargetPoint drag;

    //套物理運算的設定
    private PhysicsHair physicsHairSideLeft;
    private PhysicsHair physicsHairSideRight;
    private PhysicsHair physicsHairBackLeft;
    private PhysicsHair physicsHairBackRight;


    // Use this for initialization
    void Start()
    {
   
   

        //初始化
        Live2D.init();
        //讀取模型
        //TextAsset modelFile = Resources.Load<TextAsset>("Epsilon/runtime/Epsilon.moc");
        live2DModel = Live2DModelUnity.loadModel(modelFile.bytes);
        //與貼圖建立聯繫
        //Live2DModelUnity.loadModel(modelFile.bytes);

        for (int i = 0; i < textures.Length; i++)
        {
   
   
            live2DModel.setTexture(i, textures[i]);
        }
        //指定顯示位置與尺寸(實用正交矩陣與相關API顯示圖像,再由遊戲物體的位置和攝像機的size調整到合適的位置)
        float modelWidth = live2DModel.getCanvasWidth();

        live2DCanvasPos = Matrix4x4.Ortho(0, modelWidth, modelWidth, 0, -50, 50);

        //播放動作
        //實例化動作對象
        motions = new Live2DMotion[motionFiles.Length];
        for (int i = 0; i < motions.Length; i++)
        {
   
   
            motions[i] = Live2DMotion.loadMotion(motionFiles[i].bytes);

        }
        //設置某一個動畫的屬性

        //重複播放不淡入
        motions[0].setLoopFadeIn(false);
        //設置淡入淡出時間,參數單位爲毫秒
        motions[0].setFadeOut(1000);
        motions[0].setFadeIn(1000);
        //動畫是否循環播放
        //motions[0].setLoop(true);

        //motionQueueManager = new MotionQueueManager();
        //motionQueueManager.startMotion(motions[0]);
        #region 左右前邊
        //左發
        physicsHairSideLeft = new PhysicsHair();

        //套用物理運算(長度單位公尺影響搖擺的週期,頭髮的阻力,頭髮的重量)
        physicsHairSideLeft.setup(0.2f, 0.5f, 0.14f);
        //設置輸入參數
        //設置哪一個部分變動時進行的那一種物理運算
        PhysicsHair.Src srcX = PhysicsHair.Src.SRC_TO_X;//橫向搖擺

        physicsHairSideLeft.addSrcParam(srcX, "PARAM_ANGLE_X", 0.005f, 1);

        //設置輸出表現
        PhysicsHair.Target target = PhysicsHair.Target.TARGET_FROM_ANGLE;

        physicsHairSideLeft.addTargetParam(target, "PARAM_HAIR_SIDE_L", 0.005f, 1);

        //右發
        physicsHairSideRight = new PhysicsHair();

        //套用物理運算(長度單位公尺影響搖擺的週期,頭髮的阻力,頭髮的重量)
        physicsHairSideRight.setup(0.2f, 0.5f, 0.14f);
        //設置輸入參數
        //設置哪一個部分變動時進行的那一種物理運算
        PhysicsHair.Src srcXRight = PhysicsHair.Src.SRC_TO_X;//橫向搖擺

        physicsHairSideRight.addSrcParam(srcXRight, "PARAM_ANGLE_X", 0.005f, 1);

        //設置輸出表現
        PhysicsHair.Target targetRight = PhysicsHair.Target.TARGET_FROM_ANGLE;

        physicsHairSideRight.addTargetParam(targetRight, "PARAM_HAIR_SIDE_R", 0.005f, 1);
        #endregion

        //動作的優先級使用
        L2DMotionManager = new L2DMotionManager();

        //眨眼
        eyeBlinkMotion = new EyeBlinkMotion();

        //鼠標拖拽
        drag = new L2DTargetPoint();
    }

    // Update is called once per frame
    void Update()
    {
   
   

        //模型位置(矩陣形式的局部座標轉換成世界座標)
        live2DModel.setMatrix(transform.localToWorldMatrix * live2DCanvasPos);


        //if (Input.GetKeyDown(KeyCode.M))
        //{
   
   
        //    motionIndex++;
        //    if (motionIndex>=motions.Length)
        //   {
   
   
        //       motionIndex = 0;
        //   }
        //   motionQueueManager.startMotion(motions[motionIndex]);
        //}



        //motionQueueManager.updateParam(live2DModel);

        //模型跟隨鼠標轉向與看向
        Vector3 pos = Input.mousePosition;
        if (Input.GetMouseButton(0))
        {
   
   
            drag.Set(pos.x / Screen.width * 2 - 1, pos.y / Screen.height * 2 - 1);
        }
        else if (Input.GetMouseButtonUp(0))
        {
   
   
            drag.Set(0, 0);
        }
        //參數及時更新,考慮加速度等自然因素,計算座標,進行逐幀更新
        drag.update();
        //模型轉向
        if (drag.getX() != 0)
        {
   
   
            live2DModel.setParamFloat("PARAM_ANGLE_X", 30 * drag.getX());
            live2DModel.setParamFloat("PARAM_ANGLE_Y", 30 * drag.getY());
            live2DModel.setParamFloat("PARAM_BODY_ANGLE_X", 10 * drag.getX());
            live2DModel.setParamFloat("PARAM_EYE_BALL_X", drag.getX());
            live2DModel.setParamFloat("PARAM_EYE_BALL_Y", drag.getY());
        }
        //眨眼
        eyeBlinkMotion.setParam(live2DModel);

        long time = UtSystem.getUserTimeMSec();//執行時間

        //更新模型定點等
        live2DModel.update();

    }
    private void OnRenderObject()
    {
   
   
        live2DModel.draw();
    }
    private void StartMotion(int motionIndex, int priority)
    {
   
   
        if (L2DMotionManager.getCurrentPriority() >= priority)
        {
   
   
            return;
        }

        L2DMotionManager.startMotion(motions[motionIndex]);
    }
}

這樣我們是實現了前鬢的抖動

 using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using live2d;
using live2d.framework;

public class live2dModel : MonoBehaviour
{
   
   
    public TextAsset modelFile;
    private Live2DModelUnity live2DModel;
    private Matrix4x4 live2DCanvasPos;
    public Texture2D[] textures;

    private L2DMotionManager L2DMotionManager;
    public TextAsset[] motionFiles;
    private Live2DMotion[] motions;
    private MotionQueueManager motionQueueManager;
    public int motionIndex;

    //自動眨眼
    private EyeBlinkMotion eyeBlinkMotion;

    //鼠標拖拽引起動作變化
    private L2DTargetPoint drag;

    //套物理運算的設定
    private PhysicsHair physicsHairSideLeft;
    private PhysicsHair physicsHairSideRight;
    private PhysicsHair physicsHairBackLeft;
    private PhysicsHair physicsHairBackRight;

    
    
    // Use this for initialization
    void Start()
    {
   
   

        //初始化
        Live2D.init();
        //讀取模型
        //TextAsset modelFile = Resources.Load<TextAsset>("Epsilon/runtime/Epsilon.moc");
        live2DModel = Live2DModelUnity.loadModel(modelFile.bytes);
        //與貼圖建立聯繫
        //Live2DModelUnity.loadModel(modelFile.bytes);

        for (int i = 0; i < textures.Length; i++)
        {
   
   
            live2DModel.setTexture(i, textures[i]);
        }
        //指定顯示位置與尺寸(實用正交矩陣與相關API顯示圖像,再由遊戲物體的位置和攝像機的size調整到合適的位置)
        float modelWidth = live2DModel.getCanvasWidth();

        live2DCanvasPos = Matrix4x4.Ortho(0, modelWidth, modelWidth, 0, -50, 50);

        //播放動作
        //實例化動作對象
        motions = new Live2DMotion[motionFiles.Length];
        for (int i = 0; i < motions.Length; i++)
        {
   
   
            motions[i] = Live2DMotion.loadMotion(motionFiles[i].bytes);

        }
        //設置某一個動畫的屬性

        //重複播放不淡入
        motions[0].setLoopFadeIn(false);
        //設置淡入淡出時間,參數單位爲毫秒
        motions[0].setFadeOut(1000);
        motions[0].setFadeIn(1000);
        //動畫是否循環播放
        //motions[0].setLoop(true);

        //motionQueueManager = new MotionQueueManager();
        //motionQueueManager.startMotion(motions[0]);
        #region 左右前邊
        //左發
        physicsHairSideLeft = new PhysicsHair();

        //套用物理運算(長度單位公尺影響搖擺的週期,頭髮的阻力,頭髮的重量)
        physicsHairSideLeft.setup(0.2f, 0.5f, 0.14f);
        //設置輸入參數
        //設置哪一個部分變動時進行的那一種物理運算
        PhysicsHair.Src srcX = PhysicsHair.Src.SRC_TO_X;//橫向搖擺

        physicsHairSideLeft.addSrcParam(srcX, "PARAM_ANGLE_X", 0.005f, 1);

        //設置輸出表現
        PhysicsHair.Target target = PhysicsHair.Target.TARGET_FROM_ANGLE;

        physicsHairSideLeft.addTargetParam(target, "PARAM_HAIR_SIDE_L", 0.005f, 1);

        //右發
        physicsHairSideRight = new PhysicsHair();

        //套用物理運算(長度單位公尺影響搖擺的週期,頭髮的阻力,頭髮的重量)
        physicsHairSideRight.setup(0.2f, 0.5f, 0.14f);
        //設置輸入參數
        //設置哪一個部分變動時進行的那一種物理運算
        PhysicsHair.Src srcXRight = PhysicsHair.Src.SRC_TO_X;//橫向搖擺

        physicsHairSideRight.addSrcParam(srcXRight, "PARAM_ANGLE_X", 0.005f, 1);

        //設置輸出表現
        PhysicsHair.Target targetRight = PhysicsHair.Target.TARGET_FROM_ANGLE;

        physicsHairSideRight.addTargetParam(targetRight, "PARAM_HAIR_SIDE_R", 0.005f, 1);
        #endregion

         #region 左右後邊

        //左邊
        physicsHairBackLeft = new PhysicsHair();
        physicsHairBackLeft.setup(0.24f, 0.5f, 0.18f);

        PhysicsHair.Src srcO = PhysicsHair.Src.SRC_TO_X;
        PhysicsHair.Src srcZ = PhysicsHair.Src.SRC_TO_G_ANGLE;

        physicsHairBackLeft.addSrcParam(srcO, "PARAM_ANGLE_X", 0.005F, 1);
        physicsHairBackLeft.addSrcParam(srcZ, "PARAM_ANGLE_Z", 0.8F, 1);

        PhysicsHair.Target targetBackLeft = PhysicsHair.Target.TARGET_FROM_ANGLE;

        physicsHairBackLeft.addTargetParam(targetBackLeft, "PARAM_HAIR_BACK_L", 0.005F, 1);

        //右邊
        physicsHairBackRight = new PhysicsHair();
        physicsHairBackRight.setup(0.24f, 0.5f, 0.18f);

        PhysicsHair.Src srcOBack = PhysicsHair.Src.SRC_TO_X;
        PhysicsHair.Src srcZBack = PhysicsHair.Src.SRC_TO_G_ANGLE;

        physicsHairBackRight.addSrcParam(srcOBack, "PARAM_ANGLE_X", 0.005F, 1);
        physicsHairBackRight.addSrcParam(srcZBack, "PARAM_ANGLE_Z", 0.8F, 1);

        PhysicsHair.Target targetBackRight = PhysicsHair.Target.TARGET_FROM_ANGLE;

        physicsHairBackRight.addTargetParam(targetBackRight, "PARAM_HAIR_BACK_R", 0.005F, 1);

        #endregion
        //動作的優先級使用
        L2DMotionManager = new L2DMotionManager();

        //眨眼
        eyeBlinkMotion = new EyeBlinkMotion();


    
    //鼠標拖拽
    drag = new L2DTargetPoint();
    }

    // Update is called once per frame
    void Update()
    {
   
   

        //模型位置(矩陣形式的局部座標轉換成世界座標)
        live2DModel.setMatrix(transform.localToWorldMatrix * live2DCanvasPos);


        //if (Input.GetKeyDown(KeyCode.M))
        //{
   
   
        //    motionIndex++;
        //    if (motionIndex>=motions.Length)
        //   {
   
   
        //       motionIndex = 0;
        //   }
        //   motionQueueManager.startMotion(motions[motionIndex]);
        //}



        //motionQueueManager.updateParam(live2DModel);

        //模型跟隨鼠標轉向與看向
        Vector3 pos = Input.mousePosition;
        if (Input.GetMouseButton(0))
        {
   
   
            drag.Set(pos.x / Screen.width * 2 - 1, pos.y / Screen.height * 2 - 1);
        }
        else if (Input.GetMouseButtonUp(0))
        {
   
   
            drag.Set(0, 0);
        }
        //參數及時更新,考慮加速度等自然因素,計算座標,進行逐幀更新
        drag.update();
        //模型轉向
        if (drag.getX() != 0)
        {
   
   
            live2DModel.setParamFloat("PARAM_ANGLE_X", 30 * drag.getX());
            live2DModel.setParamFloat("PARAM_ANGLE_Y", 30 * drag.getY());
            live2DModel.setParamFloat("PARAM_BODY_ANGLE_X", 10 * drag.getX());
            live2DModel.setParamFloat("PARAM_EYE_BALL_X", drag.getX());
            live2DModel.setParamFloat("PARAM_EYE_BALL_Y", drag.getY());
        }
        //眨眼
        eyeBlinkMotion.setParam(live2DModel);

        long time = UtSystem.getUserTimeMSec();//執行時間

        //更新模型定點等
        live2DModel.update();

    }
    private void OnRenderObject()
    {
   
   
        live2DModel.draw();
    }
    private void StartMotion(int motionIndex, int priority)
    {
   
   
        if (L2DMotionManager.getCurrentPriority() >= priority)
        {
   
   
            return;
        }

        L2DMotionManager.startMotion(motions[motionIndex]);
    }
}

這樣我們就實現了頭髮的自然擺動
其中的幾個頭髮的參數也是我們live2D裏面的
嗯對
三連還是要求一下的
萬一電腦前的大帥比或者大漂亮點讚了呢



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章