c# - unity AddComponent 非常低效和缓慢
问题描述
我有一个包含近 120,000 颗星星的数据集和一个包含 215 颗星星的测试数据集(取自主数据集),我正在制作一个程序来读取数据集并在 3D 地球模型周围绘制星星。
- 读取数据集并将信息存储在多个列表中(在单例脚本中)
- 然后模拟脚本读取列表(销毁单例以提高程序效率):
void listStars()
{
int i = 0;
while (i < (StarDataBank.Instance.NumOfStars))
{
int primaryID = int.Parse(StarDataBank.Instance.StarIDID[i]);
string properName = StarDataBank.Instance.StarName[i];
string HIPID = StarDataBank.Instance.StarIDHIP[i];
string HDID = StarDataBank.Instance.StarIDHD[i];
string HRID = StarDataBank.Instance.StarIDHR[i];
string GLID = StarDataBank.Instance.StarIDGL[i];
string BFID = StarDataBank.Instance.StarIDBF[i];
decimal rightAscension = Convert.ToDecimal(StarDataBank.Instance.StarRA[i]);
decimal declination = Convert.ToDecimal(StarDataBank.Instance.StarDec[i]);
decimal Mag;
decimal CI;
float scale = 0;
int r = 0;
int g = 0;
int b = 0;
Decimal.TryParse((StarDataBank.Instance.StarMag[i]), out Mag);
Decimal.TryParse((StarDataBank.Instance.StarCI[i]), out CI);
if (PlayerPrefs.GetInt("dynamicSize") == 1)
{
if (Mag < -1)
{
scale = 77.5f;
}
else
{
if (Mag > -1 && Mag <= 5)
{
scale = 52.5f;
}
else
{
if (Mag > 5 && Mag <= 10)
{
scale = 32.5f;
}
else
{
if (Mag > 10 && Mag <= 15)
{
scale = 17.5f;
}
else
{
if (Mag > 15 && Mag <= 20)
{
scale = 7.5f;
}
else
{
if (Mag > 20 && Mag <= 25)
{
scale = 2.5f;
}
}
}
}
}
}
}
else
{
scale = 20;
}
StartCoroutine(placeStars(primaryID, properName, HIPID, HDID, HRID, GLID, BFID, rightAscension, declination, Mag, CI, scale));
i++;
}
DestroyImmediate(StarDataBank.Instance.gameObject);
}
- 每颗星都是用这种方法绘制的:
IEnumerator placeStars(int primaryID, string properName, string HIPID, string HDID, string HRID, string GLID, string BFID, decimal rightAscension, decimal declination, decimal magnitude, decimal colourIndex, float scale)
{
var thisStar = (GameObject)Instantiate(prefabStar, transform.position + getVectors(Convert.ToDecimal(rightAscension), Convert.ToDecimal(declination)), Quaternion.identity);
thisStar.name = (primaryID).ToString();
thisStar.transform.parent = StarObject.transform;
thisStar.transform.localScale = new Vector3(scale, scale, scale);
thisStar.AddComponent<Star>().newStar(primaryID, properName, HIPID, HDID, HRID, GLID, BFID, rightAscension, declination, magnitude, colourIndex);
yield return null;
}
使用只有 215 颗星的较小测试数据集,我能够将 Star 类附加到每个实例化的星。
但是对于具有约 120k 星的大型完整数据集,Unity 编辑器只会在按下播放按钮后挂起。当我注释掉这一行时:thisStar.AddComponent<Star>().newStar(...);
程序按预期工作,每个星星都绘制在场景中,唯一的问题是 Star 类没有附加到每个新实例化的星星上。
这意味着 AddComponent 函数不能很好地与我的代码配合使用,尤其是在使用大型数据集时。
有没有更有效的方法将 Star 类附加到每个实例化的 Star GameObject?
另外,在我用完单例后销毁它有什么不同吗?我使用 IEnumerator 实例化有什么不同吗?
编辑:这是明星班:
public class Star : MonoBehaviour
{
Simulation simulationInstance;
public int primaryID; // primary key NEEDS TO BE SET
public string properName; // some stars have names NEEDS TO BE SET
public string HIPID; // ID of star from Hipparcos catalogue NEEDS TO BE SET
public string HDID; // ID of star from Henry Draper catalogue NEEDS TO BE SET
public string HRID; // ID of star from Harvard Revised catalogue NEEDS TO BE SET
public string GLID; // ID of star from Gliese catalogue NEEDS TO BE SET
public string BFID; // ID of star from BayerFlamsteed catalogue NEEDS TO BE SET
public decimal rightAscension; // right ascension of star NEEDS TO BE SET
public decimal declination; // declination of star NEEDS TO BE SET
public decimal magnitude; // magnitude of the star NEEDS TO BE SET
public decimal colourIndex; // colour index of the star NEEDS TO BE SET
public int scale; // size of the sphere that will represent the star AUTOMATICALLY SET
public int red; // red colour (0-255) AUTOMATICALLY SET
public int green; // green colour (0-255) AUTOMATICALLY SET
public int blue; // blue colour (0-255) AUTOMATICALLY SET
public double x; // AUTOMATICALLY SET
public double y; // AUTOMATICALLY SET
public double z; // AUTOMATICALLY SET
void Start()
{
simulationInstance = FindObjectOfType<Simulation>();
}
public void newStar(int primaryID, string properName, string HIPID, string HDID, string HRID, string GLID, string BFID, decimal rightAscension, decimal declination, decimal magnitude, decimal colourIndex)
{
this.primaryID = primaryID;
this.properName = properName;
this.HIPID = HIPID;
this.HDID = HDID;
this.HRID = HRID;
this.GLID = GLID;
this.BFID = BFID;
this.rightAscension = rightAscension;
this.declination = declination;
this.magnitude = magnitude;
this.colourIndex = colourIndex;
}
public void tellStarInfoPanel()
{
simulationInstance.starInfoPanelManager(primaryID, properName, HIPID, HDID, HRID, GLID, BFID, rightAscension, declination, magnitude, colourIndex);
}
}
编辑:我已将 listStars() 设为协程,将 placeStars() 设为普通方法
public void placeStars(int primaryID, string properName, string HIPID, string HDID, string HRID, string GLID, string BFID, decimal rightAscension, decimal declination, decimal magnitude, decimal colourIndex, float scale)
{
var thisStar = (GameObject)Instantiate(prefabStar, transform.position + getVectors(Convert.ToDecimal(rightAscension), Convert.ToDecimal(declination)), Quaternion.identity);
thisStar.name = (primaryID).ToString();
thisStar.transform.parent = StarObject.transform;
thisStar.transform.localScale = new Vector3(scale, scale, scale);
thisStar.GetComponent<Star>().newStar(primaryID, properName, HIPID, HDID, HRID, GLID, BFID, rightAscension, declination, magnitude, colourIndex);
starsRendered++;
}
解决方案
有没有更有效的方法将 Star 类附加到每个实例化的 Star GameObject?
是的。您的 Star 预制件应该已经
Star
附加了组件。然后您可以将其实例化为var thisStar = (Star)Instantiate(prefabStar, transform.position + getVectors(Convert.ToDecimal(rightAscension), Convert.ToDecimal(declination)), Quaternion.identity);
,避免 AddComponent 步骤。
另外,在我用完单例后销毁它有什么不同吗?
不,它不消耗任何处理,您只会释放一些内存。
我使用 IEnumerator 实例化有什么不同吗?
仅当您想在多个帧上实例化对象时,如下所示。
有些事情你可以改进
- 在多个帧上实例化星星:为此,您必须将您的
listStars
方法转换为协程,使返回类型为 IEnumerator 并使用yield return placeStars(primaryID, properName, HIPID, HDID, HRID, GLID, BFID, rightAscension, declination, Mag, CI, scale)
. 您可能希望在同一帧上实例化多个星星,或者可能需要一些时间! - 你的 Star
Start
方法在每一个实例化的星星上变得越来越昂贵,最好将它作为参数传递给placeStars
方法,在循环星星之前只获取一次。 - 您不需要在每次迭代时都
dynamicSize
从中获取。PlayerPrefs
在循环开始之前存储它。单例实例也是如此。在循环开始之前缓存它并使用缓存的引用。
伪代码示例:
IEnumerator listStars()
{
var starDataBank = StarDataBank.Instance;
var dynamicSize = PlayerPrefs.GetInt("dynamicSize");
var simulationInstance = FindObjectOfType<Simulation>();
var starsPerFrame = 10;
for (int i = 0; i < starDataBank.NumOfStars; i++)
{
// do your stuff
for (int j = 0; j < starsPerFrame; j++)
placeStars(simulationInstance, primaryID, properName, HIPID, HDID, HRID, GLID, BFID, rightAscension, declination, Mag, CI, scale));
yield return null;
}
DestroyImmediate(starDataBank.gameObject);
}
推荐阅读
- python - 有没有办法打印这个未显示的标签文本?
- php - 如何在 PHP 中正确调用 gmdate()?
- java - 启动对象非静态变量时,无法从静态上下文中引用它
- twilio - 适用于 Twilio 可编程视频服务器端的 SDK,即 REST API
- java - E/MediaRecording:外部存储访问错误
- python - 编写带有 X 和 Y 轴的 JSON 文件
- c# - 为什么 WPF XAML 前端在其他机器上看起来不同?
- email - 当我将名称设置为变量时,作为 xlsx 的 Python 电子邮件附件不起作用
- reactjs - 反应代理不工作 http-proxy-middleware
- checkbox - 不使用提交的复选框列表