mirror of
https://github.com/ppy/osu.git
synced 2025-02-22 16:32:59 +08:00
Use existing bindable flow instead
This commit is contained in:
parent
585b857a0c
commit
d6f3beffb6
@ -112,10 +112,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
|
|
||||||
private void updateSlidingSample(ValueChangedEvent<bool> tracking)
|
private void updateSlidingSample(ValueChangedEvent<bool> tracking)
|
||||||
{
|
{
|
||||||
// note that samples will not start playing if exiting a seek operation in the middle of a slider.
|
if (tracking.NewValue)
|
||||||
// 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();
|
slidingSample?.Play();
|
||||||
else
|
else
|
||||||
slidingSample?.Stop();
|
slidingSample?.Stop();
|
||||||
|
@ -113,10 +113,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
|
|
||||||
private void updateSpinningSample(ValueChangedEvent<bool> tracking)
|
private void updateSpinningSample(ValueChangedEvent<bool> tracking)
|
||||||
{
|
{
|
||||||
// note that samples will not start playing if exiting a seek operation in the middle of a spinner.
|
if (tracking.NewValue)
|
||||||
// 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)
|
|
||||||
{
|
{
|
||||||
spinningSample?.Play();
|
spinningSample?.Play();
|
||||||
spinningSample?.VolumeTo(1, 200);
|
spinningSample?.VolumeTo(1, 200);
|
||||||
|
@ -22,7 +22,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
{
|
{
|
||||||
public class TestSceneSkinnableSound : OsuTestScene
|
public class TestSceneSkinnableSound : OsuTestScene
|
||||||
{
|
{
|
||||||
[Cached]
|
[Cached(typeof(ISamplePlaybackDisabler))]
|
||||||
private GameplayClock gameplayClock = new GameplayClock(new FramedClock());
|
private GameplayClock gameplayClock = new GameplayClock(new FramedClock());
|
||||||
|
|
||||||
private TestSkinSourceContainer skinSource;
|
private TestSkinSourceContainer skinSource;
|
||||||
|
@ -360,7 +360,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Resolved(canBeNull: true)]
|
[Resolved(canBeNull: true)]
|
||||||
private ISeekableClock seekableClock { get; set; }
|
private ISamplePlaybackDisabler samplePlaybackDisabler { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Calculate the position to be used for sample playback at a specified X position (0..1).
|
/// Calculate the position to be used for sample playback at a specified X position (0..1).
|
||||||
@ -374,18 +374,13 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
|||||||
return balance_adjust_amount * (userPositionalHitSounds.Value ? position - 0.5f : 0);
|
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 => seekableClock?.IsSeeking != true;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Plays all the hit sounds for this <see cref="DrawableHitObject"/>.
|
/// Plays all the hit sounds for this <see cref="DrawableHitObject"/>.
|
||||||
/// This is invoked automatically when this <see cref="DrawableHitObject"/> is hit.
|
/// This is invoked automatically when this <see cref="DrawableHitObject"/> is hit.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual void PlaySamples()
|
public virtual void PlaySamples()
|
||||||
{
|
{
|
||||||
if (Samples != null && ShouldPlaySamples)
|
if (Samples != null)
|
||||||
{
|
{
|
||||||
Samples.Balance.Value = CalculateSamplePlaybackBalance(SamplePlaybackPosition);
|
Samples.Balance.Value = CalculateSamplePlaybackBalance(SamplePlaybackPosition);
|
||||||
Samples.Play();
|
Samples.Play();
|
||||||
|
@ -107,7 +107,7 @@ namespace osu.Game.Screens.Edit
|
|||||||
UpdateClockSource();
|
UpdateClockSource();
|
||||||
|
|
||||||
dependencies.CacheAs(clock);
|
dependencies.CacheAs(clock);
|
||||||
dependencies.CacheAs<ISeekableClock>(clock);
|
dependencies.CacheAs<ISamplePlaybackDisabler>(clock);
|
||||||
AddInternal(clock);
|
AddInternal(clock);
|
||||||
|
|
||||||
// todo: remove caching of this and consume via editorBeatmap?
|
// todo: remove caching of this and consume via editorBeatmap?
|
||||||
|
@ -18,7 +18,7 @@ namespace osu.Game.Screens.Edit
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// A decoupled clock which adds editor-specific functionality, such as snapping to a user-defined beat divisor.
|
/// A decoupled clock which adds editor-specific functionality, such as snapping to a user-defined beat divisor.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class EditorClock : Component, IFrameBasedClock, IAdjustableClock, ISourceChangeableClock, ISeekableClock
|
public class EditorClock : Component, IFrameBasedClock, IAdjustableClock, ISourceChangeableClock, ISamplePlaybackDisabler
|
||||||
{
|
{
|
||||||
public IBindable<Track> Track => track;
|
public IBindable<Track> Track => track;
|
||||||
|
|
||||||
@ -32,6 +32,10 @@ namespace osu.Game.Screens.Edit
|
|||||||
|
|
||||||
private readonly DecoupleableInterpolatingFramedClock underlyingClock;
|
private readonly DecoupleableInterpolatingFramedClock underlyingClock;
|
||||||
|
|
||||||
|
public IBindable<bool> SamplePlaybackDisabled => samplePlaybackDisabled;
|
||||||
|
|
||||||
|
private readonly Bindable<bool> samplePlaybackDisabled = new Bindable<bool>();
|
||||||
|
|
||||||
public EditorClock(WorkingBeatmap beatmap, BindableBeatDivisor beatDivisor)
|
public EditorClock(WorkingBeatmap beatmap, BindableBeatDivisor beatDivisor)
|
||||||
: this(beatmap.Beatmap.ControlPointInfo, beatmap.Track.Length, beatDivisor)
|
: this(beatmap.Beatmap.ControlPointInfo, beatmap.Track.Length, beatDivisor)
|
||||||
{
|
{
|
||||||
@ -167,11 +171,14 @@ namespace osu.Game.Screens.Edit
|
|||||||
|
|
||||||
public void Stop()
|
public void Stop()
|
||||||
{
|
{
|
||||||
|
samplePlaybackDisabled.Value = true;
|
||||||
underlyingClock.Stop();
|
underlyingClock.Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Seek(double position)
|
public bool Seek(double position)
|
||||||
{
|
{
|
||||||
|
samplePlaybackDisabled.Value = true;
|
||||||
|
|
||||||
ClearTransforms();
|
ClearTransforms();
|
||||||
return underlyingClock.Seek(position);
|
return underlyingClock.Seek(position);
|
||||||
}
|
}
|
||||||
@ -212,26 +219,34 @@ namespace osu.Game.Screens.Edit
|
|||||||
|
|
||||||
private const double transform_time = 300;
|
private const double transform_time = 300;
|
||||||
|
|
||||||
public bool IsSeeking { get; private set; }
|
|
||||||
|
|
||||||
protected override void Update()
|
protected override void Update()
|
||||||
{
|
{
|
||||||
base.Update();
|
base.Update();
|
||||||
|
|
||||||
if (IsSeeking)
|
updateSeekingState();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateSeekingState()
|
||||||
|
{
|
||||||
|
if (samplePlaybackDisabled.Value)
|
||||||
{
|
{
|
||||||
bool isPaused = track.Value?.IsRunning != true;
|
if (track.Value?.IsRunning != true)
|
||||||
|
{
|
||||||
|
// seeking in the editor can happen while the track isn't running.
|
||||||
|
// in this case we always want to expose ourselves as seeking (to avoid sample playback).
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// we are either running a seek tween or doing an immediate seek.
|
// we are either running a seek tween or doing an immediate seek.
|
||||||
// in the case of an immediate seek the seeking bool will be set to false after one update.
|
// in the case of an immediate seek the seeking bool will be set to false after one update.
|
||||||
// this allows for silencing hit sounds and the likes.
|
// this allows for silencing hit sounds and the likes.
|
||||||
IsSeeking = isPaused || Transforms.Any();
|
samplePlaybackDisabled.Value = Transforms.Any();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SeekTo(double seekDestination)
|
public void SeekTo(double seekDestination)
|
||||||
{
|
{
|
||||||
IsSeeking = true;
|
samplePlaybackDisabled.Value = true;
|
||||||
|
|
||||||
if (IsRunning)
|
if (IsRunning)
|
||||||
Seek(seekDestination);
|
Seek(seekDestination);
|
||||||
|
@ -14,7 +14,7 @@ namespace osu.Game.Screens.Play
|
|||||||
/// <see cref="IFrameBasedClock"/>, as this should only be done once to ensure accuracy.
|
/// <see cref="IFrameBasedClock"/>, as this should only be done once to ensure accuracy.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class GameplayClock : IFrameBasedClock, ISeekableClock
|
public class GameplayClock : IFrameBasedClock, ISamplePlaybackDisabler
|
||||||
{
|
{
|
||||||
private readonly IFrameBasedClock underlyingClock;
|
private readonly IFrameBasedClock underlyingClock;
|
||||||
|
|
||||||
@ -48,5 +48,7 @@ namespace osu.Game.Screens.Play
|
|||||||
public FrameTimeInfo TimeInfo => underlyingClock.TimeInfo;
|
public FrameTimeInfo TimeInfo => underlyingClock.TimeInfo;
|
||||||
|
|
||||||
public IClock Source => underlyingClock;
|
public IClock Source => underlyingClock;
|
||||||
|
|
||||||
|
public IBindable<bool> SamplePlaybackDisabled => IsPaused;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
20
osu.Game/Screens/Play/ISamplePlaybackDisabler.cs
Normal file
20
osu.Game/Screens/Play/ISamplePlaybackDisabler.cs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
// 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.Bindables;
|
||||||
|
using osu.Game.Skinning;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.Play
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Allows a component to disable sample playback dynamically as required.
|
||||||
|
/// Handled by <see cref="SkinnableSound"/>.
|
||||||
|
/// </summary>
|
||||||
|
public interface ISamplePlaybackDisabler
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Whether sample playback should be disabled (or paused for looping samples).
|
||||||
|
/// </summary>
|
||||||
|
IBindable<bool> SamplePlaybackDisabled { get; }
|
||||||
|
}
|
||||||
|
}
|
@ -1,13 +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.
|
|
||||||
|
|
||||||
namespace osu.Game.Screens.Play
|
|
||||||
{
|
|
||||||
public interface ISeekableClock
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Whether an ongoing seek operation is active.
|
|
||||||
/// </summary>
|
|
||||||
bool IsSeeking { get; }
|
|
||||||
}
|
|
||||||
}
|
|
@ -50,25 +50,28 @@ namespace osu.Game.Skinning
|
|||||||
InternalChild = samplesContainer = new AudioContainer<DrawableSample>();
|
InternalChild = samplesContainer = new AudioContainer<DrawableSample>();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Bindable<bool> gameplayClockPaused;
|
private readonly IBindable<bool> samplePlaybackDisabled = new Bindable<bool>();
|
||||||
|
|
||||||
[BackgroundDependencyLoader(true)]
|
[BackgroundDependencyLoader(true)]
|
||||||
private void load(GameplayClock gameplayClock)
|
private void load(ISamplePlaybackDisabler samplePlaybackDisabler)
|
||||||
{
|
{
|
||||||
// if in a gameplay context, pause sample playback when gameplay is paused.
|
// if in a gameplay context, pause sample playback when gameplay is paused.
|
||||||
gameplayClockPaused = gameplayClock?.IsPaused.GetBoundCopy();
|
if (samplePlaybackDisabler != null)
|
||||||
gameplayClockPaused?.BindValueChanged(paused =>
|
|
||||||
{
|
{
|
||||||
if (requestedPlaying)
|
samplePlaybackDisabled.BindTo(samplePlaybackDisabler.SamplePlaybackDisabled);
|
||||||
|
samplePlaybackDisabled.BindValueChanged(disabled =>
|
||||||
{
|
{
|
||||||
if (paused.NewValue)
|
if (requestedPlaying)
|
||||||
stop();
|
{
|
||||||
// it's not easy to know if a sample has finished playing (to end).
|
if (disabled.NewValue)
|
||||||
// to keep things simple only resume playing looping samples.
|
stop();
|
||||||
else if (Looping)
|
// it's not easy to know if a sample has finished playing (to end).
|
||||||
play();
|
// to keep things simple only resume playing looping samples.
|
||||||
}
|
else if (Looping)
|
||||||
});
|
play();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool looping;
|
private bool looping;
|
||||||
@ -94,6 +97,9 @@ namespace osu.Game.Skinning
|
|||||||
|
|
||||||
private void play()
|
private void play()
|
||||||
{
|
{
|
||||||
|
if (samplePlaybackDisabled.Value)
|
||||||
|
return;
|
||||||
|
|
||||||
samplesContainer.ForEach(c =>
|
samplesContainer.ForEach(c =>
|
||||||
{
|
{
|
||||||
if (PlayWhenZeroVolume || c.AggregateVolume.Value > 0)
|
if (PlayWhenZeroVolume || c.AggregateVolume.Value > 0)
|
||||||
|
Loading…
Reference in New Issue
Block a user