Search Unity

[Released] Created a free prefab brush

Discussion in 'Assets and Asset Store' started by MCrafterzz, Nov 5, 2017.

  1. MCrafterzz

    MCrafterzz

    Joined:
    Jun 3, 2017
    Posts:
    283
    I didn't want to buy one for my game so I created my own and decided to share it. It isn't the most pretty editor but it works well and has a lot of options. You can use it however you want as long as you don't reuppload it to for example the asset store. I hope you enjoy!

    Paint by hovering over the position you want to paint on and press P. You can only paint on objects with colliders.

    Features:
    - Place a random prefab from a list
    - Place multiple prefabs at the same time
    - Random scale (same for all axis or chosen specificly for each)
    - Random rotation or align rotation to the ground's normals
    - Check if position is empty or if an object already has been placed there
    - Offset object to place objects sunken into the ground
    - Toggle painting on and off

    Note: File must be named PrefabBrush for it to work
    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEditor;
    3. using System.Collections;
    4. using System.Collections.Generic;
    5. [System.Serializable]
    6. class PrefabBrush : EditorWindow {
    7.     List<GameObject> prefabs = new List<GameObject>() {null};
    8.     Transform parent = null;
    9.     int selectedToolbar = 0;
    10.     bool alignNormals = false;
    11.     float scaleMin = 1, scaleMax = 1, scaleXMin = 1, scaleXMax = 1, scaleYMin = 1, scaleYMax = 1, scaleZMin = 1, scaleZMax = 1;
    12.     bool rotationX = false, rotationY = true, rotationZ = false;
    13.     bool painting = false;
    14.     bool selectObject = false;
    15.     int amount = 1;
    16.     float minRange = 1, maxRange = 1.5f;
    17.     bool checkOccipied = true;
    18.     List<GameObject> ignoreObjects = new List<GameObject>() {null};
    19.     Vector2 ignoreObjectsScrollPosition, prefabsScrollPosition;
    20.     float offsetX, offsetY, offsetZ;
    21.  
    22.     public enum ScaleType {Individual, Uniform};
    23.     public ScaleType scaleType = ScaleType.Uniform;
    24.  
    25.     [MenuItem ("Window/Prefab Brush")]
    26.     public static void ShowWindow () {
    27.         EditorWindow.GetWindow (typeof(PrefabBrush));
    28.     }
    29.  
    30.     void OnEnable() {
    31.         SceneView.onSceneGUIDelegate += OnSceneGUI;
    32.     }
    33.  
    34.     void OnDisable() {
    35.         SceneView.onSceneGUIDelegate -= OnSceneGUI;
    36.     }
    37.  
    38.     void OnGUI () {
    39.         EditorGUILayout.LabelField ("Prefabs");
    40.         prefabsScrollPosition = GUILayout.BeginScrollView (prefabsScrollPosition, false, true, GUILayout.MinHeight(10), GUILayout.MaxHeight (100), GUILayout.ExpandHeight(true));
    41.         for (int i = 0; i < prefabs.Count; i++) {
    42.             prefabs[i] = EditorGUILayout.ObjectField (prefabs[i], typeof(GameObject), false) as GameObject;
    43.         }
    44.         GUILayout.EndScrollView ();
    45.         if (GUILayout.Button ("Add Item")) {
    46.             prefabs.Add (null);
    47.         }
    48.  
    49.         if (GUILayout.Button ("Remove Item")) {
    50.             if (prefabs.Count > 1) {
    51.                 prefabs.RemoveAt (prefabs.Count - 1);
    52.             }
    53.         }
    54.  
    55.         parent = EditorGUILayout.ObjectField ("Parent", parent, typeof(Transform), true) as Transform;
    56.  
    57.         selectedToolbar = GUILayout.Toolbar (selectedToolbar, new string[] {"Options", "Transformations"});
    58.  
    59.         if (selectedToolbar == 0) {
    60.             EditorGUILayout.Space ();
    61.             EditorGUILayout.LabelField ("Multi", EditorStyles.boldLabel);
    62.             amount = EditorGUILayout.IntField ("Amount", amount);
    63.             amount = Mathf.Clamp (amount, 1, int.MaxValue);
    64.  
    65.             if (amount > 1) {
    66.                 minRange = EditorGUILayout.FloatField ("Min Range", minRange);
    67.                 maxRange = EditorGUILayout.FloatField ("Max Range", maxRange);
    68.             }
    69.  
    70.             EditorGUILayout.Space ();
    71.             EditorGUILayout.LabelField ("Collision", EditorStyles.boldLabel);
    72.             checkOccipied = EditorGUILayout.Toggle ("Check Occipied", checkOccipied);
    73.  
    74.             if (checkOccipied == true) {
    75.                 EditorGUILayout.LabelField ("Ignore Objects:");
    76.                 ignoreObjectsScrollPosition = GUILayout.BeginScrollView (ignoreObjectsScrollPosition, false, true, GUILayout.MaxHeight (100));
    77.  
    78.                 for (int i = 0; i < ignoreObjects.Count; i++) {
    79.                     ignoreObjects [i] = EditorGUILayout.ObjectField (ignoreObjects [i], typeof(GameObject), true) as GameObject;
    80.                 }
    81.  
    82.                 GUILayout.EndScrollView ();
    83.                 if (GUILayout.Button ("Add Item")) {
    84.                     ignoreObjects.Add (null);
    85.                 }
    86.  
    87.                 if (GUILayout.Button ("Remove Item")) {
    88.                     if (ignoreObjects.Count > 1) {
    89.                         ignoreObjects.RemoveAt (ignoreObjects.Count - 1);
    90.                     }
    91.                 }
    92.             }
    93.  
    94.             EditorGUILayout.Space ();
    95.             selectObject = EditorGUILayout.Toggle ("Select Object", selectObject);
    96.  
    97.             if (!painting) {
    98.                 if (GUILayout.Button ("Start Painting")) {
    99.                     painting = true;
    100.                 }
    101.             } else {
    102.                 if (GUILayout.Button ("Stop Painting")) {
    103.                     painting = false;
    104.                 }
    105.             }
    106.         } else {
    107.             EditorGUILayout.Space ();
    108.             EditorGUILayout.LabelField ("Scale", EditorStyles.boldLabel);
    109.  
    110.             scaleType = (ScaleType)EditorGUILayout.EnumPopup ("Scale Type", scaleType);
    111.  
    112.             if (scaleType == ScaleType.Uniform) {
    113.                 scaleMin = EditorGUILayout.FloatField ("Min Scale", scaleMin);
    114.                 scaleMax = EditorGUILayout.FloatField ("Max Scale", scaleMax);
    115.  
    116.                 if (GUILayout.Button ("Reset Scale")) {
    117.                     scaleMin = 1;
    118.                     scaleMax = 1;
    119.                 }
    120.             } else {
    121.                 scaleXMin = EditorGUILayout.FloatField ("Min X Scale", scaleXMin);
    122.                 scaleXMax = EditorGUILayout.FloatField ("Max X Scale", scaleXMax);
    123.                 scaleYMin = EditorGUILayout.FloatField ("Min Y Scale", scaleYMin);
    124.                 scaleYMax = EditorGUILayout.FloatField ("Max Y Scale", scaleYMax);
    125.                 scaleZMin = EditorGUILayout.FloatField ("Min Z Scale", scaleZMin);
    126.                 scaleZMax = EditorGUILayout.FloatField ("Max Z Scale", scaleZMax);
    127.  
    128.                 if (GUILayout.Button ("Reset X Scale")) {
    129.                     scaleXMin = 1;
    130.                     scaleXMax = 1;
    131.                 }
    132.  
    133.                 if (GUILayout.Button ("Reset Y Scale")) {
    134.                     scaleYMin = 1;
    135.                     scaleYMax = 1;
    136.                 }
    137.  
    138.                 if (GUILayout.Button ("Reset Z Scale")) {
    139.                     scaleZMin = 1;
    140.                     scaleZMax = 1;
    141.                 }
    142.             }
    143.  
    144.             EditorGUILayout.Space ();
    145.             EditorGUILayout.LabelField ("Rotation", EditorStyles.boldLabel);
    146.             alignNormals = EditorGUILayout.Toggle ("Align Normals", alignNormals);
    147.  
    148.             if (alignNormals == false) {
    149.                 rotationX = EditorGUILayout.Toggle ("Random Rotation X", rotationX);
    150.                 rotationY = EditorGUILayout.Toggle ("Random Rotation Y", rotationY);
    151.                 rotationZ = EditorGUILayout.Toggle ("Random Rotation Z", rotationZ);
    152.             }
    153.  
    154.             EditorGUILayout.Space ();
    155.             EditorGUILayout.LabelField ("Offset", EditorStyles.boldLabel);
    156.  
    157.             offsetX = EditorGUILayout.FloatField ("Offset X", offsetX);
    158.             offsetY = EditorGUILayout.FloatField ("Offset Y", offsetY);
    159.             offsetZ = EditorGUILayout.FloatField ("Offset Z", offsetZ);
    160.         }
    161.     }
    162.        
    163.     void OnSceneGUI(SceneView sv) {
    164.         Event currentEvent = Event.current;
    165.         if (painting && currentEvent.type == EventType.KeyDown && currentEvent.keyCode == KeyCode.P) {
    166.             Ray ray = Camera.current.ScreenPointToRay (new Vector3 (currentEvent.mousePosition.x, -currentEvent.mousePosition.y + Camera.current.pixelHeight));
    167.             RaycastHit raycastHit;
    168.             Vector3 originalPosition = Vector3.zero;
    169.  
    170.             for (int i = 0; i < amount; i++) {
    171.                 int tries = 0;
    172.  
    173.                 while (tries < 10) {
    174.                     tries += 1;
    175.                     if (i > 0) {
    176.                         ray = new Ray (originalPosition + randomCircle (minRange, maxRange, 100), Vector3.down);
    177.                     }
    178.  
    179.                     if (Physics.Raycast (ray, out raycastHit)) {
    180.                         bool canContinue = true;
    181.  
    182.                         if (checkOccipied == true) {
    183.                             for (int j = 0; j < ignoreObjects.Count; j++) {
    184.                                 if (ignoreObjects[j].Equals(raycastHit.transform.gameObject)) {
    185.                                     canContinue = false;
    186.                                 }
    187.                             }
    188.                         }
    189.  
    190.  
    191.                         if (canContinue == true) {
    192.                             GameObject prefab = prefabs[Random.Range(0, prefabs.Count)];
    193.                             if (prefab != null) {
    194.                                 var o = PrefabUtility.InstantiatePrefab (prefab) as GameObject;
    195.                                 o.transform.SetParent (parent);
    196.                                 o.transform.position = raycastHit.point;
    197.                                 if (i == 0) {
    198.                                     originalPosition = raycastHit.point;
    199.                                 }
    200.  
    201.                                 if (alignNormals == true) {
    202.                                     o.transform.rotation = Quaternion.FromToRotation (Vector3.up, raycastHit.normal) * Quaternion.identity;
    203.                                 } else {
    204.                                     int x = 0, y = 0, z = 0;
    205.                                     if (rotationX == true) {
    206.                                         x = Random.Range (0, 360);
    207.                                     }
    208.  
    209.                                     if (rotationY == true) {
    210.                                         y = Random.Range (0, 360);
    211.                                     }
    212.  
    213.                                     if (rotationZ == true) {
    214.                                         z = Random.Range (0, 360);
    215.                                     }
    216.  
    217.                                     o.transform.Rotate (x, y, z);
    218.                                 }
    219.  
    220.                                 if (scaleType == ScaleType.Uniform) {
    221.                                     float scale = Random.Range (scaleMin, scaleMax);
    222.                                     o.transform.localScale = new Vector3 (scale, scale, scale);
    223.                                 } else {
    224.                                     o.transform.localScale = new Vector3 (Random.Range (scaleXMin, scaleXMax), Random.Range (scaleYMin, scaleYMax), Random.Range (scaleZMin, scaleZMax));
    225.                                 }
    226.  
    227.                                 if (selectObject) {
    228.                                     GameObject[] go = { o };
    229.                                     Selection.objects = go;
    230.                                 }
    231.                
    232.                                 Undo.RegisterCreatedObjectUndo (o, "Paint Prefab " + o.name);
    233.                                 tries = 0;
    234.                                 break;
    235.                             }
    236.                         }
    237.                     }
    238.                 }
    239.             }
    240.         }
    241.     }
    242.  
    243.     public Vector3 randomCircle(float minRange, float maxRange, float y) {
    244.         Vector3 position;
    245.         float angle = Random.value * 360;
    246.         position.x = Random.Range (minRange, maxRange) * Mathf.Sin (angle * Mathf.Deg2Rad);
    247.         position.y = y;
    248.         position.z = Random.Range (minRange, maxRange) * Mathf.Cos (angle * Mathf.Deg2Rad);
    249.         return position;
    250.     }
    251. }
     
    Last edited: Nov 5, 2017
    Mike891, blockhead and getexis like this.
  2. blockhead

    blockhead

    Joined:
    Mar 23, 2013
    Posts:
    1
    This is great! So helpful to me. I had to edit it a bit to work with 2D and for my needs but thank you so much for posting this! I was having trouble finding many resources for creating such a tool.

    Thanks again!
     
    MCrafterzz likes this.
  3. Mike891

    Mike891

    Joined:
    May 18, 2019
    Posts:
    2
    Thanks for your efforts
     
    MCrafterzz likes this.