【问题标题】:Having problem with the Dictionary in unity统一字典有问题
【发布时间】:2021-10-24 20:59:21
【问题描述】:

我目前正在编写一个生成无限程序城市的游戏。到目前为止一切正常,但是因为如果场景中有太多对象会导致滞后,我想制作一个脚本,其中对象只出现在玩家附近。我观看了这个视频寻求帮助:https://www.youtube.com/watch?v=xlSkYjiE-Ck。当我尝试将此链接到我的脚本(GenerateBuilding 脚本)时,出现此错误:ArgumentException:

已添加具有相同密钥的项目。键:(0.0, 1.0) System.Collections.Generic.Dictionary...

我需要帮助来编写生成房屋和飞机的脚本,它们应该只在玩家在附近时显示 ---相关线路--- (无尽之城)

在update()中调用updateChunk函数(updateChunk/building函数在GenerateBuilding脚本中)

public void UpdateBuildings()
{
    for (int i = 0; i < buildingObjects.Count; i++)
    {
        buildingObjects[i].SetVisible(false);
    }
    buildingObjects.Clear();
}

添加到字典第 68-80 行(UpdateVisibleChunks 函数)

if (building.cityChunkDictionary.ContainsKey(viewedChunkCoord))
{
    building.cityChunkDictionary[viewedChunkCoord].UpdateCityChunk(viewerPosition, viewedChunkCoord, chunkSize, maxViewDst);
    if (building.cityChunkDictionary[viewedChunkCoord].IsVisible())
    {
        building.buildingObjects.Add(building.cityChunkDictionary[viewedChunkCoord]);
    }
}
else
{
    building.AddTest(viewedChunkCoord, chunkSize);
}

EndlessCity,CityChunk 类

CityChunk 函数,将位置发送到 GenerateBuilding 脚本以实例化正确位置的建筑物。

building.requestBuildingSquad(positionV3);

GenerateBuilding 相关行 builderH 函数,实例化建筑物

public float builderH(GameObject[] obj, float Height, Vector3 position)
{
    Transform objTrans = obj[Random.Range(0, obj.Length)].transform;
    //Instantiate house Object
    GameObject objekt = Instantiate(objTrans.gameObject, position + new Vector3(xOfsset * spaceBetween, Height, zOfsset * spaceBetween), transform.rotation);
    float height = Test.transform.localScale.y;
    objectsss.Add(objekt);
    return height;
}

AddTest 函数,将 builderH 中的实例化对象添加到字典中

public void AddTest(Vector2 viewedChunkCoord, float chunkSize)
{
    for (int i = 0; i < objectsss.Count; i++)
    {
        cityChunkDictionary.Add(viewedChunkCoord, new Testing(objectsss[i]));
    }
}

测试类,测试函数,添加对象到类

public Testing(GameObject obj)
{
    MeshObject = obj;
}

应该是所有相关的行

完整的脚本(非常相似)

EndlessCity 脚本(此脚本生成平面并为 GenerateBuilding 脚本提供位置)

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

public class EndlessCity : MonoBehaviour
{

    public const float maxViewDst = 10;
    public Transform viewer;

    private GenerateBuilding building;

    public static Vector2 viewerPosition;
    int chunkSize;
    int chunksVisibleInViewDst;

    Dictionary<Vector2, CityChunk> terrainChunkDictionary = new Dictionary<Vector2, CityChunk>();
    List<CityChunk> terrainChunksVisibleLastUpdate = new List<CityChunk>();

    void Start()
    {
        chunkSize = 8 - 1;
        chunksVisibleInViewDst = Mathf.RoundToInt(maxViewDst / chunkSize);
    }

    void Update()
    {
        
        viewerPosition = new Vector2(viewer.position.x, viewer.position.z);
        UpdateVisibleChunks();
    }

    void UpdateVisibleChunks()
    {
        building = FindObjectOfType<GenerateBuilding>();

        building.UpdateBuildings();

        for (int i = 0; i < terrainChunksVisibleLastUpdate.Count; i++)
        {
            terrainChunksVisibleLastUpdate[i].SetVisible(false);
        }
        terrainChunksVisibleLastUpdate.Clear();

        int currentChunkCoordX = Mathf.RoundToInt(viewerPosition.x / chunkSize);
        int currentChunkCoordY = Mathf.RoundToInt(viewerPosition.y / chunkSize);

        for (int yOffset = -chunksVisibleInViewDst; yOffset <= chunksVisibleInViewDst; yOffset++)
        {
            for (int xOffset = -chunksVisibleInViewDst; xOffset <= chunksVisibleInViewDst; xOffset++)
            {
                Vector2 viewedChunkCoord = new Vector2(currentChunkCoordX + xOffset, currentChunkCoordY + yOffset);

                if (terrainChunkDictionary.ContainsKey(viewedChunkCoord))
                {
                    terrainChunkDictionary[viewedChunkCoord].UpdateTerrainChunk();
                    if (terrainChunkDictionary[viewedChunkCoord].IsVisible())
                    {
                        terrainChunksVisibleLastUpdate.Add(terrainChunkDictionary[viewedChunkCoord]);
                    }
                }
                else
                {
                    terrainChunkDictionary.Add(viewedChunkCoord, new CityChunk(viewedChunkCoord, chunkSize, transform));
                }
                if (building.cityChunkDictionary.ContainsKey(viewedChunkCoord))
                {
                    building.cityChunkDictionary[viewedChunkCoord].UpdateCityChunk(viewerPosition, viewedChunkCoord, chunkSize, maxViewDst);
                    if (building.cityChunkDictionary[viewedChunkCoord].IsVisible())
                    {
                        building.buildingObjects.Add(building.cityChunkDictionary[viewedChunkCoord]);

                    }
                }
                else
                {
                    building.AddTest(viewedChunkCoord, chunkSize);

                }

            }
        }
    }
    public class CityChunk
    {
        private GenerateBuilding building;

        public GameObject meshObject;

        public Vector3 positionV3;

        Vector2 position;
        Bounds bounds;


        public CityChunk(Vector2 coord, int size, Transform parent)
        {
            building = FindObjectOfType<GenerateBuilding>();
            position = coord * size;
            bounds = new Bounds(position, Vector2.one * size);
            positionV3 = new Vector3(position.x, 0, position.y);

            int xPosition = building.xLength / 2;
            int zPosition = building.zLength / 2;

            float xOfsset = building.xOfsset;
            float zOfsset = building.zOfsset;

            float spaceBetween = building.spaceBetween;
            //Instantiate plane
            meshObject = Instantiate(building.groundObject, positionV3 + new Vector3((xPosition + xOfsset) * spaceBetween, -.5f, (xPosition + 1 + zOfsset) * spaceBetween), Quaternion.identity);
            SetVisible(false);
            building.requestBuildingSquad(positionV3);
        }

        public void UpdateTerrainChunk()
        {
            float viewerDstFromNearestEdge = Mathf.Sqrt(bounds.SqrDistance(viewerPosition));
            bool visible = viewerDstFromNearestEdge <= maxViewDst;
            SetVisible(visible);
        }

        public void SetVisible(bool visible)
        {
            meshObject.SetActive(visible);
        }

        public bool IsVisible()
        {
            return meshObject.activeSelf;
        }

    }
}

GenerateBuilding(此脚本在飞机上生成建筑物)

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

public class GenerateBuilding : MonoBehaviour
{
    public int minHeight = 2;
    public int maxHeight = 8;

    public int cubeTileX;
    public int cubeTileZ;

    public int xLength;
    public int zLength;

    public float spaceBetween;

    public float xOfsset;
    public float zOfsset;

    public GameObject TesObject;

    public GameObject[] Base;
    public GameObject[] secondB;
    public GameObject[] roof;

    public GameObject groundObject;

    public List<GameObject> objectsss;

    public Dictionary<Vector2, Testing> cityChunkDictionary = new Dictionary<Vector2, Testing>();
    public List<Testing> buildingObjects = new List<Testing>();

    public GameObject Test;
    void Start()
    {
        //requestBuildingSquad(this.transform.position);
    }

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.I))
        {
            //
        }
    }
    public void requestBuildingSquad(Vector3 position)
    {
        //*getting the middle of the city squad
        int xPosition = xLength / 2;
        int zPosition = zLength / 2;
        //*
        for (int z = 0; z < zLength; z++)
        {
            zOfsset++;
            for (int x = 0; x < xLength; x++)
            {
                GenerateBuildings(position);
            }
            xOfsset = 0;
        }
        zOfsset = 0;
    }
    public void GenerateBuildings(Vector3 position)
    {
        int bHeight = Random.Range(minHeight, maxHeight);
        float bOfsset = 0;
        bOfsset += builderH(Base, bOfsset, position);

        for (int i = 0; i < bHeight; i++)
        {
            bOfsset += builderH(secondB, bOfsset, position);
        }

        bOfsset += builderH(roof, bOfsset, position);
        xOfsset++;
    }

    public float builderH(GameObject[] obj, float Height, Vector3 position)
    {
        Transform objTrans = obj[Random.Range(0, obj.Length)].transform;
        //Instantiate house Object
        GameObject objekt = Instantiate(objTrans.gameObject, position + new Vector3(xOfsset * spaceBetween, Height, zOfsset * spaceBetween), transform.rotation);
        float height = Test.transform.localScale.y;
        objectsss.Add(objekt);
        return height;
    }

    public void AddTest(Vector2 viewedChunkCoord, float chunkSize)
    {
        for (int i = 0; i < objectsss.Count; i++)
        {
            cityChunkDictionary.Add(viewedChunkCoord, new Testing(objectsss[i]));
        }
    }

    public void UpdateBuildings()
    {
        for (int i = 0; i < buildingObjects.Count; i++)
        {
            buildingObjects[i].SetVisible(false);
        }
        buildingObjects.Clear();
    }

    public class Testing
    {
        public GameObject MeshObject;

        Vector2 position;
        Bounds bounds;
        public Testing(GameObject obj)
        {
            MeshObject = obj;
        }
        public void SetVisible(bool visiblee)
        {
            MeshObject.SetActive(visiblee);
        }
        
        public bool IsVisible()
        {
            return MeshObject.activeSelf;
        }

        public void UpdateCityChunk(Vector3 viewerPosition, Vector2 coord, int size, float maxViewDst)
        {
            position = coord * size;
            bounds = new Bounds(position, Vector2.one * size);
            float viewerDstFromNearestEdge = Mathf.Sqrt(bounds.SqrDistance(viewerPosition));
            bool visible = viewerDstFromNearestEdge <= maxViewDst;
            SetVisible(visible);
        }
    }

}

【问题讨论】:

  • 那是很多代码。你能只给我们看相关的部分吗?
  • 更具体的例外会非常有帮助;文件和行号占其中的 90%,完整的堆栈跟踪将使生活变得更快。
  • 那么在 AddTest 中,您尝试添加所有具有相同坐标的块,因此无论您只是想添加整个数组而不是单个项目,还是您需要在该坐标中为每个项目添加其他内容以使键唯一

标签: c# dictionary unity3d generator


【解决方案1】:

问题是您尝试使用相同的键添加两次元素。

here 是用于字典的Add 方法的文档,正如它所说,尝试添加现有键会引发错误。

您可以使用the TryAdd method,它在字典中不存在该键时添加一个项目,或者使用现有键as you can see here 更新值。

【讨论】:

    猜你喜欢
    • 2019-07-09
    • 2017-08-23
    • 1970-01-01
    • 1970-01-01
    • 2011-02-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多