/// <summary> /// Changes the current path of this object and starts movement. /// <summary> public void SetPath(BezierPathManager newPath) { //disable any running movement methods Stop(); //set new path container pathContainer = newPath; //restart movement StartMove(); }
//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(); }
//differ between path selection void StartPath() { switch (pathType) { case PathType.standard: pathMan = path.AddComponent <PathManager>(); pathMan.waypoints = new Transform[0]; break; case PathType.bezier: pathMan = path.AddComponent <BezierPathManager>(); BezierPathManager thisPath = pathMan as BezierPathManager; thisPath.showHandles = true; thisPath.bPoints = new List <BezierPoint>(); break; } }
//EXPERIMENTAL //called on every tween update for lerping rotation between waypoints private void OnWaypointRotation() { int lookPoint = currentPoint; lookPoint = Mathf.Clamp(pathContainer.GetWaypointIndex(currentPoint), 0, pathContainer.GetWaypointCount()); if (!tween.IsInitialized() || tween.IsComplete()) { ApplyWaypointRotation(pathContainer.GetWaypoint(lookPoint).rotation); return; } TweenerCore <Vector3, Path, PathOptions> tweenPath = tween as TweenerCore <Vector3, Path, PathOptions>; float currentDist = tweenPath.PathLength() * tweenPath.ElapsedPercentage(); float pathLength = 0f; float currentPerc = 0f; int targetPoint = currentPoint; if (moveToPath) { pathLength = tweenPath.changeValue.wpLengths[1]; currentPerc = currentDist / pathLength; ApplyWaypointRotation(Quaternion.Lerp(originRot, pathContainer.GetWaypoint(currentPoint).rotation, currentPerc)); return; } if (pathContainer is BezierPathManager) { BezierPathManager bPath = pathContainer as BezierPathManager; int curPoint = currentPoint; if (reverse) { targetPoint = bPath.GetWaypointCount() - 2 - (waypoints.Length - currentPoint - 1); curPoint = (bPath.bPoints.Count - 2) - targetPoint; } int prevPoints = (int)(curPoint * bPath.pathDetail * 10); if (bPath.customDetail) { prevPoints = 0; for (int i = 0; i < targetPoint; i++) { prevPoints += (int)(bPath.segmentDetail[i] * 10); } } if (reverse) { for (int i = 0; i <= curPoint * 10; i++) { currentDist -= tweenPath.changeValue.wpLengths[i]; } } else { for (int i = 0; i <= prevPoints; i++) { currentDist -= tweenPath.changeValue.wpLengths[i]; } } if (bPath.customDetail) { for (int i = prevPoints + 1; i <= prevPoints + bPath.segmentDetail[currentPoint] * 10; i++) { pathLength += tweenPath.changeValue.wpLengths[i]; } } else { for (int i = prevPoints + 1; i <= prevPoints + 10; i++) { pathLength += tweenPath.changeValue.wpLengths[i]; } } } else { if (reverse) { targetPoint = waypoints.Length - currentPoint - 1; } for (int i = 0; i <= targetPoint; i++) { currentDist -= tweenPath.changeValue.wpLengths[i]; } pathLength = tweenPath.changeValue.wpLengths[targetPoint + 1]; } currentPerc = currentDist / pathLength; if (pathContainer is BezierPathManager) { lookPoint = targetPoint; if (reverse) { lookPoint++; } } currentPerc = Mathf.Clamp01(currentPerc); ApplyWaypointRotation(Quaternion.Lerp(pathContainer.GetWaypoint(lookPoint).rotation, pathContainer.GetWaypoint(reverse ? lookPoint - 1 : lookPoint + 1).rotation, currentPerc)); }
//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(); }
//EXPERIMENTAL //called on every tween update for lerping rotation between waypoints private void OnWaypointRotation() { int lookPoint = currentPoint; lookPoint = Mathf.Clamp(pathContainer.GetWaypointIndex(currentPoint), 0, pathContainer.GetWaypointCount()); if (!tween.IsInitialized() || tween.IsComplete()) { ApplyWaypointRotation(pathContainer.GetWaypoint(lookPoint).rotation); return; } TweenerCore <Vector3, Path, PathOptions> tweenPath = tween as TweenerCore <Vector3, Path, PathOptions>; float currentDist = tweenPath.PathLength() * tweenPath.ElapsedPercentage(); float pathLength = 0f; float currentPerc = 0f; int targetPoint = currentPoint; if (moveToPath) { pathLength = tweenPath.changeValue.wpLengths[1]; currentPerc = currentDist / pathLength; ApplyWaypointRotation(Quaternion.Lerp(originRot, pathContainer.GetWaypoint(currentPoint).rotation, currentPerc)); return; } if (pathContainer is BezierPathManager) { BezierPathManager bPath = pathContainer as BezierPathManager; int curPoint = currentPoint; if (reverse) { targetPoint = bPath.GetWaypointCount() - 2 - (waypoints.Length - currentPoint - 1); curPoint = (bPath.bPoints.Count - 2) - targetPoint; } int prevPoints = (int)(curPoint * bPath.pathDetail * 10); if (bPath.customDetail) { prevPoints = 0; for (int i = 0; i < targetPoint; i++) { prevPoints += (int)(bPath.segmentDetail[i] * 10); } } if (reverse) { for (int i = 0; i <= curPoint * 10; i++) { currentDist -= tweenPath.changeValue.wpLengths[i]; } } else { for (int i = 0; i <= prevPoints; i++) { currentDist -= tweenPath.changeValue.wpLengths[i]; } } if (bPath.customDetail) { for (int i = prevPoints + 1; i <= prevPoints + bPath.segmentDetail[currentPoint] * 10; i++) { pathLength += tweenPath.changeValue.wpLengths[i]; } } else { for (int i = prevPoints + 1; i <= prevPoints + 10; i++) { pathLength += tweenPath.changeValue.wpLengths[i]; } } } else { if (reverse) { targetPoint = waypoints.Length - currentPoint - 1; } for (int i = 0; i <= targetPoint; i++) { currentDist -= tweenPath.changeValue.wpLengths[i]; } pathLength = tweenPath.changeValue.wpLengths[targetPoint + 1]; } currentPerc = currentDist / pathLength; if (pathContainer is BezierPathManager) { lookPoint = targetPoint; if (reverse) { lookPoint++; } } currentPerc = Mathf.Clamp01(currentPerc); //ApplyWaypointRotation(Quaternion.Lerp(pathContainer.GetWaypoint(lookPoint).rotation, pathContainer.GetWaypoint(reverse ? lookPoint - 1 : lookPoint + 1).rotation, currentPerc)); Vector3 nextPos = tween.PathGetPoint(tweenPath.ElapsedPercentage() + 0.01f); if (local) { nextPos = pathContainer.transform.TransformPoint(nextPos); } rotationTarget.LookAt(nextPos); Transform tfm = pathContainer.GetWaypoint(reverse ? lookPoint - 1 : lookPoint + 1); Quaternion q = Quaternion.FromToRotation(Vector3.forward, forwardDir); rotationTarget.rotation *= q; //q = Quaternion.Lerp(pathContainer.GetWaypoint(lookPoint).rotation, tfm.rotation, currentPerc); //rotationTarget.rotation = q * rotationTarget.rotation; q = Quaternion.Lerp(pathContainer.GetWaypoint(lookPoint).localRotation, tfm.localRotation, currentPerc); rotationTarget.localRotation *= q; rotationTarget.Rotate(eulerAngles); }