You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity 2D游戏中FrostBullet击中玩家后实现2秒持续减速的问题

解决Unity中冰冻子弹永久减速的问题

嘿,作为Unity和C#新手,能写出这样的战斗逻辑已经很赞啦!咱们来拆解下为什么减速会永久生效,以及怎么改成2秒后自动恢复正常速度:

你的代码里的核心问题

  1. 对Player_Njinja完全缺失速度恢复逻辑:你直接把它的runSpeed改成了slowSpeed,但没有任何逻辑让它变回原始速度,自然就永久减速了。
  2. Player_Knight的协程写法有问题:
    • 你把协程speedTime()嵌套在了OnTriggerEnter2D()方法内部,这在Unity里是不规范的写法,可能导致协程无法正确执行。
    • 协程里的while(isHit == true)循环会让减速→等待→恢复的逻辑重复执行,而且isHit没有在恢复后重置,容易引发异常。
    • PlayerMovementKnight maxSpeed = other.GetComponent<PlayerMovementKnight>();放在了if判断外面,当碰撞对象不是骑士玩家时,maxSpeed会变成null,运行时直接触发空引用报错。

修复后的完整代码

FrostHit脚本修改版

public class FrostHit : MonoBehaviour 
{
    float defaultMaxSpeed = 40f; 
    float slowSpeed = 20f; 
    public Rigidbody2D rb; 
    int damage = -5; 
    int slowDuration = 2; // 变量名更直观,明确是减速持续时间

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

    void OnTriggerEnter2D(Collider2D other) 
    {
        // 处理忍者玩家
        if (other.CompareTag("Player_Njinja")) 
        {
            // 扣除生命值(加空引用检查,避免组件缺失报错)
            HealthNjinja healthNjinja = other.GetComponent<HealthNinja>();
            if (healthNjinja != null)
            {
                healthNjinja.ModifyHealth(damage);
            }

            // 临时减速+启动恢复协程
            PlayerMovementNjinja playerMovement = other.GetComponent<PlayerMovementNjinja>();
            if (playerMovement != null)
            {
                float originalSpeed = playerMovement.runSpeed;
                playerMovement.runSpeed = slowSpeed;
                StartCoroutine(RevertPlayerSpeed(playerMovement, originalSpeed));
            }

            Destroy(gameObject);
            return; // 处理完忍者直接跳出,避免干扰骑士逻辑
        }

        // 处理骑士玩家
        if (other.CompareTag("Player_Knight")) 
        {
            // 扣除生命值
            HealthKnight healthKnight = other.GetComponent<HealthKnight>();
            if (healthKnight != null)
            {
                healthKnight.ModifyHealth(damage);
            }

            // 临时减速+启动恢复协程
            PlayerMovementKnight playerMovement = other.GetComponent<PlayerMovementKnight>();
            if (playerMovement != null)
            {
                float originalSpeed = playerMovement.runSpeed;
                playerMovement.runSpeed = slowSpeed;
                StartCoroutine(RevertPlayerSpeed(playerMovement, originalSpeed));
            }

            Destroy(gameObject);
        }
    }

    // 通用速度恢复协程,两种玩家都能复用
    IEnumerator RevertPlayerSpeed<T>(T playerMovement, float originalSpeed) where T : class
    {
        yield return new WaitForSeconds(slowDuration);
        // 根据玩家类型恢复原始速度
        if (playerMovement is PlayerMovementNjinja ninja)
        {
            ninja.runSpeed = originalSpeed;
        }
        else if (playerMovement is PlayerMovementKnight knight)
        {
            knight.runSpeed = originalSpeed;
        }
    }
}

关键修改点解释

  1. 通用协程复用:写了一个RevertPlayerSpeed协程,不管是忍者还是骑士玩家都能用来恢复速度,避免重复写冗余代码。
  2. 保存原始速度:修改玩家速度前先存下原始值,这样恢复时能准确回到玩家原本的移动速度(万一玩家有加速buff,默认的40f就不适用了)。
  3. 空引用防护:每次获取组件后都加了!= null判断,避免因为组件缺失导致的运行时崩溃,这在新手开发里是非常重要的习惯。
  4. 修正协程写法:把协程移到类的成员方法里,去掉了多余的while循环,协程只需要等待指定时间后恢复一次速度就结束。

额外小建议

  • 尽量用CompareTag()代替gameObject.tag == "",前者性能更好,而且写错标签名时会有明确警告。
  • 变量名尽量直观,比如timeOfReducedSpeed改成slowDuration,未来你自己看代码时也能一眼明白含义。

这样修改后,不管是忍者还是骑士玩家,被冰冻子弹击中后都会减速2秒,之后自动恢复原来的移动速度啦!

内容的提问来源于stack exchange,提问作者Hakunamatata

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 15:58:13