我有一个Object被一次成千上万的小立方体取代,然后在初始化后一个接一个地开始移动。
我的代码有效,但是当我尝试重构它以清理它时,它就会停止工作。立方体不动。当我尝试将变量初始化和运动初始化分开时,会发生这种情况。
所以这是我原来的代码段,它可以工作:
public class WallCreation : MonoBehaviour {
public Transform wallSegmentPrefab;
GameObject oldWall;
Vector3 oldWallSize;
int oldWallsizeX;
int oldWallsizeY;
int oldWallsizeZ;
Vector3 oldWallPosition;
Vector3 oldWallCornerPosition;
Transform newWall;
Transform parentWallSegment;
Transform[ , , ] wallSegments;
int[] indizes;
void Start () {
indizes= new int[3];
}
public void newWallScript(){
initializeNewWall ("zWall++");
StartCoroutine (waitForMovement ());
}
void initializeNewWall(string replaceWall)
{
oldWall = GameObject.Find(replaceWall);
oldWallSize = oldWall.transform.localScale;
oldWallPosition = oldWall.transform.localPosition;
oldWallsizeX=(int) oldWallSize.x;
oldWallsizeY=(int) oldWallSize.y;
oldWallsizeZ=(int) oldWallSize.z;
oldWallCornerPosition = oldWallPosition - oldWallSize / 2 + wallSegmentPrefab.localScale / 2;
wallSegments = new Transform[oldWallsizeX , oldWallsizeY , oldWallsizeZ];
for (int x = 0; x < oldWallsizeX; x++)
{
for (int y = 0; y < oldWallsizeY; y++)
{
for (int z = 0; z < oldWallsizeZ; z++)
{
newWall = Instantiate(wallSegmentPrefab);
GameObject _wallSegment = newWall.gameObject;
_wallSegment.AddComponent<WallMovement> ();
wallSegments[x,y,z] = newWall;
}
}
}
oldWall.SetActive(false);
}
void newWallMovement()
{
for (int x = 1; x < oldWallsizeX-1; x++)
{
indizes [0] = x;
for (int y = 0; y < oldWallsizeY; y++)
{
indizes [1] = y;
for (int z = 0; z < oldWallsizeZ; z++) {
indizes[2] = z;
newWall = wallSegments[x,y,z];
GameObject _wallSegment = newWall.gameObject;
WallMovement _WallMovement = _wallSegment.GetComponent<WallMovement> ();
_WallMovement.indizes = indizes;
_WallMovement.initializeMovement ();
}
}
}
}
IEnumerator waitForMovement()
{
yield return new WaitForSeconds(1f);
newWallMovement();
}
}
这是我改进的代码无效,(...)保持不变:
public class WallCreation : MonoBehaviour {
//(...)
public void newWallScript(){
//(...)
StartCoroutine (waitForMoving());
}
void initializeNewWall(string replaceWall)
{
(...)
}
void newWallMovement()
{
for (int x = 1; x < oldWallsizeX-1; x++)
{
indizes [0] = x;
for (int y = 0; y < oldWallsizeY; y++)
{
indizes [1] = y;
for (int z = 0; z < oldWallsizeZ; z++) {
indizes[2] = z;
newWall = wallSegments[x,y,z];
GameObject _wallSegment = newWall.gameObject;
WallMovement _WallMovement = _wallSegment.GetComponent<WallMovement> ();
_WallMovement.indizes = indizes;
//this is cut out and put into the wallMoving() void
//_WallMovement.initializeMovement ();
}
}
}
}
void wallMoving(){
for (int x = 1; x < oldWallsizeX-1; x++)
{
//indizes [0] = x; //only with this enabled it works for some reason, otherwise it doesn't
for (int y = 0; y < oldWallsizeY; y++)
{
for (int z = 0; z < oldWallsizeZ; z++) {
newWall = wallSegments[x,y,z];
GameObject _wallSegment = newWall.gameObject;
WallMovement _WallMovement = _wallSegment.GetComponent<WallMovement> ();
//same code but without giving the list indizes[] to the script/gameObject
_WallMovement.initializeMovement ();
}
}
}
}
IEnumerator waitForMovement()
{
(...)
}
IEnumerator waitForMoving()
{
yield return new WaitForSeconds(1f);
wallMoving();
}
}
当我分开这一行时
_WallMovement.initializeMovement ();
对于另一个功能,游戏继续工作,但这次墙不动。 Indizes似乎不再被初始化了。但是,这不会导致控制台出错。
这是WallMovement脚本中发生的事情,它附加到墙的每个立方体上:
public class WallMovement : MonoBehaviour {
public int[] indizes ;
int indize;
int modulo;
public void initializeMovement()
{
modulo = indizes [0] % 2;
if (modulo>0)
{
//do something
}
else
{
// do something else
}
}
}
答案 0 :(得分:1)
我的错误在于,我通过引用传递indize而不是通过值传递到wallcripts。
因此,当我更改主脚本中的indizes时,它们会在每个墙脚本中更改。 因此,当我稍后调用墙的公共函数时,它们都使用相同的indizes,最后一个我初始化,因此首先不受我的“初始化”的影响。
否则如果我在调用wall函数之前更改indizes值它会再次起作用,因为脚本现在使用正确的相应值,所以要纠正我需要逐个传递indizes,这样它们都是用相应的值初始化为真实。
感谢https://catlikecoding.com/unity/tutorials/ 看看这个真正愚蠢的错误,并告诉我这里没有其他人能做到的。至少他没有尝试纠正我的代码,因为它很慢。
所以这是我的新代码段可行,但效率低下,仍然完全符合我的要求: 为了更好的可读性,我不会编写所有可用的代码。它标有(...)并保持不变
public class WallCreation : MonoBehaviour {
(...) //stays the same as in the working code
void Start () {
indizes= new int[3];
}
public void newWallScript(){
initializeNewWall ("zWall++");
StartCoroutine (waitForMovement ());
StartCoroutine (waitForMoving()); //the new coroutine with a later start is added
}
void initializeNewWall(string replaceWall)
{
(...) //stays the same
}
void newWallMovement()
{
for (int x = 1; x < oldWallsizeX-1; x++)
{
indizes [0] = x;
for (int y = 0; y < oldWallsizeY; y++)
{
indizes [1] = y;
for (int z = 0; z < oldWallsizeZ; z++) {
indizes[2] = z;
newWall = wallSegments[x,y,z];
GameObject _wallSegment = newWall.gameObject;
WallMovement _WallMovement = _wallSegment.GetComponent<WallMovement> ();
//_WallMovement.indizes = indizes; //this is a 'passing by reference', because it is an array
_WallMovement.indizes[0] = indizes[0]; //these pass the parameter by value, you could also just say _WallMovement.indizes[0] = x; etc.
_WallMovement.indizes[1] = indizes[1];
_WallMovement.indizes[2] = indizes[2];
//this is cut out and put into the wallMoving() void
//_WallMovement.initializeMovement ();
}
}
}
}
void wallMoving(){
for (int x = 1; x < oldWallsizeX-1; x++)
{
for (int y = 0; y < oldWallsizeY; y++)
{
for (int z = 0; z < oldWallsizeZ; z++) {
newWall = wallSegments[x,y,z];
GameObject _wallSegment = newWall.gameObject;
WallMovement _WallMovement = _wallSegment.GetComponent<WallMovement> ();
_WallMovement.initializeMovement ();
}
}
}
}
IEnumerator waitForMovement()
{
(...) //stays the same
}
IEnumerator waitForMoving()
{
//the time to wait has no consequence on performance whatsoever
yield return new WaitForSeconds(1f);
wallMoving();
}
}
这就是现在WallMovement脚本中发生的事情,它附加到墙的每个立方体上:
public class WallMovement : MonoBehaviour {
public int[] indizes ;
int indize;
int modulo;
void Awake (){
indizes = new int[3]; // this is added, because we dont pass the list, but the single values, so it needs to be declared as a 3-dimensional array inbefore
}
public void initializeMovement()
{
modulo = indizes [0] % 2;
if (modulo>0)
{
//do something
}
else
{
// do something else
}
}
}
答案 1 :(得分:0)
首先,在实际获得重构代码之前,不要乱用任何你不需要的东西。否则你将尝试解决多个问题。
void newWallMovement()
{
for (int x = 1; x < oldWallsizeX-1; x++)
{
indizes [0] = x;
for (int y = 0; y < oldWallsizeY; y++)
{
indizes [1] = y;
for (int z = 0; z < oldWallsizeZ; z++) {
indizes[2] = z;
newWall = wallSegments[x,y,z];
GameObject _wallSegment = newWall.gameObject;
WallMovement _WallMovement = _wallSegment.GetComponent<WallMovement> ();
_WallMovement.indizes = indizes;
}
}
}
}
保持一切相同,只删除_WallMovement.initializeMovement ();
。
现在你必须在其他地方调用相同的函数。这是非常低效的,因为你现在必须迭代每个墙的位置,而不是一次完成所有事情。
这是一个例子。
Private List<WallMovement> WallCollection = new List<WallMovement>();
private WallMovement newWallMovement()
{
for (int x = 1; x < oldWallsizeX-1; x++)
{
indizes [0] = x;
for (int y = 0; y < oldWallsizeY; y++)
{
indizes [1] = y;
for (int z = 0; z < oldWallsizeZ; z++) {
indizes[2] = z;
newWall = wallSegments[x,y,z];
GameObject _wallSegment = newWall.gameObject;
WallMovement _WallMovement = _wallSegment.GetComponent<WallMovement> ();
_WallMovement.indizes = indizes;
WallCollection.Add(_WallMovement);
}
}
}
}
当你调用这两个函数时,你可以做这样的事情
IEnumerator waitForMovement()
{
newWallMovement();
yield return new WaitForSeconds(1f);
InializeAllWallMovement();
}
private void InializeAllWallMovement()
{
foreach(WallMovement wm in WallCollection)
{
wm.initializeMovement();
}
}
正如您所看到的,这实际上并不是一种改进,但会使您的代码更复杂并且需要更长时间。之前的方式可能就像这样简化了。如果你因为某些原因必须将代码移到外面,那么请尝试类似我建议的内容。