与 FrostBullet 碰撞时随着时间的推移变慢

Slow over time on collision with a FrostBullet

我是 Unity 和 C# 的新手。我几周前开始玩这款 2D 游戏。

所以基本上我想做的是当玩家被“FrostBullet”击中时,它应该造成伤害并随着时间的推移减缓玩家的速度。在我的脚本中,玩家被 FrostBullet 击中,它造成伤害并且减速是恒定的,而不是随着时间的推移。 我希望它是这样的,当玩家被 FrostBullet 击中时,玩家应该被减速 2 秒,然后他的移动速度恢复正常。

我的代码是这样的:

public class FrostHit : MonoBehaviour 
{
float maxS = 40f;
float slowSpeed = 20f;
public Rigidbody2D rb;
int damage = -5;
int timeOfReducedSpeed = 2;
bool isHit = false;


void Start()
{
    rb.velocity = transform.right * slowSpeed;
}
void OnTriggerEnter2D(Collider2D other)
{
    if (other.gameObject.tag == "Player_Njinja")
    {
       HealthNjinja healthNjinja = other.gameObject.GetComponent<HealthNjinja>();
       healthNjinja.ModifyHealth(damage);

       PlayerMovementNjinja reduceMoveSpeed = other.gameObject.GetComponent<PlayerMovementNjinja>();
       reduceMoveSpeed.runSpeed = slowSpeed;

       Destroy(gameObject);
    }

      PlayerMovementKnight maxSpeed = other.gameObject.GetComponent<PlayerMovementKnight>();
      maxSpeed.runSpeed = maxS;
      HealthKnight healthKnight = other.gameObject.GetComponent<HealthKnight>();

     if (other.gameObject.tag == "Player_Knight")
      {
        isHit = true;
        healthKnight.ModifyHealth(damage);
        StartCoroutine(speedTime());

        Destroy(gameObject);
     }
     IEnumerator speedTime()
     {
        while (isHit == true)
        {
            slowPlayer();
            yield return new WaitForSeconds(timeOfReducedSpeed);
            revertSpeed();
        }
      }
     void slowPlayer()
     {
        maxSpeed.runSpeed = slowSpeed;
     }
     void revertSpeed()
     {
        maxSpeed.runSpeed = maxS;
     }
}

}

还有我的 PlayerMovement 代码:

public class PlayerMovementKnight : MonoBehaviour
{
public CharacterController2D controller;
public Animator animator;

public float runSpeed = 40f;
float horizontalMove = 0f;
bool jump = false;
bool crouch = false;

public WeaponKnight Bullet;
public bool grounded;

void Update()
{
    horizontalMove = Input.GetAxisRaw("Horizontal") * runSpeed;
    animator.SetFloat("Speed", Mathf.Abs(horizontalMove));

    if (Input.GetButtonDown("Jump"))
    {
        jump = true;
        animator.SetBool("IsJumping", true);
    }
    if (Input.GetButtonDown("Crouch"))
    {
       crouch = true;
    }

   else if (Input.GetButtonUp("Crouch"))
   {
       crouch = false;
   }
   if (grounded && GetComponent<Bullet>().knockBack == false)
   {
       GetComponent<Rigidbody2D>().velocity = new Vector2(0, 0);
   }

}
public void OnLanding()
{
    animator.SetBool("IsJumping", false);
}
public void OnCrouching(bool isCrouching)
{
    animator.SetBool("IsCrouching", isCrouching);
}
void FixedUpdate()
{
    controller.Move(horizontalMove * Time.fixedDeltaTime, crouch, jump);
    jump = false;
}

}

问题似乎是您的 bool isHit 在调用协程之前设置为 true,但从未重置为 false

所以循环:

while (isHit == true)
    {
        slowPlayer();
        yield return new WaitForSeconds(timeOfReducedSpeed);
        revertSpeed();
    }

真是死循环。 您可能想在某处将 bool 重置为 false。

编辑:

根据评论,我现在看到您的脚本已附加到子弹游戏对象。在启动协程并减慢播放器速度后,您 Destroy(gameObject); 之后,脚本也被销毁,协程因此停止......没有任何东西可以让玩家的速度恢复正常。

你应该把协程移动到玩家的脚本中,需要的时候启动它。这样子弹毁了它还存在

您的布尔值 isHit 从未设置为假。导致玩家被减速,然后在他被击中一次后永远重置。

一开始就不需要创建 isHit。为什么只有当 Player_Knight 已经被击中时才需要在输入 IEnumerator 时检查玩家是否被击中。

代码示例:

public class FrostHit : MonoBehaviour
{
    float maxS = 40f;
    float slowSpeed = 20f;
    public Rigidbody2D rb;
    int damage = -5;
    int timeOfReducedSpeed = 2;

    void Start()
    {
        rb.velocity = transform.right * slowSpeed;
    }

    void OnTriggerEnter2D(Collider2D other)
    {
        if (other.gameObject.tag == "Player_Njinja")
        {
            HealthNjinja healthNjinja = other.gameObject.GetComponent<HealthNjinja>();
            healthNjinja.ModifyHealth(damage);

            PlayerMovementNjinja mSpeedNinja = other.gameObject.GetComponent<PlayerMovementNjinja>();
            StartCoroutine(speedTimeNinja());
        }

        else if (other.gameObject.tag == "Player_Knight")
        {
             HealthKnight healthKnight = other.gameObject.GetComponent<HealthKnight>();
            healthKnight.ModifyHealth(damage);

            PlayerMovementKnight mSpeedKnight = other.gameObject.GetComponent<PlayerMovementKnight>();
            StartCoroutine(speedTimeKnight());
        }
 
        // Destroy Bullet
        Destroy(gameObject);
    }
    
    IEnumerator speedTimeKnight()
    {
        mSpeedKnight.runSpeed = slowSpeed;
        yield return new WaitForSeconds(timeOfReducedSpeed);
        mSpeedKnight.runSpeed = maxS;
    }

    IEnumerator speedTimeNinja()
    {
        mSpeedNinja.runSpeed = slowSpeed;
        yield return new WaitForSeconds(timeOfReducedSpeed);
        mSpeedNinja.runSpeed = maxS;
    }
}

我改变的地方和原因:

  1. 删除了 bool 和 while 循环,没有解决任何实际问题
  2. 从内部分离 IEnumerator 和 2 个函数 OnTriggerEnter2D()
  3. 在末尾添加了 Destroy(gameObject);,因为子弹总是会被摧毁
  4. 删除了 maxSpeed.runSpeed = maxS;,因为速度已经达到了 set/reset。没理由撞到子弹后重新设置速度
  5. GetComponent for Player_Knight 放入 else if 中,即使 Player_Njinja 被命中,也没有理由执行 GetComponent
  6. 删除了 reduceMoveSpeed.runSpeed = slowSpeed; Player_Njinja 只会变慢并且永远不会恢复他的速度。而是再次使用 IEnumerator
  7. 添加了另一个 IEnumerator,以便 Player_NjinjaPlayer_Knight 都能正确减速和减速(现在甚至可以根据玩家被击中创建不同的减速时间)
  8. 去掉函数,一行代码写一个函数真的不值得。特别是当你可以在 IEnumerator 中设置它而不需要更多代码行时