简体   繁体   English

如何使用 range 属性添加更多新的实例化对象或删除对象?

[英]How can I use the range attribute to add more new instantiated objects or to remove objects?

using System;
using UnityEngine;
using Random = UnityEngine.Random;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

[ExecuteAlways]

public class CloneObjects : MonoBehaviour
{
    public Terrain terrain;
    public GameObject prefab;
    public GameObject parent;
    [Range(10, 1000)]
    public int numberOfObjects;
    public float yOffset = 10f;

    private float terrainWidth;
    private float terrainLength;
    private float xTerrainPos;
    private float zTerrainPos;

    void Start()
    {
        //Get terrain size
        terrainWidth = terrain.terrainData.size.x;
        terrainLength = terrain.terrainData.size.z;

        //Get terrain position
        xTerrainPos = terrain.transform.position.x;
        zTerrainPos = terrain.transform.position.z;

        generateObjectOnTerrain();
    }

    void generateObjectOnTerrain()
    {
        for (int i = 0; i < numberOfObjects; i++)
        {
            //Generate random x,z,y position on the terrain
            float randX = UnityEngine.Random.Range(xTerrainPos, xTerrainPos + terrainWidth);
            float randZ = UnityEngine.Random.Range(zTerrainPos, zTerrainPos + terrainLength);
            float yVal = Terrain.activeTerrain.SampleHeight(new Vector3(randX, 0, randZ));

            //Apply Offset if needed
            yVal = yVal + yOffset;

            //Generate the Prefab on the generated position
            GameObject objInstance = Instantiate(prefab, new Vector3(randX, yVal, randZ), Quaternion.identity);
            objInstance.name = "Waypoint";
            objInstance.tag = "Waypoint";
            objInstance.transform.parent = parent.transform;
        }
    }
}

I want that if I move in the editor either in edit mode or run time mode the numberOfObjects range to the right add new instantiated objects for example if there is 100 objects and I moved the Range slider to the right to 300 then add more 200 new objects.我希望,如果我在编辑模式或运行时模式下移动编辑器,则 numberOfObjects 范围向右添加新的实例化对象,例如,如果有 100 个对象,我将 Range slider 向右移动到 300,然后添加更多 200 个新对象对象。 And if I move the slider to the left for example there is 100 objects and I moved it to the left to 70 then remove 30 objects or if I first moved it to the right added 200 objects and now there are 300 and then moved it to the left to 221 the remove the need number of objects.如果我将 slider 向左移动,例如有 100 个对象,我将其向左移动到 70,然后删除 30 个对象,或者如果我首先将其移动到右侧添加 200 个对象,现在有 300 个,然后将其移动到左边为 221 删除需要的对象数。

Instead of using [Execute always] and Update you should rather do your stuff in OnValidate而不是使用[Execute always]Update你应该在OnValidate中做你的事情

This function is called when the script is loaded or a value is changed in the Inspector (Called in the editor only).这个 function 在加载脚本或在检查器中更改值时调用(仅在编辑器中调用)。

Then you need something to keep track of already created objects.然后你需要一些东西来跟踪已经创建的对象。 Since you make them all children of parent you can simply check its Transform.childCount由于您将它们全部设为parent的孩子,您可以简单地检查它的Transform.childCount

The number of children the parent Transform has.父 Transform 拥有的子代数。

So you could do eg所以你可以做例如

private void OnValidate()
{
    if(parent.transform.childCount > numberOfObjects)
    {
        if(Application.isPlaying)
        {
            // Since destroy is done delayed we have to use a fix loop
            for(var i = parent.transform.childCount; i > numberOfObjects; i--)
            {
                Destroy(parent.transform.GetChild(0).gameObject);
            }
        }
        else
        {
            // DestroyImmediate however is executed immediately so
            // here we can simply rely on the childCount directly
            while(parent.transform.childCount > numberOfObjects)
            {
                DestroyImmediate(parent.transform.GetChild(0).gameObject);
            }
        }
    }

    while(parent.transform.childCount < numberOfObjects)
    {
        //Generate random x,z,y position on the terrain
        var randX = UnityEngine.Random.Range(xTerrainPos, xTerrainPos + terrainWidth);
        var randZ = UnityEngine.Random.Range(zTerrainPos, zTerrainPos + terrainLength);
        var yVal = Terrain.activeTerrain.SampleHeight(new Vector3(randX, 0, randZ));

        //Apply Offset if needed
        yVal = yVal + yOffset;

        //Generate the Prefab on the generated position
        var objInstance = Instantiate(prefab, new Vector3(randX, yVal, randZ), Quaternion.identity);
        objInstance.name = "Waypoint";
        objInstance.tag = "Waypoint";
        objInstance.transform.parent = parent.transform;
    }
}

Half of a possible solution is already in your code.您的代码中已经有一半可能的解决方案。 You are using the ExecuteAlways attribute, and you are instantiating your objects with a for loop.您正在使用ExecuteAlways属性,并且正在使用 for 循环实例化您的对象。 The next step is to put the returned intance of your object in an array.下一步是将返回的 object 实例放入一个数组中。 That way, the reference to your gameObjects will not be lost forever when the current iteration of the for loop ends.这样,当 for 循环的当前迭代结束时,对您的 gameObjects 的引用不会永远丢失。

objects[i] = Instantiate(/*...*/);
objects[i].name = "Waypoint";
/*...*/

Once you have your GameObject[] objects array of gameObjects you can update it in the Update() method of your class: disable all objects with an index greater than your numberOfObjects , enable the rest.一旦你有了 GameObject GameObject[] objects数组,你可以在 class 的Update()方法中更新它:禁用索引大于numberOfObjects的所有对象,启用 rest。 Since Update() doesn't get called every frame when the game is not running but only when something in the scene changes, then you shouldn't have performance issues.由于Update()在游戏未运行时不会在每一帧都被调用,但只有在场景中的某些内容发生变化时才会调用,所以你不应该有性能问题。 But when you are in Play Mode then checking up to 1000 gameObjects every frame could take some time, so you want to keep that in mind.但是当您处于播放模式时,每帧检查多达 1000 个游戏对象可能需要一些时间,因此您要牢记这一点。 You could do like this:你可以这样做:

private void Update() {
    if (!Application.isPlaying) {
        //Update array
    }
}

PS. PS。 When asking the next answer, include in your post an attempted solution that shows that you put effort into solving your problem在询问下一个答案时,在您的帖子中包含一个尝试过的解决方案,表明您努力解决您的问题

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM