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

Unity3D:2D碰撞器内敌人淡入淡出效果失效问题求助

问题解决思路与修复代码

核心问题分析

  1. Unity碰撞回调返回类型错误:OnTriggerEnter2D、OnTriggerStay2D、OnTriggerExit2D是Unity内置消息函数,必须是void返回类型。改成IEnumerator后,Unity不会自动执行这些协程,导致淡入淡出的循环逻辑直接跳过,看起来就是直接显隐。
  2. 淡出逻辑完全写反:OnTriggerExit2D里的循环条件、透明度增减方向全错,不仅没实现淡出,反而会让透明度异常变化后直接跳转到0。
  3. 无协程冲突控制:快速进出碰撞器时,会重复触发协程,导致透明度逻辑混乱。

修复后的完整代码

public class AttackManager : MonoBehaviour
{
    public PlayerScriptableObjects accessPlayer;
    public GhostsScriptable accessGhost;
    Color tmpColor;
    SpriteRenderer sprite;
    bool attacking;
    GameObject find;
    int durationFade = 3;
    bool enterCollision = false;
    bool isFading = false; // 防止重复触发淡入淡出协程

    void Awake()
    {
        sprite = GetComponentInChildren<SpriteRenderer>();
        find = GameObject.FindGameObjectWithTag("Ghost");
    }

    void Start()
    {
        // 初始状态完全透明,确保敌人在碰撞器外不可见
        tmpColor = sprite.color = new Color(1, 1, 1, 0);
    }

    void OnTriggerEnter2D(Collider2D col)
    {
        if (col.gameObject.tag != "CandleRadius") return;

        enterCollision = true;
        // 仅当没有正在淡入淡出时启动协程
        if (!isFading)
        {
            StartCoroutine(FadeIn());
        }

        if (accessPlayer.MentalSanity > 0)
        {
            Attack(7);
        }
    }

    void OnTriggerStay2D(Collider2D stay)
    {
        if (stay.gameObject.tag != "CandleRadius") return;

        enterCollision = true;

        if (accessPlayer.MentalSanity > 0 && !attacking)
        {
            attacking = true;
            StartCoroutine(AttackCoroutine());
        }
    }

    void OnTriggerExit2D(Collider2D exit)
    {
        if (exit.gameObject.tag != "CandleRadius") return;

        enterCollision = false;
        if (!isFading)
        {
            StartCoroutine(FadeOut());
        }

        Debug.Log("The monster is not attacking the PLAYER Because it is outside the COLLIDER!");
    }

    // 淡入协程:从透明渐变到完全可见
    IEnumerator FadeIn()
    {
        isFading = true;
        tmpColor = sprite.color;
        tmpColor.a = 0;
        sprite.color = tmpColor;

        while (tmpColor.a < 1f)
        {
            tmpColor.a += Time.deltaTime / durationFade;
            // 用Clamp确保透明度不会超出0-1范围
            tmpColor.a = Mathf.Clamp(tmpColor.a, 0, 1);
            sprite.color = tmpColor;
            yield return null;
        }
        isFading = false;
    }

    // 淡出协程:从完全可见渐变到透明
    IEnumerator FadeOut()
    {
        isFading = true;
        tmpColor = sprite.color;
        tmpColor.a = 1;
        sprite.color = tmpColor;

        while (tmpColor.a > 0f)
        {
            tmpColor.a -= Time.deltaTime / durationFade;
            tmpColor.a = Mathf.Clamp(tmpColor.a, 0, 1);
            sprite.color = tmpColor;
            yield return null;
        }
        isFading = false;
    }

    // 处理攻击间隔的协程
    IEnumerator AttackCoroutine()
    {
        yield return new WaitForSeconds(accessGhost.AttackTime);
        Attack(7);
        attacking = false;
    }

    // 攻击逻辑(根据你的实际需求调整)
    void Attack(int damage)
    {
        if (accessPlayer != null)
        {
            accessPlayer.MentalSanity -= damage;
        }
    }
}

关键修改点说明

  • 把所有碰撞回调改回void类型,通过StartCoroutine()手动启动淡入/淡出协程,符合Unity的消息机制规范。
  • 新增isFading变量,避免同一时间执行多个淡入淡出协程,防止逻辑冲突。
  • 重写了FadeOut协程的逻辑:循环条件改为判断透明度大于0,透明度使用减法,并用Mathf.Clamp确保值始终在0-1之间,避免异常溢出。
  • 将攻击间隔逻辑抽成独立的AttackCoroutine,让碰撞回调函数更简洁,逻辑分离更清晰。
  • 简化了标签判断逻辑,先过滤非目标标签,减少代码嵌套层级,提升可读性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 06:42:49