在不使用 AddForce 的情况下击退 Unity 2D

问题描述

我有一个播放器控制器脚本。由于它在每一帧都将rigidbody.veLocity 重置为其他值,因此我无法使用AddForce 进行击退。我的击退方法通常有效,直到它碰到一个碰撞器,在该碰撞器中玩家位置不能进一步进入击退位置,因为有一个碰撞器不允许它通过,它只是卡在击退状态。这是一个自上而下的射击游戏。

代码如下: github 链接https://github.com/fireWizard23/MFGJ-Summer-2021-ver-1

private Vector2 knockbackEndpoint; // Use to store where the endpoint position of the knockback will be

void Update()
{
    currentState = GetNewState();
    DoStateLogic();
  
}

private void FixedUpdate()
{
    if(currentState != States.Attacking && currentState != States.InKnockback)
    {
        veLocity = Vector2.Lerp(veLocity,inputVector * myMobInfo.MovementSpeed,myMobInfo.MovementLerpWeight);
    }
    else
    {
        veLocity = Vector2.zero;
    }
    
}

private States GetNewState()
{
    switch (currentState)
    {
        default:
        case States.Idle:
            if (veLocity != Vector2.zero)
                return States.Walking;
            return States.Idle;
        case States.Walking:
            if (veLocity == Vector2.zero) return States.Idle;
            return States.Walking;
        case States.Attacking:
            if (isAttacking < 0) return States.Idle;
            return States.Attacking;
        case States.InKnockback:
            var dist = (knockbackEndpoint - ((Vector2)transform.position)).sqrMagnitude;
            if (dist <= 0.1f * 0.1f)
            {
                if (isAttacking > 0) return States.Attacking;
                knockbackEndpoint = Vector2.zero;
                return States.Idle;
            }
            return States.InKnockback;
    }
}

private void DoStateLogic()
{
    
    // MOVEMENT
    switch(currentState)
    {
        case States.Idle:
        case States.Walking:
            inputVector = GetInputVector();
            if(Input.GetMouseButton(0) && canAttack == 0)
            {
                Shoot();
            }

            break;
        case States.InKnockback:
            var half = (knockbackEndpoint - (Vector2)transform.position) / 3f;
            myRigidbody.MovePosition(transform.position + (Vector3)half);
            break;

    }
}
public void GetKnockback(Vector2 knockbackEndpoint)
{
    currentState = States.InKnockback;
    var end = knockbackEndpoint;

    this.knockbackEndpoint = end;

}
private void Shoot()
{
    currentState = States.Attacking;
    isAttacking = 0f;
    canAttack += Time.deltaTime;
    GameObject go = Pooler.Instance.Get("PlayerBullet");
    Vector2 dir = ((Vector2)(MyUtils.CameraUtils.MousePosition - transform.position)).normalized;
    go.GetComponent<IProjectile>()?.Setup(myMuzzlePos.position,dir );
    GetKnockback((-0.5f * dir) + (Vector2)transform.position);
}

解决方法

我用了@Kyssel的方法,做了一个协程,几秒后把currentState恢复到空闲状态。还通过将 AddForce 增加 10 并缩短击退持续时间来修复 AddForce 浮动且冗长的问题。完整代码在这里:https://pastebin.com/KJVZJSwp

public void GetKnockback(Vector2 dir,float scale,float duration=0.1f)
{
    duration = Mathf.Clamp(duration,1);
    scale = Mathf.Clamp(scale,5);
    currentState = States.InKnockback;

    myRigidbody.AddForce(dir.normalized * scale * 10f,ForceMode2D.Impulse);
    MyUtils.Time.SetTimeout(() => {
        myRigidbody.velocity = Vector2.zero;
    },duration,this);

}

如果您有任何改进建议,请发表评论。