private double ProjectMouse() { if (spline.pointCount == 0) { return(0.0); } float closestDistance = (Event.current.mousePosition - HandleUtility.WorldToGUIPoint(spline.GetPointPosition(0))).sqrMagnitude; double closestPercent = 0.0; double add = spline.moveStep; if (spline.type == Spline.Type.Linear) { add /= 2.0; } int count = 0; for (double i = add; i < 1.0; i += add) { SplineSample result = spline.Evaluate(i); Vector2 point = HandleUtility.WorldToGUIPoint(result.position); float dist = (point - Event.current.mousePosition).sqrMagnitude; if (dist < closestDistance) { closestDistance = dist; closestPercent = i; } count++; } return(closestPercent); }
public void Project(Vector3 point, SplineSample result, bool bypassCache = false) { if (_segments.Count == 0) { return; } int closestPath = 0; float closestDist = Mathf.Infinity; for (int i = 0; i < _segments.Count; i++) { if (!_segments[i].extruded && _segments[i].type == LevelSegment.Type.Extruded) { continue; } _segments[i].Project(point, resultAlloc, 0.0, 1.0, bypassCache ? SplinePath.EvaluateMode.Accurate : SplinePath.EvaluateMode.Cached); float dist = (resultAlloc.position - point).sqrMagnitude; if (dist < closestDist) { closestDist = dist; closestPath = i; result.CopyFrom(resultAlloc); } } result.percent = LocalToGlobalPercent(result.percent, closestPath); }
/// <summary> /// Evaluate the generated path of the segment. This is the path after the segment is extruded. /// </summary> /// <param name="percent">Percent along the segment path [0-1]</param> /// <param name="result">The SplineSample object to write the result into</param> /// <param name="mode">If set to EvaluateMode.Accurate, the actual spline will be evaluated instead of the cached samples.</param> public virtual void Evaluate(double percent, SplineSample result, EvaluateMode mode = EvaluateMode.Cached) { if (mode == EvaluateMode.Accurate) { spline.Evaluate(result, percent); return; } if (samples.Length == 0) { return; } percent = DMath.Clamp01(percent); int index = DMath.FloorInt(percent * (samples.Length - 1)); double percentExcess = (samples.Length - 1) * percent - index; if (result == null) { result = new SplineSample(); } result.CopyFrom(samples[index]); if (percentExcess > 0.0 && index < samples.Length - 1) { result.Lerp(samples[index + 1], percentExcess); } }
void Evaluate(double percent, SplineSample result) { if (samples.Length == 0) { return; } percent = DMath.Clamp01(percent); int index = DMath.FloorInt(percent * (samples.Length - 1)); double percentExcess = (samples.Length - 1) * percent - index; if (result == null) { result = new SplineSample(); } result.CopyFrom(samples[index]); if (percentExcess > 0.0 && index < samples.Length - 1) { result.Lerp(samples[index + 1], percentExcess); } if (useRelativeCoordinates) { result.position = trsMatrix.MultiplyPoint3x4(result.position); result.forward = trsMatrix.MultiplyVector(result.forward); result.up = trsMatrix.MultiplyVector(result.up); } }
protected override void OnPostGeneration(SplinePoint[] points) { base.OnPostGeneration(points); double range = 1.0 / segmentCount; double from = range * currentSegmentIndex; double to = range * (currentSegmentIndex + 1); SplineSample result = new SplineSample(); for (int i = 0; i < points.Length; i++) { double percent = DMath.Lerp(from, to, (double)i / (points.Length - 1)); Evaluate(percent, result); points[i].position = result.position; points[i].tangent2 = result.forward; points[i].normal = result.up; points[i].size = result.size; points[i].color = result.color; } for (int i = 0; i < points.Length; i++) { float pointDistance = 0f; if (i == 0) { pointDistance = Vector3.Distance(points[i].position, points[i + 1].position); } else { pointDistance = Vector3.Distance(points[i].position, points[i - 1].position); } points[i].tangent2 = points[i].position + points[i].tangent2 * pointDistance / 3f; points[i].tangent = points[i].position + (points[i].position - points[i].tangent2); } currentSegmentIndex++; }
public virtual void StartFollow() { if (LevelGenerator.instance == null || !LevelGenerator.instance.ready || LevelGenerator.instance.segments.Count == 0) { Debug.LogError(name + " Runner attempting to start following but the Level Generator isn't ready."); return; } int segmentIndex = 0; double localPercent = 0.0; switch (startMode) { case StartMode.Percent: localPercent = LevelGenerator.instance.GlobalToLocalPercent(startPercent, out segmentIndex); break; case StartMode.Distance: localPercent = LevelGenerator.instance.GlobalToLocalPercent(LevelGenerator.instance.Travel(0.0, startDistance, Spline.Direction.Forward), out segmentIndex); Debug.DrawRay(LevelGenerator.instance.EvaluatePosition(LevelGenerator.instance.Travel(0.0, startDistance, Spline.Direction.Forward)), Vector3.up * 10f, Color.red, 5f); break; case StartMode.Project: SplineSample result = new SplineSample(); LevelGenerator.instance.Project(transform.position, result); localPercent = LevelGenerator.instance.GlobalToLocalPercent(result.percent, out segmentIndex); break; } Init(LevelGenerator.instance.segments[segmentIndex], localPercent); follow = true; }
void AddConnection(SplineComputer computer, int pointIndex) { Node node = (Node)target; Node.Connection[] connections = node.GetConnections(); if (EditorUtility.DisplayDialog("Link point?", "Add point " + (pointIndex + 1) + " to connections?", "Yes", "No")) { Undo.RecordObject(addComp, "Add connection"); Undo.RecordObject(node, "Add Connection"); if (connections.Length == 0) { switch (EditorUtility.DisplayDialogComplex("Align node to point?", "This is the first connection for the node, would you like to snap or align the node's Transform the spline point.", "No", "Snap", "Snap and Align")) { case 1: SplinePoint point = addComp.GetPoint(pointIndex); node.transform.position = point.position; break; case 2: SplineSample result = addComp.Evaluate(pointIndex); node.transform.position = result.position; node.transform.rotation = result.rotation; break; } } computer.ConnectNode(node, pointIndex); addComp = null; addPoint = 0; SceneView.RepaintAll(); Repaint(); } }
public static double ScreenPointToSplinePercent(SplineComputer computer, Vector2 screenPoint) { SplinePoint[] points = computer.GetPoints(); float closestDistance = (screenPoint - HandleUtility.WorldToGUIPoint(points[0].position)).sqrMagnitude; double closestPercent = 0.0; double add = computer.moveStep; if (computer.type == Spline.Type.Linear) { add /= 2f; } int count = 0; for (double i = add; i < 1.0; i += add) { SplineSample result = computer.Evaluate(i); Vector2 point = HandleUtility.WorldToGUIPoint(result.position); float dist = (point - screenPoint).sqrMagnitude; if (dist < closestDistance) { closestDistance = dist; closestPercent = i; } count++; } return(closestPercent); }
public void DistributeEvenly() { if (selectedPoints.Count < 3) { return; } RecordUndo("Distribute Evenly"); int min = points.Length - 1, max = 0; for (int i = 0; i < selectedPoints.Count; i++) { if (selectedPoints[i] < min) { min = selectedPoints[i]; } if (selectedPoints[i] > max) { max = selectedPoints[i]; } } double minPercent = (double)min / (points.Length - 1); double maxPercent = (double)max / (points.Length - 1); float length = calculateLength(minPercent, maxPercent); float step = length / (max - min); SplineSample evalResult = new SplineSample(); evaluate(minPercent, evalResult); for (int i = min + 1; i < max; i++) { double percent = travel(evalResult.percent, step, Spline.Direction.Forward); evaluate(percent, evalResult); points[i].SetPosition(evalResult.position); } ResetCurrentModule(); }
protected void ApplyMotion(SplineSample SplineSample, MotionModule module) { module.SplineSample = SplineSample; #if UNITY_EDITOR if (!Application.isPlaying) { if (targetTransform == null) { RefreshTargets(); } if (targetTransform == null) { return; } module.ApplyTransform(targetTransform); return; } #endif switch (physicsMode) { case PhysicsMode.Transform: if (targetTransform == null) { RefreshTargets(); } if (targetTransform == null) { return; } module.ApplyTransform(targetTransform); break; case PhysicsMode.Rigidbody: if (targetRigidbody == null) { RefreshTargets(); if (targetRigidbody == null) { throw new MissingComponentException("There is no Rigidbody attached to " + name + " but the Physics mode is set to use one."); } } module.ApplyRigidbody(targetRigidbody); break; case PhysicsMode.Rigidbody2D: if (targetRigidbody2D == null) { RefreshTargets(); if (targetRigidbody2D == null) { throw new MissingComponentException("There is no Rigidbody2D attached to " + name + " but the Physics mode is set to use one."); } } module.ApplyRigidbody2D(targetRigidbody2D); break; } }
public static void DrawSpline(Spline spline, Color color, double from = 0.0, double to = 1.0, bool drawThickness = false, bool thicknessAutoRotate = false) { double add = spline.moveStep; if (add < 0.0025) add = 0.0025; Color prevColor = Handles.color; Handles.color = color; int iterations = spline.iterations; if (drawThickness) { Transform editorCamera = SceneView.currentDrawingSceneView.camera.transform; if (positions.Length != iterations * 6) positions = new Vector3[iterations * 6]; SplineSample prevResult = spline.Evaluate(from); Vector3 prevNormal = prevResult.up; if (thicknessAutoRotate) prevNormal = (editorCamera.position - prevResult.position).normalized; Vector3 prevRight = Vector3.Cross(prevResult.forward, prevNormal).normalized * prevResult.size * 0.5f; int pointIndex = 0; for (int i = 1; i < iterations; i++) { double p = DMath.Lerp(from, to, (double)i / (iterations - 1)); SplineSample newResult = spline.Evaluate(p); Vector3 newNormal = newResult.up; if (thicknessAutoRotate) newNormal = (editorCamera.position - newResult.position).normalized; Vector3 newRight = Vector3.Cross(newResult.forward, newNormal).normalized * newResult.size * 0.5f; positions[pointIndex] = prevResult.position + prevRight; positions[pointIndex + iterations * 2] = prevResult.position - prevRight; positions[pointIndex + iterations * 4] = newResult.position - newRight; pointIndex++; positions[pointIndex] = newResult.position + newRight; positions[pointIndex + iterations * 2] = newResult.position - newRight; positions[pointIndex + iterations * 4] = newResult.position + newRight; pointIndex++; prevResult = newResult; prevRight = newRight; prevNormal = newNormal; } } else { if (positions.Length != iterations * 2) positions = new Vector3[iterations * 2]; Vector3 prevPoint = spline.EvaluatePosition(from); int pointIndex = 0; for (int i = 1; i < iterations; i++) { double p = DMath.Lerp(from, to, (double)i / (iterations - 1)); positions[pointIndex] = prevPoint; pointIndex++; positions[pointIndex] = spline.EvaluatePosition(p); pointIndex++; prevPoint = positions[pointIndex - 1]; } } Handles.DrawLines(positions); Handles.color = prevColor; }
protected virtual void Evaluate(double percent, SplineSample result) { if (_segment.type == LevelSegment.Type.Custom && _segment.customMainPath >= 0 && _segment.customPaths.Length > 0) { _segment.customPaths[_segment.customMainPath].Evaluate(percent, result); } else { _segment.Evaluate(percent, result); } }
protected override void OnFollow(SplineSample followResult) { laneBlend = Mathf.MoveTowards(laneBlend, 1f, Time.deltaTime * laneSwitchSpeed); laneValue = Mathf.Lerp(lastLane, _lane, laneSwitchSpeedCurve.Evaluate(laneBlend)); if (useCustomPaths) //Custom lane following { if (customPathResults.Length < _segment.customPaths.Length) { SplineSample[] newResults = new SplineSample[_segment.customPaths.Length]; customPathResults.CopyTo(newResults, 0); customPathResults = newResults; for (int i = 0; i < customPathResults.Length; i++) { if (customPathResults[i] == null) { customPathResults[i] = new SplineSample(); } } } for (int i = 0; i < _segment.customPaths.Length; i++) { _segment.customPaths[i].Evaluate(_result.percent, customPathResults[i]); } if (_segment.customPaths.Length > 1) //Interpolate between custom paths { if (lane > _segment.customPaths.Length) { lane = _segment.customPaths.Length; } if (laneValue > _segment.customPaths.Length) { laneValue = _segment.customPaths.Length; } if (lastLane > _segment.customPaths.Length) { lastLane = _segment.customPaths.Length; } _result.CopyFrom(customPathResults[lastLane - 1]); _result.Lerp(customPathResults[lane - 1], Mathf.Abs(laneValue - lastLane)); ApplyMotion(_result, motion); return; } else if (_segment.customPaths.Length > 0) { _result.CopyFrom(customPathResults[0]); //Use custom path but apply offset } } laneModule.CopyFrom(motion); //Copy the motion from the existing module //Apply lane offset: laneModule.offset += Vector2.Lerp(-laneVector * width * 0.5f, laneVector * width * 0.5f, (laneValue - 1f) / (laneCount - 1)); ApplyMotion(_result, laneModule); }
protected override void Evaluate(double percent, SplineSample result) { if (usePreviousLane) { _segment.customPaths[_lastLane - 1].Evaluate(percent, result); } else { _segment.customPaths[_lane - 1].Evaluate(percent, result); } }
public void Evaluate(double percent, SplineSample result) { if (_segments.Count == 0) { return; } int pathIndex; double localPercent = GlobalToLocalPercent(percent, out pathIndex); _segments[pathIndex].Evaluate(localPercent, result); result.percent = percent; }
void SetTRS() { if (LevelGenerator.instance.segments.Count > 0) { SplineSample result = new SplineSample(); LevelGenerator.instance.Evaluate(1.0, result); trsMatrix.SetTRS(transform.InverseTransformPoint(result.position), Quaternion.Inverse(transform.rotation) * result.rotation, Vector3.one); } else { trsMatrix.SetTRS(Vector3.zero, Quaternion.identity, Vector3.one); } }
public override void Continue(LevelSegment segment) { base.Continue(segment); SplineSample sample = new SplineSample(); segment.Evaluate(1.0, sample); SplinePoint lastPoint = segment.path.spline.points[segment.path.spline.points.Length - 1]; lastPointHL.position = transform.InverseTransformPoint(lastPoint.position); lastPointHL.rotation = (Quaternion.Inverse(transform.rotation) * sample.rotation).eulerAngles; lastPointHL.size = sample.size; lastPointHL.color = sample.color; }
protected override void OnFollow(SplineSample followResult) { if (laneLerp != 1f) { usePreviousLane = true; Traverse(previousLaneResult); usePreviousLane = false; laneLerp = Mathf.MoveTowards(laneLerp, 1f, Time.deltaTime * laneSwitchSpeed); SplineSample.Lerp(previousLaneResult, _result, laneSwitchSpeedCurve.Evaluate(laneLerp), newLaneResult); followResult = newLaneResult; } base.OnFollow(followResult); }
void SetNormals(int mode) { mode--; Vector3 avg = Vector3.zero; for (int i = 0; i < selectedPoints.Count; i++) { avg += points[selectedPoints[i]].position; } if (selectedPoints.Count > 1) { avg /= selectedPoints.Count; } Camera editorCamera = SceneView.lastActiveSceneView.camera; for (int i = 0; i < selectedPoints.Count; i++) { switch (mode) { case 0: points[selectedPoints[i]].normal *= -1; break; case 1: points[selectedPoints[i]].normal = Vector3.Normalize(editorCamera.transform.position - points[selectedPoints[i]].position); break; case 2: points[selectedPoints[i]].normal = editorCamera.transform.forward; break; case 3: points[selectedPoints[i]].normal = CalculatePointNormal(points, selectedPoints[i], isClosed); break; case 4: points[selectedPoints[i]].normal = Vector3.left; break; case 5: points[selectedPoints[i]].normal = Vector3.right; break; case 6: points[selectedPoints[i]].normal = Vector3.up; break; case 7: points[selectedPoints[i]].normal = Vector3.down; break; case 8: points[selectedPoints[i]].normal = Vector3.forward; break; case 9: points[selectedPoints[i]].normal = Vector3.back; break; case 10: points[selectedPoints[i]].normal = Vector3.Normalize(avg - points[selectedPoints[i]].position); break; case 11: SplineSample result = new SplineSample(); editor.evaluateAtPoint(selectedPoints[i], result); points[selectedPoints[i]].normal = Vector3.Cross(result.forward, result.right).normalized; break; } } }
protected void DrawResult(SplineSample result) { SplineTracer tracer = (SplineTracer)target; Handles.color = Color.white; Handles.DrawLine(tracer.transform.position, result.position); SplineEditorHandles.DrawSolidSphere(result.position, HandleUtility.GetHandleSize(result.position) * 0.2f); Handles.color = Color.blue; Handles.DrawLine(result.position, result.position + result.forward * HandleUtility.GetHandleSize(result.position) * 0.5f); Handles.color = Color.green; Handles.DrawLine(result.position, result.position + result.up * HandleUtility.GetHandleSize(result.position) * 0.5f); Handles.color = Color.red; Handles.DrawLine(result.position, result.position + result.right * HandleUtility.GetHandleSize(result.position) * 0.5f); Handles.color = Color.white; }
protected override void KeyHandles(SplineSampleModifier.Key key, bool edit) { if (!isOpen) { return; } bool is2D = user.spline != null && user.spline.is2D; SplineSample result = new SplineSample(); List <SplineSampleModifier.Key> keys = module.GetKeys(); OffsetModifier.OffsetKey offsetKey = (OffsetModifier.OffsetKey)key; user.spline.Evaluate(offsetKey.position, result); matrix.SetTRS(result.position, Quaternion.LookRotation(result.direction, result.normal), Vector3.one * result.size); Vector3 pos = matrix.MultiplyPoint(offsetKey.offset); if (is2D) { Handles.DrawLine(result.position, result.position + result.right * offsetKey.offset.x * result.size); Handles.DrawLine(result.position, result.position - result.right * offsetKey.offset.x * result.size); } else { Handles.DrawWireDisc(result.position, result.direction, offsetKey.offset.magnitude * result.size); } Handles.DrawLine(result.position, pos); if (edit) { Vector3 lastPos = pos; pos = SplineEditorHandles.FreeMoveRectangle(pos, HandleUtility.GetHandleSize(pos) * 0.1f); if (pos != lastPos) { pos = matrix.inverse.MultiplyPoint(pos); pos.z = 0f; if (is2D) { offsetKey.offset = Vector2.right * pos.x; } else { offsetKey.offset = pos; } user.Rebuild(); } } base.KeyHandles(key, edit); }
protected void OffsetPoints(SplinePoint[] points, Vector3 offset, Space space) { if (offset != Vector3.zero) { segment.stitch = false; } SplineSample result = new SplineSample(); if (space == Space.Self && segment.previous != null) { segment.previous.Evaluate(1.0, result); } for (int i = 0; i < points.Length; i++) { points[i].SetPosition(points[i].position + offset); } }
internal void CopyFrom(MotionModule input) { enabled = input.enabled; offset = input.offset; useSplineSizes = input.useSplineSizes; rotationOffset = input.rotationOffset; baseScale = input.baseScale; SplineSample = input.SplineSample; applyPositionX = input.applyPositionX; applyPositionY = input.applyPositionY; applyPositionZ = input.applyPositionZ; applyRotationX = input.applyRotationX; applyRotationY = input.applyRotationY; applyRotationZ = input.applyRotationZ; applyScaleX = input.applyScaleX; applyScaleY = input.applyScaleY; applyScaleZ = input.applyScaleZ; }
protected void OffsetPoints(SplinePoint[] points, Vector3 offset, Space space) { if (offset != Vector3.zero) { segment.stitch = false; } SplineSample result = new SplineSample(); if (space == Space.Self && segment.previous != null) { segment.previous.Evaluate(1.0, result); offset = result.forward * offset.z + result.right * offset.x + result.up * offset.y; } transform.InverseTransformDirection(offset); for (int i = 0; i < points.Length; i++) { points[i].SetPosition(points[i].position + offset); } }
protected override void KeyHandles(SplineSampleModifier.Key key, bool edit) { RotationModifier.RotationKey rotationKey = (RotationModifier.RotationKey)key; SplineSample result = new SplineSample(); user.spline.Evaluate(rotationKey.position, result); if (rotationKey.useLookTarget) { if (rotationKey.target != null) { Handles.DrawDottedLine(result.position, rotationKey.target.position, 5f); if (edit) { Vector3 lastPos = rotationKey.target.position; rotationKey.target.position = Handles.PositionHandle(rotationKey.target.position, Quaternion.identity); if (lastPos != rotationKey.target.position) { user.Rebuild(); } } } } else { Quaternion directionRot = Quaternion.LookRotation(result.forward, result.up); Quaternion rot = directionRot * Quaternion.Euler(rotationKey.rotation); SplineEditorHandles.DrawArrowCap(result.position, rot, HandleUtility.GetHandleSize(result.position)); if (edit) { Vector3 lastEuler = rot.eulerAngles; rot = Handles.RotationHandle(rot, result.position); rot = Quaternion.Inverse(directionRot) * rot; rotationKey.rotation = rot.eulerAngles; if (rot.eulerAngles != lastEuler) { user.Rebuild(); } } } base.KeyHandles(key, edit); }
public override void DrawScene() { bool change = false; Camera editorCamera = SceneView.currentDrawingSceneView.camera; for (int i = 0; i < spline.pointCount; i++) { Vector3 pos = spline.GetPointPosition(i); if (SplineEditorHandles.CircleButton(pos, Quaternion.LookRotation(editorCamera.transform.position - pos), HandleUtility.GetHandleSize(pos) * 0.12f, 1f, spline.editorPathColor)) { SplitAtPoint(i); change = true; break; } } SplineSample projected = spline.Evaluate(ProjectMouse()); if (!change) { float pointValue = (float)projected.percent * (spline.pointCount - 1); int pointIndex = Mathf.FloorToInt(pointValue); float size = HandleUtility.GetHandleSize(projected.position) * 0.3f; Vector3 up = Vector3.Cross(editorCamera.transform.forward, projected.forward).normalized *size + projected.position; Vector3 down = Vector3.Cross(projected.forward, editorCamera.transform.forward).normalized *size + projected.position; Handles.color = spline.editorPathColor; Handles.DrawLine(up, down); Handles.color = Color.white; if (pointValue - pointIndex > spline.moveStep) { if (SplineEditorHandles.CircleButton(projected.position, Quaternion.LookRotation(editorCamera.transform.position - projected.position), HandleUtility.GetHandleSize(projected.position) * 0.12f, 1f, spline.editorPathColor)) { SplitAtPercent(projected.percent); change = true; } } SceneView.RepaintAll(); } Handles.color = Color.white; SplineDrawer.DrawSplineComputer(spline, 0.0, projected.percent, 1f); SplineDrawer.DrawSplineComputer(spline, projected.percent, 1.0, 0.4f); }
protected void Traverse(SplineSample input) { float absFollowSpeed = followSpeed; Spline.Direction direction = Spline.Direction.Forward; if (absFollowSpeed < 0f) { absFollowSpeed *= -1f; direction = Spline.Direction.Backward; } float travelDistance = Time.deltaTime * absFollowSpeed; float traveled; Evaluate(Travel(input.percent, travelDistance, direction, out traveled), input); if (traveled < travelDistance && ((direction == Spline.Direction.Forward && input.percent > 0.99999) || (direction == Spline.Direction.Backward && input.percent < 0.00001))) { //we have reached the end of the segment if (direction == Spline.Direction.Forward) { if (_segment.next != null) { _segment = _segment.next; OnEnteredSegment(_segment); Evaluate(Travel(0.0, travelDistance - traveled, direction, out traveled), input); } } else { if (_segment.previous != null) { _segment = _segment.previous; OnEnteredSegment(_segment); Evaluate(Travel(1.0, travelDistance - traveled, direction, out traveled), input); } } } }
public static void DrawSplineComputer(SplineComputer comp, double fromPercent = 0.0, double toPercent = 1.0, float alpha = 1f) { if (comp == null) { return; } Color prevColor = Handles.color; Color orange = new Color(1f, 0.564f, 0f); Color handleColor = comp.editorPathColor; handleColor.a = alpha; Handles.color = handleColor; if (comp.pointCount < 2) { return; } if (comp.type == Spline.Type.BSpline && comp.pointCount > 1) { SplinePoint[] compPoints = comp.GetPoints(); Handles.color = new Color(handleColor.r, handleColor.g, handleColor.b, 0.5f * alpha); for (int i = 0; i < compPoints.Length - 1; i++) { Handles.DrawLine(compPoints[i].position, compPoints[i + 1].position); } Handles.color = handleColor; } if (!comp.drawThinckness) { if (positions.Length != comp.sampleCount * 2) { positions = new Vector3[comp.sampleCount * 2]; } Vector3 prevPoint = comp.EvaluatePosition(fromPercent); int pointIndex = 0; for (int i = 1; i < comp.sampleCount; i++) { positions[pointIndex] = prevPoint; pointIndex++; positions[pointIndex] = comp.samples[i].position; pointIndex++; prevPoint = positions[pointIndex - 1]; } Handles.DrawLines(positions); } else { Transform editorCamera = SceneView.currentDrawingSceneView.camera.transform; if (positions.Length != comp.sampleCount * 6) { positions = new Vector3[comp.sampleCount * 6]; } SplineSample prevResult = comp.Evaluate(fromPercent); Vector3 prevNormal = prevResult.normal; if (comp.billboardThickness) { prevNormal = (editorCamera.position - prevResult.position).normalized; } Vector3 prevRight = Vector3.Cross(prevResult.direction, prevNormal).normalized *prevResult.size * 0.5f; int pointIndex = 0; for (int i = 1; i < comp.sampleCount; i++) { SplineSample newResult = comp.samples[i]; Vector3 newNormal = newResult.normal; if (comp.billboardThickness) { newNormal = (editorCamera.position - newResult.position).normalized; } Vector3 newRight = Vector3.Cross(newResult.direction, newNormal).normalized *newResult.size * 0.5f; positions[pointIndex] = prevResult.position + prevRight; positions[pointIndex + comp.sampleCount * 2] = prevResult.position - prevRight; positions[pointIndex + comp.sampleCount * 4] = newResult.position - newRight; pointIndex++; positions[pointIndex] = newResult.position + newRight; positions[pointIndex + comp.sampleCount * 2] = newResult.position - newRight; positions[pointIndex + comp.sampleCount * 4] = newResult.position + newRight; pointIndex++; prevResult = newResult; prevRight = newRight; prevNormal = newNormal; } Handles.DrawLines(positions); } Handles.color = prevColor; }
IEnumerator CreateSegment() { while (!levels[levelIndex].isReady && !testMode) { yield return(null); } HandleLevelChange(); while (LevelSegment.generationState != LevelSegment.GenerationState.Idle) { yield return(null); } if (levels[levelIndex].IsDone() && !testMode) { yield break; } LevelSegment segment = null; if (testMode) { GameObject go = Instantiate(debugSegments[Random.Range(0, debugSegments.Length)]); segment = go.GetComponent <LevelSegment>(); } else { segment = levels[levelIndex].InstantiateSegment(); } Transform segmentTrs = segment.transform; Vector3 spawnPos = segmentTrs.position; Quaternion spawnRot = segmentTrs.rotation; if (segments.Count > 0) { SplineSample lastSegmentEndResult = new SplineSample(); _segments[_segments.Count - 1].Evaluate(1.0, lastSegmentEndResult); spawnPos = lastSegmentEndResult.position; spawnRot = lastSegmentEndResult.rotation; switch (segment.axis) { case LevelSegment.Axis.X: spawnRot = Quaternion.AngleAxis(90f, Vector3.up) * spawnRot; break; case LevelSegment.Axis.Y: spawnRot = Quaternion.AngleAxis(90f, Vector3.right) * spawnRot; break; } } segmentTrs.position = spawnPos; if (segment.objectProperties[0].extrusionSettings.applyRotation) { segmentTrs.rotation = spawnRot; } if (segment.type == LevelSegment.Type.Extruded) { switch (segment.axis) { case LevelSegment.Axis.X: segment.transform.position += segment.transform.right * segment.GetBounds().size.x; break; case LevelSegment.Axis.Y: segment.transform.position += segment.transform.up * segment.GetBounds().size.y; break; case LevelSegment.Axis.Z: segment.transform.position += segment.transform.forward * segment.GetBounds().size.z; break; } } if (_segments.Count > 0) { segment.previous = _segments[_segments.Count - 1]; } segment.level = levels[levelIndex]; if (segment.type == LevelSegment.Type.Custom) { Quaternion entranceRotationDelta = segment.customEntrance.rotation * Quaternion.Inverse(spawnRot); segment.transform.rotation = segment.transform.rotation * Quaternion.Inverse(entranceRotationDelta); if (segment.customKeepUpright) { segment.transform.rotation = Quaternion.FromToRotation(segment.customEntrance.up, Vector3.up) * segment.transform.rotation; } Vector3 entranceOffset = segment.transform.position - segment.customEntrance.position; segment.transform.position = spawnPos + entranceOffset; } if (segmentIndex == int.MaxValue) { segmentIndex = 2; } segment.Initialize(segmentIndex++); segment.transform.parent = transform; currentPathGenerator.GeneratePath(segment); _segments.Add(segment); //Remove old segments if (type == Type.Infinite && _segments.Count > maxSegments) { StartCoroutine(CleanupRoutine()); } if (levels[levelIndex].IsDone() && !testMode) { if (levelIteration == LevelIteration.Ordered && levelIndex >= levels.Length - 1) { if (onLevelsDepleted != null) { onLevelsDepleted(); } yield break; } if (levelIteration == LevelIteration.None) { if (onLevelsDepleted != null) { onLevelsDepleted(); } yield break; } NextLevel(); } }
/// <summary> /// Project a world space point onto the spline and write to a SplineSample. /// </summary> /// <param name="point">3D Point in world space</param> /// <param name="result">The SplineSample object to write the result into</param> /// <param name="from">Sample from [0-1] default: 0.0</param> /// <param name="to">Sample to [0-1] default: 1.0</param> /// <returns></returns> public virtual void Project(Vector3 point, SplineSample result, double from = 0.0, double to = 1.0, EvaluateMode mode = EvaluateMode.Cached) { if (mode == EvaluateMode.Accurate) { spline.Evaluate(result, spline.Project(point, 4, from, to)); return; } if (samples.Length == 0) { return; } if (samples.Length == 1) { if (result == null) { result = new SplineSample(samples[0]); } else { result.CopyFrom(samples[0]); } return; } //First make a very rough sample of the from-to region int steps = 2; if (spline != null) { steps = (spline.points.Length - 1) * 6; //Sampling six points per segment is enough to find the closest point range } int step = samples.Length / steps; if (step < 1) { step = 1; } float minDist = (point - samples[0].position).sqrMagnitude; int fromIndex = 0; int toIndex = samples.Length - 1; if (from != 0.0) { fromIndex = DMath.FloorInt(from * (samples.Length - 1)); } if (to != 1.0) { toIndex = Mathf.CeilToInt((float)to * (samples.Length - 1)); } int checkFrom = fromIndex; int checkTo = toIndex; //Find the closest point range which will be checked in detail later for (int i = fromIndex; i <= toIndex; i += step) { if (i > toIndex) { i = toIndex; } float dist = (point - samples[i].position).sqrMagnitude; if (dist < minDist) { minDist = dist; checkFrom = Mathf.Max(i - step, 0); checkTo = Mathf.Min(i + step, samples.Length - 1); } if (i == toIndex) { break; } } minDist = (point - samples[checkFrom].position).sqrMagnitude; int index = checkFrom; //Find the closest result within the range for (int i = checkFrom + 1; i <= checkTo; i++) { float dist = (point - samples[i].position).sqrMagnitude; if (dist < minDist) { minDist = dist; index = i; } } //Project the point on the line between the two closest samples int backIndex = index - 1; if (backIndex < 0) { backIndex = 0; } int frontIndex = index + 1; if (frontIndex > samples.Length - 1) { frontIndex = samples.Length - 1; } Vector3 back = LinearAlgebraUtility.ProjectOnLine(samples[backIndex].position, samples[index].position, point); Vector3 front = LinearAlgebraUtility.ProjectOnLine(samples[index].position, samples[frontIndex].position, point); float backLength = (samples[index].position - samples[backIndex].position).magnitude; float frontLength = (samples[index].position - samples[frontIndex].position).magnitude; float backProjectDist = (back - samples[backIndex].position).magnitude; float frontProjectDist = (front - samples[frontIndex].position).magnitude; if (backIndex < index && index < frontIndex) { if ((point - back).sqrMagnitude < (point - front).sqrMagnitude) { SplineSample.Lerp(samples[backIndex], samples[index], backProjectDist / backLength, result); } else { SplineSample.Lerp(samples[frontIndex], samples[index], frontProjectDist / frontLength, result); } } else if (backIndex < index) { SplineSample.Lerp(samples[backIndex], samples[index], backProjectDist / backLength, result); } else { SplineSample.Lerp(samples[frontIndex], samples[index], frontProjectDist / frontLength, result); } }