diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneFruitRandomness.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneFruitRandomness.cs index de3d9d6530..8e7f77285c 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneFruitRandomness.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneFruitRandomness.cs @@ -26,6 +26,8 @@ namespace osu.Game.Rulesets.Catch.Tests AddSliderStep("start time", 500, 600, 0, x => { drawableFruit.HitObject.StartTime = drawableBanana.HitObject.StartTime = x; + drawableFruit.RefreshStateTransforms(); + drawableBanana.RefreshStateTransforms(); }); } @@ -44,6 +46,8 @@ namespace osu.Game.Rulesets.Catch.Tests AddStep("Initialize start time", () => { drawableFruit.HitObject.StartTime = drawableBanana.HitObject.StartTime = initial_start_time; + drawableFruit.RefreshStateTransforms(); + drawableBanana.RefreshStateTransforms(); fruitRotation = drawableFruit.DisplayRotation; bananaRotation = drawableBanana.DisplayRotation; @@ -54,6 +58,8 @@ namespace osu.Game.Rulesets.Catch.Tests AddStep("change start time", () => { drawableFruit.HitObject.StartTime = drawableBanana.HitObject.StartTime = another_start_time; + drawableFruit.RefreshStateTransforms(); + drawableBanana.RefreshStateTransforms(); }); AddAssert("fruit rotation is changed", () => drawableFruit.DisplayRotation != fruitRotation); @@ -64,6 +70,8 @@ namespace osu.Game.Rulesets.Catch.Tests AddStep("reset start time", () => { drawableFruit.HitObject.StartTime = drawableBanana.HitObject.StartTime = initial_start_time; + drawableFruit.RefreshStateTransforms(); + drawableBanana.RefreshStateTransforms(); }); AddAssert("rotation and size restored", () => diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index bf649a0a15..e31656e0ff 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -260,7 +260,6 @@ namespace osu.Game.Rulesets.Objects.Drawables } StartTimeBindable.BindTo(HitObject.StartTimeBindable); - StartTimeBindable.BindValueChanged(onStartTimeChanged); if (HitObject is IHasComboInformation combo) { @@ -311,9 +310,6 @@ namespace osu.Game.Rulesets.Objects.Drawables samplesBindable.UnbindFrom(HitObject.SamplesBindable); - // Changes in start time trigger state updates. When a new hitobject is applied, OnApply() automatically performs a state update anyway. - StartTimeBindable.ValueChanged -= onStartTimeChanged; - // When a new hitobject is applied, the samples will be cleared before re-populating. // In order to stop this needless update, the event is unbound and re-bound as late as possible in Apply(). samplesBindable.CollectionChanged -= onSamplesChanged; @@ -333,6 +329,8 @@ namespace osu.Game.Rulesets.Objects.Drawables Entry.NestedEntries.RemoveAll(nestedEntry => nestedEntry is SyntheticHitObjectEntry); ClearNestedHitObjects(); + // Changes to `HitObject` properties trigger default application, which triggers `State` updates. + // When a new hitobject is applied, `OnApply()` automatically performs a state update. HitObject.DefaultsApplied -= onDefaultsApplied; entry.RevertResult -= onRevertResult; @@ -375,8 +373,6 @@ namespace osu.Game.Rulesets.Objects.Drawables private void onSamplesChanged(object sender, NotifyCollectionChangedEventArgs e) => LoadSamples(); - private void onStartTimeChanged(ValueChangedEvent startTime) => updateState(State.Value, true); - private void onNewResult(DrawableHitObject drawableHitObject, JudgementResult result) => OnNewResult?.Invoke(drawableHitObject, result); private void onRevertResult() @@ -394,6 +390,15 @@ namespace osu.Game.Rulesets.Objects.Drawables Debug.Assert(Entry != null); Apply(Entry); + // Applied defaults indicate a change in hit object state. + // We need to update the judgement result time to the new end time + // and update state to ensure the hit object fades out at the correct time. + if (Result is not null) + { + Result.TimeOffset = 0; + updateState(State.Value, true); + } + DefaultsApplied?.Invoke(this); }