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

Unity C#开发魔方游戏:如何避免列表重复添加同一元素?

解决魔方游戏中List重复添加元素及Contains失效的问题

我看你遇到的问题核心在于自定义node类的List.Contains()方法没有按预期工作,导致同一逻辑下的元素被重复添加到列表里。这背后的原因和C#中自定义类型的默认比较规则有关,咱们一步步来解决:

为什么Contains()会失效?

C#里的List.Contains()默认使用对象的引用相等性来判断是否存在该元素。而你在Update()的三重循环里,每一帧都new node(...)创建全新的实例——哪怕两个node的InRubikCubePos完全一样,它们也是内存中不同的对象,所以Contains()会返回false,自然就会重复添加。

解决方案1:重写node类的Equals和GetHashCode方法

既然InRubikCubePos是每个魔方块的唯一标识(比如(1,1,1)这种位置不会重复),我们可以基于这个字段来定义两个node对象相等的规则:

修改你的node类:

public class node{
    public Vector3 InRubikCubePos;
    public Vector3 inWorldPos;

    public node(Vector3 IRCPos, Vector3 IWPos) {
        InRubikCubePos = IRCPos;
        inWorldPos = IWPos;
    }

    // 重写Equals方法,基于InRubikCubePos比较
    public override bool Equals(object obj)
    {
        if (obj is node otherNode)
        {
            // Vector3是值类型,可以直接用==比较
            return InRubikCubePos == otherNode.InRubikCubePos;
        }
        return false;
    }

    // 必须同时重写GetHashCode,和Equals逻辑保持一致
    public override int GetHashCode()
    {
        // 用InRubikCubePos的哈希值作为当前对象的哈希码
        return InRubikCubePos.GetHashCode();
    }
}

这样修改后,List.Contains()就会基于InRubikCubePos的值来判断元素是否存在,而不是引用了。

解决方案2:不依赖Contains(),直接通过位置判断

如果你不想修改node类,也可以在添加/移除元素时,直接检查列表中是否存在InRubikCubePos匹配的元素:

比如处理topYFaces的逻辑可以改成这样:

// 替换原来的if (!topYFaces.Contains(Node_)) topYFaces.Add(Node_);
if (!topYFaces.Any(n => n.InRubikCubePos == Node_.InRubikCubePos))
{
    topYFaces.Add(Node_);
}

移除的时候同理:

// 替换原来的if (topYFaces.Contains(Node_)) topYFaces.Remove(Node_);
var existingNode = topYFaces.FirstOrDefault(n => n.InRubikCubePos == Node_.InRubikCubePos);
if (existingNode != null)
{
    topYFaces.Remove(existingNode);
}

这种方式不需要修改node类,但每次判断都会遍历列表,性能上和Contains()差不多,适合小规模列表(你的魔方最多27个元素,完全没问题)。

额外优化:避免每一帧都重新创建nodes数组

你现在在Update()里每一帧都new node[3,3,3]并创建27个新node实例,这会产生大量不必要的GC垃圾,长期运行可能导致卡顿。建议把nodes的初始化移到Start()或Awake()里,只在魔方位置变化时(比如旋转后)更新inWorldPos,而不是每一帧都重建整个数组:

private node[,,] nodes;

void Start()
{
    // 只初始化一次nodes数组
    nodes = new node[3, 3, 3];
    Vector3 cubeButtonLeftDown = new Vector3((size / 2 * -1) + (size / 3), (size / 2 * -1) + (size / 3) , (size / 2 * -1) + (size / 3));
    for (int x = -1; x <= 1; x++) {
        for (int y = -1; y <= 1; y++) {
            for (int z = -1; z <= 1; z++) {
                node Node = new node(new Vector3(x, y, z), new Vector3 (x * size / 6, y * size / 6, z * size / 6));
                nodes[x + 1, y + 1, z + 1] = Node;
            }
        }
    }
}

void Update()
{
    // 只在需要的时候更新node的inWorldPos,比如魔方旋转后更新位置...

    // 后续的面判断逻辑保持不变(或者用上面的解决方案修改)
}

这样既能解决重复添加的问题,又能优化性能,一举两得~

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 20:03:13