protected virtual void ApplyCustomState(DrawableHitObject drawable, ArmedState state) { var h = (OsuHitObject)drawable.HitObject; // apply grow effect switch (drawable) { case DrawableSliderHead _: case DrawableSliderTail _: // special cases we should *not* be scaling. break; case DrawableSlider _: case DrawableHitCircle _: { using (drawable.BeginAbsoluteSequence(h.StartTime - h.TimePreempt)) drawable.ScaleTo(StartScale).Then().ScaleTo(EndScale, h.TimePreempt, Easing.OutSine); break; } } // remove approach circles switch (drawable) { case DrawableHitCircle circle: // we don't want to see the approach circle using (circle.BeginAbsoluteSequence(h.StartTime - h.TimePreempt)) circle.ApproachCircle.Hide(); break; } }
private void applyTransform(DrawableHitObject drawable, ArmedState state) { switch (drawable) { case DrawableSliderHead _: case DrawableSliderTail _: case DrawableSliderTick _: case DrawableSliderRepeat _: return; default: var hitObject = (OsuHitObject)drawable.HitObject; float appearDistance = (float)(hitObject.TimePreempt - hitObject.TimeFadeIn) / 2; Vector2 originalPosition = drawable.Position; Vector2 appearOffset = new Vector2(MathF.Cos(theta), MathF.Sin(theta)) * appearDistance; // the - 1 and + 1 prevents the hit objects to appear in the wrong position. double appearTime = hitObject.StartTime - hitObject.TimePreempt - 1; double moveDuration = hitObject.TimePreempt + 1; using (drawable.BeginAbsoluteSequence(appearTime, true)) { drawable .MoveToOffset(appearOffset) .MoveTo(originalPosition, moveDuration, Easing.InOutSine); } theta += (float)hitObject.TimeFadeIn / 1000; break; } }
protected void ApplyHiddenState(DrawableHitObject drawable, ArmedState state) { if (!(drawable is DrawableOsuHitObject d)) return; var fadeOutStartTime = d.HitObject.StartTime - preEmpt + d.FadeInDuration; var fadeOutDuration = preEmpt * fade_out_duration_multiplier; // new duration from completed fade in to end (before fading out) var longFadeDuration = ((d.HitObject as IHasEndTime)?.EndTime ?? d.HitObject.StartTime) - fadeOutStartTime; switch (drawable) { case DrawableHitCircle circle: // we don't want to see the approach circle circle.ApproachCircle.Hide(); // fade out immediately after fade in. using (drawable.BeginAbsoluteSequence(fadeOutStartTime, true)) circle.FadeOut(fadeOutDuration); break; case DrawableSlider slider: using (slider.BeginAbsoluteSequence(fadeOutStartTime, true)) { slider.Body.FadeOut(longFadeDuration, Easing.Out); // delay a bit less to let the sliderball fade out peacefully instead of having a hard cut using (slider.BeginDelayedSequence(longFadeDuration - fadeOutDuration, true)) slider.Ball.FadeOut(fadeOutDuration); } break; case DrawableSpinner spinner: // hide elements we don't care about. spinner.Disc.Hide(); spinner.Ticks.Hide(); spinner.Background.Hide(); using (spinner.BeginAbsoluteSequence(fadeOutStartTime + longFadeDuration, true)) { spinner.FadeOut(fadeOutDuration); // speed up the end sequence accordingly switch (state) { case ArmedState.Hit: spinner.ScaleTo(spinner.Scale * 1.2f, fadeOutDuration * 2, Easing.Out); break; case ArmedState.Miss: spinner.ScaleTo(spinner.Scale * 0.8f, fadeOutDuration * 2, Easing.In); break; } spinner.Expire(); } break; } }
private void updateState(DrawableHitObject hitObject, ArmedState state) { if (state == ArmedState.Idle || hitAnimations.Value) { return; } if (hitObject is DrawableHitCircle circle) { circle.ApproachCircle .FadeOutFromOne(EDITOR_HIT_OBJECT_FADE_OUT_EXTENSION * 4) .Expire(); circle.ApproachCircle.ScaleTo(1.1f, 300, Easing.OutQuint); } if (hitObject is IHasMainCirclePiece mainPieceContainer) { // clear any explode animation logic. // this is scheduled after children to ensure that the clear happens after invocations of ApplyCustomUpdateState on the circle piece's nested skinnables. ScheduleAfterChildren(() => { if (hitObject.HitObject == null) { return; } mainPieceContainer.CirclePiece.ApplyTransformsAt(hitObject.StateUpdateTime, true); mainPieceContainer.CirclePiece.ClearTransformsAfter(hitObject.StateUpdateTime, true); }); } if (hitObject is DrawableSliderRepeat repeat) { repeat.Arrow.ApplyTransformsAt(hitObject.StateUpdateTime, true); repeat.Arrow.ClearTransformsAfter(hitObject.StateUpdateTime, true); } // adjust the visuals of top-level object types to make them stay on screen for longer than usual. switch (hitObject) { case DrawableSlider _: case DrawableHitCircle _: // Get the existing fade out transform var existing = hitObject.Transforms.LastOrDefault(t => t.TargetMember == nameof(Alpha)); if (existing == null) { return; } hitObject.RemoveTransform(existing); using (hitObject.BeginAbsoluteSequence(hitObject.HitStateUpdateTime)) hitObject.FadeOut(EDITOR_HIT_OBJECT_FADE_OUT_EXTENSION).Expire(); break; } }
private void drawableOnApplyCustomUpdateState(DrawableHitObject drawable, ArmedState state) { var osuObject = (OsuHitObject)drawable.HitObject; Vector2 origin = drawable.Position; // Wiggle the repeat points and the tail with the slider instead of independently. // Also fixes an issue with repeat points being positioned incorrectly. if (osuObject is SliderRepeat || osuObject is SliderTailCircle) { return; } Random objRand = new Random((int)osuObject.StartTime); // Wiggle all objects during TimePreempt int amountWiggles = (int)osuObject.TimePreempt / wiggle_duration; void wiggle() { float nextAngle = (float)(objRand.NextDouble() * 2 * Math.PI); float nextDist = (float)(objRand.NextDouble() * wiggle_strength); drawable.MoveTo(new Vector2((float)(nextDist * Math.Cos(nextAngle) + origin.X), (float)(nextDist * Math.Sin(nextAngle) + origin.Y)), wiggle_duration); } for (int i = 0; i < amountWiggles; i++) { using (drawable.BeginAbsoluteSequence(osuObject.StartTime - osuObject.TimePreempt + i * wiggle_duration)) wiggle(); } // Keep wiggling sliders and spinners for their duration if (!(osuObject is IHasDuration endTime)) { return; } amountWiggles = (int)(endTime.Duration / wiggle_duration); for (int i = 0; i < amountWiggles; i++) { using (drawable.BeginAbsoluteSequence(osuObject.StartTime + i * wiggle_duration)) wiggle(); } }
private void dropOffScreen(DrawableHitObject obj, double failTime, float randomRotation, Vector2 originalScale, Vector2 originalPosition) { using (obj.BeginAbsoluteSequence(failTime)) { obj.RotateTo(randomRotation, duration); obj.ScaleTo(originalScale * 0.5f, duration); obj.MoveTo(originalPosition + new Vector2(0, 400), duration); } }
protected override void ApplyHiddenState(DrawableHitObject o, ArmedState state) { const float hiddenTime = 2000f; var ho = o.HitObject; double start = ho.StartTime - hiddenTime; using (o.BeginAbsoluteSequence(start, true)) o.FadeOut(hiddenTime); }
protected void ApplyHiddenState(DrawableHitObject drawable, ArmedState state) { if (!(drawable is DrawableOsuHitObject d)) { return; } var h = d.HitObject; var fadeOutStartTime = h.StartTime - h.TimePreempt + h.TimeFadein; var fadeOutDuration = h.TimePreempt * fade_out_duration_multiplier; // new duration from completed fade in to end (before fading out) var longFadeDuration = ((h as IHasEndTime)?.EndTime ?? h.StartTime) - fadeOutStartTime; switch (drawable) { case DrawableHitCircle circle: // we don't want to see the approach circle using (circle.BeginAbsoluteSequence(h.StartTime - h.TimePreempt, true)) circle.ApproachCircle.Hide(); // fade out immediately after fade in. using (drawable.BeginAbsoluteSequence(fadeOutStartTime, true)) circle.FadeOut(fadeOutDuration); break; case DrawableSlider slider: using (slider.BeginAbsoluteSequence(fadeOutStartTime, true)) slider.Body.FadeOut(longFadeDuration, Easing.Out); break; case DrawableSliderTick sliderTick: // slider ticks fade out over up to one second var tickFadeOutDuration = Math.Min(sliderTick.HitObject.TimePreempt - DrawableSliderTick.ANIM_DURATION, 1000); using (sliderTick.BeginAbsoluteSequence(sliderTick.HitObject.StartTime - tickFadeOutDuration, true)) sliderTick.FadeOut(tickFadeOutDuration); break; case DrawableSpinner spinner: // hide elements we don't care about. spinner.Disc.Hide(); spinner.Ticks.Hide(); spinner.Background.Hide(); using (spinner.BeginAbsoluteSequence(fadeOutStartTime + longFadeDuration, true)) spinner.FadeOut(fadeOutDuration); break; } }
private void drawableOnApplyCustomUpdateState(DrawableHitObject drawable, ArmedState state) { var osuObject = (OsuHitObject)drawable.HitObject; Vector2 origin = drawable.Position; Random objRand = new Random((int)osuObject.StartTime); // Wiggle all objects during TimePreempt int amountWiggles = (int)osuObject.TimePreempt / wiggle_duration; void wiggle() { float nextAngle = (float)(objRand.NextDouble() * 2 * Math.PI); float nextDist = (float)(objRand.NextDouble() * wiggle_strength); drawable.MoveTo(new Vector2((float)(nextDist * Math.Cos(nextAngle) + origin.X), (float)(nextDist * Math.Sin(nextAngle) + origin.Y)), wiggle_duration); } for (int i = 0; i < amountWiggles; i++) { using (drawable.BeginAbsoluteSequence(osuObject.StartTime - osuObject.TimePreempt + i * wiggle_duration, true)) wiggle(); } // Keep wiggling sliders and spinners for their duration if (!(osuObject is IHasEndTime endTime)) { return; } amountWiggles = (int)(endTime.Duration / wiggle_duration); for (int i = 0; i < amountWiggles; i++) { using (drawable.BeginAbsoluteSequence(osuObject.StartTime + i * wiggle_duration, true)) wiggle(); } }
private void updateState(DrawableHitObject hitObject, ArmedState state) { if (state == ArmedState.Idle || hitAnimations.Value) { return; } if (hitObject is DrawableHitCircle circle) { circle.ApproachCircle .FadeOutFromOne(editor_hit_object_fade_out_extension * 4) .Expire(); circle.ApproachCircle.ScaleTo(1.1f, 300, Easing.OutQuint); } if (hitObject is IHasMainCirclePiece mainPieceContainer) { // clear any explode animation logic. mainPieceContainer.CirclePiece.ApplyTransformsAt(hitObject.HitStateUpdateTime, true); mainPieceContainer.CirclePiece.ClearTransformsAfter(hitObject.HitStateUpdateTime, true); } if (hitObject is DrawableSliderRepeat repeat) { repeat.Arrow.ApplyTransformsAt(hitObject.HitStateUpdateTime, true); repeat.Arrow.ClearTransformsAfter(hitObject.HitStateUpdateTime, true); } // adjust the visuals of top-level object types to make them stay on screen for longer than usual. switch (hitObject) { case DrawableSlider _: case DrawableHitCircle _: // Get the existing fade out transform var existing = hitObject.Transforms.LastOrDefault(t => t.TargetMember == nameof(Alpha)); if (existing == null) { return; } hitObject.RemoveTransform(existing); using (hitObject.BeginAbsoluteSequence(hitObject.HitStateUpdateTime)) hitObject.FadeOut(editor_hit_object_fade_out_extension).Expire(); break; } }
protected void ApplyHiddenState(DrawableHitObject drawable, ArmedState state) { if (!(drawable is DrawableOsuHitObject d)) { return; } var fadeOutStartTime = d.HitObject.StartTime - d.HitObject.TimePreempt + d.HitObject.TimeFadein; var fadeOutDuration = d.HitObject.TimePreempt * fade_out_duration_multiplier; // new duration from completed fade in to end (before fading out) var longFadeDuration = ((d.HitObject as IHasEndTime)?.EndTime ?? d.HitObject.StartTime) - fadeOutStartTime; switch (drawable) { case DrawableHitCircle circle: // we don't want to see the approach circle circle.ApproachCircle.Hide(); // fade out immediately after fade in. using (drawable.BeginAbsoluteSequence(fadeOutStartTime, true)) { circle.FadeOut(fadeOutDuration); } break; case DrawableSlider slider: using (slider.BeginAbsoluteSequence(fadeOutStartTime, true)) { slider.Body.FadeOut(longFadeDuration, Easing.Out); } break; case DrawableSpinner spinner: // hide elements we don't care about. spinner.Disc.Hide(); spinner.Ticks.Hide(); spinner.Background.Hide(); using (spinner.BeginAbsoluteSequence(fadeOutStartTime + longFadeDuration, true)) { spinner.FadeOut(fadeOutDuration); } break; } }
private void updateState(DrawableHitObject hitObject, ArmedState state) { if (state == ArmedState.Idle || hitAnimations.Value) { return; } // adjust the visuals of certain object types to make them stay on screen for longer than usual. switch (hitObject) { default: // there are quite a few drawable hit types we don't want to extend (spinners, ticks etc.) return; case DrawableSlider _: // no specifics to sliders but let them fade slower below. break; case DrawableHitCircle circle: // also handles slider heads circle.ApproachCircle .FadeOutFromOne(editor_hit_object_fade_out_extension * 4) .Expire(); circle.ApproachCircle.ScaleTo(1.1f, 300, Easing.OutQuint); var circlePieceDrawable = circle.CirclePiece.Drawable; // clear any explode animation logic. circlePieceDrawable.ApplyTransformsAt(circle.HitStateUpdateTime, true); circlePieceDrawable.ClearTransformsAfter(circle.HitStateUpdateTime, true); break; } // Get the existing fade out transform var existing = hitObject.Transforms.LastOrDefault(t => t.TargetMember == nameof(Alpha)); if (existing == null) { return; } hitObject.RemoveTransform(existing); using (hitObject.BeginAbsoluteSequence(hitObject.HitStateUpdateTime)) hitObject.FadeOut(editor_hit_object_fade_out_extension).Expire(); }
private void updateState(DrawableHitObject hitObject, ArmedState state) { switch (state) { case ArmedState.Miss: // Get the existing fade out transform var existing = hitObject.Transforms.LastOrDefault(t => t.TargetMember == nameof(Alpha)); if (existing == null) { return; } using (hitObject.BeginAbsoluteSequence(existing.StartTime)) hitObject.FadeOut(editor_hit_object_fade_out_extension).Expire(); break; } }
private void updateState(DrawableHitObject hitObject, ArmedState state) { if (state == ArmedState.Idle) { return; } // adjust the visuals of certain object types to make them stay on screen for longer than usual. switch (hitObject) { default: // there are quite a few drawable hit types we don't want to extent (spinners, ticks etc.) return; case DrawableSlider _: // no specifics to sliders but let them fade slower below. break; case DrawableHitCircle circle: // also handles slider heads circle.ApproachCircle .FadeOutFromOne(editor_hit_object_fade_out_extension) .Expire(); break; } // Get the existing fade out transform var existing = hitObject.Transforms.LastOrDefault(t => t.TargetMember == nameof(Alpha)); if (existing == null) { return; } hitObject.RemoveTransform(existing); using (hitObject.BeginAbsoluteSequence(existing.StartTime)) hitObject.FadeOut(editor_hit_object_fade_out_extension).Expire(); }
protected override void ApplyNormalVisibilityState(DrawableHitObject hitObject, ArmedState state) { switch (hitObject) { case DrawableDrumRollTick _: case DrawableHit _: double preempt = drawableRuleset.TimeRange.Value / drawableRuleset.ControlPointAt(hitObject.HitObject.StartTime).Multiplier; double start = hitObject.HitObject.StartTime - preempt * fade_out_start_time; double duration = preempt * fade_out_duration; using (hitObject.BeginAbsoluteSequence(start)) { hitObject.FadeOut(duration); // DrawableHitObject sets LifetimeEnd to LatestTransformEndTime if it isn't manually changed. // in order for the object to not be killed before its actual end time (as the latest transform ends earlier), set lifetime end explicitly. hitObject.LifetimeEnd = state == ArmedState.Idle || !hitObject.AllJudged ? hitObject.HitObject.GetEndTime() + hitObject.HitObject.HitWindows.WindowFor(HitResult.Miss) : hitObject.HitStateUpdateTime; } break; } }
private void applyState(DrawableHitObject drawable, bool increaseVisibility) { if (!(drawable is DrawableOsuHitObject d)) { return; } var h = d.HitObject; var fadeOutStartTime = h.StartTime - h.TimePreempt + h.TimeFadeIn; var fadeOutDuration = h.TimePreempt * fade_out_duration_multiplier; // new duration from completed fade in to end (before fading out) var longFadeDuration = h.GetEndTime() - fadeOutStartTime; switch (drawable) { case DrawableSliderTail sliderTail: // use stored values from head circle to achieve same fade sequence. fadeOutDuration = lastSliderHeadFadeOutDuration; fadeOutStartTime = lastSliderHeadFadeOutStartTime; using (drawable.BeginAbsoluteSequence(fadeOutStartTime, true)) sliderTail.FadeOut(fadeOutDuration); break; case DrawableSliderRepeat sliderRepeat: // use stored values from head circle to achieve same fade sequence. fadeOutDuration = lastSliderHeadFadeOutDuration; fadeOutStartTime = lastSliderHeadFadeOutStartTime; using (drawable.BeginAbsoluteSequence(fadeOutStartTime, true)) // only apply to circle piece – reverse arrow is not affected by hidden. sliderRepeat.CirclePiece.FadeOut(fadeOutDuration); break; case DrawableHitCircle circle: if (circle is DrawableSliderHead) { lastSliderHeadFadeOutDuration = fadeOutDuration; lastSliderHeadFadeOutStartTime = fadeOutStartTime; } Drawable fadeTarget = circle; if (increaseVisibility) { // only fade the circle piece (not the approach circle) for the increased visibility object. fadeTarget = circle.CirclePiece; } else { // we don't want to see the approach circle using (circle.BeginAbsoluteSequence(h.StartTime - h.TimePreempt, true)) circle.ApproachCircle.Hide(); } // fade out immediately after fade in. using (drawable.BeginAbsoluteSequence(fadeOutStartTime, true)) fadeTarget.FadeOut(fadeOutDuration); break; case DrawableSlider slider: using (slider.BeginAbsoluteSequence(fadeOutStartTime, true)) slider.Body.FadeOut(longFadeDuration, Easing.Out); break; case DrawableSliderTick sliderTick: // slider ticks fade out over up to one second var tickFadeOutDuration = Math.Min(sliderTick.HitObject.TimePreempt - DrawableSliderTick.ANIM_DURATION, 1000); using (sliderTick.BeginAbsoluteSequence(sliderTick.HitObject.StartTime - tickFadeOutDuration, true)) sliderTick.FadeOut(tickFadeOutDuration); break; case DrawableSpinner spinner: // hide elements we don't care about. // todo: hide background using (spinner.BeginAbsoluteSequence(fadeOutStartTime + longFadeDuration, true)) spinner.FadeOut(fadeOutDuration); break; } }