Sometimes we want to create "lots" of pickups, randomly in our scene. Rather than doing this by hand, it is possible to add a custom menu and item to the Unity editor, which, when selected, will execute a script. In this recipe, we create a menu item that calls a script to create 100 randomly positioned star pickup prefabs in the Scene.
This recipe assumes you are starting with the project Simple2Dgame_SpaceGirl
setup from the first recipe in this chapter.
To create an editor extension to add 100 randomly located copies of a prefab with one menu click, follow these steps:
Simple2Dgame_SpaceGirl
.Prefabs
. Inside this new folder, create a new empty prefab named prefab
_star
. Populate this prefab by dragging GameObject star
from the Hierarchy panel over prefab
_star
in the Project panel. The prefab should now turn blue and have a copy of all of GameObject star's properties and components.star
from the Hierarchy.Editor
. Inside this new folder, create a new C# script class named MyGreatGameEditor
, with the following code:using UnityEngine; using UnityEditor; using System.Collections; using System; public class MyGreatGameEditor : MonoBehaviour { const float X_MAX = 10f; const float Y_MAX = 10f; static GameObject starPrefab; [MenuItem("My-Great-Game/Make 100 stars")] static void PlacePrefabs(){ string assetPath = "Assets/Prefabs/prefab_star.prefab"; starPrefab = (GameObject)AssetDatabase.LoadMainAssetAtPath(assetPath); int total = 100; for(int i = 0; i < total; i++){ CreateRandomInstance(); } } static void CreateRandomInstance(){ float x = UnityEngine.Random.Range(-X_MAX, X_MAX); float y = UnityEngine.Random.Range(-Y_MAX, Y_MAX); float z = 0; Vector3 randomPosition = new Vector3(x,y,z); Instantiate(starPrefab, randomPosition, Quaternion.identity); } }
The core aim of this recipe is to add a new menu, containing a single menu item that will execute the action we desire. C# attribute [MenuItem("<menuName>/<menuItemName>")]
declares the menu name and the menu item name, and Unity will execute the static method that follows in the code listing, each time the menu item is selected by the user.
In this recipe, the [MenuItem("My-Great-Game/Make 100 stars")]
statement declares the menu name as My-Great-Game
and the menu item as Make 100 stars
. The method immediately following this attribute is the PlacePrefabs()
method. When this method is executed, it makes the starPrefab
variable become a reference to the prefab found via the Assets/Prefabs/prefab_star.prefab
path. Then, a for
loop is executed 100 times, each time calling the CreateRandomInstance()
method.
The CreateRandomInstance()
method creates a Vector3 randomPosition
variable, making use of X_MAX
and Y_MAX
constants. The Instantiate(...)
built-in method is then used to create a new GameObject in the scene, making a clone of the prefab and locating it at the position defined by randomPosition
.
Some details you don't want to miss:
Rather than having hundreds of new object clones fill up our Hierarchy panel, a good way to keep things tidy is to have an empty "parent" GameObject and child a collection of related GameObjects to it. Let's have a GameObject in the Hierarchy named Star-container and child all the new stars to this object.
We need a variable that will be a reference to our container object, starContainerGO
. We also need a new method, CreateStarContainerGO()
, which will find a reference to GameObject star-container, if such an object already exists it is deleted, and then the method will create a new empty GameObject and give it this name. Add the following variable and method to our script class:
static GameObject starContainerGO; static void CreateStarContainerGO() { string containerName = "Star-container"; starContainerGO = GameObject.Find(containerName); if (null != starContainerGO) DestroyImmediate(starContainerGO); starContainerGO = new GameObject(containerName); }
Before we create the prefab clones, we need to first ensure we have created our star container GameObject. So we need to call our new method as the first thing we do when the PlacePrefabs()
method is executed, so add a statement to call this method at the beginning of the PlacePrefabs()
method:
static void PlacePrefabs(){ CreateStarContainerGO(); // rest of method as before ... }
Now we need to modify the CreateRandomInstance()
method so that it gets a reference to the new GameObject it has just created and can then child this new object to our star-container GameObject variable starContainerGO
. Modify the CreateRandomInstance()
method so that it looks as follows:
static void CreateRandomInstance() { float x = UnityEngine.Random.Range(-X_MAX, X_MAX); float y = UnityEngine.Random.Range(-Y_MAX, Y_MAX); float z = 0; Vector3 randomPosition = new Vector3(x,y,z); GameObject newStarGO = (GameObject)Instantiate(starPrefab, randomPosition, Quaternion.identity); newStarGO.transform.parent = starContainerGO.transform; }
18.119.106.135