维护在编辑器中创建并存储在可编写脚本的对象中的对象之间的关系(引用)

问题描述 投票:0回答:1

所以我最近发现了Unity中上下文菜单的使用。我有一个带有一堆三角形的网格,每个三角形有 3 个顶点。

我有一个可编写脚本的对象,

LevelData

[CreateAssetMenu(fileName = "LevelData", menuName = "Tactics/LevelData", order = 0)]
public class LevelData : ScriptableObject {
    public List<Tri> AllTris = new List<Tri>();
    public List<Vertex> AllVerts = new List<Vertex>();
   
    public Vertex GetVertexFromVector3(Vector3 position)
    {
        foreach (Vertex v in AllVerts)
        {
            if (v.pos == position)
            {
                return v;
            }
        }
        return null;
    }
} 

我设置了 AllTris 和 AllVerts:

 [ContextMenu("Find All Vertices")]
    void GetAllVerts(){
        mesh = GetComponent<MeshFilter>().sharedMesh;
        levelData.AllVerts = new List<Vertex>();
        for (int t = 0; t < mesh.vertices.Length; t++)
        {
            levelData.AllVerts.Add(new Vertex(t, mesh.vertices[t]));
        }
    }

    [ContextMenu("Find All Triangles")]
    void GetAllTris(){
        mesh = GetComponent<MeshFilter>().sharedMesh;
        levelData.AllTris = new List<Tri>();
        List<Vertex> verts = levelData.AllVerts;
        for (int t = 0; t < mesh.triangles.Length; t+=3)
        {
            Vertex v1 = verts[mesh.triangles[t+0]];
            Vertex v2 = verts[mesh.triangles[t+1]];
            Vertex v3 = verts[mesh.triangles[t+2]];
            levelData.AllTris.Add(new Tri( (t+3)/3 - 1, v1, v2, v3 ));
        }
    }

我希望的是,当我移动 AllVerts 中的顶点时,这会影响 AllTris 中的该顶点

我创建这个是为了测试它:

    [ContextMenu("Test relationship between AllVerts and AllTris")]
    void MoveVertexAndLogTriangle(){
        Debug.Log(levelData.AllTris.First().First.pos);
        Vertex v1 = levelData.GetVertexFromVector3(levelData.AllTris.First().First.pos);
        v1.pos += Vector3.up;
        Debug.Log(levelData.AllTris.First().First.pos);
    } 

这在我按下播放之前就起作用了。它记录向下移动的顶点。

但是在运行时,它不起作用。我的猜测是 AllVerts 和 AllTris 中的顶点之间的链接丢失了。但我真的不知道。

我将 GetAllTris 和 GetAllVerts 都放在 start 方法中,它按预期工作,如下所示:

    private void Start() {


        mesh = GetComponent<MeshFilter>().mesh;
        levelData.AllVerts = new List<Vertex>();
        for (int t = 0; t < mesh.vertices.Length; t++)
        {
            //do we need an id?
            levelData.AllVerts.Add(new Vertex(t, mesh.vertices[t]));
        }
        levelData.AllTris = new List<Tri>();
        for (int t = 0; t < mesh.triangles.Length; t+=3)
        {
            Vertex v1 = levelData.AllVerts[mesh.triangles[t+0]];
            Vertex v2 = levelData.AllVerts[mesh.triangles[t+1]];
            Vertex v3 = levelData.AllVerts[mesh.triangles[t+2]];
            levelData.AllTris.Add(new Tri( (t+3)/3 - 1, v1, v2, v3 ));
        }
       
        MoveVertexAndLogTriangle();

    }

但我希望能够预先计算所有这些以节省性能。

有谁知道为什么从可编写脚本的对象加载 tris 和 verts 列表不起作用?有办法解决这个问题吗?预先感谢!

我想知道带有 Id 的东西是否可以工作?

c# unity-game-engine oop mesh
1个回答
0
投票

我看不到您对

Vertex
Tri
的实现。

但一般来说:当您在 Unity 中序列化某些不是

UnityEngine.Object
类型而只是“正常”
[Serializable]
类型的内容时,它始终会按 BY VALUE 进行序列化。

请记住,

ScriptableObject
(与场景和预制件等大多数其他资产一样)基本上只是一个包含文本的 YAML 文件。

现在,当从该 YAML 文件加载

ScriptableObject
时,解析器无法判断
AllTris
中的最初条目与
c#
中元素的相同
AllVerts
实例。

它只会将两者单独反序列化为两个单独的实例,没有任何连接。

它适用于

UnityEngine.Object
引用,因为 Unity 序列化器专门通过存储在
.meta
文件中的 GUID 来处理这些引用(这就是为什么如果丢失
.meta
文件,所有引用都会丢失)。


那么现在该怎么办呢?

说实话,我还不太清楚你到底想做什么。但您必须确保使用不同的方式以独特的方式引用/识别顶点。

=> 为什么不简单地坚持 Unity 的做法:不是将实际的

Vertex
实例存储到
Triangle
中,而是将顶点的 index 存储在整个
vertices
数组中。

您可以执行相同的操作,并在您的

Tri
中仅将三个索引传递到
Vertex
中的
AllVerts
实例。

这可能也会回答

//我们需要一个id吗?

如果您只是按索引进行操作 - 不,不是真的。

© www.soinside.com 2019 - 2024. All rights reserved.