【问题标题】:Instantiate doesn't work when changing GameObject within loop在循环内更改 GameObject 时实例化不起作用
【发布时间】:2018-01-17 11:15:20
【问题描述】:

我有这两个代码在理论上做同样的事情,但在实践中表现得非常不同,我想知道为什么/如何修复它。

void BlockPlacer(){ //Places breakable objects
    BlockType BlockKind = BlockType.Hard;
    GameObject Block = ReturnBlock (BlockKind);
    while(true){
        for(int j = 1; j < 4; j++){
            for(float i = -width; i < width; i++){
                GameObject created = Instantiate (Block, new Vector3 (i, height - j, 10), Quaternion.Euler (0, 0, 0));
                print (created.transform.position);
            }
        }
        break;
    }
}

如您所见,我正在实例化一个在我的两个 for 循环之外创建的 GameObject,并且在另一个示例中可以正常工作

void BlockPlacer(){ //Places breakable objects
    BlockType BlockKind = BlockType.Hard;
    while(true){
        for(int j = 1; j < 4; j++){
            for(float i = -width; i < width; i++){
                GameObject created = Instantiate (ReturnBlock (BlockKind), new Vector3 (i, height - j, 10), Quaternion.Euler (0, 0, 0));
                print (created.transform.position);
            }
        }
        break;
    }
}

我正在做同样的事情,但这次我在循环中获取我的游戏对象,并且程序只实例化一次(我检查了我的代码,所有内容都被调用并以我想要的方式返回,只有实例化的行为不应该如此

我的测试理论是,游戏对象在循环的每一次循环中都会被创建,但它会在下一次循环中被删除并再次创建,这可能不是真的,但现在,我没有任何东西更好的。所有 GameObjects 都是从同一个 Prefab 创建的,因此可能存在一些继承问题。这是返回我的游戏对象的代码

GameObject ReturnBlock(BlockType Type){
    if (Type == BlockType.Soft) {
        GameObject SoftBlock = Resources.Load("GameBorderPrefab") as GameObject;
        SoftBlock.name = "SoftBlock";
        SoftBlock.tag = "Soft"; //Sets a tag for that gameobject
        SoftBlock.AddComponent<HitCounter>();
        string TextureName = "";
        for (int i = 0; i < GameManager.Bricks.Count; i++) {
            if (GameManager.Bricks [i].ID == "Soft") {
                TextureName = GameManager.Bricks [i].TextureName;
                SoftBlock.GetComponent<HitCounter> ().HP = System.Int32.Parse(GameManager.Bricks [i].HitPoints);
            }
        }
        SoftBlock.GetComponent<Renderer> ().material = Resources.Load (TextureName) as Material;
        return SoftBlock;
    }if (Type == BlockType.Medium) {
        GameObject MediumBlock = Resources.Load("GameBorderPrefab") as GameObject;
        MediumBlock.name = "MediumBlock";
        MediumBlock.tag = "Medium";
        MediumBlock.AddComponent<HitCounter>();
        string TextureName = "";
        for (int i = 0; i < GameManager.Bricks.Count; i++) {
            if (GameManager.Bricks [i].ID == "Medium") {
                TextureName = GameManager.Bricks [i].TextureName;
                MediumBlock.GetComponent<HitCounter> ().HP = System.Int32.Parse(GameManager.Bricks [i].HitPoints);
            }
        }
        MediumBlock.GetComponent<Renderer> ().material = Resources.Load (TextureName) as Material;
        return MediumBlock;
    }else{//if (Type == BlockType.Hard) {
        GameObject HardBlock = Resources.Load ("GameBorderPrefab") as GameObject;
        HardBlock.name = "HardBlock";
        HardBlock.tag = "Hard";
        HardBlock.AddComponent<HitCounter> ();
        string TextureName = "";
        for (int i = 0; i < GameManager.Bricks.Count; i++) {
            if (GameManager.Bricks [i].ID == "Hard") {
                TextureName = GameManager.Bricks [i].TextureName;
                HardBlock.GetComponent<HitCounter> ().HP = System.Int32.Parse (GameManager.Bricks [i].HitPoints);
            }
        }
        HardBlock.GetComponent<Renderer> ().material = Resources.Load (TextureName) as Material;
        return HardBlock;
    }
}

在进一步的测试中,我编写了这段代码,其行为与我展示的第一个代码一样,希望我能看到正在创建的三行不同的对象。只有第一个 Instantiate 按预期工作,其他人什么也没做,但 我的所有打印功能都按预期工作

BlockType BlockKind = BlockType.Hard;
    GameObject Block = ReturnBlock (BlockKind);
    int j = 1;
    for(float i = -width; i < width; i++){
        GameObject created = Instantiate (Block, new Vector3 (i, height - j, 10), Quaternion.Euler (0, 0, 0));
        print (created.transform.position);
    }
    j = 2;
    BlockKind = BlockType.Soft;
    Block = ReturnBlock (BlockKind);
    for(float i = -width; i < width; i++){
        GameObject created = Instantiate (Block, new Vector3 (i, height - j, 10), Quaternion.Euler (0, 0, 0));
        print (created.transform.position);
    }
    j = 3;
    BlockKind = BlockType.Medium;
    Block = ReturnBlock (BlockKind);
    for(float i = -width; i < width; i++){
        GameObject created = Instantiate (Block, new Vector3 (i, height - j, 10), Quaternion.Euler (0, 0, 0));
        print (created.transform.position);
    }

【问题讨论】:

  • 请将您的代码以文本形式发布,图片无法正常缩放,无法复制和测试代码,并且视障人士无法阅读。
  • 去掉图片,改成代码
  • 能把ReturnBlock方法的代码贴出来吗?
  • 在第一个代码中,当您使用GameObject Block = ReturnBlock (BlockKind); 时,它确实会为您创建一个游戏对象。根据ReturnBlock () 方法,它可能只是创建一个空的游戏对象。这会在循环中重复。如果可以,请发布ReturnBlock () 代码

标签: c# unity3d instantiation gameobject


【解决方案1】:

解决方案在于 Unity 无法将正在实例化的内容和保留为资源文件夹中的空预制件的内容分开,这就是为什么在第二次调用 ReturnBlock() 函数时实例化函数会出错的原因.我通过为我的每一种块类型从头开始创建一个新的预制件来修复我的错误,它是否优化了,这是一个好的做法,但现在它完成工作。

TL;DR 不要使用一个预制件来实例化多个对象,否则继承会开始,你会遇到麻烦。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-06-22
    • 1970-01-01
    • 2021-12-03
    • 1970-01-01
    • 1970-01-01
    • 2019-06-09
    • 1970-01-01
    相关资源
    最近更新 更多