黑魂复刻游戏的玩家控制器(降落、落地检测)——Unity随手记(2021.3.30)

今天实现的内容:

加入降落动画

降落发生在跳跃之后,所以降落动画要紧接着跳跃动画播放,动画机如下。
在这里插入图片描述
这两条Transition都has exit time,并且jump到fall的优先级高于jump到ground,因为目前为止这两个转换都没有条件。
在这里插入图片描述
在图示位置调整优先级。

落地检测的实现及相关动画运用

要实现落地检测,需要使用Physics.Overlap里的东西,使用Physics.Overlap可以找到某个形状范围内有重合的所有碰撞体。比如我们要用到的Physics.OverlapCapsule就是在一个给定的胶囊体内得到所有与胶囊体有重合的特定layer的碰撞体,Overlap只能得到有哪些碰撞体重合,而不知道其它信息(先后,远近等等)。
在这里插入图片描述
我们新建落地检测器脚本OnGroundSensor,挂载到PlayerController游戏对象的子物体sensor下,sensor对象将专门由于各种检测器的挂载。
在这里插入图片描述
OnGroundSensor代码如下。通过SendMessage来告诉PlayerController当前是否正在地面。

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

// 落地检测器
public class OnGroundSensor : MonoBehaviour
{
    
    
    // 用于引用PlayerController游戏对象上的CapsuleCollider
    public CapsuleCollider capCol;

    // 用于绘制胶囊检测器的两个点
    private Vector3 point1;
    private Vector3 point2;
    // 用于绘制胶囊检测器的半径
    private float radius;


    void Awake()
    {
    
    
        radius = capCol.radius;
    }

    void FixedUpdate()
    {
    
    
        // 更新检测器的位置
        point1 = transform.position + transform.up * radius;
        point2 = transform.position + transform.up * (capCol.height - radius);
        // 检测地面碰撞
        Collider[] outputCols = 
            Physics.OverlapCapsule(point1, point2, radius, LayerMask.GetMask("Ground"));
        // 判断是否撞到地面 并向父物体发送对应消息
        if(outputCols.Length != 0)
        {
    
    
            // 在地面
            SendMessageUpwards("IsGround");
        }
        else
        {
    
    
            // 不在地面
            SendMessageUpwards("IsNotGround");
        }
    }
}

接下来要做的就是,在PlayerController中实现消息接收。

// 在地面时执行的方法 通过OnGroundSensor中的SendMessage调用
    public void IsGround()
    {
    
    
        m_anim.SetBool("isGround", true);
    }

    // 不在地面时执行的方法 通过OnGroundSensor中的SendMessage调用
    public void IsNotGround()
    {
    
    
        m_anim.SetBool("isGround", false);
    }

在动画机中添加新参数isGround,用于PlayerController进行控制。
在这里插入图片描述
好的,现在调回先前的jump转换优先级,将jump到ground和fall到ground的转换条件设置为isGround为true。
在这里插入图片描述加粗样式
到目前为止,落地检测的实现及相关动画运用基本完成。

落地检测器优化

建议改小检测器的半径以及稍微将检测器向下移动一点。来得到更好的检测结果。

	// 检测器偏移量
    public float offset = 0.1f;

	void Awake()
    {
    
    
        m_radius = capCol.radius * 0.6f;
    }

    void FixedUpdate()
    {
    
    
        // 更新检测器的位置
        m_point1 = transform.position + transform.up * (m_radius - offset);
        m_point2 = transform.position + transform.up * (capCol.height - m_radius - offset);
        
        // ...
	}

失足掉落

由于我们的掉落动画只有在跳跃的前提下才能触发,所以特此加入失足掉落的设置。这样一来,只要离开地面就会播放,而不是离开地面依旧和在地面没有两样(在没有跳起来离开地面的情况下)。是的,我们在没有起跳的情况下离开地面和在地面没有区别,依然可以正常操作。
首先是动画机的设置,直接拉一条transition从ground到fall就行,条件为isGround为false。
在这里插入图片描述
接下来,在掉落时要和跳跃一样锁死操作。现在就当一次笨蛋,在进入fall状态时发送消息给PlayerController(更好的方法是在离开ground时发送消息,这样还可以省掉进入跳跃时发送消息这个操作)。

    // 进入掉落时执行的方法 通过PlayerController动画机中的fall节点上挂载的FSMOnEnter中的SendMessage调用
    public void OnFallEnter()
    {
    
    
        // 关闭输入并且锁定平面移动
        DisableInput_LockPlanar();
    }

    // 关闭输入并且锁定平面移动
    private void DisableInput_LockPlanar()
    {
    
    
        // 关闭输入模块
        pi.inputEnabled = false;
        // 锁死平台移动计算
        m_lockPlanar = true;
    }

动画的优化及改进

除了jump到fall,其它所有的transition都不要勾选has exit time,这样能带来更流畅的动画效果。
在这里插入图片描述


BUG以及缺陷:

当动画进入到下落阶段时,角色将不再拥有向前的速度。要解决这个问题,需要将原来在跳跃结束后处理的打开输入模块以及解锁平台移动的代码放到真正触地以后再执行。具体操作方法是将OnJumpExit中执行的操作转移到新的方法OnGroundEnter中。代码如下。

    // 进入地面时执行的方法 通过PlayerController动画机中的ground节点上挂载的FSMOnEnter中的SendMessage调用
    public void OnGroundEnter()
    {
    
    
        // 打开输入模块
        pi.inputEnabled = true;
        // 解锁平台移动计算
        m_lockPlanar = false;
    }

OnGroundEnter将通过PlayerController动画机中的ground节点上挂载的FSMOnEnter中的SendMessage来调用。原理和OnJumpExit类似。
在这里插入图片描述
而OnJumpExit,暂时就没用了。


如果我们的跳跃高度在一个很微妙的数值,在这个数值下,跳跃动画能够播放完,但是会在正在转换到fall时触碰到地面。这样动画会在触地的情况下快速做出一个fall的动作。
在这里插入图片描述
要解决这个问题,需要用到Interruption Source。Interruption Source可以用于,如果状态转换时触发了别的条件,是否需要打断当前转换直接进行这个别的触发条件的转换。
打断分为Current State和Next State,对于这个情况,ground是Current State,fall是Next State(transition的箭头之前和之后)。关于这个问题可以点击这个链接了解更多:[外文翻译] Animator- Interruption Source用法
我们希望如果碰到地面以后能打断jump到fall的进行而直接进行jump到ground,所以对于Interruption Source我们选择Current State。这样一来问题就解决啦!
在这里插入图片描述


值得注意的:


猜你喜欢

转载自blog.csdn.net/qq_37856544/article/details/115323174
今日推荐