Unity 2D平台跳跃游戏中冲刺和蓄力冲刺实现(新的输入系统)

使用新的输入系统去进行冲刺和蓄力冲刺的制作,我们要解决几个问题:

1.如何实现冲刺效果。

2.如何判断玩家是长按按键还是短按。

3.冲刺过程中如果撞到墙,应该怎么办?

4.冲刺时的镜头抖动应该怎么做?

我们一个一个来解决。

至于多向冲刺我个人认为可以单独开一篇来讲,主要介绍键盘和手柄去控制,以及手柄输入时的优化问题。

1.实现冲刺效果

新的输入系统在这里不做讲解,直接使用。

public class PlayerController : Singleton<PlayerController>
{
    public PlayerInputSystem inputControl;

    public float dashFroce;
    public float dashTime;
    public float dashCoolTime;

    public bool canDash;//冲刺的前置条件
    public bool isDashing;

    private void Awake()
    {
        canDash = true;
        isDashing = false;
        
        inputControl = new PlayerInputSystem();

        inputControl.GamePlay.Dash.started += Dash;
        inputControl.GamePlay.Dash.performed += EnergyStorageDash;
        inputControl.GamePlay.Dash.canceled += DisDash;
    }
    
    public void OnEnable()
    {
        inputControl.Enable();
    }

    public void OnDisable()
    {
        inputControl.Disable();
    }

    private void Dash(InputAction.CallbackContext obj)
    {
        if (canDash)
        {
            PrerequisiteDash();
            StartCoroutine(PlayerDash(dashTime,dashCoolTime));
        }  
    }

    private void PrerequisiteDash()
    {
        canDash = false;
        isDashing = true;
    }

    private IEnumerator PlayerDash(float dashTime,float dashCoolTime)
    {
        float originalGravity = rb.gravityScale;
        rb.gravityScale = 0f;
        rb.velocity = new Vector2(transform.localScale.x * dashFroce, 0);
        Debug.Log("冲刺开始");
        
        yield return new WaitForSeconds(dashTime);
        rb.velocity = new Vector2(0, 0);
        rb.gravityScale = originalGravity;
        isDashing = false;
        Debug.Log("冲刺结束");
        
        yield return new WaitForSeconds(dashCoolTime);
        canDash = true;
    }
}

冲刺主要通过协程来实现,两个bool分别用来判断是否可以冲刺和是否在冲刺过程中,这样具有很好的拓展性,可以在冲刺基础上实现更多想法,例如蓄力冲刺,多向冲刺等。

2.如何判断长按按键还是短按

这里说一种非常容易理解的方式,刚才的冲刺是按下一瞬间执行,而我现在使用另一种方法:如果玩家按按键超过一定时间我就执行蓄力冲刺,如果没有就执行冲刺,而具体执行的方法我放在松开按键的时候去执行。

1.如何设置超过多少时间去触发蓄力冲刺呢?

 绿色框可以添加事件,我选择Hold,然后会出现默认参数,取消勾选蓝色方框中的Default,就可以自定义时间去触发了持续按住按键的事件了。 

2.书写脚本逻辑

    private void EnergyStorageDash(InputAction.CallbackContext obj)
    {
        if (playerCheck.isGround)
        {
            isEnergyStorageDash = true;
            inputControl.GamePlay.Move.Disable();
            Debug.Log("蓄力冲刺");
        }
    }

    private void DisDash(InputAction.CallbackContext obj)
    {
        if (!isEnergyStorageDash)
        {
            PrerequisiteDash();
            StartCoroutine(PlayerDash(dashTime,dashCoolTime));
        }else
        {
            PrerequisiteDash();
            StartCoroutine(PlayerDash(energyStorageDashTime, energyStorageDashCoolTime));
        }
        
    }

3.冲刺过程中撞到墙之后如何停下来

我们需要单独写一个物理检测的脚本挂载人物身上,当检测到墙壁时并且在移动过程中,我们就让刚体的速度等于零即可

4.冲刺时的镜头抖动

使用Cinemachine官方插件,创建一个空物体,添加Cinemachine Impulse Sourece的组件(脚本),这相当于一个振动源,再给摄像机挂一个脚本,用来监听震动事件,一旦玩家冲刺便广播这个冲刺事件,然后摄像机执行震动。

1.人物脚本去广播事件:

    public UnityEvent OnTakeDash;//添加广播事件

    OnTakeDash?.Invoke();//执行广播事件

 2.事件中心

using UnityEngine;
using UnityEngine.Events;

[CreateAssetMenu(menuName = "Event/VoidEventSO")]

public class VoidEventSO : ScriptableObject
{
    public UnityAction OnEventRaised;

    public void RaiseEvent()
    {
        OnEventRaised?.Invoke();
    }
}

这个是写成了SO文件的形式,也可以用代码写一个,只不过这样更加可视化。

3.摄像机监听事件并执行震动方法

public class CameraControl : MonoBehaviour
{
    [Header("震动源")]
    public CinemachineImpulseSource impulseSource_Dash;

    [Header("事件监听")]
    public VoidEventSO cameraShakeEvent;

    private void OnEnable()
    {
        cameraShakeEvent.OnEventRaised += OnCameraShakeEvent;
    }

    private void OnDisable()
    {
        cameraShakeEvent.OnEventRaised -= OnCameraShakeEvent;
    }


    private void OnCameraShakeEvent()
    {
        Debug.Log("相机震动");
        impulseSource_Dash.GenerateImpulse();
    }
}

在我的理解中,事件中心相当于一个中继站,一边接收广播,一边去给监听发指令。

最后,文中代码部分需要自己再完善一下,只是介绍一种解决思路,如果有更好的方法也可以仙人指路或者评论区分享。