统一 - 重构摇摇欲坠的墙脚本停止工作?

Unity - Refactored crumbling wall script stops working?

我有一个对象,它一次被数千个小立方体取代,然后在初始化后开始一个接一个地移动。

我有可用的代码,但当我尝试重构它以清理它时,它停止工作了。立方体不动。当我尝试将变量初始化和运动初始化分开时会发生这种情况。

所以这是我的原始代码段并且有效:

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
    }
}

}

首先,在重构代码实际运行之前,不要乱搞任何不必要的事情。否则您将尝试解决多个问题。

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(); 
   }
}

如您所见,这实际上并不是改进,而是使您的代码更复杂并且花费的时间更长。以前的方式可能会像现在这样简化。如果出于某种原因必须将该代码移到外面,请尝试我建议的方法。

我的错误是,我通过引用而不是通过值将 indize 传递给 wallscripts。

因此,当我在主脚本中更改 indizes 时,它们在每个墙脚本中都会更改。 所以当我稍后调用墙的 public 函数时,它们都使用相同的 indizes,我最后初始化的,因此首先不受我的 "Initialization" 的影响。

否则,如果我在调用 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
        }
    }
}