mirror of
https://github.com/ppy/osu.git
synced 2024-12-14 08:52:55 +08:00
Merge pull request #10717 from smoogipoo/dho-apply
This commit is contained in:
commit
8706b51b77
@ -52,6 +52,6 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.1030.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.1030.0" />
|
||||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2020.1109.0" />
|
<PackageReference Include="ppy.osu.Framework.Android" Version="2020.1110.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
44
osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleApplication.cs
Normal file
44
osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleApplication.cs
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
// 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 NUnit.Framework;
|
||||||
|
using osu.Framework.Timing;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
|
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||||
|
using osu.Game.Tests.Visual;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Osu.Tests
|
||||||
|
{
|
||||||
|
public class TestSceneHitCircleApplication : OsuTestScene
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void TestApplyNewCircle()
|
||||||
|
{
|
||||||
|
DrawableHitCircle dho = null;
|
||||||
|
|
||||||
|
AddStep("create circle", () => Child = dho = new DrawableHitCircle(prepareObject(new HitCircle
|
||||||
|
{
|
||||||
|
Position = new Vector2(256, 192),
|
||||||
|
IndexInCurrentCombo = 0
|
||||||
|
}))
|
||||||
|
{
|
||||||
|
Clock = new FramedClock(new StopwatchClock())
|
||||||
|
});
|
||||||
|
|
||||||
|
AddStep("apply new circle", () => dho.Apply(prepareObject(new HitCircle
|
||||||
|
{
|
||||||
|
Position = new Vector2(128, 128),
|
||||||
|
ComboIndex = 1,
|
||||||
|
})));
|
||||||
|
}
|
||||||
|
|
||||||
|
private HitCircle prepareObject(HitCircle circle)
|
||||||
|
{
|
||||||
|
circle.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
||||||
|
return circle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
59
osu.Game.Rulesets.Osu.Tests/TestSceneSliderApplication.cs
Normal file
59
osu.Game.Rulesets.Osu.Tests/TestSceneSliderApplication.cs
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
// 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 NUnit.Framework;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
|
using osu.Game.Rulesets.Objects;
|
||||||
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
|
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||||
|
using osu.Game.Tests.Visual;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Osu.Tests
|
||||||
|
{
|
||||||
|
public class TestSceneSliderApplication : OsuTestScene
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void TestApplyNewSlider()
|
||||||
|
{
|
||||||
|
DrawableSlider dho = null;
|
||||||
|
|
||||||
|
AddStep("create slider", () => Child = dho = new DrawableSlider(prepareObject(new Slider
|
||||||
|
{
|
||||||
|
Position = new Vector2(256, 192),
|
||||||
|
IndexInCurrentCombo = 0,
|
||||||
|
StartTime = Time.Current,
|
||||||
|
Path = new SliderPath(PathType.Linear, new[]
|
||||||
|
{
|
||||||
|
Vector2.Zero,
|
||||||
|
new Vector2(150, 100),
|
||||||
|
new Vector2(300, 0),
|
||||||
|
})
|
||||||
|
})));
|
||||||
|
|
||||||
|
AddWaitStep("wait for progression", 1);
|
||||||
|
|
||||||
|
AddStep("apply new slider", () => dho.Apply(prepareObject(new Slider
|
||||||
|
{
|
||||||
|
Position = new Vector2(256, 192),
|
||||||
|
ComboIndex = 1,
|
||||||
|
StartTime = dho.HitObject.StartTime,
|
||||||
|
Path = new SliderPath(PathType.Bezier, new[]
|
||||||
|
{
|
||||||
|
Vector2.Zero,
|
||||||
|
new Vector2(150, 100),
|
||||||
|
new Vector2(300, 0),
|
||||||
|
}),
|
||||||
|
RepeatCount = 1
|
||||||
|
})));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Slider prepareObject(Slider slider)
|
||||||
|
{
|
||||||
|
slider.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
||||||
|
return slider;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
46
osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerApplication.cs
Normal file
46
osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerApplication.cs
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
// 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 NUnit.Framework;
|
||||||
|
using osu.Framework.Timing;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
|
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||||
|
using osu.Game.Tests.Visual;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Osu.Tests
|
||||||
|
{
|
||||||
|
public class TestSceneSpinnerApplication : OsuTestScene
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void TestApplyNewCircle()
|
||||||
|
{
|
||||||
|
DrawableSpinner dho = null;
|
||||||
|
|
||||||
|
AddStep("create spinner", () => Child = dho = new DrawableSpinner(prepareObject(new Spinner
|
||||||
|
{
|
||||||
|
Position = new Vector2(256, 192),
|
||||||
|
IndexInCurrentCombo = 0,
|
||||||
|
Duration = 0,
|
||||||
|
}))
|
||||||
|
{
|
||||||
|
Clock = new FramedClock(new StopwatchClock())
|
||||||
|
});
|
||||||
|
|
||||||
|
AddStep("apply new spinner", () => dho.Apply(prepareObject(new Spinner
|
||||||
|
{
|
||||||
|
Position = new Vector2(256, 192),
|
||||||
|
ComboIndex = 1,
|
||||||
|
Duration = 1000,
|
||||||
|
})));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Spinner prepareObject(Spinner circle)
|
||||||
|
{
|
||||||
|
circle.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
||||||
|
return circle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using JetBrains.Annotations;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
@ -30,7 +31,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
private Container scaleContainer;
|
private Container scaleContainer;
|
||||||
private InputManager inputManager;
|
private InputManager inputManager;
|
||||||
|
|
||||||
public DrawableHitCircle(HitCircle h)
|
public DrawableHitCircle([CanBeNull] HitCircle h = null)
|
||||||
: base(h)
|
: base(h)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -72,10 +73,10 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
|
|
||||||
Size = HitArea.DrawSize;
|
Size = HitArea.DrawSize;
|
||||||
|
|
||||||
PositionBindable.BindValueChanged(_ => Position = HitObject.StackedPosition, true);
|
PositionBindable.BindValueChanged(_ => Position = HitObject.StackedPosition);
|
||||||
StackHeightBindable.BindValueChanged(_ => Position = HitObject.StackedPosition, true);
|
StackHeightBindable.BindValueChanged(_ => Position = HitObject.StackedPosition);
|
||||||
ScaleBindable.BindValueChanged(scale => scaleContainer.Scale = new Vector2(scale.NewValue), true);
|
ScaleBindable.BindValueChanged(scale => scaleContainer.Scale = new Vector2(scale.NewValue));
|
||||||
AccentColour.BindValueChanged(accent => ApproachCircle.Colour = accent.NewValue, true);
|
AccentColour.BindValueChanged(accent => ApproachCircle.Colour = accent.NewValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
|
@ -9,6 +9,7 @@ using osu.Framework.Graphics;
|
|||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
using osu.Game.Rulesets.Osu.Judgements;
|
using osu.Game.Rulesets.Osu.Judgements;
|
||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Osu.UI;
|
using osu.Game.Rulesets.Osu.UI;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
@ -49,6 +50,11 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
ShakeDuration = 30,
|
ShakeDuration = 30,
|
||||||
RelativeSizeAxes = Axes.Both
|
RelativeSizeAxes = Axes.Both
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnApply(HitObject hitObject)
|
||||||
|
{
|
||||||
|
base.OnApply(hitObject);
|
||||||
|
|
||||||
IndexInCurrentComboBindable.BindTo(HitObject.IndexInCurrentComboBindable);
|
IndexInCurrentComboBindable.BindTo(HitObject.IndexInCurrentComboBindable);
|
||||||
PositionBindable.BindTo(HitObject.PositionBindable);
|
PositionBindable.BindTo(HitObject.PositionBindable);
|
||||||
@ -56,6 +62,16 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
ScaleBindable.BindTo(HitObject.ScaleBindable);
|
ScaleBindable.BindTo(HitObject.ScaleBindable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void OnFree(HitObject hitObject)
|
||||||
|
{
|
||||||
|
base.OnFree(hitObject);
|
||||||
|
|
||||||
|
IndexInCurrentComboBindable.UnbindFrom(HitObject.IndexInCurrentComboBindable);
|
||||||
|
PositionBindable.UnbindFrom(HitObject.PositionBindable);
|
||||||
|
StackHeightBindable.UnbindFrom(HitObject.StackHeightBindable);
|
||||||
|
ScaleBindable.UnbindFrom(HitObject.ScaleBindable);
|
||||||
|
}
|
||||||
|
|
||||||
// Forward all internal management to shakeContainer.
|
// Forward all internal management to shakeContainer.
|
||||||
// This is a bit ugly but we don't have the concept of InternalContent so it'll have to do for now. (https://github.com/ppy/osu-framework/issues/1690)
|
// This is a bit ugly but we don't have the concept of InternalContent so it'll have to do for now. (https://github.com/ppy/osu-framework/issues/1690)
|
||||||
protected override void AddInternal(Drawable drawable) => shakeContainer.Add(drawable);
|
protected override void AddInternal(Drawable drawable) => shakeContainer.Add(drawable);
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using JetBrains.Annotations;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
@ -32,14 +33,15 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
|
|
||||||
private PlaySliderBody sliderBody => Body.Drawable as PlaySliderBody;
|
private PlaySliderBody sliderBody => Body.Drawable as PlaySliderBody;
|
||||||
|
|
||||||
public readonly IBindable<int> PathVersion = new Bindable<int>();
|
public IBindable<int> PathVersion => pathVersion;
|
||||||
|
private readonly Bindable<int> pathVersion = new Bindable<int>();
|
||||||
|
|
||||||
private Container<DrawableSliderHead> headContainer;
|
private Container<DrawableSliderHead> headContainer;
|
||||||
private Container<DrawableSliderTail> tailContainer;
|
private Container<DrawableSliderTail> tailContainer;
|
||||||
private Container<DrawableSliderTick> tickContainer;
|
private Container<DrawableSliderTick> tickContainer;
|
||||||
private Container<DrawableSliderRepeat> repeatContainer;
|
private Container<DrawableSliderRepeat> repeatContainer;
|
||||||
|
|
||||||
public DrawableSlider(Slider s)
|
public DrawableSlider([CanBeNull] Slider s = null)
|
||||||
: base(s)
|
: base(s)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -63,11 +65,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
headContainer = new Container<DrawableSliderHead> { RelativeSizeAxes = Axes.Both },
|
headContainer = new Container<DrawableSliderHead> { RelativeSizeAxes = Axes.Both },
|
||||||
};
|
};
|
||||||
|
|
||||||
PathVersion.BindTo(HitObject.Path.Version);
|
PositionBindable.BindValueChanged(_ => Position = HitObject.StackedPosition);
|
||||||
|
StackHeightBindable.BindValueChanged(_ => Position = HitObject.StackedPosition);
|
||||||
PositionBindable.BindValueChanged(_ => Position = HitObject.StackedPosition, true);
|
ScaleBindable.BindValueChanged(scale => Ball.Scale = new Vector2(scale.NewValue));
|
||||||
StackHeightBindable.BindValueChanged(_ => Position = HitObject.StackedPosition, true);
|
|
||||||
ScaleBindable.BindValueChanged(scale => Ball.Scale = new Vector2(scale.NewValue), true);
|
|
||||||
|
|
||||||
AccentColour.BindValueChanged(colour =>
|
AccentColour.BindValueChanged(colour =>
|
||||||
{
|
{
|
||||||
@ -78,6 +78,22 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
Tracking.BindValueChanged(updateSlidingSample);
|
Tracking.BindValueChanged(updateSlidingSample);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void OnApply(HitObject hitObject)
|
||||||
|
{
|
||||||
|
base.OnApply(hitObject);
|
||||||
|
|
||||||
|
// Ensure that the version will change after the upcoming BindTo().
|
||||||
|
pathVersion.Value = int.MaxValue;
|
||||||
|
PathVersion.BindTo(HitObject.Path.Version);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnFree(HitObject hitObject)
|
||||||
|
{
|
||||||
|
base.OnFree(hitObject);
|
||||||
|
|
||||||
|
PathVersion.UnbindFrom(HitObject.Path.Version);
|
||||||
|
}
|
||||||
|
|
||||||
private PausableSkinnableSound slidingSample;
|
private PausableSkinnableSound slidingSample;
|
||||||
|
|
||||||
protected override void LoadSamples()
|
protected override void LoadSamples()
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using JetBrains.Annotations;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Audio;
|
using osu.Framework.Audio;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
@ -32,7 +33,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
private Bindable<bool> isSpinning;
|
private Bindable<bool> isSpinning;
|
||||||
private bool spinnerFrequencyModulate;
|
private bool spinnerFrequencyModulate;
|
||||||
|
|
||||||
public DrawableSpinner(Spinner s)
|
public DrawableSpinner([CanBeNull] Spinner s = null)
|
||||||
: base(s)
|
: base(s)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -72,7 +73,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
PositionBindable.BindValueChanged(pos => Position = pos.NewValue, true);
|
PositionBindable.BindValueChanged(pos => Position = pos.NewValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
// 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.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
@ -28,9 +27,10 @@ namespace osu.Game.Rulesets.Taiko.Tests
|
|||||||
// suppress locally to allow hiding the visuals wherever necessary.
|
// suppress locally to allow hiding the visuals wherever necessary.
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
protected override void LoadComplete()
|
||||||
private void load()
|
|
||||||
{
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
Result.Type = Type;
|
Result.Type = Type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Specialized;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
@ -27,7 +28,10 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
|||||||
{
|
{
|
||||||
public event Action<DrawableHitObject> DefaultsApplied;
|
public event Action<DrawableHitObject> DefaultsApplied;
|
||||||
|
|
||||||
public readonly HitObject HitObject;
|
/// <summary>
|
||||||
|
/// The <see cref="HitObject"/> currently represented by this <see cref="DrawableHitObject"/>.
|
||||||
|
/// </summary>
|
||||||
|
public HitObject HitObject { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The colour used for various elements of this DrawableHitObject.
|
/// The colour used for various elements of this DrawableHitObject.
|
||||||
@ -96,10 +100,10 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
|||||||
/// </remarks>
|
/// </remarks>
|
||||||
protected virtual float SamplePlaybackPosition => 0.5f;
|
protected virtual float SamplePlaybackPosition => 0.5f;
|
||||||
|
|
||||||
private BindableList<HitSampleInfo> samplesBindable;
|
private readonly Bindable<double> startTimeBindable = new Bindable<double>();
|
||||||
private Bindable<double> startTimeBindable;
|
private readonly BindableList<HitSampleInfo> samplesBindable = new BindableList<HitSampleInfo>();
|
||||||
private Bindable<bool> userPositionalHitSounds;
|
private readonly Bindable<bool> userPositionalHitSounds = new Bindable<bool>();
|
||||||
private Bindable<int> comboIndexBindable;
|
private readonly Bindable<int> comboIndexBindable = new Bindable<int>();
|
||||||
|
|
||||||
public override bool RemoveWhenNotAlive => false;
|
public override bool RemoveWhenNotAlive => false;
|
||||||
public override bool RemoveCompletedTransforms => false;
|
public override bool RemoveCompletedTransforms => false;
|
||||||
@ -111,52 +115,157 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
|||||||
|
|
||||||
public IBindable<ArmedState> State => state;
|
public IBindable<ArmedState> State => state;
|
||||||
|
|
||||||
protected DrawableHitObject([NotNull] HitObject hitObject)
|
/// <summary>
|
||||||
|
/// Whether <see cref="HitObject"/> is currently applied.
|
||||||
|
/// </summary>
|
||||||
|
private bool hasHitObjectApplied;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new <see cref="DrawableHitObject"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="initialHitObject">
|
||||||
|
/// The <see cref="HitObject"/> to be initially applied to this <see cref="DrawableHitObject"/>.
|
||||||
|
/// If <c>null</c>, a hitobject is expected to be later applied via <see cref="Apply"/> (or automatically via pooling).
|
||||||
|
/// </param>
|
||||||
|
protected DrawableHitObject([CanBeNull] HitObject initialHitObject = null)
|
||||||
{
|
{
|
||||||
HitObject = hitObject ?? throw new ArgumentNullException(nameof(hitObject));
|
HitObject = initialHitObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuConfigManager config)
|
private void load(OsuConfigManager config)
|
||||||
{
|
{
|
||||||
userPositionalHitSounds = config.GetBindable<bool>(OsuSetting.PositionalHitSounds);
|
config.BindWith(OsuSetting.PositionalHitSounds, userPositionalHitSounds);
|
||||||
var judgement = HitObject.CreateJudgement();
|
|
||||||
|
|
||||||
Result = CreateResult(judgement);
|
|
||||||
if (Result == null)
|
|
||||||
throw new InvalidOperationException($"{GetType().ReadableName()} must provide a {nameof(JudgementResult)} through {nameof(CreateResult)}.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadAsyncComplete()
|
protected override void LoadAsyncComplete()
|
||||||
{
|
{
|
||||||
base.LoadAsyncComplete();
|
base.LoadAsyncComplete();
|
||||||
|
|
||||||
LoadSamples();
|
if (HitObject != null)
|
||||||
|
Apply(HitObject);
|
||||||
HitObject.DefaultsApplied += onDefaultsApplied;
|
|
||||||
|
|
||||||
startTimeBindable = HitObject.StartTimeBindable.GetBoundCopy();
|
|
||||||
startTimeBindable.BindValueChanged(_ => updateState(State.Value, true));
|
|
||||||
|
|
||||||
if (HitObject is IHasComboInformation combo)
|
|
||||||
{
|
|
||||||
comboIndexBindable = combo.ComboIndexBindable.GetBoundCopy();
|
|
||||||
comboIndexBindable.BindValueChanged(_ => updateComboColour(), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
samplesBindable = HitObject.SamplesBindable.GetBoundCopy();
|
|
||||||
samplesBindable.CollectionChanged += (_, __) => LoadSamples();
|
|
||||||
|
|
||||||
apply(HitObject);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
|
|
||||||
|
startTimeBindable.BindValueChanged(_ => updateState(State.Value, true));
|
||||||
|
comboIndexBindable.BindValueChanged(_ => updateComboColour(), true);
|
||||||
|
|
||||||
updateState(ArmedState.Idle, true);
|
updateState(ArmedState.Idle, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Applies a new <see cref="HitObject"/> to be represented by this <see cref="DrawableHitObject"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hitObject">The <see cref="HitObject"/> to apply.</param>
|
||||||
|
public void Apply(HitObject hitObject)
|
||||||
|
{
|
||||||
|
free();
|
||||||
|
|
||||||
|
HitObject = hitObject ?? throw new InvalidOperationException($"Cannot apply a null {nameof(HitObject)}.");
|
||||||
|
|
||||||
|
// Ensure this DHO has a result.
|
||||||
|
Result ??= CreateResult(HitObject.CreateJudgement())
|
||||||
|
?? throw new InvalidOperationException($"{GetType().ReadableName()} must provide a {nameof(JudgementResult)} through {nameof(CreateResult)}.");
|
||||||
|
|
||||||
|
foreach (var h in HitObject.NestedHitObjects)
|
||||||
|
{
|
||||||
|
var drawableNested = CreateNestedHitObject(h) ?? throw new InvalidOperationException($"{nameof(CreateNestedHitObject)} returned null for {h.GetType().ReadableName()}.");
|
||||||
|
|
||||||
|
drawableNested.OnNewResult += onNewResult;
|
||||||
|
drawableNested.OnRevertResult += onRevertResult;
|
||||||
|
drawableNested.ApplyCustomUpdateState += onApplyCustomUpdateState;
|
||||||
|
|
||||||
|
nestedHitObjects.Value.Add(drawableNested);
|
||||||
|
AddNestedHitObject(drawableNested);
|
||||||
|
}
|
||||||
|
|
||||||
|
startTimeBindable.BindTo(HitObject.StartTimeBindable);
|
||||||
|
if (HitObject is IHasComboInformation combo)
|
||||||
|
comboIndexBindable.BindTo(combo.ComboIndexBindable);
|
||||||
|
|
||||||
|
samplesBindable.BindTo(HitObject.SamplesBindable);
|
||||||
|
samplesBindable.BindCollectionChanged(onSamplesChanged, true);
|
||||||
|
|
||||||
|
HitObject.DefaultsApplied += onDefaultsApplied;
|
||||||
|
|
||||||
|
OnApply(hitObject);
|
||||||
|
|
||||||
|
// If not loaded, the state update happens in LoadComplete(). Otherwise, the update is scheduled to allow for lifetime updates.
|
||||||
|
if (IsLoaded)
|
||||||
|
Schedule(() => updateState(ArmedState.Idle, true));
|
||||||
|
|
||||||
|
hasHitObjectApplied = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes the currently applied <see cref="HitObject"/>
|
||||||
|
/// </summary>
|
||||||
|
private void free()
|
||||||
|
{
|
||||||
|
if (!hasHitObjectApplied)
|
||||||
|
return;
|
||||||
|
|
||||||
|
startTimeBindable.UnbindFrom(HitObject.StartTimeBindable);
|
||||||
|
if (HitObject is IHasComboInformation combo)
|
||||||
|
comboIndexBindable.UnbindFrom(combo.ComboIndexBindable);
|
||||||
|
|
||||||
|
samplesBindable.UnbindFrom(HitObject.SamplesBindable);
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
if (nestedHitObjects.IsValueCreated)
|
||||||
|
{
|
||||||
|
foreach (var obj in nestedHitObjects.Value)
|
||||||
|
{
|
||||||
|
obj.OnNewResult -= onNewResult;
|
||||||
|
obj.OnRevertResult -= onRevertResult;
|
||||||
|
obj.ApplyCustomUpdateState -= onApplyCustomUpdateState;
|
||||||
|
}
|
||||||
|
|
||||||
|
nestedHitObjects.Value.Clear();
|
||||||
|
ClearNestedHitObjects();
|
||||||
|
}
|
||||||
|
|
||||||
|
HitObject.DefaultsApplied -= onDefaultsApplied;
|
||||||
|
|
||||||
|
OnFree(HitObject);
|
||||||
|
|
||||||
|
HitObject = null;
|
||||||
|
hasHitObjectApplied = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected sealed override void FreeAfterUse()
|
||||||
|
{
|
||||||
|
base.FreeAfterUse();
|
||||||
|
|
||||||
|
// Freeing while not in a pool would cause the DHO to not be usable elsewhere in the hierarchy without being re-applied.
|
||||||
|
if (!IsInPool)
|
||||||
|
return;
|
||||||
|
|
||||||
|
free();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Invoked for this <see cref="DrawableHitObject"/> to take on any values from a newly-applied <see cref="HitObject"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hitObject">The <see cref="HitObject"/> being applied.</param>
|
||||||
|
protected virtual void OnApply(HitObject hitObject)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Invoked for this <see cref="DrawableHitObject"/> to revert any values previously taken on from the currently-applied <see cref="HitObject"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hitObject">The currently-applied <see cref="HitObject"/>.</param>
|
||||||
|
protected virtual void OnFree(HitObject hitObject)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Invoked by the base <see cref="DrawableHitObject"/> to populate samples, once on initial load and potentially again on any change to the samples collection.
|
/// Invoked by the base <see cref="DrawableHitObject"/> to populate samples, once on initial load and potentially again on any change to the samples collection.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -183,34 +292,20 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
|||||||
AddInternal(Samples);
|
AddInternal(Samples);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void onSamplesChanged(object sender, NotifyCollectionChangedEventArgs e) => LoadSamples();
|
||||||
|
|
||||||
|
private void onNewResult(DrawableHitObject drawableHitObject, JudgementResult result) => OnNewResult?.Invoke(drawableHitObject, result);
|
||||||
|
|
||||||
|
private void onRevertResult(DrawableHitObject drawableHitObject, JudgementResult result) => OnRevertResult?.Invoke(drawableHitObject, result);
|
||||||
|
|
||||||
|
private void onApplyCustomUpdateState(DrawableHitObject drawableHitObject, ArmedState state) => ApplyCustomUpdateState?.Invoke(drawableHitObject, state);
|
||||||
|
|
||||||
private void onDefaultsApplied(HitObject hitObject)
|
private void onDefaultsApplied(HitObject hitObject)
|
||||||
{
|
{
|
||||||
apply(hitObject);
|
Apply(hitObject);
|
||||||
updateState(state.Value, true);
|
|
||||||
DefaultsApplied?.Invoke(this);
|
DefaultsApplied?.Invoke(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void apply(HitObject hitObject)
|
|
||||||
{
|
|
||||||
if (nestedHitObjects.IsValueCreated)
|
|
||||||
{
|
|
||||||
nestedHitObjects.Value.Clear();
|
|
||||||
ClearNestedHitObjects();
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var h in hitObject.NestedHitObjects)
|
|
||||||
{
|
|
||||||
var drawableNested = CreateNestedHitObject(h) ?? throw new InvalidOperationException($"{nameof(CreateNestedHitObject)} returned null for {h.GetType().ReadableName()}.");
|
|
||||||
|
|
||||||
drawableNested.OnNewResult += (d, r) => OnNewResult?.Invoke(d, r);
|
|
||||||
drawableNested.OnRevertResult += (d, r) => OnRevertResult?.Invoke(d, r);
|
|
||||||
drawableNested.ApplyCustomUpdateState += (d, j) => ApplyCustomUpdateState?.Invoke(d, j);
|
|
||||||
|
|
||||||
nestedHitObjects.Value.Add(drawableNested);
|
|
||||||
AddNestedHitObject(drawableNested);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Invoked by the base <see cref="DrawableHitObject"/> to add nested <see cref="DrawableHitObject"/>s to the hierarchy.
|
/// Invoked by the base <see cref="DrawableHitObject"/> to add nested <see cref="DrawableHitObject"/>s to the hierarchy.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -600,19 +695,20 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
|||||||
protected override void Dispose(bool isDisposing)
|
protected override void Dispose(bool isDisposing)
|
||||||
{
|
{
|
||||||
base.Dispose(isDisposing);
|
base.Dispose(isDisposing);
|
||||||
HitObject.DefaultsApplied -= onDefaultsApplied;
|
|
||||||
|
if (HitObject != null)
|
||||||
|
HitObject.DefaultsApplied -= onDefaultsApplied;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract class DrawableHitObject<TObject> : DrawableHitObject
|
public abstract class DrawableHitObject<TObject> : DrawableHitObject
|
||||||
where TObject : HitObject
|
where TObject : HitObject
|
||||||
{
|
{
|
||||||
public new readonly TObject HitObject;
|
public new TObject HitObject => (TObject)base.HitObject;
|
||||||
|
|
||||||
protected DrawableHitObject(TObject hitObject)
|
protected DrawableHitObject(TObject hitObject)
|
||||||
: base(hitObject)
|
: base(hitObject)
|
||||||
{
|
{
|
||||||
HitObject = hitObject;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,14 +3,14 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Pooling;
|
||||||
|
|
||||||
namespace osu.Game.Skinning
|
namespace osu.Game.Skinning
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A drawable which has a callback when the skin changes.
|
/// A drawable which has a callback when the skin changes.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class SkinReloadableDrawable : CompositeDrawable
|
public abstract class SkinReloadableDrawable : PoolableDrawable
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Invoked when <see cref="CurrentSkin"/> has changed.
|
/// Invoked when <see cref="CurrentSkin"/> has changed.
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||||
<PackageReference Include="ppy.osu.Framework" Version="2020.1109.0" />
|
<PackageReference Include="ppy.osu.Framework" Version="2020.1110.0" />
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.1030.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.1030.0" />
|
||||||
<PackageReference Include="Sentry" Version="2.1.6" />
|
<PackageReference Include="Sentry" Version="2.1.6" />
|
||||||
<PackageReference Include="SharpCompress" Version="0.26.0" />
|
<PackageReference Include="SharpCompress" Version="0.26.0" />
|
||||||
|
@ -70,7 +70,7 @@
|
|||||||
<Reference Include="System.Net.Http" />
|
<Reference Include="System.Net.Http" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup Label="Package References">
|
<ItemGroup Label="Package References">
|
||||||
<PackageReference Include="ppy.osu.Framework.iOS" Version="2020.1109.0" />
|
<PackageReference Include="ppy.osu.Framework.iOS" Version="2020.1110.0" />
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.1030.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.1030.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<!-- See https://github.com/dotnet/runtime/issues/35988 (can be removed after Xamarin uses net5.0 / net6.0) -->
|
<!-- See https://github.com/dotnet/runtime/issues/35988 (can be removed after Xamarin uses net5.0 / net6.0) -->
|
||||||
@ -88,7 +88,7 @@
|
|||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||||
<PackageReference Include="ppy.osu.Framework" Version="2020.1109.0" />
|
<PackageReference Include="ppy.osu.Framework" Version="2020.1110.0" />
|
||||||
<PackageReference Include="SharpCompress" Version="0.26.0" />
|
<PackageReference Include="SharpCompress" Version="0.26.0" />
|
||||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||||
<PackageReference Include="SharpRaven" Version="2.4.0" />
|
<PackageReference Include="SharpRaven" Version="2.4.0" />
|
||||||
|
Loading…
Reference in New Issue
Block a user