【问题标题】:Unity - Refactored crumbling wall script stops working?Unity - 重构的摇摇欲坠的墙脚本停止工作?
【发布时间】:2023-03-19 14:24:01
【问题描述】:

我有一个对象,它一次被成千上万个小立方体替换,然后在初始化后开始一个接一个地移动。

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

所以这是我的原始代码段,它可以工作:

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

}

【问题讨论】:

  • Indizes 是为了让墙段知道他在哪里,这样他就可以沿着它定位自己。所以它包含 x、y 和 z 位置。是的,我没有使用它,因为在第二个代码中应该已经为指定的墙段声明了它。如果没有再次设置 indize,第一个有效,第二个无效。
  • 运行这个时控制台没有错误吗?它可能会帮助您缩小搜索范围。
  • 您的新脚本中是否缺少代码,因为我看不到 Start 方法?
  • 不,它不是,但显然它不再是问题了,对不起。不知何故迷路了。
  • 你从来没有真正调用过newWallScript(),所以协程永远不会开始。

标签: unity3d initialization coroutine gameobject


【解决方案1】:

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

因此,当我更改主脚本中的 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
        }
    }
}

【讨论】:

  • 那么正确的代码是什么?目前您的答案不完整。
【解决方案2】:

首先,在您真正让重构的代码工作之前,不要乱做任何您不需要做的事情。否则,您将尝试解决多个问题。

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

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

【讨论】:

猜你喜欢
  • 2012-03-05
  • 1970-01-01
  • 2018-09-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-12-18
  • 2013-12-24
相关资源
最近更新 更多