使用foreach循环时Physics2D.IgnoreLayerCollision失效问题
颜色匹配门碰撞失效问题修复方案
问题描述
游戏规则为玩家与方形门精灵颜色一致时可穿过门,否则触发碰撞。当前实现中,仅初始颜色对应的门生效,切换玩家颜色后碰撞忽略功能失效。原代码如下:
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Rendering.Universal; public class PlayerColor : MonoBehaviour { private Color currentColor; private Light2D olight; private SpriteRenderer sprite; public Color[] colorArray = { new Color(0.07843138f, 0.7490196f, 0.1803922f, 1.0f), //Green 14BF2E new Color(0.09019608f, 0.5019608f, 0.9098039f, 1.0f), //Blue 1780E8 new Color(0.6313726f, 0.2705882f, 0.9019608f, 1.0f), //Purple A145E6 new Color(1f, 0.6392157f, 0.09019608f, 1.0f) //Orange FFA317 }; void Start() { olight = GetComponent<Light2D>(); sprite = GetComponent<SpriteRenderer>(); ChangeColor(sprite.color); } public Color ChangeColor(Color _color) { Color oldCol = currentColor; currentColor = _color; olight.color = currentColor; sprite.color = currentColor; int index = 6; foreach(Color color in colorArray) { if(color == sprite.color) { Physics2D.IgnoreLayerCollision(3, index); } else { Physics2D.IgnoreLayerCollision(3, index, false); } index++; } return oldCol; } }
问题根源
- 浮点数精度问题:直接使用
color == sprite.color比较颜色,由于Color的RGBA值是浮点数,微小的数值差异会导致比较结果为false,切换颜色后无法正确匹配数组中的颜色。 - 状态重置不彻底:循环中逐个设置图层碰撞状态,若颜色匹配失败,会错误地将所有图层设为不忽略碰撞,导致功能失效。
修复方案
修改后的代码
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Rendering.Universal; public class PlayerColor : MonoBehaviour { private Color currentColor; private Light2D olight; private SpriteRenderer sprite; public Color[] colorArray = { new Color(0.07843138f, 0.7490196f, 0.1803922f, 1.0f), //Green 14BF2E new Color(0.09019608f, 0.5019608f, 0.9098039f, 1.0f), //Blue 1780E8 new Color(0.6313726f, 0.2705882f, 0.9019608f, 1.0f), //Purple A145E6 new Color(1f, 0.6392157f, 0.09019608f, 1.0f) //Orange FFA317 }; void Start() { olight = GetComponent<Light2D>(); sprite = GetComponent<SpriteRenderer>(); // 初始时通过近似匹配找到颜色索引,初始化碰撞状态 int initialIndex = FindColorIndex(sprite.color); if (initialIndex != -1) { ChangeColorByIndex(initialIndex); } } // 通过颜色索引切换颜色并处理碰撞逻辑 public void ChangeColorByIndex(int colorIndex) { if (colorIndex < 0 || colorIndex >= colorArray.Length) return; currentColor = colorArray[colorIndex]; olight.color = currentColor; sprite.color = currentColor; int layerIndex = 6; // 先重置所有门图层与玩家图层的碰撞状态 foreach (Color _ in colorArray) { Physics2D.IgnoreLayerCollision(3, layerIndex, false); layerIndex++; } // 仅开启当前颜色对应门图层的碰撞忽略 Physics2D.IgnoreLayerCollision(3, 6 + colorIndex); } // 近似匹配颜色,解决浮点数精度问题 private int FindColorIndex(Color targetColor) { for (int i = 0; i < colorArray.Length; i++) { if (ColorApproximatelyEqual(colorArray[i], targetColor)) { return i; } } return -1; } // 自定义颜色比较方法,设置容忍度避免精度误差 private bool ColorApproximatelyEqual(Color a, Color b) { const float tolerance = 0.001f; return Mathf.Abs(a.r - b.r) < tolerance && Mathf.Abs(a.g - b.g) < tolerance && Mathf.Abs(a.b - b.b) < tolerance && Mathf.Abs(a.a - b.a) < tolerance; } // 保留原方法兼容现有调用,内部转用索引逻辑 public Color ChangeColor(Color _color) { Color oldCol = currentColor; int index = FindColorIndex(_color); if (index != -1) { ChangeColorByIndex(index); } return oldCol; } }
关键修改点
- 近似颜色比较:新增
ColorApproximatelyEqual方法,通过设置容忍度比较颜色,避免浮点数精度导致的匹配失败。 - 索引驱动逻辑:新增
ChangeColorByIndex方法,直接通过颜色数组索引对应门图层(6+索引),逻辑更可靠。 - 状态重置优先:每次切换颜色时先重置所有门图层的碰撞状态,再单独开启当前颜色对应的忽略碰撞,确保状态正确。
- 初始化优化:Start方法中改用近似匹配初始化,确保初始状态正确生效。
内容的提问来源于stack exchange,提问作者Okorare Tega
相关产品推荐
相关产品推荐

