Advertisement
Guest User

Untitled

a guest
Jan 16th, 2018
258
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 15.02 KB | None | 0 0
  1. using UnityEngine;
  2. using UnityEditor;
  3. using System.Collections;
  4. using System.Linq;
  5. using System.Collections.Generic;
  6. using System.IO;
  7.  
  8.  
  9.  
  10. [CustomEditor( typeof( GoDummyPath ) )]
  11. public class GoDummyPathEditor : Editor
  12. {
  13. private GoDummyPath _target;
  14. private GUIStyle _labelStyle;
  15. private GUIStyle _indexStyle;
  16.  
  17. private int _insertIndex = 0;
  18. private float _snapDistance = 5f;
  19. private bool _showNodeDetails;
  20. private bool _fileLoadSaveDetails;
  21. private int _selectedNodeIndex = -1;
  22.  
  23. private Quaternion handleRotation; //I ADDED THIS
  24. private Transform handleTransform; //I ADDED THIS
  25.  
  26. #region Monobehaviour and Editor
  27.  
  28. void OnEnable()
  29. {
  30. // setup the font for the 'begin' 'end' text
  31. _labelStyle = new GUIStyle();
  32. _labelStyle.fontStyle = FontStyle.Bold;
  33. _labelStyle.normal.textColor = Color.white;
  34. _labelStyle.fontSize = 16;
  35.  
  36. _indexStyle = new GUIStyle();
  37. _indexStyle.fontStyle = FontStyle.Bold;
  38. _indexStyle.normal.textColor = Color.white;
  39. _indexStyle.fontSize = 12;
  40.  
  41. _target = (GoDummyPath)target;
  42.  
  43. //I ADDED THIS
  44. handleTransform = _target.transform;
  45. handleRotation = Tools.pivotRotation == PivotRotation.Local ?
  46. handleTransform.rotation : Quaternion.identity;
  47.  
  48. for (var i = 0; i < _target.nodes.Count; i++)
  49. _target.nodes [i] = handleTransform.TransformPoint (_target.nodes [i]);
  50. // TO HERE
  51. }
  52.  
  53.  
  54. public override void OnInspectorGUI()
  55. {
  56. // what kind of handles shall we use?
  57. EditorGUILayout.BeginHorizontal();
  58. EditorGUILayout.PrefixLabel( "Use Standard Handles" );
  59. _target.useStandardHandles = EditorGUILayout.Toggle( _target.useStandardHandles );
  60. EditorGUILayout.EndHorizontal();
  61.  
  62.  
  63. // path name:
  64. EditorGUILayout.BeginHorizontal();
  65. EditorGUILayout.PrefixLabel( "Route Name" );
  66. _target.pathName = EditorGUILayout.TextField( _target.pathName );
  67. EditorGUILayout.EndHorizontal();
  68.  
  69. if( _target.pathName == string.Empty )
  70. _target.pathName = "route" + Random.Range( 1, 100000 );
  71.  
  72.  
  73. // path color:
  74. EditorGUILayout.BeginHorizontal();
  75. EditorGUILayout.PrefixLabel( "Route Color" );
  76. _target.pathColor = EditorGUILayout.ColorField( _target.pathColor );
  77. EditorGUILayout.EndHorizontal();
  78.  
  79.  
  80. // force straight lines:
  81. EditorGUILayout.BeginHorizontal();
  82. EditorGUILayout.PrefixLabel( "Force Straight Line Path" );
  83. _target.forceStraightLinePath = EditorGUILayout.Toggle( _target.forceStraightLinePath );
  84. EditorGUILayout.EndHorizontal();
  85.  
  86.  
  87. // resolution
  88. EditorGUILayout.BeginHorizontal();
  89. EditorGUILayout.PrefixLabel( "Editor Drawing Resolution" );
  90. _target.pathResolution = EditorGUILayout.IntSlider( _target.pathResolution, 2, 100 );
  91. EditorGUILayout.EndHorizontal();
  92.  
  93.  
  94. EditorGUILayout.Separator();
  95.  
  96.  
  97. // insert node - we need 3 or more nodes for insert to make sense
  98. if( _target.nodes.Count > 2 )
  99. {
  100. EditorGUILayout.BeginHorizontal();
  101. EditorGUILayout.PrefixLabel( "Insert Node" );
  102. _insertIndex = EditorGUILayout.IntField( _insertIndex );
  103. if( GUILayout.Button( "Insert" ) )
  104. {
  105. // validate the index
  106. if( _insertIndex >= 0 && _insertIndex < _target.nodes.Count )
  107. {
  108. // insert the node offsetting it a bit from the previous node
  109. var copyNodeIndex = _insertIndex == 0 ? 0 : _insertIndex;
  110. var copyNode = _target.nodes[copyNodeIndex];
  111. copyNode.x += 10;
  112. copyNode.z += 10;
  113.  
  114. insertNodeAtIndex( copyNode, _insertIndex );
  115. }
  116. }
  117. EditorGUILayout.EndHorizontal();
  118. }
  119.  
  120.  
  121. // close route?
  122. if( GUILayout.Button( "Close Path" ) )
  123. {
  124. Undo.RecordObject( _target, "Path Vector Changed" );
  125. closeRoute();
  126. GUI.changed = true;
  127. }
  128.  
  129.  
  130. // shift the start point to the origin
  131. if( GUILayout.Button( "Shift Path to Start at Origin" ) )
  132. {
  133. Undo.RecordObject( _target, "Path Vector Changed" );
  134.  
  135. var offset = Vector3.zero;
  136.  
  137. // see what kind of path we are. the simplest case is just a straight line
  138. var path = new GoSpline( _target.nodes, _target.forceStraightLinePath );
  139. if( path.splineType == GoSplineType.StraightLine || _target.nodes.Count < 5 )
  140. offset = Vector3.zero - _target.nodes[0];
  141. else
  142. offset = Vector3.zero - _target.nodes[1];
  143.  
  144. for( var i = 0; i < _target.nodes.Count; i++ )
  145. _target.nodes[i] += offset;
  146.  
  147. GUI.changed = true;
  148. }
  149.  
  150.  
  151. // reverse
  152. if( GUILayout.Button( "Reverse Path" ) )
  153. {
  154. Undo.RecordObject( _target, "Path Vector Changed" );
  155. _target.nodes.Reverse();
  156. GUI.changed = true;
  157. }
  158.  
  159.  
  160. // persist to disk
  161. EditorGUILayout.Space();
  162. EditorGUILayout.LabelField( "Save to/Read from Disk" );
  163.  
  164. EditorGUILayout.Space();
  165. EditorGUILayout.BeginHorizontal();
  166. EditorGUILayout.PrefixLabel( "Serialize and Save Path" );
  167. if( GUILayout.Button( "Save" ) )
  168. {
  169. var path = EditorUtility.SaveFilePanel( "Save path", Application.dataPath + "/StreamingAssets", _target.pathName + ".asset", "asset" );
  170. if( path != string.Empty )
  171. {
  172. persistRouteToDisk( path );
  173.  
  174. // fetch the filename and set it as the routeName
  175. _target.pathName = Path.GetFileName( path ).Replace( ".asset", string.Empty );
  176. GUI.changed = true;
  177. }
  178. }
  179. EditorGUILayout.EndHorizontal();
  180.  
  181.  
  182. // load from disk
  183. EditorGUILayout.BeginHorizontal();
  184. EditorGUILayout.PrefixLabel( "Load saved path" );
  185. if( GUILayout.Button( "Load" ) )
  186. {
  187. var path = EditorUtility.OpenFilePanel( "Choose path to load", Path.Combine( Application.dataPath, "StreamingAssets" ), "asset" );
  188. if( path != string.Empty )
  189. {
  190. if( !File.Exists( path ) )
  191. {
  192. EditorUtility.DisplayDialog( "File does not exist", "Path couldn't find the file you specified", "Close" );
  193. }
  194. else
  195. {
  196. _target.nodes = GoSpline.bytesToVector3List( File.ReadAllBytes( path ) );
  197. _target.pathName = Path.GetFileName( path ).Replace( ".asset", string.Empty );
  198. GUI.changed = true;
  199. }
  200. }
  201. }
  202. EditorGUILayout.EndHorizontal();
  203.  
  204.  
  205. // node display
  206. EditorGUILayout.Space();
  207. _showNodeDetails = EditorGUILayout.Foldout( _showNodeDetails, "Show Node Values" );
  208. if( _showNodeDetails )
  209. {
  210. EditorGUI.indentLevel++;
  211. for( int i = 0; i < _target.nodes.Count; i++ )
  212. _target.nodes[i] = EditorGUILayout.Vector3Field( "Node " + ( i + 1 ), _target.nodes[i] );
  213. EditorGUI.indentLevel--;
  214. }
  215.  
  216.  
  217. // instructions
  218. EditorGUILayout.Space();
  219. EditorGUILayout.HelpBox( "While dragging a node, hold down Ctrl and slowly move the cursor to snap to a nearby point\n\n" +
  220. "Click the 'Close Path' button to add a new node that will close out the current path.\n\n" +
  221. "Hold Command while dragging a node to snap in 5 point increments\n\n" +
  222. "Double click to add a new node at the end of the path\n\n" +
  223. "Hold down alt while adding a node to prepend the new node at the front of the route\n\n" +
  224. "Press delete or backspace to delete the selected node\n\n" +
  225. "NOTE: make sure you have the pan tool selected while editing paths", MessageType.None );
  226.  
  227.  
  228. // update and redraw:
  229. if( GUI.changed )
  230. {
  231. ///I ADDED THIS
  232. for (var i = 0; i < _target.nodes.Count; i++)
  233. _target.nodes [i] = handleTransform.InverseTransformPoint(_target.nodes [i]);
  234. // TO HERE
  235. EditorUtility.SetDirty( _target );
  236. Repaint();
  237. }
  238. }
  239.  
  240.  
  241. void OnSceneGUI()
  242. {
  243. if( !_target.gameObject.activeSelf )
  244. return;
  245.  
  246. // handle current selection and node addition via double click or ctrl click
  247. if( Event.current.type == EventType.mouseDown )
  248. {
  249. var nearestIndex = getNearestNodeForMousePosition( Event.current.mousePosition );
  250. _selectedNodeIndex = nearestIndex;
  251.  
  252. // double click to add
  253. if( Event.current.clickCount > 1 )
  254. {
  255. var translatedPoint = HandleUtility.GUIPointToWorldRay( Event.current.mousePosition )
  256. .GetPoint( ( _target.transform.position - Camera.current.transform.position ).magnitude );
  257.  
  258. Undo.RecordObject( _target, "Path Node Added" );
  259.  
  260. // if alt is down then prepend the node to the beginning
  261. if( Event.current.alt )
  262. insertNodeAtIndex( translatedPoint, 0 );
  263. else
  264. appendNodeAtPoint( translatedPoint );
  265. }
  266. }
  267.  
  268.  
  269. if( _selectedNodeIndex >= 0 )
  270. {
  271. // shall we delete the selected node?
  272. if( Event.current.keyCode == KeyCode.Delete || Event.current.keyCode == KeyCode.Backspace )
  273. {
  274. if (_target.nodes.Count > 2) {
  275. Undo.RecordObject( _target, "Path Node Deleted" );
  276. Event.current.Use();
  277. removeNodeAtIndex( _selectedNodeIndex );
  278. _selectedNodeIndex = -1;
  279. }
  280. }
  281. }
  282.  
  283.  
  284. if( _target.nodes.Count > 1 )
  285. {
  286. // allow path adjustment undo:
  287. Undo.RecordObject( _target, "Path Vector Changed" );
  288.  
  289. // path begin and end labels or just one if the path is closed
  290. if( Vector3.Distance( _target.nodes[0], _target.nodes[_target.nodes.Count - 1] ) == 0 )
  291. {
  292. Handles.Label( _target.nodes[0], " Begin and End", _labelStyle );
  293. }
  294. else
  295. {
  296. Handles.Label( _target.nodes[0], " Begin", _labelStyle );
  297. Handles.Label( _target.nodes[_target.nodes.Count - 1], " End", _labelStyle );
  298. }
  299.  
  300. // draw the handles, arrows and lines
  301. drawRoute();
  302.  
  303. for( var i = 0; i < _target.nodes.Count; i++ )
  304. {
  305. Handles.color = _target.pathColor;
  306.  
  307. // dont label the first and last nodes
  308. if( i > 0 && i < _target.nodes.Count - 1 )
  309. Handles.Label( _target.nodes[i] + new Vector3( 3f, 0, 1.5f ), i.ToString(), _indexStyle );
  310.  
  311. Handles.color = Color.white;
  312. if( _target.useStandardHandles )
  313. {
  314. //_target.nodes[i] = Handles.PositionHandle( _target.nodes[i], Quaternion.identity ); // COMMENTED THIS
  315.  
  316. _target.nodes[i] = Handles.DoPositionHandle(_target.nodes[i], handleRotation); // ADDED TO
  317. }
  318. else
  319. {
  320. // how big shall we draw the handles?
  321. var distanceToTarget = Vector3.Distance( SceneView.lastActiveSceneView.camera.transform.position, _target.transform.position );
  322. distanceToTarget = Mathf.Abs( distanceToTarget );
  323. var handleSize = Mathf.Ceil( distanceToTarget / 75 );
  324.  
  325. _target.nodes[i] = Handles.FreeMoveHandle( _target.nodes[i],
  326. Quaternion.identity,
  327. handleSize,
  328. new Vector3( 5, 0, 5 ),
  329. Handles.SphereCap );
  330. }
  331.  
  332.  
  333. // should we snap? we need at least 4 nodes because we dont snap to the previous and next nodes
  334. if( Event.current.control && _target.nodes.Count > 3 )
  335. {
  336. // dont even bother checking for snapping to the previous/next nodes
  337. var index = getNearestNode( _target.nodes[i], i, i + 1, i - 1 );
  338. var nearest = _target.nodes[index];
  339. var distanceToNearestNode = Vector3.Distance( nearest, _target.nodes[i] );
  340.  
  341. // is it close enough to snap?
  342. if( distanceToNearestNode <= _snapDistance )
  343. {
  344. GUI.changed = true;
  345. _target.nodes[i] = nearest;
  346. }
  347. else if( distanceToNearestNode <= _snapDistance * 2 )
  348. {
  349. // show which nodes are getting close enough to snap to
  350. var color = Color.red;
  351. color.a = 0.3f;
  352. Handles.color = color;
  353. Handles.SphereCap( 0, _target.nodes[i], Quaternion.identity, _snapDistance * 2 );
  354. //Handles.DrawWireDisc( _target.nodes[i], Vector3.up, _snapDistance );
  355. Handles.color = Color.white;
  356. }
  357. }
  358. } // end for
  359.  
  360.  
  361. if( GUI.changed )
  362. {
  363. Repaint();
  364. EditorUtility.SetDirty( _target );
  365. }
  366. } // end if
  367. }
  368.  
  369. #endregion
  370.  
  371.  
  372. #region Private methods
  373.  
  374. private void appendNodeAtPoint( Vector3 node )
  375. {
  376. _target.nodes.Add( node );
  377.  
  378. GUI.changed = true;
  379. }
  380.  
  381.  
  382. private void removeNodeAtIndex( int index )
  383. {
  384. if( index >= _target.nodes.Count || index < 0 )
  385. return;
  386.  
  387. _target.nodes.RemoveAt( index );
  388.  
  389. GUI.changed = true;
  390. }
  391.  
  392.  
  393. private void insertNodeAtIndex( Vector3 node, int index )
  394. {
  395. // validate the index
  396. if( index >= 0 && index < _target.nodes.Count )
  397. {
  398. _target.nodes.Insert( index, node );
  399.  
  400. GUI.changed = true;
  401. }
  402. }
  403.  
  404.  
  405. private void drawArrowBetweenPoints( Vector3 point1, Vector3 point2 )
  406. {
  407. // no need to draw arrows for tiny segments
  408. var distance = Vector3.Distance( point1, point2 );
  409. if( distance < 40 )
  410. return;
  411.  
  412. // we dont want to be exactly in the middle so we offset the length of the arrow
  413. var lerpModifier = ( distance * 0.5f - 25 ) / distance;
  414.  
  415. Handles.color = _target.pathColor;
  416.  
  417. // get the midpoint between the 2 points
  418. var dir = Vector3.Lerp( point1, point2, lerpModifier );
  419. var quat = Quaternion.LookRotation( point2 - point1 );
  420. Handles.ArrowCap( 0, dir, quat, 25 );
  421.  
  422. Handles.color = Color.white;
  423. }
  424.  
  425.  
  426. private int getNearestNode( Vector3 pos, params int[] excludeNodes )
  427. {
  428. var excludeNodesList = new System.Collections.Generic.List<int>( excludeNodes );
  429. var bestDistance = float.MaxValue;
  430. var index = -1;
  431.  
  432. var distance = float.MaxValue;
  433. for( var i = _target.nodes.Count - 1; i >= 0; i-- )
  434. {
  435. if( excludeNodesList.Contains( i ) )
  436. continue;
  437.  
  438. distance = Vector3.Distance( pos, _target.nodes[i] );
  439. if( distance < bestDistance )
  440. {
  441. bestDistance = distance;
  442. index = i;
  443. }
  444. }
  445. return index;
  446. }
  447.  
  448.  
  449. private int getNearestNodeForMousePosition( Vector3 mousePos )
  450. {
  451. var bestDistance = float.MaxValue;
  452. var index = -1;
  453.  
  454. var distance = float.MaxValue;
  455. for( var i = _target.nodes.Count - 1; i >= 0; i-- )
  456. {
  457. var nodeToGui = HandleUtility.WorldToGUIPoint( _target.nodes[i] );
  458. distance = Vector2.Distance( nodeToGui, mousePos );
  459.  
  460. if( distance < bestDistance )
  461. {
  462. bestDistance = distance;
  463. index = i;
  464. }
  465. }
  466.  
  467. // make sure we are close enough to a node
  468. if( bestDistance < 10 )
  469. return index;
  470. return -1;
  471. }
  472.  
  473.  
  474. private void closeRoute()
  475. {
  476. // we will use the GoSpline class to handle the dirtywork of closing the path
  477. var path = new GoSpline( _target.nodes, _target.forceStraightLinePath );
  478. path.closePath();
  479.  
  480. _target.nodes = path.nodes;
  481.  
  482. GUI.changed = true;
  483. }
  484.  
  485.  
  486. private void persistRouteToDisk( string path )
  487. {
  488. var bytes = new List<byte>();
  489.  
  490. for( int k = 0; k < _target.nodes.Count; ++k )
  491. {
  492. Vector3 vec = _target.nodes[k];
  493. bytes.AddRange( System.BitConverter.GetBytes( vec.x ) );
  494. bytes.AddRange( System.BitConverter.GetBytes( vec.y ) );
  495. bytes.AddRange( System.BitConverter.GetBytes( vec.z ) );
  496. }
  497.  
  498. File.WriteAllBytes( path, bytes.ToArray() );
  499. }
  500.  
  501.  
  502. private void drawRoute()
  503. {
  504. // if we are forcing straight lines just use this setup
  505. if( _target.forceStraightLinePath )
  506. {
  507. // draw just the route here and optional arrows
  508. for( var i = 0; i < _target.nodes.Count; i++ )
  509. {
  510. Handles.color = _target.pathColor;
  511. if( i < _target.nodes.Count - 1 )
  512. {
  513. Handles.DrawLine( _target.nodes[i], _target.nodes[i + 1] );
  514. drawArrowBetweenPoints( _target.nodes[i], _target.nodes[i + 1] );
  515. }
  516. }
  517. }
  518. }
  519.  
  520. #endregion
  521.  
  522. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement