//called whenever this inspector window is loaded public void OnEnable() { //we create a reference to our script object by passing in the target script = (BezierPathManager)target; //reposition handles of the first and last point to the waypoint //they only have one control point so we set the other one to zero BezierPoint first = script.bPoints[0]; first.cp[0].position = first.wp.position; BezierPoint last = script.bPoints[script.bPoints.Count - 1]; last.cp[1].position = last.wp.position; //recalculate path points script.CalculatePath(); }
//bezier path placement void PlaceBezierPoint(Vector3 placePos) { //create new bezier point property class BezierPoint newPoint = new BezierPoint(); //instantiate waypoint gameobject Transform wayp = new GameObject("Waypoint").transform; //assign waypoint to the class newPoint.wp = wayp; //same as above if (wpList.Count == 0) { pathMan.transform.position = placePos; } //position current waypoint at clicked position in scene view if (mode2D) { placePos.z = 0f; } wayp.position = placePos; //parent it to the defined path wayp.parent = pathMan.transform; //create new array with bezier point handle positions Transform left = new GameObject("Left").transform; Transform right = new GameObject("Right").transform; left.parent = right.parent = wayp; left.position = wayp.position + new Vector3(2, 0, 0); right.position = wayp.position + new Vector3(-2, 0, 0); newPoint.cp = new[] { left, right }; BezierPathManager thisPath = pathMan as BezierPathManager; //add waypoint to the list of waypoints thisPath.bPoints.Add(newPoint); thisPath.segmentDetail.Add(thisPath.pathDetail); //add waypoint to temporary list wpList.Add(wayp.gameObject); //rename waypoint to match the list count wayp.name = "Waypoint " + (wpList.Count - 1); //recalculate bezier path thisPath.CalculatePath(); }
//called whenever this inspector window is loaded public void OnEnable() { //we create a reference to our script object by passing in the target script = (BezierPathManager)target; //reposition handles of the first and last point to the waypoint //they only have one control point so we set the other one to zero BezierPoint first = script.bPoints[0]; first.cp[0].position = first.wp.position; BezierPoint last = script.bPoints[script.bPoints.Count - 1]; last.cp[1].position = last.wp.position; //recalculate path points script.CalculatePath(); }
//bezier path placement void PlaceBezierPoint(Vector3 placePos) { //create new bezier point property class BezierPoint newPoint = new BezierPoint(); //instantiate waypoint gameobject Transform wayp = new GameObject("Waypoint").transform; //assign waypoint to the class newPoint.wp = wayp; //same as above if (wpList.Count == 0) { pathMan.transform.position = placePos; } //position current waypoint at clicked position in scene view if (mode2D) { placePos.z = 0f; } wayp.position = placePos; //parent it to the defined path wayp.parent = pathMan.transform; BezierPathManager thisPath = pathMan as BezierPathManager; //create new array with bezier point handle positions Transform left = new GameObject("Left").transform; Transform right = new GameObject("Right").transform; left.parent = right.parent = wayp; //initialize positions and last waypoint Vector3 handleOffset = new Vector3(2, 0, 0); Vector3 targetDir = Vector3.zero; int lastIndex = wpList.Count - 1; //position handles to the left/right of the waypoint respectively left.position = wayp.position + wayp.rotation * handleOffset; right.position = wayp.position + wayp.rotation * -handleOffset; newPoint.cp = new[] { left, right }; //position first handle in direction of the second waypoint if (wpList.Count == 1) { targetDir = (wayp.position - wpList[0].transform.position).normalized; thisPath.bPoints[0].cp[1].localPosition = targetDir * 2; } //always position last handle to look at the previous waypoint else if (wpList.Count >= 1) { targetDir = (wpList[lastIndex].transform.position - wayp.position); wayp.transform.rotation = Quaternion.LookRotation(targetDir) * Quaternion.Euler(0, -90, 0); } //position handle direction to the center of both last and next waypoints //takes into account 2D mode if (wpList.Count >= 2) { //get last point and center direction BezierPoint lastPoint = thisPath.bPoints[lastIndex]; targetDir = (wayp.position - wpList[lastIndex].transform.position) + (wpList[lastIndex - 1].transform.position - wpList[lastIndex].transform.position); //rotate to the center 2D/3D Quaternion lookRot = Quaternion.LookRotation(targetDir); if (mode2D) { float angle = Mathf.Atan2(targetDir.y, targetDir.x) * Mathf.Rad2Deg + 90; lookRot = Quaternion.AngleAxis(angle, Vector3.forward); } lastPoint.wp.rotation = lookRot; //cache handle and get previous of last waypoint Vector3 leftPos = lastPoint.cp[0].position; Vector3 preLastPos = wpList[lastIndex - 1].transform.position; //calculate whether right or left handle distance is greater to last waypoint //left handle should point to the last waypoint, so reposition if necessary if (Vector3.Distance(leftPos, preLastPos) > Vector3.Distance(lastPoint.cp[1].position, preLastPos)) { lastPoint.cp[0].position = lastPoint.cp[1].position; lastPoint.cp[1].position = leftPos; } } //add waypoint to the list of waypoints thisPath.bPoints.Add(newPoint); thisPath.segmentDetail.Add(thisPath.pathDetail); //add waypoint to temporary list wpList.Add(wayp.gameObject); //rename waypoint to match the list count wayp.name = "Waypoint " + (wpList.Count - 1); //recalculate bezier path thisPath.CalculatePath(); }
public override void OnInspectorGUI() { //don't draw inspector fields if the path contains less than 2 points //(a path with less than 2 points really isn't a path) if (script.bPoints.Count < 2) { return; } //checkbox field to enable editable path properties script.showHandles = EditorGUILayout.Toggle("Show Handles", script.showHandles); //checkbox field for toggling control point connectedness script.connectHandles = EditorGUILayout.Toggle("Connect Handles", script.connectHandles); //checkbox field for drawing gizmo path lines script.drawCurved = EditorGUILayout.Toggle("Draw Smooth Lines", script.drawCurved); //create new color fields for editing path gizmo colors script.color1 = EditorGUILayout.ColorField("Color1", script.color1); script.color2 = EditorGUILayout.ColorField("Color2", script.color2); script.color3 = EditorGUILayout.ColorField("Color3", script.color3); //calculate path length of all waypoints float pathLength = WaypointManager.GetPathLength(script.pathPoints); //path length label, show calculated path length GUILayout.Label("Path Length: " + pathLength); float thisDetail = script.pathDetail; //slider to modify the smoothing factor of the final path, //round because of path point imprecision placement (micro loops) script.pathDetail = EditorGUILayout.Slider("Path Detail", script.pathDetail, 0.5f, 10); script.pathDetail = Mathf.Round(script.pathDetail * 10f) / 10f; //toggle custom detail when modifying the whole path if (thisDetail != script.pathDetail) { script.customDetail = false; } //draw custom detail settings EditorGUILayout.Space(); DetailSettings(); EditorGUILayout.Space(); //waypoint index header GUILayout.Label("Waypoints: ", EditorStyles.boldLabel); //loop through the waypoint array for (int i = 0; i < script.bPoints.Count; i++) { GUILayout.BeginHorizontal(); //indicate each array slot with index number in front of it GUILayout.Label(i + ".", GUILayout.Width(20)); //create an object field for every waypoint EditorGUILayout.ObjectField(script.bPoints[i].wp, typeof(Transform), true); //display an "Add Waypoint" button for every array row except the last one //on click we call AddWaypointAtIndex() to insert a new waypoint slot AFTER the selected slot if (i < script.bPoints.Count && GUILayout.Button("+", GUILayout.Width(30f))) { AddWaypointAtIndex(i); break; } //display an "Remove Waypoint" button for every array row except the first and last one //on click we call RemoveWaypointAtIndex() to delete the selected waypoint slot if (i > 0 && i < script.bPoints.Count - 1 && GUILayout.Button("-", GUILayout.Width(30f))) { RemoveWaypointAtIndex(i); break; } GUILayout.EndHorizontal(); } EditorGUILayout.Space(); EditorGUILayout.BeginHorizontal(); //button to rename waypoints to current index order if (GUILayout.Button("Rename Waypoints")) { string wpName = string.Empty; string[] nameSplit; for (int i = 0; i < script.bPoints.Count; i++) { //cache name and split into strings wpName = script.bPoints[i].wp.name; nameSplit = wpName.Split(' '); //ignore custom names and just rename if (!script.skipCustomNames) { wpName = "Waypoint " + i; } else if (nameSplit.Length == 2 && nameSplit[0] == "Waypoint") { //try parsing the current index and rename, //not ignoring custom names here int index; if (int.TryParse(nameSplit[1], out index)) { wpName = nameSplit[0] + " " + i; } } //set the desired index or leave it script.bPoints[i].wp.name = wpName; } } EditorGUILayout.LabelField("Skip Custom", GUILayout.Width(80)); script.skipCustomNames = EditorGUILayout.Toggle(script.skipCustomNames, GUILayout.Width(20)); EditorGUILayout.EndHorizontal(); //button to move all waypoints down to the ground if (GUILayout.Button("Place to Ground")) { //for each waypoint of this path foreach (BezierPoint bp in script.bPoints) { //define ray to cast downwards waypoint position Ray ray = new Ray(bp.wp.position + new Vector3(0, 2f, 0), -Vector3.up); Undo.RecordObject(bp.wp, "PlaceToGround"); RaycastHit hit; //cast ray against ground, if it hit: if (Physics.Raycast(ray, out hit, 100)) { //position waypoint to hit point bp.wp.position = hit.point; } //also try to raycast against 2D colliders RaycastHit2D hit2D = Physics2D.Raycast(ray.origin, -Vector2.up, 100); if (hit2D) { bp.wp.position = new Vector3(hit2D.point.x, hit2D.point.y, bp.wp.position.z); } } } //invert direction of whole path if (GUILayout.Button("Invert Direction")) { Undo.RecordObject(script, "Invert"); //to reverse the whole path we need to know where the waypoints were before //for this purpose a new copy must be created BezierPoint[] waypointCache = new BezierPoint[script.bPoints.Count]; for (int i = 0; i < waypointCache.Length; i++) { waypointCache[i] = script.bPoints[i]; } //reverse order based on the old list for (int i = 0; i < waypointCache.Length; i++) { BezierPoint currentPoint = script.bPoints[waypointCache.Length - 1 - i]; script.bPoints[waypointCache.Length - 1 - i] = waypointCache[i]; Vector3 leftHandle = currentPoint.cp[0].position; Undo.RecordObject(currentPoint.cp[0], "Invert"); Undo.RecordObject(currentPoint.cp[1], "Invert"); currentPoint.cp[0].position = currentPoint.cp[1].position; currentPoint.cp[1].position = leftHandle; } } EditorGUILayout.Space(); //draw object field for new waypoint object script.replaceObject = (GameObject)EditorGUILayout.ObjectField("Replace Object", script.replaceObject, typeof(GameObject), true); //replace all waypoints with the prefab if (GUILayout.Button("Replace Waypoints with Object")) { ReplaceWaypoints(); } //recalculate on inspector changes if (GUI.changed) { script.CalculatePath(); EditorUtility.SetDirty(target); } }
public override void OnInspectorGUI() { //don't draw inspector fields if the path contains less than 2 points //(a path with less than 2 points really isn't a path) if (script.bPoints.Count < 2) { //button to create path manually if (GUILayout.Button("Create Path from Children")) { Undo.RecordObject(script, "Create Path"); script.Create(); SceneView.RepaintAll(); } return; } //create new checkboxes for path gizmo property script.showHandles = EditorGUILayout.Toggle("Show Handles", script.showHandles); script.connectHandles = EditorGUILayout.Toggle("Connect Handles", script.connectHandles); script.drawCurved = EditorGUILayout.Toggle("Draw Smooth Lines", script.drawCurved); script.drawDirection = EditorGUILayout.Toggle("Draw Direction", script.drawDirection); //create new color fields for editing path gizmo colors script.color1 = EditorGUILayout.ColorField("Color1", script.color1); script.color2 = EditorGUILayout.ColorField("Color2", script.color2); script.color3 = EditorGUILayout.ColorField("Color3", script.color3); //calculate path length of all waypoints float pathLength = WaypointManager.GetPathLength(script.pathPoints); GUILayout.Label("Path Length: " + pathLength); float thisDetail = script.pathDetail; //slider to modify the smoothing factor of the final path, //round because of path point imprecision placement (micro loops) script.pathDetail = EditorGUILayout.Slider("Path Detail", script.pathDetail, 0.5f, 10); script.pathDetail = Mathf.Round(script.pathDetail * 10f) / 10f; //toggle custom detail when modifying the whole path if (thisDetail != script.pathDetail) { script.customDetail = false; } //draw custom detail settings DetailSettings(); //button for switching over to the WaypointManager for further path editing if (GUILayout.Button("Continue Editing")) { Selection.activeGameObject = (GameObject.FindObjectOfType(typeof(WaypointManager)) as WaypointManager).gameObject; WaypointEditor.ContinuePath(script); } //more path modifiers DrawPathOptions(); EditorGUILayout.Space(); //waypoint index header GUILayout.Label("Waypoints: ", EditorStyles.boldLabel); //loop through the waypoint array for (int i = 0; i < script.bPoints.Count; i++) { GUILayout.BeginHorizontal(); //indicate each array slot with index number in front of it GUILayout.Label(i + ".", GUILayout.Width(20)); //create an object field for every waypoint EditorGUILayout.ObjectField(script.bPoints[i].wp, typeof(Transform), true); //display an "Add Waypoint" button for every array row except the last one //on click we call AddWaypointAtIndex() to insert a new waypoint slot AFTER the selected slot if (i < script.bPoints.Count && GUILayout.Button("+", GUILayout.Width(30f))) { AddWaypointAtIndex(i); break; } //display an "Remove Waypoint" button for every array row except the first and last one //on click we call RemoveWaypointAtIndex() to delete the selected waypoint slot if (i > 0 && i < script.bPoints.Count - 1 && GUILayout.Button("-", GUILayout.Width(30f))) { RemoveWaypointAtIndex(i); break; } GUILayout.EndHorizontal(); } //recalculate on inspector changes if (GUI.changed) { script.CalculatePath(); EditorUtility.SetDirty(target); } }