Unity3D:2D碰撞器内敌人淡入淡出效果失效问题求助
问题解决思路与修复代码
核心问题分析
- Unity碰撞回调返回类型错误:
OnTriggerEnter2D、OnTriggerStay2D、OnTriggerExit2D是Unity内置消息函数,必须是void返回类型。改成IEnumerator后,Unity不会自动执行这些协程,导致淡入淡出的循环逻辑直接跳过,看起来就是直接显隐。 - 淡出逻辑完全写反:
OnTriggerExit2D里的循环条件、透明度增减方向全错,不仅没实现淡出,反而会让透明度异常变化后直接跳转到0。 - 无协程冲突控制:快速进出碰撞器时,会重复触发协程,导致透明度逻辑混乱。
修复后的完整代码
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
相关产品推荐
相关产品推荐

