public void SetCurveState(SerializedProperty curve, CurveState state) { if (!m_Curves.ContainsKey(curve)) throw new KeyNotFoundException("curve"); m_Curves[curve] = state; }
public void AddCurve(CurveState transition, double start, double end) { CurveTransition = transition; StartCurve = start; EndCurve = end; CurveStep = (EndCurve - StartCurve) / _segmentCount; }
public void SetCurveState(AnimationCurve curve, CurveState state) { if (!_mCurves.ContainsKey(curve)) { throw new KeyNotFoundException("curve"); } _mCurves[curve] = state; }
public void Add(SerializedProperty curve, CurveState state) { // Make sure the property is in fact an AnimationCurve var animCurve = curve.animationCurveValue; if (animCurve == null) throw new ArgumentException("curve"); if (m_Curves.ContainsKey(curve)) Debug.LogWarning("Curve has already been added to the editor"); m_Curves.Add(curve, state); }
void OnCurveGUI(Rect rect, SerializedProperty curve, CurveState state) { // Discard invisible curves if (!state.visible) { return; } var animCurve = curve.animationCurveValue; var keys = animCurve.keys; var length = keys.Length; // Curve drawing // Slightly dim non-editable curves var color = state.color; if (!state.editable) { color.a *= 0.5f; } Handles.color = color; var bounds = settings.bounds; if (length == 0) { var p1 = CurveToCanvas(new Vector3(bounds.xMin, state.zeroKeyConstantValue)); var p2 = CurveToCanvas(new Vector3(bounds.xMax, state.zeroKeyConstantValue)); Handles.DrawAAPolyLine(state.width, p1, p2); } else if (length == 1) { var p1 = CurveToCanvas(new Vector3(bounds.xMin, keys[0].value)); var p2 = CurveToCanvas(new Vector3(bounds.xMax, keys[0].value)); Handles.DrawAAPolyLine(state.width, p1, p2); } else { var prevKey = keys[0]; for (int k = 1; k < length; k++) { var key = keys[k]; var pts = BezierSegment(prevKey, key); if (float.IsInfinity(prevKey.outTangent) || float.IsInfinity(key.inTangent)) { var s = HardSegment(prevKey, key); Handles.DrawAAPolyLine(state.width, s[0], s[1], s[2]); } else { Handles.DrawBezier(pts[0], pts[3], pts[1], pts[2], color, null, state.width); } prevKey = key; } // Curve extents & loops if (keys[0].time > bounds.xMin) { if (state.loopInBounds) { var p1 = keys[length - 1]; p1.time -= settings.bounds.width; var p2 = keys[0]; var pts = BezierSegment(p1, p2); if (float.IsInfinity(p1.outTangent) || float.IsInfinity(p2.inTangent)) { var s = HardSegment(p1, p2); Handles.DrawAAPolyLine(state.width, s[0], s[1], s[2]); } else { Handles.DrawBezier(pts[0], pts[3], pts[1], pts[2], color, null, state.width); } } else { var p1 = CurveToCanvas(new Vector3(bounds.xMin, keys[0].value)); var p2 = CurveToCanvas(keys[0]); Handles.DrawAAPolyLine(state.width, p1, p2); } } if (keys[length - 1].time < bounds.xMax) { if (state.loopInBounds) { var p1 = keys[length - 1]; var p2 = keys[0]; p2.time += settings.bounds.width; var pts = BezierSegment(p1, p2); if (float.IsInfinity(p1.outTangent) || float.IsInfinity(p2.inTangent)) { var s = HardSegment(p1, p2); Handles.DrawAAPolyLine(state.width, s[0], s[1], s[2]); } else { Handles.DrawBezier(pts[0], pts[3], pts[1], pts[2], color, null, state.width); } } else { var p1 = CurveToCanvas(keys[length - 1]); var p2 = CurveToCanvas(new Vector3(bounds.xMax, keys[length - 1].value)); Handles.DrawAAPolyLine(state.width, p1, p2); } } } // Make sure selection is correct (undo can break it) bool isCurrentlySelectedCurve = curve == m_SelectedCurve; if (isCurrentlySelectedCurve && m_SelectedKeyframeIndex >= length) { m_SelectedKeyframeIndex = -1; } // Handles & keys for (int k = 0; k < length; k++) { bool isCurrentlySelectedKeyframe = k == m_SelectedKeyframeIndex; var e = Event.current; var pos = CurveToCanvas(keys[k]); var hitRect = new Rect(pos.x - 8f, pos.y - 8f, 16f, 16f); var offset = isCurrentlySelectedCurve ? new RectOffset(5, 5, 5, 5) : new RectOffset(6, 6, 6, 6); var outTangent = pos + CurveTangentToCanvas(keys[k].outTangent).normalized * 40f; var inTangent = pos - CurveTangentToCanvas(keys[k].inTangent).normalized * 40f; var inTangentHitRect = new Rect(inTangent.x - 7f, inTangent.y - 7f, 14f, 14f); var outTangentHitrect = new Rect(outTangent.x - 7f, outTangent.y - 7f, 14f, 14f); // Draw if (state.showNonEditableHandles) { if (e.type == EventType.Repaint) { var selectedColor = (isCurrentlySelectedCurve && isCurrentlySelectedKeyframe) ? settings.selectionColor : state.color; // Keyframe EditorGUI.DrawRect(offset.Remove(hitRect), selectedColor); // Tangents if (isCurrentlySelectedCurve && (!state.onlyShowHandlesOnSelection || (state.onlyShowHandlesOnSelection && isCurrentlySelectedKeyframe))) { Handles.color = selectedColor; if (k > 0 || state.loopInBounds) { Handles.DrawAAPolyLine(state.handleWidth, pos, inTangent); EditorGUI.DrawRect(offset.Remove(inTangentHitRect), selectedColor); } if (k < length - 1 || state.loopInBounds) { Handles.DrawAAPolyLine(state.handleWidth, pos, outTangent); EditorGUI.DrawRect(offset.Remove(outTangentHitrect), selectedColor); } } } } // Events if (state.editable) { // Keyframe move if (m_EditMode == EditMode.Moving && e.type == EventType.MouseDrag && isCurrentlySelectedCurve && isCurrentlySelectedKeyframe) { EditMoveKeyframe(animCurve, keys, k); } // Tangent editing if (m_EditMode == EditMode.TangentEdit && e.type == EventType.MouseDrag && isCurrentlySelectedCurve && isCurrentlySelectedKeyframe) { bool alreadyBroken = !(Mathf.Approximately(keys[k].inTangent, keys[k].outTangent) || (float.IsInfinity(keys[k].inTangent) && float.IsInfinity(keys[k].outTangent))); EditMoveTangent(animCurve, keys, k, m_TangentEditMode, e.shift || !(alreadyBroken || e.control)); } // Keyframe selection & context menu if (e.type == EventType.MouseDown && rect.Contains(e.mousePosition)) { if (hitRect.Contains(e.mousePosition)) { if (e.button == 0) { SelectKeyframe(curve, k); m_EditMode = EditMode.Moving; e.Use(); } else if (e.button == 1) { // Keyframe context menu var menu = new GenericMenu(); menu.AddItem(new GUIContent("Delete Key"), false, (x) => { var action = (MenuAction)x; var curveValue = action.curve.animationCurveValue; action.curve.serializedObject.Update(); RemoveKeyframe(curveValue, action.index); m_SelectedKeyframeIndex = -1; SaveCurve(action.curve, curveValue); action.curve.serializedObject.ApplyModifiedProperties(); }, new MenuAction(curve, k)); menu.ShowAsContext(); e.Use(); } } } // Tangent selection & edit mode if (e.type == EventType.MouseDown && rect.Contains(e.mousePosition)) { if (inTangentHitRect.Contains(e.mousePosition) && (k > 0 || state.loopInBounds)) { SelectKeyframe(curve, k); m_EditMode = EditMode.TangentEdit; m_TangentEditMode = Tangent.In; e.Use(); } else if (outTangentHitrect.Contains(e.mousePosition) && (k < length - 1 || state.loopInBounds)) { SelectKeyframe(curve, k); m_EditMode = EditMode.TangentEdit; m_TangentEditMode = Tangent.Out; e.Use(); } } // Mouse up - clean up states if (e.rawType == EventType.MouseUp && m_EditMode != EditMode.None) { m_EditMode = EditMode.None; } // Set cursors { EditorGUIUtility.AddCursorRect(hitRect, MouseCursor.MoveArrow); if (k > 0 || state.loopInBounds) { EditorGUIUtility.AddCursorRect(inTangentHitRect, MouseCursor.RotateArrow); } if (k < length - 1 || state.loopInBounds) { EditorGUIUtility.AddCursorRect(outTangentHitrect, MouseCursor.RotateArrow); } } } } Handles.color = Color.white; SaveCurve(curve, animCurve); }
public void Add(AnimationCurve curve, CurveState state) { _mCurves.Add(curve, state); }
void OnCurveGUI(Rect rect, SerializedProperty curve, CurveState state) { // Discard invisible curves if (!state.visible) return; var animCurve = curve.animationCurveValue; var keys = animCurve.keys; var length = keys.Length; // Curve drawing // Slightly dim non-editable curves var color = state.color; if (!state.editable) color.a *= 0.5f; Handles.color = color; var bounds = settings.bounds; if (length == 0) { var p1 = CurveToCanvas(new Vector3(bounds.xMin, state.zeroKeyConstantValue)); var p2 = CurveToCanvas(new Vector3(bounds.xMax, state.zeroKeyConstantValue)); Handles.DrawAAPolyLine(state.width, p1, p2); } else if (length == 1) { var p1 = CurveToCanvas(new Vector3(bounds.xMin, keys[0].value)); var p2 = CurveToCanvas(new Vector3(bounds.xMax, keys[0].value)); Handles.DrawAAPolyLine(state.width, p1, p2); } else { var prevKey = keys[0]; for (int k = 1; k < length; k++) { var key = keys[k]; var pts = BezierSegment(prevKey, key); if (float.IsInfinity(prevKey.outTangent) || float.IsInfinity(key.inTangent)) { var s = HardSegment(prevKey, key); Handles.DrawAAPolyLine(state.width, s[0], s[1], s[2]); } else Handles.DrawBezier(pts[0], pts[3], pts[1], pts[2], color, null, state.width); prevKey = key; } // Curve extents & loops if (keys[0].time > bounds.xMin) { if (state.loopInBounds) { var p1 = keys[length - 1]; p1.time -= settings.bounds.width; var p2 = keys[0]; var pts = BezierSegment(p1, p2); if (float.IsInfinity(p1.outTangent) || float.IsInfinity(p2.inTangent)) { var s = HardSegment(p1, p2); Handles.DrawAAPolyLine(state.width, s[0], s[1], s[2]); } else Handles.DrawBezier(pts[0], pts[3], pts[1], pts[2], color, null, state.width); } else { var p1 = CurveToCanvas(new Vector3(bounds.xMin, keys[0].value)); var p2 = CurveToCanvas(keys[0]); Handles.DrawAAPolyLine(state.width, p1, p2); } } if (keys[length - 1].time < bounds.xMax) { if (state.loopInBounds) { var p1 = keys[length - 1]; var p2 = keys[0]; p2.time += settings.bounds.width; var pts = BezierSegment(p1, p2); if (float.IsInfinity(p1.outTangent) || float.IsInfinity(p2.inTangent)) { var s = HardSegment(p1, p2); Handles.DrawAAPolyLine(state.width, s[0], s[1], s[2]); } else Handles.DrawBezier(pts[0], pts[3], pts[1], pts[2], color, null, state.width); } else { var p1 = CurveToCanvas(keys[length - 1]); var p2 = CurveToCanvas(new Vector3(bounds.xMax, keys[length - 1].value)); Handles.DrawAAPolyLine(state.width, p1, p2); } } } // Make sure selection is correct (undo can break it) bool isCurrentlySelectedCurve = curve == m_SelectedCurve; if (isCurrentlySelectedCurve && m_SelectedKeyframeIndex >= length) m_SelectedKeyframeIndex = -1; // Handles & keys for (int k = 0; k < length; k++) { bool isCurrentlySelectedKeyframe = k == m_SelectedKeyframeIndex; var e = Event.current; var pos = CurveToCanvas(keys[k]); var hitRect = new Rect(pos.x - 8f, pos.y - 8f, 16f, 16f); var offset = isCurrentlySelectedCurve ? new RectOffset(5, 5, 5, 5) : new RectOffset(6, 6, 6, 6); var outTangent = pos + CurveTangentToCanvas(keys[k].outTangent).normalized * 40f; var inTangent = pos - CurveTangentToCanvas(keys[k].inTangent).normalized * 40f; var inTangentHitRect = new Rect(inTangent.x - 7f, inTangent.y - 7f, 14f, 14f); var outTangentHitrect = new Rect(outTangent.x - 7f, outTangent.y - 7f, 14f, 14f); // Draw if (state.showNonEditableHandles) { if (e.type == EventType.repaint) { var selectedColor = (isCurrentlySelectedCurve && isCurrentlySelectedKeyframe) ? settings.selectionColor : state.color; // Keyframe EditorGUI.DrawRect(offset.Remove(hitRect), selectedColor); // Tangents if (isCurrentlySelectedCurve && (!state.onlyShowHandlesOnSelection || (state.onlyShowHandlesOnSelection && isCurrentlySelectedKeyframe))) { Handles.color = selectedColor; if (k > 0 || state.loopInBounds) { Handles.DrawAAPolyLine(state.handleWidth, pos, inTangent); EditorGUI.DrawRect(offset.Remove(inTangentHitRect), selectedColor); } if (k < length - 1 || state.loopInBounds) { Handles.DrawAAPolyLine(state.handleWidth, pos, outTangent); EditorGUI.DrawRect(offset.Remove(outTangentHitrect), selectedColor); } } } } // Events if (state.editable) { // Keyframe move if (m_EditMode == EditMode.Moving && e.type == EventType.MouseDrag && isCurrentlySelectedCurve && isCurrentlySelectedKeyframe) { EditMoveKeyframe(animCurve, keys, k); } // Tangent editing if (m_EditMode == EditMode.TangentEdit && e.type == EventType.MouseDrag && isCurrentlySelectedCurve && isCurrentlySelectedKeyframe) { bool alreadyBroken = !(Mathf.Approximately(keys[k].inTangent, keys[k].outTangent) || (float.IsInfinity(keys[k].inTangent) && float.IsInfinity(keys[k].outTangent))); EditMoveTangent(animCurve, keys, k, m_TangentEditMode, e.shift || !(alreadyBroken || e.control)); } // Keyframe selection if (e.type == EventType.mouseDown && rect.Contains(e.mousePosition)) { if (hitRect.Contains(e.mousePosition)) { SelectKeyframe(curve, k); m_EditMode = EditMode.Moving; e.Use(); } } // Tangent selection & edit mode if (e.type == EventType.mouseDown && rect.Contains(e.mousePosition)) { if (inTangentHitRect.Contains(e.mousePosition) && (k > 0 || state.loopInBounds)) { SelectKeyframe(curve, k); m_EditMode = EditMode.TangentEdit; m_TangentEditMode = Tangent.In; e.Use(); } else if (outTangentHitrect.Contains(e.mousePosition) && (k < length - 1 || state.loopInBounds)) { SelectKeyframe(curve, k); m_EditMode = EditMode.TangentEdit; m_TangentEditMode = Tangent.Out; e.Use(); } } // Mouse up - clean up states if (e.rawType == EventType.MouseUp && m_EditMode != EditMode.None) { m_EditMode = EditMode.None; } // Set cursors { EditorGUIUtility.AddCursorRect(hitRect, MouseCursor.MoveArrow); if (k > 0 || state.loopInBounds) EditorGUIUtility.AddCursorRect(inTangentHitRect, MouseCursor.RotateArrow); if (k < length - 1 || state.loopInBounds) EditorGUIUtility.AddCursorRect(outTangentHitrect, MouseCursor.RotateArrow); } } } Handles.color = Color.white; SaveCurve(curve, animCurve); }
private void GenerateRoad() { _roadParams = new RoadParameters { MaxHeight = 900, MaxCurve = 400, Length = 12, NumberOfZones = 12, Curvy = 0.8, Mountiany = 0.8, NumberOfSegmentsPerZone = 250, RoadSegmentSize = 5, NumberOfSegmentsPerColor = 4, OffRoadOffset = 130, }; _roadParams.Length = _roadParams.NumberOfZones * _roadParams.NumberOfSegmentsPerZone; _road = new List <RoadSegment>(); _roadZones = new List <RoadZone>(); HeightState currentStateHeight = HeightState.Flat; CurveState currentStateCurve = CurveState.Straight; var currentHeight = 0.0; var currentCurve = 0.0; var zones = _roadParams.NumberOfZones; while (zones-- > 0) { var zone = new RoadZone(_roadParams.NumberOfSegmentsPerZone); // Generate current zone var finalHeight = 0.0; switch (currentStateHeight) { case HeightState.Flat: { finalHeight = 0.0; break; } case HeightState.Up: { finalHeight = _roadParams.MaxHeight * _random.NextDouble(); break; } case HeightState.Down: { finalHeight = -_roadParams.MaxHeight * _random.NextDouble(); break; } } var finalCurve = 0.0; switch (currentStateCurve) { case CurveState.Straight: { finalCurve = 0.0; break; } case CurveState.Left: { finalCurve = -_roadParams.MaxCurve * _random.NextDouble(); break; } case CurveState.Right: { finalCurve = _roadParams.MaxCurve * _random.NextDouble(); break; } } zone.AddCurve(currentStateCurve, currentCurve, finalCurve); zone.AddHeight(currentStateHeight, currentHeight, finalHeight); for (int i = 0; i < _roadParams.NumberOfSegmentsPerZone; i++) { var segment = new RoadSegment { Height = zone.StartHeight + (zone.HeightStep * i), Curve = zone.StartCurve + (zone.CurveStep * i), SegmentSprite = SelectSegmentSprite(i) }; _road.Add(segment); zone.AddSegment(segment); } currentHeight = finalHeight; currentCurve = finalCurve; currentStateHeight = SelectNextZoneHeightTransition(); currentStateCurve = SelectNextZoneCurveTransition(); _roadZones.Add(zone); } }