To find objects of the same value using Queue.contains() in C#, Unity

混江龙づ霸主 提交于 2019-12-23 06:03:49

问题


I try to find coordinate values with the same values. And I'm going to link three coordinate values.

I am doing this to make mesh at Unity.

I first found the same coordinates by bfs method.

And there is a problem trying to connect the three adjacent coordinates.

I did the following to find out if there are any adjacent points in eight directions.

private int[,] fx = new int[8, 2] { { -1, 0 }, { -1, 0 }, { 1, 0 }, { 1, 1 }, 
                                    { -1, 0 }, { -1, 0 }, { 0, 1 }, { 0, 1 } };

private int[,] fy = new int[8, 2] { { -1, -1 }, { 0, -1 }, { -1, -1 }, { -1, 0 }, 
                                    { 0, 1 }, { 1, 1 }, { 1, 0 }, { 1, 1 } };

void CreateTriangle()
{
    int index = 0;
    while (SegNode.Count > 0)
    {
        Node curNode = SegNode.Peek();
        for (int i = 0; i < 8; i++)
        {


            Node nextNode = new Node(curNode.x + fx[i, 0], curNode.y + fy[i, 0], curNode.color);
            Node nextNode2 = new Node(curNode.x + fx[i, 1], curNode.y + fy[i, 1], curNode.color);

            Debug.Log("CurNode " + curNode.x + " , " + curNode.y + 
                " NextNode " + nextNode.x + " , " + nextNode.y + 
                " NextNode2 " + nextNode2.x + " , " + nextNode2.y);


            if (SegNode.Contains(nextNode) && SegNode.Contains(nextNode2))
            {
                newTriangles.Add(SegNode.ToArray().ToList().IndexOf(curNode) + index);
                newTriangles.Add(SegNode.ToArray().ToList().IndexOf(nextNode) + index);
                newTriangles.Add(SegNode.ToArray().ToList().IndexOf(nextNode2) + index);
            }
        }
        index++;
        SegNode.Dequeue();
    }
}

there is clearly a point about (0,1) (1,0), but I can't find it using Queue.Contains()

Maybe Contains() don't recognize it because I used [new] to create a new object. How can I find an object?

Here is my full code

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;

public class MeshCreator : MonoBehaviour
{

// This first list contains every vertex of the mesh that we are going to render
public List<Vector3> newVertices = new List<Vector3>();

// The triangles tell Unity how to build each section of the mesh joining
// the vertices
public List<int> newTriangles = new List<int>();

// The UV list is unimportant right now but it tells Unity how the texture is
// aligned on each polygon
public List<Vector2> newUV = new List<Vector2>();


// A mesh is made up of the vertices, triangles and UVs we are going to define,
// after we make them up we'll save them as this mesh


private Mesh mesh;
// Start is called before the first frame update

private int[,] pixel = new int[15, 15] {
                                        { 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                                        { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                                        { 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                                        { 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                                        { 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                                        { 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                                        { 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                                        { 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
                                        { 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
                                        { 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 2, 0, 0, 0 },
                                        { 0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 2, 2, 0, 0, 0 },
                                        { 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0 },
                                        { 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0 },
                                        { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0 },
                                        { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
                                       };


private bool[,] visit = new bool[15, 15];

private int[] dx = new int[4] { 0, 1, -1, 0 };
private int[] dy = new int[4] { 1, 0, 0, -1 };

public int idx = 0;

public class Node
{
    public int x, y, color;

    public Node(int x, int y, int color)
    {
        this.x = x;
        this.y = y;
        this.color = color;
    }
}


public Queue<Node> SegNode = new Queue<Node>();

void bfs(int r, int c, int color)
{
    Queue<Node> q = new Queue<Node>();
    q.Enqueue(new Node(r, c, color));

    while (q.Count > 0)
    {
        Node curNode = q.Dequeue();
        SegNode.Enqueue(curNode);
        for (int i = 0; i < 4; i++)
        {
            int tr = curNode.x + dx[i];
            int tc = curNode.y + dy[i];

            if (tr >= 0 && tr < 15 && tc >= 0 && tc < 15)
            {
                if (!visit[tr, tc] && pixel[tr, tc] == color)
                {
                    visit[tr, tc] = true;
                    q.Enqueue(new Node(tr, tc, color));

                    newVertices.Add(new Vector3(tr, tc, 0));
                }
            }
        }
    }
}

private int[,] fx = new int[8, 2] { { -1, 0 }, { -1, 0 }, { 1, 0 }, { 1, 1 }, 
                                    { -1, 0 }, { -1, 0 }, { 0, 1 }, { 0, 1 } };
private int[,] fy = new int[8, 2] { { -1, -1 }, { 0, -1 }, { -1, -1 }, { -1, 0 }, 
                                    { 0, 1 }, { 1, 1 }, { 1, 0 }, { 1, 1 } };


void CreateTriangle()
{
    int index = 0;
    while (SegNode.Count > 0)
    {
        Node curNode = SegNode.Peek();
        for (int i = 0; i < 8; i++)
        {


            Node nextNode = new Node(curNode.x + fx[i, 0], curNode.y + fy[i, 0], curNode.color);
            Node nextNode2 = new Node(curNode.x + fx[i, 1], curNode.y + fy[i, 1], curNode.color);

            Debug.Log("CurNode " + curNode.x + " , " + curNode.y + 
                " NextNode " + nextNode.x + " , " + nextNode.y + 
                " NextNode2 " + nextNode2.x + " , " + nextNode2.y);


            if (SegNode.Contains(nextNode) && SegNode.Contains(nextNode2))
            {
                newTriangles.Add(SegNode.ToArray().ToList().IndexOf(curNode) + index);
                newTriangles.Add(SegNode.ToArray().ToList().IndexOf(nextNode) + index);
                newTriangles.Add(SegNode.ToArray().ToList().IndexOf(nextNode2) + index);
            }
        }
        index++;
        SegNode.Dequeue();
    }
}



void Start()
{

    //int result = 0;
    for (int r = 0; r < 15; r++)
    {
        for (int c = 0; c < 15; c++)
        {
            if (!visit[r, c] && pixel[r, c] != 0)
            {
                newVertices.Add(new Vector3(r, c, 0));
                bfs(r, c, pixel[r, c]);
                //result++;
            }
        }
    }

    CreateTriangle();

    mesh = GetComponent<MeshFilter>().mesh;
}
}

回答1:


classes are reference types. That means your SegNode queue doesn't actually contain values but references to instances of Node.

As you said already your Contains check doesn't work like that since you are checking if the same reference to the excatly same instance of Node exists in the queue.


You could simply make your Node a value type instead by changing it from a class to a struct

public struct Node
{
    public int x, y, color;

    public Node(int x, int y, int color)
    {
        this.x = x;
        this.y = y;
        this.color = color;
    }
}

than your check

Node nextNode = new Node(curNode.x + fx[i, 0], curNode.y + fy[i, 0], curNode.color);
Node nextNode2 = new Node(curNode.x + fx[i, 1], curNode.y + fy[i, 1], curNode.color);

Debug.Log("CurNode " + curNode.x + " , " + curNode.y + 
          " NextNode " + nextNode.x + " , " + nextNode.y + 
          " NextNode2 " + nextNode2.x + " , " + nextNode2.y);

if (SegNode.Contains(nextNode) && SegNode.Contains(nextNode2))
{
    //...
}

should work.


Alternatively you can use e.g. Linq FirstOrDefault like

var nextNode = SegNode.FirstOrDefault(n => n.x == curNode.x + fx[i, 0] 
                                        && n.y == curNode.y + fy[i, 0]);

var nextNode2 = SegNode.FirstOrDefault(n => n.x == curNode.x + fx[i, 1] 
                                        && n.y == curNode.y + fy[i, 1]);

if(nextNode != null && nextNode2 != null)
{
    // ...
}
  • FirstOrDefault returns the first match defined by the predicate e.g.

    n.x == curNode.x + fx[i, 0] && n.y == curNode.y + fy[i, 0]
    

    or null if no matches are found or the list/queue is empty


as a broader alternative you could also let your Node implement IEquatable but that's maybe a bit overkill for your usecase ;)



来源:https://stackoverflow.com/questions/55095183/to-find-objects-of-the-same-value-using-queue-contains-in-c-unity

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!