mirror of
https://github.com/osukey/osukey.git
synced 2025-08-07 16:43:52 +09:00
Merge pull request #18239 from peppy/editor-readability
Add lingering hitobject display to editor, replacing "Hit Animations" toggle
This commit is contained in:
@ -1,114 +0,0 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using NUnit.Framework;
|
|
||||||
using osu.Framework.Allocation;
|
|
||||||
using osu.Framework.Graphics;
|
|
||||||
using osu.Framework.Graphics.Transforms;
|
|
||||||
using osu.Framework.Testing;
|
|
||||||
using osu.Framework.Utils;
|
|
||||||
using osu.Game.Configuration;
|
|
||||||
using osu.Game.Rulesets.Objects;
|
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
|
||||||
using osu.Game.Rulesets.Osu.Edit;
|
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
|
||||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Tests.Editor
|
|
||||||
{
|
|
||||||
[TestFixture]
|
|
||||||
public class TestSceneOsuEditorHitAnimations : TestSceneOsuEditor
|
|
||||||
{
|
|
||||||
[Resolved]
|
|
||||||
private OsuConfigManager config { get; set; }
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void TestHitCircleAnimationDisable()
|
|
||||||
{
|
|
||||||
HitCircle hitCircle = null;
|
|
||||||
DrawableHitCircle drawableHitCircle = null;
|
|
||||||
|
|
||||||
AddStep("retrieve first hit circle", () => hitCircle = getHitCircle(0));
|
|
||||||
toggleAnimations(true);
|
|
||||||
seekSmoothlyTo(() => hitCircle.StartTime + 10);
|
|
||||||
|
|
||||||
AddStep("retrieve drawable", () => drawableHitCircle = (DrawableHitCircle)getDrawableObjectFor(hitCircle));
|
|
||||||
assertFutureTransforms(() => drawableHitCircle.CirclePiece, true);
|
|
||||||
|
|
||||||
AddStep("retrieve second hit circle", () => hitCircle = getHitCircle(1));
|
|
||||||
toggleAnimations(false);
|
|
||||||
seekSmoothlyTo(() => hitCircle.StartTime + 10);
|
|
||||||
|
|
||||||
AddStep("retrieve drawable", () => drawableHitCircle = (DrawableHitCircle)getDrawableObjectFor(hitCircle));
|
|
||||||
assertFutureTransforms(() => drawableHitCircle.CirclePiece, false);
|
|
||||||
AddAssert("hit circle has longer fade-out applied", () =>
|
|
||||||
{
|
|
||||||
var alphaTransform = drawableHitCircle.Transforms.Last(t => t.TargetMember == nameof(Alpha));
|
|
||||||
return alphaTransform.EndTime - alphaTransform.StartTime == DrawableOsuEditorRuleset.EDITOR_HIT_OBJECT_FADE_OUT_EXTENSION;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void TestSliderAnimationDisable()
|
|
||||||
{
|
|
||||||
Slider slider = null;
|
|
||||||
DrawableSlider drawableSlider = null;
|
|
||||||
DrawableSliderRepeat sliderRepeat = null;
|
|
||||||
|
|
||||||
AddStep("retrieve first slider with repeats", () => slider = getSliderWithRepeats(0));
|
|
||||||
toggleAnimations(true);
|
|
||||||
seekSmoothlyTo(() => slider.StartTime + slider.SpanDuration + 10);
|
|
||||||
|
|
||||||
retrieveDrawables();
|
|
||||||
assertFutureTransforms(() => sliderRepeat, true);
|
|
||||||
|
|
||||||
AddStep("retrieve second slider with repeats", () => slider = getSliderWithRepeats(1));
|
|
||||||
toggleAnimations(false);
|
|
||||||
seekSmoothlyTo(() => slider.StartTime + slider.SpanDuration + 10);
|
|
||||||
|
|
||||||
retrieveDrawables();
|
|
||||||
assertFutureTransforms(() => sliderRepeat.Arrow, false);
|
|
||||||
seekSmoothlyTo(() => slider.GetEndTime());
|
|
||||||
AddAssert("slider has longer fade-out applied", () =>
|
|
||||||
{
|
|
||||||
var alphaTransform = drawableSlider.Transforms.Last(t => t.TargetMember == nameof(Alpha));
|
|
||||||
return alphaTransform.EndTime - alphaTransform.StartTime == DrawableOsuEditorRuleset.EDITOR_HIT_OBJECT_FADE_OUT_EXTENSION;
|
|
||||||
});
|
|
||||||
|
|
||||||
void retrieveDrawables() =>
|
|
||||||
AddStep("retrieve drawables", () =>
|
|
||||||
{
|
|
||||||
drawableSlider = (DrawableSlider)getDrawableObjectFor(slider);
|
|
||||||
sliderRepeat = (DrawableSliderRepeat)getDrawableObjectFor(slider.NestedHitObjects.OfType<SliderRepeat>().First());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private HitCircle getHitCircle(int index)
|
|
||||||
=> EditorBeatmap.HitObjects.OfType<HitCircle>().ElementAt(index);
|
|
||||||
|
|
||||||
private Slider getSliderWithRepeats(int index)
|
|
||||||
=> EditorBeatmap.HitObjects.OfType<Slider>().Where(s => s.RepeatCount >= 1).ElementAt(index);
|
|
||||||
|
|
||||||
private DrawableHitObject getDrawableObjectFor(HitObject hitObject)
|
|
||||||
=> this.ChildrenOfType<DrawableHitObject>().Single(ho => ho.HitObject == hitObject);
|
|
||||||
|
|
||||||
private IEnumerable<Transform> getTransformsRecursively(Drawable drawable)
|
|
||||||
=> drawable.ChildrenOfType<Drawable>().SelectMany(d => d.Transforms);
|
|
||||||
|
|
||||||
private void toggleAnimations(bool enabled)
|
|
||||||
=> AddStep($"toggle animations {(enabled ? "on" : "off")}", () => config.SetValue(OsuSetting.EditorHitAnimations, enabled));
|
|
||||||
|
|
||||||
private void seekSmoothlyTo(Func<double> targetTime)
|
|
||||||
{
|
|
||||||
AddStep("seek smoothly", () => EditorClock.SeekSmoothlyTo(targetTime.Invoke()));
|
|
||||||
AddUntilStep("wait for seek", () => Precision.AlmostEquals(targetTime.Invoke(), EditorClock.CurrentTime));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void assertFutureTransforms(Func<Drawable> getDrawable, bool hasFutureTransforms)
|
|
||||||
=> AddAssert($"object {(hasFutureTransforms ? "has" : "has no")} future transforms",
|
|
||||||
() => getTransformsRecursively(getDrawable()).Any(t => t.EndTime >= EditorClock.CurrentTime) == hasFutureTransforms);
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,86 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Framework.Utils;
|
||||||
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
|
using osu.Game.Rulesets.Osu.Skinning.Default;
|
||||||
|
using osu.Game.Screens.Edit;
|
||||||
|
using osu.Game.Skinning;
|
||||||
|
using osuTK;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components
|
||||||
|
{
|
||||||
|
public class HitCircleOverlapMarker : BlueprintPiece<HitCircle>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Hit objects are intentionally made to fade out at a constant slower rate than in gameplay.
|
||||||
|
/// This allows a mapper to gain better historical context and use recent hitobjects as reference / snap points.
|
||||||
|
/// </summary>
|
||||||
|
public const double FADE_OUT_EXTENSION = 700;
|
||||||
|
|
||||||
|
private readonly RingPiece ring;
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private EditorClock editorClock { get; set; }
|
||||||
|
|
||||||
|
public HitCircleOverlapMarker()
|
||||||
|
{
|
||||||
|
Origin = Anchor.Centre;
|
||||||
|
|
||||||
|
Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2);
|
||||||
|
|
||||||
|
InternalChildren = new Drawable[]
|
||||||
|
{
|
||||||
|
new Circle
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Colour = Color4.White,
|
||||||
|
},
|
||||||
|
ring = new RingPiece
|
||||||
|
{
|
||||||
|
BorderThickness = 4,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private ISkinSource skin { get; set; }
|
||||||
|
|
||||||
|
public override void UpdateFrom(HitCircle hitObject)
|
||||||
|
{
|
||||||
|
base.UpdateFrom(hitObject);
|
||||||
|
|
||||||
|
Scale = new Vector2(hitObject.Scale);
|
||||||
|
|
||||||
|
if (hitObject is IHasComboInformation combo)
|
||||||
|
ring.BorderColour = combo.GetComboColour(skin);
|
||||||
|
|
||||||
|
double editorTime = editorClock.CurrentTime;
|
||||||
|
double hitObjectTime = hitObject.StartTime;
|
||||||
|
bool hasReachedObject = editorTime >= hitObjectTime;
|
||||||
|
|
||||||
|
if (hasReachedObject)
|
||||||
|
{
|
||||||
|
float alpha = Interpolation.ValueAt(editorTime, 0, 1f, hitObjectTime, hitObjectTime + FADE_OUT_EXTENSION, Easing.In);
|
||||||
|
float ringScale = MathHelper.Clamp(Interpolation.ValueAt(editorTime, 0, 1f, hitObjectTime, hitObjectTime + FADE_OUT_EXTENSION / 2, Easing.OutQuint), 0, 1);
|
||||||
|
|
||||||
|
ring.Scale = new Vector2(1 + 0.1f * ringScale);
|
||||||
|
Alpha = 0.9f * (1 - alpha);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Alpha = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Hide()
|
||||||
|
{
|
||||||
|
// intentional no op so we are not hidden when not selected.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Primitives;
|
using osu.Framework.Graphics.Primitives;
|
||||||
using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components;
|
using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
@ -14,11 +15,16 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles
|
|||||||
protected new DrawableHitCircle DrawableObject => (DrawableHitCircle)base.DrawableObject;
|
protected new DrawableHitCircle DrawableObject => (DrawableHitCircle)base.DrawableObject;
|
||||||
|
|
||||||
protected readonly HitCirclePiece CirclePiece;
|
protected readonly HitCirclePiece CirclePiece;
|
||||||
|
private readonly HitCircleOverlapMarker marker;
|
||||||
|
|
||||||
public HitCircleSelectionBlueprint(HitCircle circle)
|
public HitCircleSelectionBlueprint(HitCircle circle)
|
||||||
: base(circle)
|
: base(circle)
|
||||||
{
|
{
|
||||||
InternalChild = CirclePiece = new HitCirclePiece();
|
InternalChildren = new Drawable[]
|
||||||
|
{
|
||||||
|
marker = new HitCircleOverlapMarker(),
|
||||||
|
CirclePiece = new HitCirclePiece(),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Update()
|
protected override void Update()
|
||||||
@ -26,6 +32,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles
|
|||||||
base.Update();
|
base.Update();
|
||||||
|
|
||||||
CirclePiece.UpdateFrom(HitObject);
|
CirclePiece.UpdateFrom(HitObject);
|
||||||
|
marker.UpdateFrom(HitObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => DrawableObject.HitArea.ReceivePositionalInputAt(screenSpacePos);
|
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => DrawableObject.HitArea.ReceivePositionalInputAt(screenSpacePos);
|
||||||
|
@ -1,19 +1,29 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Framework.Allocation;
|
||||||
using osu.Game.Rulesets.Edit;
|
using osu.Game.Rulesets.Edit;
|
||||||
|
using osu.Game.Rulesets.Objects;
|
||||||
|
using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||||
|
using osu.Game.Screens.Edit;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Edit.Blueprints
|
namespace osu.Game.Rulesets.Osu.Edit.Blueprints
|
||||||
{
|
{
|
||||||
public abstract class OsuSelectionBlueprint<T> : HitObjectSelectionBlueprint<T>
|
public abstract class OsuSelectionBlueprint<T> : HitObjectSelectionBlueprint<T>
|
||||||
where T : OsuHitObject
|
where T : OsuHitObject
|
||||||
{
|
{
|
||||||
|
[Resolved]
|
||||||
|
private EditorClock editorClock { get; set; }
|
||||||
|
|
||||||
protected new DrawableOsuHitObject DrawableObject => (DrawableOsuHitObject)base.DrawableObject;
|
protected new DrawableOsuHitObject DrawableObject => (DrawableOsuHitObject)base.DrawableObject;
|
||||||
|
|
||||||
protected override bool AlwaysShowWhenSelected => true;
|
protected override bool AlwaysShowWhenSelected => true;
|
||||||
|
|
||||||
|
protected override bool ShouldBeAlive => base.ShouldBeAlive
|
||||||
|
|| (editorClock.CurrentTime >= Item.StartTime && editorClock.CurrentTime - Item.GetEndTime() < HitCircleOverlapMarker.FADE_OUT_EXTENSION);
|
||||||
|
|
||||||
protected OsuSelectionBlueprint(T hitObject)
|
protected OsuSelectionBlueprint(T hitObject)
|
||||||
: base(hitObject)
|
: base(hitObject)
|
||||||
{
|
{
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components;
|
using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
@ -13,20 +14,38 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
|||||||
|
|
||||||
private readonly Slider slider;
|
private readonly Slider slider;
|
||||||
private readonly SliderPosition position;
|
private readonly SliderPosition position;
|
||||||
|
private readonly HitCircleOverlapMarker marker;
|
||||||
|
|
||||||
public SliderCircleOverlay(Slider slider, SliderPosition position)
|
public SliderCircleOverlay(Slider slider, SliderPosition position)
|
||||||
{
|
{
|
||||||
this.slider = slider;
|
this.slider = slider;
|
||||||
this.position = position;
|
this.position = position;
|
||||||
|
|
||||||
InternalChild = CirclePiece = new HitCirclePiece();
|
InternalChildren = new Drawable[]
|
||||||
|
{
|
||||||
|
marker = new HitCircleOverlapMarker(),
|
||||||
|
CirclePiece = new HitCirclePiece(),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Update()
|
protected override void Update()
|
||||||
{
|
{
|
||||||
base.Update();
|
base.Update();
|
||||||
|
|
||||||
CirclePiece.UpdateFrom(position == SliderPosition.Start ? (HitCircle)slider.HeadCircle : slider.TailCircle);
|
var circle = position == SliderPosition.Start ? (HitCircle)slider.HeadCircle : slider.TailCircle;
|
||||||
|
|
||||||
|
CirclePiece.UpdateFrom(circle);
|
||||||
|
marker.UpdateFrom(circle);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Hide()
|
||||||
|
{
|
||||||
|
CirclePiece.Hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Show()
|
||||||
|
{
|
||||||
|
CirclePiece.Show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,16 +2,8 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using osu.Framework.Allocation;
|
|
||||||
using osu.Framework.Bindables;
|
|
||||||
using osu.Framework.Graphics;
|
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Configuration;
|
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
|
||||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
|
||||||
using osu.Game.Rulesets.Osu.Skinning.Default;
|
|
||||||
using osu.Game.Rulesets.Osu.UI;
|
using osu.Game.Rulesets.Osu.UI;
|
||||||
using osu.Game.Rulesets.UI;
|
using osu.Game.Rulesets.UI;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
@ -20,12 +12,6 @@ namespace osu.Game.Rulesets.Osu.Edit
|
|||||||
{
|
{
|
||||||
public class DrawableOsuEditorRuleset : DrawableOsuRuleset
|
public class DrawableOsuEditorRuleset : DrawableOsuRuleset
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Hit objects are intentionally made to fade out at a constant slower rate than in gameplay.
|
|
||||||
/// This allows a mapper to gain better historical context and use recent hitobjects as reference / snap points.
|
|
||||||
/// </summary>
|
|
||||||
public const double EDITOR_HIT_OBJECT_FADE_OUT_EXTENSION = 700;
|
|
||||||
|
|
||||||
public DrawableOsuEditorRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList<Mod> mods)
|
public DrawableOsuEditorRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList<Mod> mods)
|
||||||
: base(ruleset, beatmap, mods)
|
: base(ruleset, beatmap, mods)
|
||||||
{
|
{
|
||||||
@ -37,85 +23,12 @@ namespace osu.Game.Rulesets.Osu.Edit
|
|||||||
|
|
||||||
private class OsuEditorPlayfield : OsuPlayfield
|
private class OsuEditorPlayfield : OsuPlayfield
|
||||||
{
|
{
|
||||||
private Bindable<bool> hitAnimations;
|
|
||||||
|
|
||||||
protected override GameplayCursorContainer CreateCursor() => null;
|
protected override GameplayCursorContainer CreateCursor() => null;
|
||||||
|
|
||||||
public OsuEditorPlayfield()
|
public OsuEditorPlayfield()
|
||||||
{
|
{
|
||||||
HitPolicy = new AnyOrderHitPolicy();
|
HitPolicy = new AnyOrderHitPolicy();
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load(OsuConfigManager config)
|
|
||||||
{
|
|
||||||
hitAnimations = config.GetBindable<bool>(OsuSetting.EditorHitAnimations);
|
|
||||||
hitAnimations.BindValueChanged(_ =>
|
|
||||||
{
|
|
||||||
foreach (var d in HitObjectContainer.AliveObjects)
|
|
||||||
d.RefreshStateTransforms();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnNewDrawableHitObject(DrawableHitObject d)
|
|
||||||
{
|
|
||||||
d.ApplyCustomUpdateState += updateState;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateState(DrawableHitObject hitObject, ArmedState state)
|
|
||||||
{
|
|
||||||
if (state == ArmedState.Idle || hitAnimations.Value)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (hitObject is DrawableHitCircle circle)
|
|
||||||
{
|
|
||||||
using (circle.BeginAbsoluteSequence(circle.HitStateUpdateTime))
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -163,7 +163,6 @@ namespace osu.Game.Configuration
|
|||||||
SetDefault(OsuSetting.DiscordRichPresence, DiscordRichPresenceMode.Full);
|
SetDefault(OsuSetting.DiscordRichPresence, DiscordRichPresenceMode.Full);
|
||||||
|
|
||||||
SetDefault(OsuSetting.EditorWaveformOpacity, 0.25f);
|
SetDefault(OsuSetting.EditorWaveformOpacity, 0.25f);
|
||||||
SetDefault(OsuSetting.EditorHitAnimations, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public IDictionary<OsuSetting, string> GetLoggableState() =>
|
public IDictionary<OsuSetting, string> GetLoggableState() =>
|
||||||
@ -356,7 +355,6 @@ namespace osu.Game.Configuration
|
|||||||
GameplayDisableWinKey,
|
GameplayDisableWinKey,
|
||||||
SeasonalBackgroundMode,
|
SeasonalBackgroundMode,
|
||||||
EditorWaveformOpacity,
|
EditorWaveformOpacity,
|
||||||
EditorHitAnimations,
|
|
||||||
DiscordRichPresence,
|
DiscordRichPresence,
|
||||||
AutomaticallyDownloadWhenSpectating,
|
AutomaticallyDownloadWhenSpectating,
|
||||||
ShowOnlineExplicitContent,
|
ShowOnlineExplicitContent,
|
||||||
|
@ -89,16 +89,12 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
// set the body piece's alpha directly to avoid arbitrarily rendering frame buffers etc. of children.
|
// set the body piece's alpha directly to avoid arbitrarily rendering frame buffers etc. of children.
|
||||||
foreach (var d in InternalChildren)
|
foreach (var d in InternalChildren)
|
||||||
d.Hide();
|
d.Hide();
|
||||||
|
|
||||||
Hide();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void OnSelected()
|
protected virtual void OnSelected()
|
||||||
{
|
{
|
||||||
foreach (var d in InternalChildren)
|
foreach (var d in InternalChildren)
|
||||||
d.Show();
|
d.Show();
|
||||||
|
|
||||||
Show();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// When not selected, input is only required for the blueprint itself to receive IsHovering
|
// When not selected, input is only required for the blueprint itself to receive IsHovering
|
||||||
|
@ -271,7 +271,6 @@ namespace osu.Game.Screens.Edit
|
|||||||
Items = new MenuItem[]
|
Items = new MenuItem[]
|
||||||
{
|
{
|
||||||
new WaveformOpacityMenuItem(config.GetBindable<float>(OsuSetting.EditorWaveformOpacity)),
|
new WaveformOpacityMenuItem(config.GetBindable<float>(OsuSetting.EditorWaveformOpacity)),
|
||||||
new HitAnimationsMenuItem(config.GetBindable<bool>(OsuSetting.EditorHitAnimations))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,16 +2,21 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Timing;
|
using osu.Framework.Timing;
|
||||||
using osu.Game.Rulesets.Edit;
|
using osu.Game.Rulesets.Edit;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
|
using osu.Game.Screens.Edit;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual
|
namespace osu.Game.Tests.Visual
|
||||||
{
|
{
|
||||||
public abstract class SelectionBlueprintTestScene : OsuManualInputManagerTestScene
|
public abstract class SelectionBlueprintTestScene : OsuManualInputManagerTestScene
|
||||||
{
|
{
|
||||||
|
[Cached]
|
||||||
|
private readonly EditorClock editorClock = new EditorClock();
|
||||||
|
|
||||||
protected override Container<Drawable> Content => content ?? base.Content;
|
protected override Container<Drawable> Content => content ?? base.Content;
|
||||||
private readonly Container content;
|
private readonly Container content;
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user