【发布时间】: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