1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-14 04:02:55 +08:00

Merge pull request #9646 from peppy/add-slider-slide-support

Add slider "sliding" sample support
This commit is contained in:
Dan Balasescu 2020-07-23 21:53:27 +09:00 committed by GitHub
commit f3247b07be
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 64 additions and 7 deletions

View File

@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text.
using System;
using System.Linq;
using osuTK;
using osu.Framework.Graphics;
using osu.Game.Rulesets.Objects.Drawables;
@ -11,6 +12,7 @@ using osu.Framework.Bindables;
using osu.Framework.Graphics.Containers;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Osu.Skinning;
using osu.Game.Rulesets.Osu.UI;
using osu.Game.Rulesets.Scoring;
using osuTK.Graphics;
using osu.Game.Skinning;
@ -81,6 +83,42 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
foreach (var drawableHitObject in NestedHitObjects)
drawableHitObject.AccentColour.Value = colour.NewValue;
}, true);
Tracking.BindValueChanged(updateSlidingSample);
}
private SkinnableSound slidingSample;
protected override void LoadSamples()
{
base.LoadSamples();
slidingSample?.Expire();
slidingSample = null;
var firstSample = HitObject.Samples.FirstOrDefault();
if (firstSample != null)
{
var clone = HitObject.SampleControlPoint.ApplyTo(firstSample);
clone.Name = "sliderslide";
AddInternal(slidingSample = new SkinnableSound(clone)
{
Looping = true
});
}
}
private void updateSlidingSample(ValueChangedEvent<bool> tracking)
{
// note that samples will not start playing if exiting a seek operation in the middle of a slider.
// may be something we want to address at a later point, but not so easy to make happen right now
// (SkinnableSound would need to expose whether the sample is already playing and this logic would need to run in Update).
if (tracking.NewValue && ShouldPlaySamples)
slidingSample?.Play();
else
slidingSample?.Stop();
}
protected override void AddNestedHitObject(DrawableHitObject hitObject)
@ -156,6 +194,10 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
Tracking.Value = Ball.Tracking;
if (Tracking.Value && slidingSample != null)
// keep the sliding sample playing at the current tracking position
slidingSample.Balance.Value = CalculateSamplePlaybackBalance(Ball.X / OsuPlayfield.BASE_SIZE.X);
double completionProgress = Math.Clamp((Time.Current - slider.StartTime) / slider.Duration, 0, 1);
Ball.UpdateProgress(completionProgress);

View File

@ -126,7 +126,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
if (Result == null)
throw new InvalidOperationException($"{GetType().ReadableName()} must provide a {nameof(JudgementResult)} through {nameof(CreateResult)}.");
loadSamples();
LoadSamples();
}
protected override void LoadComplete()
@ -145,14 +145,14 @@ namespace osu.Game.Rulesets.Objects.Drawables
}
samplesBindable = HitObject.SamplesBindable.GetBoundCopy();
samplesBindable.CollectionChanged += (_, __) => loadSamples();
samplesBindable.CollectionChanged += (_, __) => LoadSamples();
apply(HitObject);
updateState(ArmedState.Idle, true);
}
private void loadSamples()
protected virtual void LoadSamples()
{
if (Samples != null)
{
@ -353,17 +353,32 @@ namespace osu.Game.Rulesets.Objects.Drawables
[Resolved(canBeNull: true)]
private GameplayClock gameplayClock { get; set; }
/// <summary>
/// Calculate the position to be used for sample playback at a specified X position (0..1).
/// </summary>
/// <param name="position">The lookup X position. Generally should be <see cref="SamplePlaybackPosition"/>.</param>
/// <returns></returns>
protected double CalculateSamplePlaybackBalance(double position)
{
const float balance_adjust_amount = 0.4f;
return balance_adjust_amount * (userPositionalHitSounds.Value ? position - 0.5f : 0);
}
/// <summary>
/// Whether samples should currently be playing. Will be false during seek operations.
/// </summary>
protected bool ShouldPlaySamples => gameplayClock?.IsSeeking != true;
/// <summary>
/// Plays all the hit sounds for this <see cref="DrawableHitObject"/>.
/// This is invoked automatically when this <see cref="DrawableHitObject"/> is hit.
/// </summary>
public virtual void PlaySamples()
{
const float balance_adjust_amount = 0.4f;
if (Samples != null && gameplayClock?.IsSeeking != true)
if (Samples != null && ShouldPlaySamples)
{
Samples.Balance.Value = balance_adjust_amount * (userPositionalHitSounds.Value ? SamplePlaybackPosition - 0.5f : 0);
Samples.Balance.Value = CalculateSamplePlaybackBalance(SamplePlaybackPosition);
Samples.Play();
}
}