protected override bool OnMouseMove(InputState state) { if (dragging) { Debug.Assert(state.Mouse.PositionMouseDown != null); // don't start rotating until we're moved a minimum distance away from the mouse down location, // else it can have an annoying effect. startRotation |= Vector2Extensions.Distance(state.Mouse.Position, state.Mouse.PositionMouseDown.Value) > 30; if (startRotation) { Vector2 offset = state.Mouse.Position - state.Mouse.PositionMouseDown.Value; float degrees = (float)MathHelper.RadiansToDegrees(Math.Atan2(-offset.X, offset.Y)) + 24.3f; // Always rotate in the direction of least distance float diff = (degrees - ActiveCursor.Rotation) % 360; if (diff < -180) { diff += 360; } if (diff > 180) { diff -= 360; } degrees = ActiveCursor.Rotation + diff; ActiveCursor.RotateTo(degrees, 600, Easing.OutQuint); } } return(base.OnMouseMove(state)); }
public virtual void HandleMousePositionChange(InputState state) { var mouse = state.Mouse; foreach (var h in InputHandlers) { if (h.Enabled && h is INeedsMousePositionFeedback handler) { handler.FeedbackMousePositionChange(mouse.Position); } } handleMouseMove(state); if (!dragStarted) { if (mouse.IsPressed(MouseButton.Left) && Vector2Extensions.Distance(mouse.PositionMouseDown ?? mouse.Position, mouse.Position) > click_drag_distance) { handleMouseDragStart(state); } } else { handleMouseDrag(state); } }
private IEnumerable <Vector2> getPolygonAngles(float offset, int sides, int projectiles) { var angles = new List <Vector2>(); var points = getPolygonPoints(sides).ToArray(); var sideLen = Vector2Extensions.Distance(points[0], points[1]); var space = sideLen / (int)(projectiles / sides); for (var i = 0; i < points.Length; i++) { var point = points[i]; var nextPoint = points[(i + 1) % points.Length]; var angle = Math.Atan2(nextPoint.Y - point.Y, nextPoint.X - point.X); var xT = Math.Cos(angle) * space; var yT = Math.Sin(angle) * space; for (var j = 0; j < projectiles / sides; j++) { var x = point.X + xT * j; var y = point.Y + yT * j; var xRot = x * Math.Cos(offset) - y * Math.Sin(offset); var yRot = x * Math.Sin(offset) + y * Math.Cos(offset); angles.Add(new Vector2((float)xRot, (float)yRot)); } } return(angles); }
protected override bool OnClick(ClickEvent e) { var relativePos = (e.ScreenSpaceMouseDownPosition - ScreenSpaceDrawQuad.Centre) / SkeletonDrawScale; var distances = Skeleton.Bones.Select(b => Vector2Extensions.Distance(b.Root2D, relativePos)); var close = Skeleton.Bones.Zip(distances, (bone, distance) => (bone, distance)) .Where(b => b.distance < MathF.Sqrt(2) * KinematicsDrawNode.BONE_NODE_SIZE) .OrderBy(b => b.distance); if (close.Count() > 0) { BoneClicked?.Invoke(close.First().bone); return(true); } return(base.OnClick(e)); }
public virtual void HandlePositionChange(InputState state, Vector2 lastPosition) { if (EnableDrag) { if (!DragStarted) { var mouse = state.Mouse; if (mouse.IsPressed(Button) && Vector2Extensions.Distance(MouseDownPosition ?? mouse.Position, mouse.Position) > ClickDragDistance) { HandleMouseDragStart(state); } } else { HandleMouseDrag(state, lastPosition); } } }
private void applyStackingOld(Beatmap <OsuHitObject> beatmap) { for (int i = 0; i < beatmap.HitObjects.Count; i++) { OsuHitObject currHitObject = beatmap.HitObjects[i]; if (currHitObject.StackHeight != 0 && !(currHitObject is Slider)) { continue; } double startTime = currHitObject.GetEndTime(); int sliderStack = 0; for (int j = i + 1; j < beatmap.HitObjects.Count; j++) { double stackThreshold = beatmap.HitObjects[i].TimePreempt * beatmap.BeatmapInfo.StackLeniency; if (beatmap.HitObjects[j].StartTime - stackThreshold > startTime) { break; } // The start position of the hitobject, or the position at the end of the path if the hitobject is a slider Vector2 position2 = currHitObject is Slider currSlider ? currSlider.Position + currSlider.Path.PositionAt(1) : currHitObject.Position; if (Vector2Extensions.Distance(beatmap.HitObjects[j].Position, currHitObject.Position) < stack_distance) { currHitObject.StackHeight++; startTime = beatmap.HitObjects[j].GetEndTime(); } else if (Vector2Extensions.Distance(beatmap.HitObjects[j].Position, position2) < stack_distance) { //Case for sliders - bump notes down and right, rather than up and left. sliderStack++; beatmap.HitObjects[j].StackHeight -= sliderStack; startTime = beatmap.HitObjects[j].GetEndTime(); } } } }
/// <summary> /// Add a caught fruit to the catcher's stack. /// </summary> /// <param name="fruit">The fruit that was caught.</param> public void Add(DrawableHitObject fruit) { float ourRadius = fruit.DrawSize.X / 2 * fruit.Scale.X; float theirRadius = 0; const float allowance = 6; while (caughtFruit.Any(f => f.LifetimeEnd == double.MaxValue && Vector2Extensions.Distance(f.Position, fruit.Position) < (ourRadius + (theirRadius = f.DrawSize.X / 2 * f.Scale.X)) / (allowance / 2))) { float diff = (ourRadius + theirRadius) / allowance; fruit.X += (RNG.NextSingle() - 0.5f) * 2 * diff; fruit.Y -= RNG.NextSingle() * diff; } fruit.X = MathHelper.Clamp(fruit.X, -CATCHER_SIZE / 2, CATCHER_SIZE / 2); caughtFruit.Add(fruit); }
protected override bool OnMouseMove(MouseMoveEvent e) { if (dragRotationState != DragRotationState.NotDragging) { var position = e.MousePosition; var distance = Vector2Extensions.Distance(position, positionMouseDown); // don't start rotating until we're moved a minimum distance away from the mouse down location, // else it can have an annoying effect. if (dragRotationState == DragRotationState.DragStarted && distance > 30) { dragRotationState = DragRotationState.Rotating; } // don't rotate when distance is zero to avoid NaN if (dragRotationState == DragRotationState.Rotating && distance > 0) { Vector2 offset = e.MousePosition - positionMouseDown; float degrees = (float)MathHelper.RadiansToDegrees(Math.Atan2(-offset.X, offset.Y)) + 24.3f; // Always rotate in the direction of least distance float diff = (degrees - activeCursor.Rotation) % 360; if (diff < -180) { diff += 360; } if (diff > 180) { diff -= 360; } degrees = activeCursor.Rotation + diff; activeCursor.RotateTo(degrees, 600, Easing.OutQuint); } } return(base.OnMouseMove(e)); }
private void applyStackingOld(Beatmap <OsuHitObject> beatmap) { for (int i = 0; i < beatmap.HitObjects.Count; i++) { OsuHitObject currHitObject = beatmap.HitObjects[i]; if (currHitObject.StackHeight != 0 && !(currHitObject is Slider)) { continue; } double startTime = (currHitObject as IHasEndTime)?.EndTime ?? currHitObject.StartTime; int sliderStack = 0; for (int j = i + 1; j < beatmap.HitObjects.Count; j++) { double stackThreshold = beatmap.HitObjects[i].TimePreempt * beatmap.BeatmapInfo.StackLeniency; if (beatmap.HitObjects[j].StartTime - stackThreshold > startTime) { break; } if (Vector2Extensions.Distance(beatmap.HitObjects[j].Position, currHitObject.Position) < stack_distance) { currHitObject.StackHeight++; startTime = (beatmap.HitObjects[j] as IHasEndTime)?.EndTime ?? beatmap.HitObjects[i].StartTime; } else if (Vector2Extensions.Distance(beatmap.HitObjects[j].Position, currHitObject.EndPosition) < stack_distance) { //Case for sliders - bump notes down and right, rather than up and left. sliderStack++; beatmap.HitObjects[j].StackHeight -= sliderStack; startTime = (beatmap.HitObjects[j] as IHasEndTime)?.EndTime ?? beatmap.HitObjects[i].StartTime; } } } }
private void applyStacking(Beatmap <OsuHitObject> beatmap, int startIndex, int endIndex) { if (startIndex > endIndex) { throw new ArgumentOutOfRangeException(nameof(startIndex), $"{nameof(startIndex)} cannot be greater than {nameof(endIndex)}."); } if (startIndex < 0) { throw new ArgumentOutOfRangeException(nameof(startIndex), $"{nameof(startIndex)} cannot be less than 0."); } if (endIndex < 0) { throw new ArgumentOutOfRangeException(nameof(endIndex), $"{nameof(endIndex)} cannot be less than 0."); } int extendedEndIndex = endIndex; if (endIndex < beatmap.HitObjects.Count - 1) { // Extend the end index to include objects they are stacked on for (int i = endIndex; i >= startIndex; i--) { int stackBaseIndex = i; for (int n = stackBaseIndex + 1; n < beatmap.HitObjects.Count; n++) { OsuHitObject stackBaseObject = beatmap.HitObjects[stackBaseIndex]; if (stackBaseObject is Spinner) { break; } OsuHitObject objectN = beatmap.HitObjects[n]; if (objectN is Spinner) { continue; } double endTime = stackBaseObject.GetEndTime(); double stackThreshold = objectN.TimePreempt * beatmap.BeatmapInfo.StackLeniency; if (objectN.StartTime - endTime > stackThreshold) { //We are no longer within stacking range of the next object. break; } if (Vector2Extensions.Distance(stackBaseObject.Position, objectN.Position) < stack_distance || (stackBaseObject is Slider && Vector2Extensions.Distance(stackBaseObject.EndPosition, objectN.Position) < stack_distance)) { stackBaseIndex = n; // HitObjects after the specified update range haven't been reset yet objectN.StackHeight = 0; } } if (stackBaseIndex > extendedEndIndex) { extendedEndIndex = stackBaseIndex; if (extendedEndIndex == beatmap.HitObjects.Count - 1) { break; } } } } //Reverse pass for stack calculation. int extendedStartIndex = startIndex; for (int i = extendedEndIndex; i > startIndex; i--) { int n = i; /* We should check every note which has not yet got a stack. * Consider the case we have two interwound stacks and this will make sense. * * o <-1 o <-2 * o <-3 o <-4 * * We first process starting from 4 and handle 2, * then we come backwards on the i loop iteration until we reach 3 and handle 1. * 2 and 1 will be ignored in the i loop because they already have a stack value. */ OsuHitObject objectI = beatmap.HitObjects[i]; if (objectI.StackHeight != 0 || objectI is Spinner) { continue; } double stackThreshold = objectI.TimePreempt * beatmap.BeatmapInfo.StackLeniency; /* If this object is a hitcircle, then we enter this "special" case. * It either ends with a stack of hitcircles only, or a stack of hitcircles that are underneath a slider. * Any other case is handled by the "is Slider" code below this. */ if (objectI is HitCircle) { while (--n >= 0) { OsuHitObject objectN = beatmap.HitObjects[n]; if (objectN is Spinner) { continue; } double endTime = objectN.GetEndTime(); if (objectI.StartTime - endTime > stackThreshold) { //We are no longer within stacking range of the previous object. break; } // HitObjects before the specified update range haven't been reset yet if (n < extendedStartIndex) { objectN.StackHeight = 0; extendedStartIndex = n; } /* This is a special case where hticircles are moved DOWN and RIGHT (negative stacking) if they are under the *last* slider in a stacked pattern. * o==o <- slider is at original location * o <- hitCircle has stack of -1 * o <- hitCircle has stack of -2 */ if (objectN is Slider && Vector2Extensions.Distance(objectN.EndPosition, objectI.Position) < stack_distance) { int offset = objectI.StackHeight - objectN.StackHeight + 1; for (int j = n + 1; j <= i; j++) { //For each object which was declared under this slider, we will offset it to appear *below* the slider end (rather than above). OsuHitObject objectJ = beatmap.HitObjects[j]; if (Vector2Extensions.Distance(objectN.EndPosition, objectJ.Position) < stack_distance) { objectJ.StackHeight -= offset; } } //We have hit a slider. We should restart calculation using this as the new base. //Breaking here will mean that the slider still has StackCount of 0, so will be handled in the i-outer-loop. break; } if (Vector2Extensions.Distance(objectN.Position, objectI.Position) < stack_distance) { //Keep processing as if there are no sliders. If we come across a slider, this gets cancelled out. //NOTE: Sliders with start positions stacking are a special case that is also handled here. objectN.StackHeight = objectI.StackHeight + 1; objectI = objectN; } } } else if (objectI is Slider) { /* We have hit the first slider in a possible stack. * From this point on, we ALWAYS stack positive regardless. */ while (--n >= startIndex) { OsuHitObject objectN = beatmap.HitObjects[n]; if (objectN is Spinner) { continue; } if (objectI.StartTime - objectN.StartTime > stackThreshold) { //We are no longer within stacking range of the previous object. break; } if (Vector2Extensions.Distance(objectN.EndPosition, objectI.Position) < stack_distance) { objectN.StackHeight = objectI.StackHeight + 1; objectI = objectN; } } } } }
/// <summary> /// Distance from an arbitrary point to this line. /// </summary> public float DistanceToPoint(Vector2 p) { return(Vector2Extensions.Distance(p, ClosestPointTo(p))); }
private void updateMouseEvents(InputState state) { MouseState mouse = (MouseState)state.Mouse; var last = state.Last?.Mouse as MouseState; if (last == null) { return; } if (mouse.Position != last.Position) { handleMouseMove(state); if (isDragging) { handleMouseDrag(state); } } for (MouseButton b = 0; b < MouseButton.LastButton; b++) { var lastPressed = last.IsPressed(b); if (lastPressed != mouse.IsPressed(b)) { if (lastPressed) { handleMouseUp(state, b); } else { handleMouseDown(state, b); } } } if (mouse.WheelDelta != 0 && Host.Window.CursorInWindow) { handleWheel(state); } if (mouse.HasAnyButtonPressed) { if (!last.HasAnyButtonPressed) { //stuff which only happens once after the mousedown state mouse.PositionMouseDown = state.Mouse.Position; LastActionTime = Time.Current; if (mouse.IsPressed(MouseButton.Left)) { isValidClick = true; if (Time.Current - lastClickTime < double_click_time) { if (handleMouseDoubleClick(state)) { //when we handle a double-click we want to block a normal click from firing. isValidClick = false; } lastClickTime = 0; } else { lastClickTime = Time.Current; } } } if (!isDragging && Vector2Extensions.Distance(mouse.PositionMouseDown ?? mouse.Position, mouse.Position) > drag_start_distance) { isDragging = true; handleMouseDragStart(state); } } else if (last.HasAnyButtonPressed) { if (isValidClick && (DraggedDrawable == null || Vector2Extensions.Distance(mouse.PositionMouseDown ?? mouse.Position, mouse.Position) < click_drag_distance)) { handleMouseClick(state); } mouseDownInputQueue = null; mouse.PositionMouseDown = null; isValidClick = false; if (isDragging) { isDragging = false; handleMouseDragEnd(state); } } }