天天看點

槍械的瞄準——Unity随手記(2021.1.28)今天實作的内容:BUG以及缺陷:值得注意的:

文章目錄

  • 今天實作的内容:
        • 槍械的瞄準動畫層
        • 槍械瞄準的邏輯實作
  • BUG以及缺陷:
  • 值得注意的:

今天實作的内容:

槍械的瞄準動畫層

采用了和基本移動層類似的方法,射擊動畫由腳本直接播放。

槍械的瞄準——Unity随手記(2021.1.28)今天實作的内容:BUG以及缺陷:值得注意的:

瞄準狀态的進入和退出由一個bool參數Aim來控制。

槍械的瞄準——Unity随手記(2021.1.28)今天實作的内容:BUG以及缺陷:值得注意的:

Idle和Reload層的Idle在形式上和功能上是一樣的。形式上都是一個空節點,功能是為了在目前動畫權重為1并且沒有播放本層其他動畫時依然能夠播放其他層的動畫。

槍械的瞄準——Unity随手記(2021.1.28)今天實作的内容:BUG以及缺陷:值得注意的:

權重記得設定為1。之前的Reload層也可以設定為1。

槍械的瞄準——Unity随手記(2021.1.28)今天實作的内容:BUG以及缺陷:值得注意的:

槍械瞄準的邏輯實作

由于每種槍都可能有不同的瞄準邏輯(比如不同的瞄具放大倍率啥的),我們在基類Firearms中設計了抽象方法Aim,讓子類來具體實作瞄準邏輯。

// 瞄準 每種槍的瞄準會有不同(也許吧) 放大會有不同(機瞄,二倍鏡,三倍鏡) 需要派生類來具體實作
  protected abstract void Aim();
           

通過修改錄影機的FOV來實作瞄準放大的效果。eyeCamera是錄影機的引用,originFOV用于存儲錄影機原本的FOV值。

// 錄影機 用于瞄準時修改FOV
        public Camera eyeCamera;
        // 錄影機FOV的原數值
        protected float originFOV;
           

Aim方法邏輯很簡單,由于大頭都被動畫實作了,是以我們要做的就是修改動畫參數。

// 瞄準
        protected override void Aim()
        {
            gunAnimator.SetBool("Aim", m_isAiming);
        }
           

重點在這裡,Update方法中的瞄準邏輯,我們專門做了一個bool值m_isAiming來判斷目前是否處于瞄準狀态。由于Aim隻是修改動畫參數,是以我們要實作的邏輯是 m_isAiming要能反映目前是否處于瞄準狀态。按住瞄準鍵就能保持瞄準狀态,松開瞄準鍵退出瞄準。

// 瞄準 按住就會瞄準
            if (Input.GetMouseButtonDown(1))
            {
                m_isAiming = true;
                Aim();
            }
            // 松開按鍵退出瞄準
            if (Input.GetMouseButtonUp(1))
            {
                m_isAiming = false;
                Aim();
            }
           

在Shooting方法中修改一下動畫播放代碼,由于兩個層的開火動畫節點都叫"Fire",是以動畫名稱不用改,隻需要根據是否正在瞄準修改layer就行。

// 播放開火動畫 注意我們會根據是否處于瞄準播放不同層的Fire
		gunAnimator.Play("Fire", m_isAiming ? 2 : 0, 0);
           

接下來定義一個協程方法DoAim來實作瞄準要做的事情。在目前DoAim隻用來實作瞄準時畫面“放大”的效果。通過調整錄影機FOV值來實作。

// 目前主要處理瞄準時視野放大功能
        private IEnumerator DoAim()
        {
            float temp_currentFOV = 0;
            while (true)
            {
                yield return null;

                eyeCamera.fieldOfView =
                       Mathf.SmoothDamp(eyeCamera.fieldOfView,
                       m_isAiming ? m_targetFOV : originFOV,
                       ref temp_currentFOV,
                       Time.deltaTime * 10f);
                if(Mathf.Abs(eyeCamera.fieldOfView - m_targetFOV) < 0.0001f)
                {
                    eyeCamera.fieldOfView = m_targetFOV;
                    yield break;
                }
            }
        }
           

接下來再按照UP的方式來進行防協程沖突的代碼編寫,以下代碼實作在Aim中。

// 開啟DoAim協程
            if (doAimCoroutine == null) // 說明協程還沒有打開
            {
                doAimCoroutine = DoAim();
                StartCoroutine(doAimCoroutine); 
            }
            else // 不為空說明協程已經打開了
            {
                // 首先停下之前的協程
                StopCoroutine(doAimCoroutine);
                doAimCoroutine = null;
                // 指派以後再執行起來
                doAimCoroutine = DoAim();
                StartCoroutine(doAimCoroutine);
            }
           

BUG以及缺陷:

各個層由于權重都是1,是以會出現很多動畫沖突和BUG,比如瞄準時換彈并不能看到換彈但是換彈邏輯是在執行的,我覺得要麼為每個層再單獨做每個功能的動畫(就像COD16瞄準時也能換彈,而且有單獨的換彈動畫那樣),要麼就好好掰扯一下各個層的權重之間的協調。

如果在BaseLayer狀态下開槍的同時按下瞄準鍵會出現BUG,之後在瞄準開槍時動畫會在Aim Layer的Fire和Base Layer的idle(Fire?)之間快速切換。十分鬼畜。

目前這個BUG已經解決了,應該是要播放開火動畫的同時又要播放舉槍動畫所引起的BUG。方法就是在要舉槍時不要再播放開火動畫就行了。又添加了一些參數和代碼。

// ------------------------------Shooting--------------------------------------
            // 是否正在舉槍 為了規避BUG 舉槍動畫播放時不能播放Fire動畫
            if (!m_isAimingIn)
            {
                // 播放開火動畫 注意我們會根據是否處于瞄準播放不同層的Fire
                gunAnimator.Play("Fire", m_isAiming ? 2 : 0, 0);
            }
// ------------------------------Update---------------------------------------
            // 瞄準 按住就會瞄準
            if (Input.GetMouseButtonDown(1))
            {
                m_isAiming = true;
                m_isAimingIn = true;
                m_startAimInTime = Time.time;
                Aim();
            }
            if (Input.GetMouseButtonUp(1))// 松開按鍵退出瞄準
            {
                m_isAiming = false;
                Aim();
            }
            if(!(Time.time - m_startAimInTime < 0.3f)) //是否正在舉槍 舉槍時無法開槍
            {
                m_isAimingIn = false;
            }
           

值得注意的:

關于Mathf.SmoothDamp,這個方法的smoothTime也就是緩沖時間的值越大,current到target的數值的變化速度就越慢。

不同倍率瞄具的資料儲存可以通過ScriptableObject來實作。