枪械的瞄准——Unity随手记(2021.1.28)

今天实现的内容:

枪械的瞄准动画层

采用了和基本移动层类似的方法,射击动画由脚本直接播放。
在这里插入图片描述
瞄准状态的进入和退出由一个bool参数Aim来控制。
在这里插入图片描述
Idle和Reload层的Idle在形式上和功能上是一样的。形式上都是一个空节点,功能是为了在当前动画权重为1并且没有播放本层其他动画时依然能够播放其他层的动画。
在这里插入图片描述
权重记得设置为1。之前的Reload层也可以设置为1。
在这里插入图片描述

枪械瞄准的逻辑实现

由于每种枪都可能有不同的瞄准逻辑(比如不同的瞄具放大倍率啥的),我们在基类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来实现。


猜你喜欢

转载自blog.csdn.net/qq_37856544/article/details/113309412