├── LICENSE.txt.meta ├── package.json.meta ├── Plugins.meta ├── Plugins ├── SimpleGridFramework │ ├── README.txt.meta │ ├── Editor │ │ ├── SimpleGridFramework.Editor.asmdef.meta │ │ ├── GridEditor.cs.meta │ │ ├── GridEditorSettings.cs.meta │ │ ├── SimpleGridFramework.Editor.asmdef │ │ ├── GridEditorSettings.cs │ │ └── GridEditor.cs │ ├── Editor.meta │ └── README.txt └── SimpleGridFramework.meta ├── package.json ├── LICENSE.txt └── .github └── README.md /LICENSE.txt.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5fdcce1ac902f544fa75e59246a1ff24 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /package.json.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 015035cf29be5d74385f6ae3e016dc5c 3 | PackageManifestImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Plugins.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 922e6abf6dd10d1419db12d929196a82 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Plugins/SimpleGridFramework/README.txt.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 63e757fbe7dfac14cb55059ae4c9a3f7 3 | timeCreated: 1563308858 4 | licenseType: Free 5 | TextScriptImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Plugins/SimpleGridFramework/Editor/SimpleGridFramework.Editor.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 678f9b5a86d90b047bf68367c21af88d 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Plugins/SimpleGridFramework.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8a7559606a1e4ee41810e6738feaacef 3 | folderAsset: yes 4 | timeCreated: 1524389789 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Plugins/SimpleGridFramework/Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 986e220517237cf4f8387776ca196d6c 3 | folderAsset: yes 4 | timeCreated: 1524389811 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Plugins/SimpleGridFramework/Editor/GridEditor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: eb6cec1df0905244baa3f251c70294a6 3 | timeCreated: 1524389816 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Plugins/SimpleGridFramework/Editor/GridEditorSettings.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f6daa397bf2b68b4c8dbb7fafc1f3c69 3 | timeCreated: 1524389848 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Plugins/SimpleGridFramework/Editor/SimpleGridFramework.Editor.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "SimpleGridFramework.Editor", 3 | "references": [], 4 | "includePlatforms": [ 5 | "Editor" 6 | ], 7 | "excludePlatforms": [], 8 | "allowUnsafeCode": false, 9 | "overrideReferences": false, 10 | "precompiledReferences": [], 11 | "autoReferenced": true, 12 | "defineConstraints": [], 13 | "versionDefines": [], 14 | "noEngineReferences": false 15 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "com.yasirkula.gridframework", 3 | "displayName": "Simple Grid Framework", 4 | "version": "1.1.0", 5 | "documentationUrl": "https://github.com/yasirkula/UnityGridFramework", 6 | "changelogUrl": "https://github.com/yasirkula/UnityGridFramework/releases", 7 | "licensesUrl": "https://github.com/yasirkula/UnityGridFramework/blob/master/LICENSE.txt", 8 | "description": "This plugin helps you place prefabs on a customizable grid easily." 9 | } 10 | -------------------------------------------------------------------------------- /Plugins/SimpleGridFramework/README.txt: -------------------------------------------------------------------------------- 1 | = Simple Grid Framework = 2 | 3 | Online documentation available at: https://github.com/yasirkula/UnityGridFramework 4 | E-mail: yasirkula@gmail.com 5 | 6 | 1. ABOUT 7 | This plugin helps you place prefabs on a customizable grid easily. 8 | 9 | 2. HOW TO 10 | - open Window/Grid Editor 11 | - select a prefab from Project view (or a prefab instance from Hierarchy view) 12 | - hover mouse cursor over Scene view and left click to place the prefab 13 | - drag the mouse to place multiple instances at once 14 | 15 | 3. HINTS 16 | - use Q and E keys to rotate the selected prefab around its Y-axis easily (Scene View should have the focus) 17 | - use CTRL+Q and CTRL+E keys to switch between prefab states easily (Scene View should have the focus) 18 | - settings for the framework will be stored at Plugins/SimpleGridFramework/Settings.asset -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Süleyman Yasir KULA 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /.github/README.md: -------------------------------------------------------------------------------- 1 | # Unity Simple Grid Framework 2 | 3 | ![screenshot](https://yasirkula.files.wordpress.com/2017/02/grideditor.png) 4 | 5 | This plugin helps you place prefabs on a customizable grid easily. 6 | 7 | ## FEATURES 8 | 9 | - Simple user-interface 10 | - Easy-to-use 11 | - Undo-redo support 12 | - Ability to set different grid states and per-prefab prefab states 13 | - Works in XZ, XY and YZ space 14 | 15 | ## INSTALLATION 16 | 17 | There are 4 ways to install this plugin: 18 | 19 | - import [GridFramework.unitypackage](https://github.com/yasirkula/UnityGridFramework/releases) via *Assets-Import Package* 20 | - clone/[download](https://github.com/yasirkula/UnityGridFramework/archive/master.zip) this repository and move the *Plugins* folder to your Unity project's *Assets* folder 21 | - *(via Package Manager)* add the following line to *Packages/manifest.json*: 22 | - `"com.yasirkula.gridframework": "https://github.com/yasirkula/UnityGridFramework.git",` 23 | - *(via [OpenUPM](https://openupm.com))* after installing [openupm-cli](https://github.com/openupm/openupm-cli), run the following command: 24 | - `openupm add com.yasirkula.gridframework` 25 | 26 | ## HOW TO 27 | 28 | - Open **Window/Grid Editor** 29 | - Select a prefab from Project view (or a prefab instance from Hierarchy view) 30 | - Hover mouse cursor over Scene view and left click to place the prefab 31 | - Drag the mouse to place multiple instances at once 32 | 33 | ## HINTS 34 | 35 | - Use *Q* and *E* keys to rotate the selected prefab around its *Y-axis* easily (Scene View should have the focus) 36 | - Use *CTRL+Q* and *CTRL+E* keys to switch between prefab states easily (Scene View should have the focus) 37 | - Settings for the framework will be stored at *Plugins/SimpleGridFramework/Settings.asset* 38 | -------------------------------------------------------------------------------- /Plugins/SimpleGridFramework/Editor/GridEditorSettings.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using UnityEditor; 3 | using System.Collections.Generic; 4 | using UnityEngine.Serialization; 5 | 6 | namespace SimpleGridFramework 7 | { 8 | #region Helper Classes 9 | [System.Serializable] 10 | public class PrefabStateHolder 11 | { 12 | public GameObject prefab; 13 | public List states = new List(); 14 | 15 | public PrefabStateHolder( GameObject prefab ) 16 | { 17 | this.prefab = prefab; 18 | } 19 | } 20 | 21 | [System.Serializable] 22 | public class PrefabState 23 | { 24 | public string name; 25 | 26 | public Vector3 rotation = Vector3.zero; 27 | public Vector3 shift = Vector3.zero; 28 | 29 | public PrefabState( string name ) 30 | { 31 | this.name = name; 32 | } 33 | 34 | public PrefabState( string name, Vector3 rotation, Vector3 shift ) 35 | { 36 | this.name = name; 37 | this.rotation = rotation; 38 | this.shift = shift; 39 | } 40 | 41 | public PrefabState( string name, PrefabState copyFrom ) 42 | { 43 | this.name = name; 44 | this.rotation = copyFrom.rotation; 45 | this.shift = copyFrom.shift; 46 | } 47 | 48 | public void Draw( GridEditorSettings settings, bool isDefaultState ) 49 | { 50 | EditorGUI.BeginChangeCheck(); 51 | string _name = EditorGUILayout.TextField( "Name", name ); 52 | if( EditorGUI.EndChangeCheck() ) 53 | { 54 | Undo.RecordObject( settings, "Change Prefab State Name" ); 55 | if( !isDefaultState ) 56 | name = _name; 57 | else 58 | settings.CreatePrefabStateForSelection( new PrefabState( _name, rotation, shift ) ); 59 | 60 | settings.UpdatePrefabStatesPopupList(); 61 | } 62 | 63 | EditorGUI.BeginChangeCheck(); 64 | Vector3 _rotation = EditorGUILayout.Vector3Field( "Rotation", rotation ); 65 | if( EditorGUI.EndChangeCheck() ) 66 | { 67 | Undo.RecordObject( settings, "Change Prefab Rotation" ); 68 | if( !isDefaultState ) 69 | rotation = _rotation; 70 | else 71 | settings.CreatePrefabStateForSelection( new PrefabState( name, _rotation, shift ) ); 72 | } 73 | 74 | EditorGUI.BeginChangeCheck(); 75 | Vector3 _shift = EditorGUILayout.Vector3Field( "Shift", shift ); 76 | if( EditorGUI.EndChangeCheck() ) 77 | { 78 | Undo.RecordObject( settings, "Change Prefab Shift" ); 79 | if( !isDefaultState ) 80 | shift = _shift; 81 | else 82 | settings.CreatePrefabStateForSelection( new PrefabState( name, rotation, _shift ) ); 83 | } 84 | } 85 | } 86 | 87 | [System.Serializable] 88 | public class GridState 89 | { 90 | public string name; 91 | 92 | // Color of the grids drawn on the Scene view 93 | public Color gridlineColor = new Color( 0.8f, 0.8f, 0.8f, 1f ); 94 | 95 | // Size of the grids (a grid is a square) 96 | public float gridSize = 1f; 97 | 98 | // Number of grids 99 | public int gridlineCount = 50; 100 | 101 | // Alignment plane of the grids 102 | public GridEditor.GridAlignment gridAlignment = GridEditor.GridAlignment.XZ; 103 | 104 | // Position of the grids 105 | [FormerlySerializedAs( "gridYPos" )] 106 | public float gridPos = 0f; 107 | 108 | // How many units to shift the grids 109 | [FormerlySerializedAs( "gridShiftX" )] 110 | public float gridShiftAxis1 = 0f; 111 | [FormerlySerializedAs( "gridShiftZ" )] 112 | public float gridShiftAxis2 = 0f; 113 | 114 | public GridState( string name ) 115 | { 116 | this.name = name; 117 | } 118 | 119 | public GridState( string name, GridState copyFrom ) 120 | { 121 | this.name = name; 122 | this.gridlineColor = copyFrom.gridlineColor; 123 | this.gridSize = copyFrom.gridSize; 124 | this.gridlineCount = copyFrom.gridlineCount; 125 | this.gridAlignment = copyFrom.gridAlignment; 126 | this.gridPos = copyFrom.gridPos; 127 | this.gridShiftAxis1 = copyFrom.gridShiftAxis1; 128 | this.gridShiftAxis2 = copyFrom.gridShiftAxis2; 129 | } 130 | 131 | public void Draw( GridEditorSettings settings ) 132 | { 133 | EditorGUI.BeginChangeCheck(); 134 | string _name = EditorGUILayout.TextField( "Name", name ); 135 | if( EditorGUI.EndChangeCheck() ) 136 | { 137 | Undo.RecordObject( settings, "Change State Name" ); 138 | name = _name; 139 | 140 | settings.UpdateStatesPopupList(); 141 | } 142 | 143 | EditorGUI.BeginChangeCheck(); 144 | Color _gridlineColor = EditorGUILayout.ColorField( "Gridline Color", gridlineColor ); 145 | if( EditorGUI.EndChangeCheck() ) 146 | { 147 | Undo.RecordObject( settings, "Change Gridline Color" ); 148 | gridlineColor = _gridlineColor; 149 | } 150 | 151 | EditorGUI.BeginChangeCheck(); 152 | float _gridSize = EditorGUILayout.FloatField( "Grid Size", gridSize ); 153 | if( EditorGUI.EndChangeCheck() ) 154 | { 155 | Undo.RecordObject( settings, "Change Grid Size" ); 156 | gridSize = _gridSize; 157 | } 158 | 159 | EditorGUI.BeginChangeCheck(); 160 | int _gridlineCount = EditorGUILayout.IntField( "Gridline Count", gridlineCount ); 161 | if( EditorGUI.EndChangeCheck() ) 162 | { 163 | Undo.RecordObject( settings, "Change Gridline Count" ); 164 | gridlineCount = _gridlineCount; 165 | } 166 | 167 | EditorGUI.BeginChangeCheck(); 168 | GridEditor.GridAlignment _gridAlignment = (GridEditor.GridAlignment) EditorGUILayout.EnumPopup( "Grid Alignment", gridAlignment ); 169 | if( EditorGUI.EndChangeCheck() ) 170 | { 171 | Undo.RecordObject( settings, "Change Grid Alignment" ); 172 | gridAlignment = _gridAlignment; 173 | } 174 | 175 | string posLabel, shiftXLabel, shiftZLabel; 176 | if( gridAlignment == GridEditor.GridAlignment.XZ ) 177 | { 178 | posLabel = "Grid Y Pos"; 179 | shiftXLabel = "Grid Shift X"; 180 | shiftZLabel = "Grid Shift Z"; 181 | } 182 | else if( gridAlignment == GridEditor.GridAlignment.XY ) 183 | { 184 | posLabel = "Grid Z Pos"; 185 | shiftXLabel = "Grid Shift X"; 186 | shiftZLabel = "Grid Shift Y"; 187 | } 188 | else 189 | { 190 | posLabel = "Grid X Pos"; 191 | shiftXLabel = "Grid Shift Y"; 192 | shiftZLabel = "Grid Shift Z"; 193 | } 194 | 195 | EditorGUI.BeginChangeCheck(); 196 | float _gridPos = EditorGUILayout.FloatField( posLabel, gridPos ); 197 | if( EditorGUI.EndChangeCheck() ) 198 | { 199 | Undo.RecordObject( settings, "Change Grid Pos" ); 200 | gridPos = _gridPos; 201 | } 202 | 203 | EditorGUI.BeginChangeCheck(); 204 | float _gridShiftAxis1 = EditorGUILayout.FloatField( shiftXLabel, gridShiftAxis1 ); 205 | if( EditorGUI.EndChangeCheck() ) 206 | { 207 | Undo.RecordObject( settings, "Change Grid Shift Axis 1" ); 208 | gridShiftAxis1 = _gridShiftAxis1; 209 | } 210 | 211 | EditorGUI.BeginChangeCheck(); 212 | float _gridShiftAxis2 = EditorGUILayout.FloatField( shiftZLabel, gridShiftAxis2 ); 213 | if( EditorGUI.EndChangeCheck() ) 214 | { 215 | Undo.RecordObject( settings, "Change Grid Shift Axis 2" ); 216 | gridShiftAxis2 = _gridShiftAxis2; 217 | } 218 | } 219 | } 220 | #endregion 221 | 222 | public class GridEditorSettings : ScriptableObject 223 | { 224 | public const string SAVE_PATH = "Assets/Plugins/SimpleGridFramework/Settings.asset"; 225 | 226 | public List states = new List(); 227 | public List prefabStates = new List(); 228 | 229 | [HideInInspector] 230 | public int currentState; 231 | [HideInInspector] 232 | public int currentPrefabState; 233 | 234 | private string[] statesPopup; 235 | private string[] prefabStatesPopup; 236 | 237 | private GameObject selectedPrefab; 238 | private List selectedPrefabStates; 239 | private PrefabState defaultPrefabState; 240 | 241 | private bool showGridSettings = false; 242 | private bool showPrefabSettings = true; 243 | 244 | public GridState GridState 245 | { 246 | get 247 | { 248 | if( currentState >= states.Count ) 249 | currentState = Mathf.Max( 0, states.Count - 1 ); 250 | 251 | return states[currentState]; 252 | } 253 | } 254 | 255 | public GameObject Prefab { get { return selectedPrefab; } } 256 | public PrefabState PrefabState 257 | { 258 | get 259 | { 260 | if( selectedPrefabStates == null ) 261 | { 262 | if( defaultPrefabState == null ) 263 | defaultPrefabState = new PrefabState( "default" ); 264 | 265 | return defaultPrefabState; 266 | } 267 | 268 | if( currentPrefabState >= selectedPrefabStates.Count ) 269 | currentPrefabState = Mathf.Max( 0, selectedPrefabStates.Count - 1 ); 270 | 271 | return selectedPrefabStates[currentPrefabState]; 272 | } 273 | } 274 | 275 | private void OnEnable() 276 | { 277 | if( states.Count == 0 ) 278 | CreateState(); 279 | } 280 | 281 | private void Reset() 282 | { 283 | if( states.Count == 0 ) 284 | CreateState(); 285 | } 286 | 287 | private void CreateState( GridState referenceState = null ) 288 | { 289 | int index = 1; 290 | string name = "State " + index; 291 | for( int i = 0; i < states.Count; i++ ) 292 | { 293 | if( states[i].name == name ) 294 | { 295 | index++; 296 | name = "State " + index; 297 | i = -1; 298 | } 299 | } 300 | 301 | states.Add( referenceState != null ? new GridState( name, referenceState ) : new GridState( name ) ); 302 | } 303 | 304 | public void UpdateStatesPopupList() 305 | { 306 | statesPopup = new string[states.Count]; 307 | for( int i = 0; i < states.Count; i++ ) 308 | statesPopup[i] = ( i + 1 ) + ". " + states[i].name; 309 | } 310 | 311 | public void UpdatePrefabStatesPopupList() 312 | { 313 | if( selectedPrefabStates == null ) 314 | prefabStatesPopup = new string[] { "1. default" }; 315 | else 316 | { 317 | prefabStatesPopup = new string[selectedPrefabStates.Count]; 318 | for( int i = 0; i < selectedPrefabStates.Count; i++ ) 319 | prefabStatesPopup[i] = ( i + 1 ) + ". " + selectedPrefabStates[i].name; 320 | } 321 | } 322 | 323 | public void OnSelectionChanged() 324 | { 325 | GameObject selectedObject = Selection.activeGameObject; 326 | #if UNITY_2018_3_OR_NEWER 327 | if( selectedObject != null && PrefabUtility.IsPartOfAnyPrefab( selectedObject ) ) 328 | { 329 | selectedPrefab = PrefabUtility.GetCorrespondingObjectFromSource( selectedObject ); 330 | #else 331 | if( selectedObject != null && PrefabUtility.GetPrefabObject( selectedObject ) != null ) 332 | { 333 | selectedPrefab = (GameObject) PrefabUtility.GetPrefabParent( selectedObject ); 334 | #endif 335 | if( selectedPrefab == null ) 336 | selectedPrefab = selectedObject; 337 | 338 | for( int i = 0; i < prefabStates.Count; i++ ) 339 | { 340 | if( prefabStates[i].prefab == selectedPrefab ) 341 | { 342 | selectedPrefabStates = prefabStates[i].states; 343 | 344 | UpdateStatesPopupList(); 345 | UpdatePrefabStatesPopupList(); 346 | 347 | return; 348 | } 349 | } 350 | 351 | selectedPrefabStates = null; 352 | } 353 | else 354 | { 355 | selectedPrefab = null; 356 | selectedPrefabStates = null; 357 | } 358 | 359 | UpdateStatesPopupList(); 360 | UpdatePrefabStatesPopupList(); 361 | } 362 | 363 | public void CreatePrefabStateForSelection( PrefabState state, bool forceNewState = false ) 364 | { 365 | if( !selectedPrefab ) 366 | return; 367 | 368 | for( int i = 0; i < prefabStates.Count; i++ ) 369 | { 370 | if( prefabStates[i].prefab == selectedPrefab ) 371 | { 372 | prefabStates[i].states.Add( state ); 373 | return; 374 | } 375 | } 376 | 377 | PrefabStateHolder stateHolder = new PrefabStateHolder( selectedPrefab ); 378 | if( forceNewState ) 379 | stateHolder.states.Add( new PrefabState( "default" ) ); 380 | 381 | stateHolder.states.Add( state ); 382 | prefabStates.Add( stateHolder ); 383 | 384 | selectedPrefabStates = stateHolder.states; 385 | } 386 | 387 | public void RotateSelectedPrefab( float yDegrees ) 388 | { 389 | if( !selectedPrefab ) 390 | return; 391 | 392 | Undo.IncrementCurrentGroup(); 393 | Undo.RecordObject( this, "Rotate Prefab" ); 394 | if( selectedPrefabStates == null ) 395 | { 396 | CreatePrefabStateForSelection( new PrefabState( "default" ) ); 397 | currentPrefabState = 0; 398 | } 399 | 400 | Vector3 rotation = selectedPrefabStates[currentPrefabState].rotation; 401 | rotation.y += yDegrees; 402 | 403 | while( rotation.y >= 360f ) 404 | rotation.y -= 360f; 405 | while( rotation.y < 0f ) 406 | rotation.y += 360f; 407 | 408 | selectedPrefabStates[currentPrefabState].rotation = rotation; 409 | } 410 | 411 | public void PreviousPrefabState() 412 | { 413 | if( selectedPrefabStates == null || selectedPrefabStates.Count <= 1 ) 414 | return; 415 | 416 | Undo.IncrementCurrentGroup(); 417 | Undo.RecordObject( this, "Change Prefab State" ); 418 | currentPrefabState--; 419 | if( currentPrefabState < 0 ) 420 | currentPrefabState = selectedPrefabStates.Count - 1; 421 | } 422 | 423 | public void NextPrefabState() 424 | { 425 | if( selectedPrefabStates == null || selectedPrefabStates.Count <= 1 ) 426 | return; 427 | 428 | Undo.IncrementCurrentGroup(); 429 | Undo.RecordObject( this, "Change Prefab State" ); 430 | currentPrefabState++; 431 | if( currentPrefabState >= selectedPrefabStates.Count ) 432 | currentPrefabState = 0; 433 | } 434 | 435 | // Draw GUI controllers to be able to tweak settings via Unity editor 436 | // (this function is called by OnGUI function) 437 | public void Draw() 438 | { 439 | Color c = GUI.color; 440 | 441 | // Draw horizontal line 442 | // Credit: http://answers.unity3d.com/questions/216584/horizontal-line.html 443 | GUILayout.Box( "", GUILayout.ExpandWidth( true ), GUILayout.Height( 1 ) ); 444 | 445 | if( currentState >= states.Count ) 446 | currentState = states.Count - 1; 447 | 448 | showGridSettings = EditorGUILayout.Foldout( showGridSettings, "Show Grid Settings", true ); 449 | if( showGridSettings ) 450 | { 451 | GUILayout.BeginHorizontal(); 452 | 453 | EditorGUI.BeginChangeCheck(); 454 | int _state = EditorGUILayout.Popup( "State", currentState, statesPopup ); 455 | if( EditorGUI.EndChangeCheck() ) 456 | { 457 | Undo.RecordObject( this, "Change State" ); 458 | currentState = _state; 459 | } 460 | 461 | GUI.color = Color.yellow; 462 | 463 | if( GUILayout.Button( "+", GUILayout.Width( 25f ), GUILayout.Height( 14f ) ) ) 464 | { 465 | Undo.RecordObject( this, "Create State" ); 466 | CreateState( states[currentState] ); 467 | 468 | currentState = states.Count - 1; 469 | 470 | UpdateStatesPopupList(); 471 | } 472 | 473 | if( states.Count <= 1 ) 474 | GUI.enabled = false; 475 | 476 | GUI.color = new Color( 1f, 0.5f, 0.5f ); 477 | 478 | if( GUILayout.Button( "X", GUILayout.Width( 25f ), GUILayout.Height( 14f ) ) ) 479 | { 480 | Undo.RecordObject( this, "Delete State" ); 481 | states.RemoveAt( currentState ); 482 | 483 | if( currentState >= states.Count ) 484 | currentState = states.Count - 1; 485 | 486 | UpdateStatesPopupList(); 487 | } 488 | 489 | GUI.color = c; 490 | GUI.enabled = true; 491 | 492 | GUILayout.EndHorizontal(); 493 | 494 | states[currentState].Draw( this ); 495 | } 496 | 497 | // Draw horizontal line 498 | GUILayout.Box( "", GUILayout.ExpandWidth( true ), GUILayout.Height( 1 ) ); 499 | 500 | if( !selectedPrefab ) 501 | EditorGUILayout.HelpBox( "No prefab is selected", MessageType.Info ); 502 | else 503 | { 504 | GUI.enabled = false; 505 | EditorGUILayout.ObjectField( "Prefab", selectedPrefab, typeof( GameObject ), false ); 506 | GUI.enabled = true; 507 | 508 | showPrefabSettings = EditorGUILayout.Foldout( showPrefabSettings, "Show Prefab Settings", true ); 509 | if( showPrefabSettings ) 510 | { 511 | GUILayout.BeginHorizontal(); 512 | 513 | PrefabState state; 514 | bool isDefaultState; 515 | if( selectedPrefabStates == null || selectedPrefabStates.Count == 0 ) 516 | { 517 | if( defaultPrefabState == null ) 518 | defaultPrefabState = new PrefabState( "default" ); 519 | 520 | EditorGUILayout.Popup( "Prefab State", 0, prefabStatesPopup ); 521 | 522 | state = defaultPrefabState; 523 | isDefaultState = true; 524 | } 525 | else 526 | { 527 | if( currentPrefabState >= selectedPrefabStates.Count ) 528 | currentPrefabState = selectedPrefabStates.Count - 1; 529 | 530 | EditorGUI.BeginChangeCheck(); 531 | int _state = EditorGUILayout.Popup( "Prefab State", currentPrefabState, prefabStatesPopup ); 532 | if( EditorGUI.EndChangeCheck() ) 533 | { 534 | Undo.RecordObject( this, "Change Prefab State" ); 535 | currentPrefabState = _state; 536 | } 537 | 538 | state = selectedPrefabStates[currentPrefabState]; 539 | isDefaultState = false; 540 | } 541 | 542 | GUI.color = Color.yellow; 543 | 544 | if( GUILayout.Button( "+", GUILayout.Width( 25f ), GUILayout.Height( 14f ) ) ) 545 | { 546 | Undo.RecordObject( this, "Create Prefab State" ); 547 | CreatePrefabStateForSelection( new PrefabState( "unnamed", selectedPrefabStates[currentPrefabState] ), true ); 548 | 549 | currentPrefabState = selectedPrefabStates.Count - 1; 550 | 551 | UpdatePrefabStatesPopupList(); 552 | } 553 | 554 | if( selectedPrefabStates == null || selectedPrefabStates.Count <= 1 ) 555 | GUI.enabled = false; 556 | 557 | GUI.color = new Color( 1f, 0.5f, 0.5f ); 558 | 559 | if( GUILayout.Button( "X", GUILayout.Width( 25f ), GUILayout.Height( 14f ) ) ) 560 | { 561 | Undo.RecordObject( this, "Delete Prefab State" ); 562 | selectedPrefabStates.RemoveAt( currentPrefabState ); 563 | 564 | if( currentPrefabState >= selectedPrefabStates.Count ) 565 | currentPrefabState = selectedPrefabStates.Count - 1; 566 | 567 | UpdatePrefabStatesPopupList(); 568 | } 569 | 570 | GUI.color = c; 571 | GUI.enabled = true; 572 | 573 | GUILayout.EndHorizontal(); 574 | 575 | state.Draw( this, isDefaultState ); 576 | } 577 | } 578 | } 579 | } 580 | } -------------------------------------------------------------------------------- /Plugins/SimpleGridFramework/Editor/GridEditor.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using UnityEditor; 3 | 4 | namespace SimpleGridFramework 5 | { 6 | public class GridEditor : EditorWindow 7 | { 8 | public enum GridAlignment { XZ = 0, XY = 1, YZ = 2 }; 9 | 10 | private const string PREF_ENABLED = "SGF_Enabled"; 11 | private const string PREF_SHOW_GRIDS = "SGF_ShowGrids"; 12 | private const string PREF_SNAP_TO_GRID = "SGF_SnapToGrid"; 13 | 14 | private GridEditorSettings settings; 15 | private GridState gridSettings; 16 | 17 | // Is the framework enabled 18 | private bool isEnabled; 19 | 20 | // Should the grids be drawn 21 | private bool showGrids; 22 | 23 | // Is snap-to-grid enabled 24 | private bool snapToGrid; 25 | 26 | // Settings cached from gridSettings on every Update call 27 | private GridAlignment gridAlignment; 28 | private int gridlineCount; 29 | private float gridSize; 30 | private float gridPos; 31 | private float gridShiftAxis1; 32 | private float gridShiftAxis2; 33 | 34 | // Material used to draw the grid lines on Scene view 35 | private Material lineMaterial; 36 | 37 | // Preview object that is used to show where the instantiation will happen 38 | private Transform prefabPreview; 39 | 40 | private Vector3 areaSpawnStartPos; 41 | private int areaSpawnLength1; 42 | private int areaSpawnLength2; 43 | 44 | // Some variables necessary for the framework to work correctly 45 | private bool mousePressValid = false; 46 | private bool keyDown = false; 47 | private bool leftMouseButtonDown = false; 48 | private bool rightMouseButtonDown = false; 49 | 50 | private Vector2 scrollPos = Vector2.zero; 51 | 52 | // Called when the framework window is opened 53 | [MenuItem( "Window/Grid Editor" )] 54 | public static void Init() 55 | { 56 | GridEditor window = GetWindow(); 57 | window.titleContent = new GUIContent( "Grid Editor" ); 58 | window.minSize = new Vector2( 300f, 150f ); 59 | window.Show(); 60 | } 61 | 62 | // Script is initialized 63 | private void OnEnable() 64 | { 65 | LoadSettings(); 66 | 67 | // Register to certain events 68 | #if UNITY_2019_1_OR_NEWER 69 | SceneView.duringSceneGui -= SceneUpdate; 70 | SceneView.duringSceneGui += SceneUpdate; 71 | #else 72 | SceneView.onSceneGUIDelegate -= SceneUpdate; 73 | SceneView.onSceneGUIDelegate += SceneUpdate; 74 | #endif 75 | 76 | Undo.undoRedoPerformed -= OnUndoRedo; 77 | Undo.undoRedoPerformed += OnUndoRedo; 78 | 79 | Selection.selectionChanged -= OnSelectionChanged; 80 | Selection.selectionChanged += OnSelectionChanged; 81 | 82 | OnSelectionChanged(); 83 | 84 | // Repaint the editor window when the script is reloaded 85 | Repaint(); 86 | Refresh(); 87 | } 88 | 89 | // Window is destroyed 90 | void OnDisable() 91 | { 92 | Tools.hidden = false; 93 | 94 | // Destroy prefab preview object when the editor window is closed 95 | if( prefabPreview ) 96 | DestroyImmediate( prefabPreview.gameObject ); 97 | 98 | // Unregister from events 99 | #if UNITY_2019_1_OR_NEWER 100 | SceneView.duringSceneGui -= SceneUpdate; 101 | #else 102 | SceneView.onSceneGUIDelegate -= SceneUpdate; 103 | #endif 104 | 105 | Undo.undoRedoPerformed -= OnUndoRedo; 106 | Selection.selectionChanged -= OnSelectionChanged; 107 | } 108 | 109 | private void LoadSettings() 110 | { 111 | isEnabled = EditorPrefs.GetBool( PREF_ENABLED, true ); 112 | showGrids = EditorPrefs.GetBool( PREF_SHOW_GRIDS, true ); 113 | snapToGrid = EditorPrefs.GetBool( PREF_SNAP_TO_GRID, true ); 114 | 115 | settings = AssetDatabase.LoadAssetAtPath( GridEditorSettings.SAVE_PATH ); 116 | if( !settings ) 117 | { 118 | System.IO.Directory.CreateDirectory( System.IO.Path.GetDirectoryName( GridEditorSettings.SAVE_PATH ) ); 119 | 120 | settings = CreateInstance(); 121 | AssetDatabase.CreateAsset( settings, GridEditorSettings.SAVE_PATH ); 122 | AssetDatabase.SaveAssets(); 123 | } 124 | } 125 | 126 | private void OnUndoRedo() 127 | { 128 | settings.OnSelectionChanged(); 129 | 130 | Repaint(); 131 | Refresh(); 132 | } 133 | 134 | private void OnSelectionChanged() 135 | { 136 | settings.OnSelectionChanged(); 137 | 138 | Repaint(); 139 | Refresh(); 140 | } 141 | 142 | // Refresh the prefab preview 143 | private void Refresh() 144 | { 145 | Vector3 pos = Vector3.zero; 146 | 147 | if( prefabPreview ) 148 | { 149 | pos = prefabPreview.localPosition; 150 | DestroyImmediate( prefabPreview.gameObject ); 151 | } 152 | 153 | if( isEnabled ) 154 | { 155 | GameObject obj = settings.Prefab; 156 | 157 | if( obj != null ) 158 | { 159 | prefabPreview = ( (GameObject) Instantiate( obj ) ).transform; 160 | prefabPreview.localPosition = pos; 161 | 162 | // Preview object should not be visible in the Hierarchy 163 | prefabPreview.gameObject.hideFlags = HideFlags.HideAndDontSave; 164 | prefabPreview.gameObject.layer = 2; // IgnoreRaycast 165 | prefabPreview.localEulerAngles = settings.PrefabState.rotation; 166 | } 167 | } 168 | 169 | SceneView.RepaintAll(); 170 | } 171 | 172 | // Always keep the prefab preview up-to-date 173 | private void Update() 174 | { 175 | gridSettings = settings.GridState; 176 | 177 | gridAlignment = gridSettings.gridAlignment; 178 | gridlineCount = gridSettings.gridlineCount; 179 | gridSize = gridSettings.gridSize; 180 | gridPos = gridSettings.gridPos; 181 | gridShiftAxis1 = gridSettings.gridShiftAxis1; 182 | gridShiftAxis2 = gridSettings.gridShiftAxis2; 183 | 184 | if( settings.Prefab && prefabPreview ) 185 | { 186 | prefabPreview.localEulerAngles = settings.PrefabState.rotation; 187 | SceneView.RepaintAll(); 188 | } 189 | 190 | Tools.hidden = isEnabled; 191 | } 192 | 193 | // Draw the contents of the editor window 194 | private void OnGUI() 195 | { 196 | scrollPos = EditorGUILayout.BeginScrollView( scrollPos ); 197 | 198 | // Draw base settings 199 | GUILayout.BeginHorizontal(); 200 | 201 | EditorGUI.BeginChangeCheck(); 202 | isEnabled = GUILayout.Toggle( isEnabled, "Enabled", GUI.skin.button ); 203 | if( EditorGUI.EndChangeCheck() ) 204 | { 205 | EditorPrefs.SetBool( PREF_ENABLED, isEnabled ); 206 | Refresh(); 207 | } 208 | 209 | EditorGUI.BeginChangeCheck(); 210 | showGrids = GUILayout.Toggle( showGrids, "Show Grids", GUI.skin.button ); 211 | if( EditorGUI.EndChangeCheck() ) 212 | { 213 | EditorPrefs.SetBool( PREF_SHOW_GRIDS, showGrids ); 214 | SceneView.RepaintAll(); 215 | } 216 | 217 | GUI.enabled = isEnabled; 218 | EditorGUI.BeginChangeCheck(); 219 | snapToGrid = GUILayout.Toggle( snapToGrid, "Snap To Grid", GUI.skin.button ); 220 | if( EditorGUI.EndChangeCheck() ) 221 | EditorPrefs.SetBool( PREF_SNAP_TO_GRID, snapToGrid ); 222 | GUI.enabled = true; 223 | 224 | GUILayout.EndHorizontal(); 225 | 226 | // Draw grid and prefab settings 227 | EditorGUI.BeginChangeCheck(); 228 | settings.Draw(); 229 | if( EditorGUI.EndChangeCheck() ) 230 | SceneView.RepaintAll(); 231 | 232 | EditorGUILayout.EndScrollView(); 233 | } 234 | 235 | // Draw gridlines on Scene view 236 | // Code was inspired from: http://docs.unity3d.com/ScriptReference/GL.html 237 | private void DrawGridlines( SceneView scenePanel ) 238 | { 239 | if( !lineMaterial ) 240 | { 241 | lineMaterial = new Material( Shader.Find( "Hidden/Internal-Colored" ) ) 242 | { 243 | hideFlags = HideFlags.HideAndDontSave 244 | }; 245 | } 246 | 247 | lineMaterial.SetPass( 0 ); 248 | 249 | GL.Begin( GL.LINES ); 250 | GL.Color( gridSettings.gridlineColor ); 251 | 252 | Vector3 pos = scenePanel.camera.transform.position; 253 | 254 | if( gridAlignment == GridAlignment.XZ ) 255 | { 256 | pos.x -= pos.x % gridSize; 257 | pos.z -= pos.z % gridSize; 258 | 259 | float startX = pos.x - gridlineCount * gridSize * 0.5f + gridShiftAxis1; 260 | float startZ = pos.z - gridlineCount * gridSize * 0.5f + gridShiftAxis2; 261 | float endX = pos.x + gridlineCount * gridSize * 0.5f + gridShiftAxis1; 262 | float endZ = pos.z + gridlineCount * gridSize * 0.5f + gridShiftAxis2; 263 | 264 | float x = startX; 265 | float y = gridPos; 266 | float z = startZ; 267 | 268 | for( int i = 0; i <= gridlineCount; i++ ) 269 | { 270 | GL.Vertex3( startX, y, z ); 271 | GL.Vertex3( endX, y, z ); 272 | 273 | z += gridSize; 274 | } 275 | 276 | for( int i = 0; i <= gridlineCount; i++ ) 277 | { 278 | GL.Vertex3( x, y, startZ ); 279 | GL.Vertex3( x, y, endZ ); 280 | 281 | x += gridSize; 282 | } 283 | } 284 | else if( gridAlignment == GridAlignment.XY ) 285 | { 286 | pos.x -= pos.x % gridSize; 287 | pos.y -= pos.y % gridSize; 288 | 289 | float startX = pos.x - gridlineCount * gridSize * 0.5f + gridShiftAxis1; 290 | float startY = pos.y - gridlineCount * gridSize * 0.5f + gridShiftAxis2; 291 | float endX = pos.x + gridlineCount * gridSize * 0.5f + gridShiftAxis1; 292 | float endY = pos.y + gridlineCount * gridSize * 0.5f + gridShiftAxis2; 293 | 294 | float x = startX; 295 | float y = startY; 296 | float z = gridPos; 297 | 298 | for( int i = 0; i <= gridlineCount; i++ ) 299 | { 300 | GL.Vertex3( startX, y, z ); 301 | GL.Vertex3( endX, y, z ); 302 | 303 | y += gridSize; 304 | } 305 | 306 | for( int i = 0; i <= gridlineCount; i++ ) 307 | { 308 | GL.Vertex3( x, startY, z ); 309 | GL.Vertex3( x, endY, z ); 310 | 311 | x += gridSize; 312 | } 313 | } 314 | else 315 | { 316 | pos.y -= pos.y % gridSize; 317 | pos.z -= pos.z % gridSize; 318 | 319 | float startY = pos.y - gridlineCount * gridSize * 0.5f + gridShiftAxis1; 320 | float startZ = pos.z - gridlineCount * gridSize * 0.5f + gridShiftAxis2; 321 | float endY = pos.y + gridlineCount * gridSize * 0.5f + gridShiftAxis1; 322 | float endZ = pos.z + gridlineCount * gridSize * 0.5f + gridShiftAxis2; 323 | 324 | float x = gridPos; 325 | float y = startY; 326 | float z = startZ; 327 | 328 | for( int i = 0; i <= gridlineCount; i++ ) 329 | { 330 | GL.Vertex3( x, startY, z ); 331 | GL.Vertex3( x, endY, z ); 332 | 333 | z += gridSize; 334 | } 335 | 336 | for( int i = 0; i <= gridlineCount; i++ ) 337 | { 338 | GL.Vertex3( x, y, startZ ); 339 | GL.Vertex3( x, y, endZ ); 340 | 341 | y += gridSize; 342 | } 343 | } 344 | 345 | GL.End(); 346 | } 347 | 348 | // Called each time Scene View updates 349 | private void SceneUpdate( SceneView scenePanel ) 350 | { 351 | // Draw gridlines on screen 352 | if( showGrids ) 353 | DrawGridlines( scenePanel ); 354 | 355 | // If the framework is enabled 356 | if( !isEnabled || !settings.Prefab ) 357 | return; 358 | 359 | PrefabState prefabSettings = settings.PrefabState; 360 | Event e = Event.current; 361 | 362 | if( e.type == EventType.KeyDown ) 363 | { 364 | if( !rightMouseButtonDown && !keyDown ) 365 | { 366 | if( e.keyCode == KeyCode.Q ) 367 | { 368 | if( !e.control ) 369 | settings.RotateSelectedPrefab( -45f ); 370 | else 371 | settings.PreviousPrefabState(); 372 | 373 | Repaint(); 374 | 375 | keyDown = true; 376 | } 377 | else if( e.keyCode == KeyCode.E ) 378 | { 379 | if( !e.control ) 380 | settings.RotateSelectedPrefab( 45f ); 381 | else 382 | settings.NextPrefabState(); 383 | 384 | Repaint(); 385 | 386 | keyDown = true; 387 | } 388 | } 389 | } 390 | else if( e.type == EventType.KeyUp ) 391 | { 392 | if( e.keyCode == KeyCode.Q || e.keyCode == KeyCode.E ) 393 | keyDown = false; 394 | } 395 | 396 | if( e.isMouse ) 397 | { 398 | // Find the position to show the preview object at 399 | Ray ray = HandleUtility.GUIPointToWorldRay( e.mousePosition ); 400 | float distance; 401 | 402 | Plane plane; 403 | if( gridAlignment == GridAlignment.XZ ) 404 | plane = new Plane( Vector3.up, new Vector3( 0, gridPos, 0 ) ); 405 | else if( gridAlignment == GridAlignment.XY ) 406 | plane = new Plane( Vector3.forward, new Vector3( 0, 0, gridPos ) ); 407 | else 408 | plane = new Plane( Vector3.right, new Vector3( gridPos, 0, 0 ) ); 409 | 410 | // Calculate cursor's collision point with the gridlines 411 | if( !plane.Raycast( ray, out distance ) ) 412 | return; 413 | 414 | Vector3 rayPos = ray.GetPoint( distance ); 415 | 416 | // Snap the point if snapToGrid is enabled 417 | if( snapToGrid ) 418 | { 419 | if( gridAlignment == GridAlignment.XZ ) 420 | { 421 | rayPos.x -= gridShiftAxis1; 422 | rayPos.z -= gridShiftAxis2; 423 | 424 | if( rayPos.x > 0 ) 425 | rayPos.x = rayPos.x - rayPos.x % gridSize + gridSize * 0.5f; 426 | else 427 | rayPos.x = rayPos.x - rayPos.x % gridSize - gridSize * 0.5f; 428 | 429 | if( rayPos.z > 0 ) 430 | rayPos.z = rayPos.z - rayPos.z % gridSize + gridSize * 0.5f; 431 | else 432 | rayPos.z = rayPos.z - rayPos.z % gridSize - gridSize * 0.5f; 433 | 434 | rayPos.x += gridShiftAxis1; 435 | rayPos.z += gridShiftAxis2; 436 | } 437 | else if( gridAlignment == GridAlignment.XY ) 438 | { 439 | rayPos.x -= gridShiftAxis1; 440 | rayPos.y -= gridShiftAxis2; 441 | 442 | if( rayPos.x > 0 ) 443 | rayPos.x = rayPos.x - rayPos.x % gridSize + gridSize * 0.5f; 444 | else 445 | rayPos.x = rayPos.x - rayPos.x % gridSize - gridSize * 0.5f; 446 | 447 | if( rayPos.y > 0 ) 448 | rayPos.y = rayPos.y - rayPos.y % gridSize + gridSize * 0.5f; 449 | else 450 | rayPos.y = rayPos.y - rayPos.y % gridSize - gridSize * 0.5f; 451 | 452 | rayPos.x += gridShiftAxis1; 453 | rayPos.y += gridShiftAxis2; 454 | } 455 | else 456 | { 457 | rayPos.y -= gridShiftAxis1; 458 | rayPos.z -= gridShiftAxis2; 459 | 460 | if( rayPos.y > 0 ) 461 | rayPos.y = rayPos.y - rayPos.y % gridSize + gridSize * 0.5f; 462 | else 463 | rayPos.y = rayPos.y - rayPos.y % gridSize - gridSize * 0.5f; 464 | 465 | if( rayPos.z > 0 ) 466 | rayPos.z = rayPos.z - rayPos.z % gridSize + gridSize * 0.5f; 467 | else 468 | rayPos.z = rayPos.z - rayPos.z % gridSize - gridSize * 0.5f; 469 | 470 | rayPos.y += gridShiftAxis1; 471 | rayPos.z += gridShiftAxis2; 472 | } 473 | } 474 | 475 | prefabPreview.localPosition = rayPos + prefabSettings.shift; 476 | 477 | if( e.type == EventType.MouseDown ) 478 | { 479 | if( e.button != 0 ) 480 | rightMouseButtonDown = true; 481 | else if( !leftMouseButtonDown ) 482 | { 483 | leftMouseButtonDown = true; 484 | 485 | if( e.alt || rightMouseButtonDown ) 486 | mousePressValid = false; 487 | else 488 | { 489 | GUIUtility.hotControl = GUIUtility.GetControlID( GetHashCode(), FocusType.Passive ); 490 | mousePressValid = true; 491 | 492 | areaSpawnStartPos = prefabPreview.localPosition; 493 | areaSpawnLength1 = 0; 494 | areaSpawnLength2 = 0; 495 | } 496 | } 497 | } 498 | else if( e.type == EventType.MouseDrag ) 499 | { 500 | Vector3 deltaPos = prefabPreview.localPosition - areaSpawnStartPos; 501 | 502 | if( gridAlignment == GridAlignment.XZ ) 503 | { 504 | areaSpawnLength1 = Mathf.RoundToInt( deltaPos.x / gridSize ); 505 | areaSpawnLength2 = Mathf.RoundToInt( deltaPos.z / gridSize ); 506 | } 507 | else if( gridAlignment == GridAlignment.XY ) 508 | { 509 | areaSpawnLength1 = Mathf.RoundToInt( deltaPos.x / gridSize ); 510 | areaSpawnLength2 = Mathf.RoundToInt( deltaPos.y / gridSize ); 511 | } 512 | else 513 | { 514 | areaSpawnLength1 = Mathf.RoundToInt( deltaPos.y / gridSize ); 515 | areaSpawnLength2 = Mathf.RoundToInt( deltaPos.z / gridSize ); 516 | } 517 | } 518 | else if( e.type == EventType.MouseUp ) 519 | { 520 | if( e.button != 0 ) 521 | rightMouseButtonDown = false; 522 | else 523 | { 524 | leftMouseButtonDown = false; 525 | 526 | if( mousePressValid && !rightMouseButtonDown ) 527 | { 528 | mousePressValid = false; 529 | GUIUtility.hotControl = 0; 530 | 531 | Vector3 spawnPosChange1, spawnPosChange2; 532 | if( gridAlignment == GridAlignment.XZ ) 533 | { 534 | spawnPosChange1 = new Vector3( gridSize, 0f, 0f ); 535 | spawnPosChange2 = new Vector3( 0f, 0f, gridSize ); 536 | } 537 | else if( gridAlignment == GridAlignment.XY ) 538 | { 539 | spawnPosChange1 = new Vector3( gridSize, 0f, 0f ); 540 | spawnPosChange2 = new Vector3( 0f, gridSize, 0f ); 541 | } 542 | else 543 | { 544 | spawnPosChange1 = new Vector3( 0f, gridSize, 0f ); 545 | spawnPosChange2 = new Vector3( 0f, 0f, gridSize ); 546 | } 547 | 548 | if( areaSpawnLength1 < 0 ) 549 | { 550 | spawnPosChange1 = -spawnPosChange1; 551 | areaSpawnLength1 = -areaSpawnLength1; 552 | } 553 | if( areaSpawnLength2 < 0 ) 554 | { 555 | spawnPosChange2 = -spawnPosChange2; 556 | areaSpawnLength2 = -areaSpawnLength2; 557 | } 558 | 559 | for( int i = 0; i <= areaSpawnLength1; i++ ) 560 | { 561 | for( int j = 0; j <= areaSpawnLength2; j++ ) 562 | { 563 | GameObject instance; 564 | if( settings.Prefab.transform.root == settings.Prefab.transform ) 565 | instance = (GameObject) PrefabUtility.InstantiatePrefab( settings.Prefab ); 566 | else 567 | instance = (GameObject) Instantiate( settings.Prefab ); 568 | 569 | instance.transform.position = areaSpawnStartPos + spawnPosChange1 * i + spawnPosChange2 * j; 570 | instance.transform.eulerAngles = prefabSettings.rotation; 571 | Undo.RegisterCreatedObjectUndo( instance, "Create Object" ); 572 | } 573 | } 574 | } 575 | } 576 | } 577 | } 578 | 579 | 580 | // Draw area spawn preview 581 | if( mousePressValid && leftMouseButtonDown && !rightMouseButtonDown ) 582 | { 583 | Color c = Handles.color; 584 | Handles.color = Color.green; 585 | 586 | if( gridAlignment == GridAlignment.XZ ) 587 | Handles.DrawWireCube( areaSpawnStartPos + new Vector3( areaSpawnLength1, 0, areaSpawnLength2 ) * gridSize * 0.5f, new Vector3( Mathf.Abs( areaSpawnLength1 ) + 1, 0.1f, Mathf.Abs( areaSpawnLength2 ) + 1 ) * gridSize ); 588 | else if( gridAlignment == GridAlignment.XY ) 589 | Handles.DrawWireCube( areaSpawnStartPos + new Vector3( areaSpawnLength1, areaSpawnLength2, 0 ) * gridSize * 0.5f, new Vector3( Mathf.Abs( areaSpawnLength1 ) + 1, Mathf.Abs( areaSpawnLength2 ) + 1, 0.1f ) * gridSize ); 590 | else 591 | Handles.DrawWireCube( areaSpawnStartPos + new Vector3( 0, areaSpawnLength1, areaSpawnLength2 ) * gridSize * 0.5f, new Vector3( 0.1f, Mathf.Abs( areaSpawnLength1 ) + 1, Mathf.Abs( areaSpawnLength2 ) + 1 ) * gridSize ); 592 | 593 | Handles.color = c; 594 | } 595 | } 596 | } 597 | } --------------------------------------------------------------------------------