Everything about editor scripting in Unity with C# code

2. Add prefabs along a line

There comes a time in your life where you have to build a fence or place cones in long lines:

Fences and cones in Unity

Placing the fence pieces or cones one-by-one is a kinda boring process, so a better way is to make an Editor script to help you. The first script you need is called ObjectManagerLine and you need to attach it to an empty gameobject in the Editor. This script is kinda basic if you've been into Unity and it will just remove gameobjects and hold some parameters we need. You also need to add a prefab to this script which could be a simple sphere.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ObjectManagerLine : MonoBehaviour 
{
    //The object we want to add
    public GameObject prefabGO;

    //Whats the size of the prefab we want to add?
    //You can increase the size if you want to have a gap between the objects
    public float objectSize;

    //Where is the line ending? It starts at the position of the gameobject the script is attached to
    public Vector3 endOfLinePos;

    //Kill all children to this gameobject
    public void KillAllChildren()
    {
        //Get an array with all children to this transform
        GameObject[] allChildren = GetAllChildren();

        //Now destroy them
        foreach (GameObject child in allChildren)
        {
            DestroyImmediate(child);
        }
    }

    //Get an array with all children to this GO
    private GameObject[] GetAllChildren()
    {
        //This array will hold all children
        GameObject[] allChildren = new GameObject[transform.childCount];

        //Fill the array
        int childCount = 0;
        foreach (Transform child in transform)
        {
            allChildren[childCount] = child.gameObject;
            childCount += 1;
        }

        return allChildren;
    }
}

The next script you need to add is the Editor script that will improve the script above. In this script you will be able to move the start/end positions of the line - and if one of them has moved then the script will add prefabs along the line. It's really important that you place this Editor script in a folder called Editor. Remember that you can have multiple Editor folders to make it easier to organize your project.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;

[CustomEditor(typeof(ObjectManagerLine))]
public class ObjectManagerLineEditor : Editor
{
    private ObjectManagerLine objectManager;

    private void OnEnable()
    {
        //This is a reference to the script
        objectManager = target as ObjectManagerLine;

        //Hide the handles of the GO
        Tools.hidden = true;
    }

    private void OnDisable()
    {
        //Unhide the handles of the GO
        Tools.hidden = false;
    }

    private void OnSceneGUI()
    {
        //Move the line's start and end positions and add objects if we have moved one of the positions

        //End position
        objectManager.endOfLinePos = MovePoint(objectManager.endOfLinePos);

        //Start position
        objectManager.transform.position = MovePoint(objectManager.transform.position);
    }

    private Vector3 MovePoint(Vector3 pos)
    {    
        //Change position
        if (Tools.current == Tool.Move)
        {
            //Check if we have moved the point
            EditorGUI.BeginChangeCheck();

            //Get the new position and display the position with axis
            pos = Handles.PositionHandle(pos, Quaternion.identity);

            //If we have moved the point
            if (EditorGUI.EndChangeCheck())
            {
                MarkSceneAsDirty();

                UpdateObjects();
            }
        }

        return pos;
    }

    //Update the objects between the path
    private void UpdateObjects()
    {
        //First kill all current objects
        objectManager.KillAllChildren();

        //How many object fit between the points?

        //Make sure the size of the object is not zero because then we can fit infinite amount of objects
        if (objectManager.objectSize == 0f)
        {
            return;
        }

        //The distance between the points
        float distanceBetween = (objectManager.endOfLinePos - objectManager.transform.position).magnitude;

        //If we divide the distance between the points and the size of one object we know how many can fit between 
        int objects = Mathf.FloorToInt(distanceBetween / objectManager.objectSize);

        //The direction between the points
        Vector3 direction = (objectManager.endOfLinePos - objectManager.transform.position).normalized;

        //Where should we instantiate the first object
        Vector3 instantiatePos = objectManager.transform.position + direction * objectManager.objectSize * 0.5f;

        //Add the objects
        for (int i = 0; i < objects; i++)
        {
            GameObject newGO = PrefabUtility.InstantiatePrefab(objectManager.prefabGO) as GameObject;

            //Parent it so we can delete it by killing all children
            newGO.transform.parent = objectManager.transform;

            //Give it the position
            newGO.transform.position = instantiatePos;

            //Orient it by making it look at the position we are going to
            newGO.transform.forward = direction;

            //Move to the next object
            instantiatePos += direction * objectManager.objectSize;
        }
    }

    //Force unity to save changes or Unity may not save when we have instantiated/removed prefabs despite pressing save button
    private void MarkSceneAsDirty()
    {
        UnityEngine.SceneManagement.Scene activeScene = UnityEditor.SceneManagement.EditorSceneManager.GetActiveScene();

        UnityEditor.SceneManagement.EditorSceneManager.MarkSceneDirty(activeScene);
    }
}

Now select the gamobject to which you attached the script. If everything is working, you should be able to do this if you move the start/end position of the line:

Final objects along line gif