mirror of
https://github.com/ppy/osu
synced 2024-12-27 01:12:45 +00:00
Fix SPM changing incorrectly with playback rate changes
This commit is contained in:
parent
0cecb2bba3
commit
3f788da06d
@ -2,11 +2,13 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Screens.Play;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
@ -77,6 +79,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
|
||||
private bool rotationTransferred;
|
||||
|
||||
[Resolved]
|
||||
private GameplayClock gameplayClock { get; set; }
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
@ -126,7 +131,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
currentRotation += angle;
|
||||
// rate has to be applied each frame, because it's not guaranteed to be constant throughout playback
|
||||
// (see: ModTimeRamp)
|
||||
RateAdjustedRotation += (float)(Math.Abs(angle) * Clock.Rate);
|
||||
RateAdjustedRotation += (float)(Math.Abs(angle) * gameplayClock.TrueGameplayRate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,9 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Timing;
|
||||
@ -59,7 +61,7 @@ namespace osu.Game.Rulesets.UI
|
||||
{
|
||||
if (clock != null)
|
||||
{
|
||||
stabilityGameplayClock.ParentGameplayClock = parentGameplayClock = clock;
|
||||
parentGameplayClock = stabilityGameplayClock.ParentGameplayClock = clock;
|
||||
GameplayClock.IsPaused.BindTo(clock.IsPaused);
|
||||
}
|
||||
}
|
||||
@ -191,7 +193,9 @@ namespace osu.Game.Rulesets.UI
|
||||
|
||||
private class StabilityGameplayClock : GameplayClock
|
||||
{
|
||||
public IFrameBasedClock ParentGameplayClock;
|
||||
public GameplayClock ParentGameplayClock;
|
||||
|
||||
public override IEnumerable<Bindable<double>> NonGameplayAdjustments => ParentGameplayClock.NonGameplayAdjustments;
|
||||
|
||||
public StabilityGameplayClock(FramedClock underlyingClock)
|
||||
: base(underlyingClock)
|
||||
|
@ -1,6 +1,8 @@
|
||||
// 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.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Timing;
|
||||
|
||||
@ -20,6 +22,11 @@ namespace osu.Game.Screens.Play
|
||||
|
||||
public readonly BindableBool IsPaused = new BindableBool();
|
||||
|
||||
/// <summary>
|
||||
/// All adjustments applied to this clock which don't come from gameplay or mods.
|
||||
/// </summary>
|
||||
public virtual IEnumerable<Bindable<double>> NonGameplayAdjustments => Enumerable.Empty<Bindable<double>>();
|
||||
|
||||
public GameplayClock(IFrameBasedClock underlyingClock)
|
||||
{
|
||||
this.underlyingClock = underlyingClock;
|
||||
@ -29,6 +36,23 @@ namespace osu.Game.Screens.Play
|
||||
|
||||
public double Rate => underlyingClock.Rate;
|
||||
|
||||
/// <summary>
|
||||
/// The rate of gameplay when playback is at 100%.
|
||||
/// This excludes any seeking / user adjustments.
|
||||
/// </summary>
|
||||
public double TrueGameplayRate
|
||||
{
|
||||
get
|
||||
{
|
||||
double baseRate = Rate;
|
||||
|
||||
foreach (var adjustment in NonGameplayAdjustments)
|
||||
baseRate /= adjustment.Value;
|
||||
|
||||
return baseRate;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsRunning => underlyingClock.IsRunning;
|
||||
|
||||
/// <summary>
|
||||
|
@ -2,6 +2,7 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
@ -50,8 +51,10 @@ namespace osu.Game.Screens.Play
|
||||
/// <summary>
|
||||
/// The final clock which is exposed to underlying components.
|
||||
/// </summary>
|
||||
[Cached]
|
||||
public readonly GameplayClock GameplayClock;
|
||||
public GameplayClock GameplayClock => localGameplayClock;
|
||||
|
||||
[Cached(typeof(GameplayClock))]
|
||||
private readonly LocalGameplayClock localGameplayClock;
|
||||
|
||||
private Bindable<double> userAudioOffset;
|
||||
|
||||
@ -79,7 +82,7 @@ namespace osu.Game.Screens.Play
|
||||
userOffsetClock = new HardwareCorrectionOffsetClock(platformOffsetClock);
|
||||
|
||||
// the clock to be exposed via DI to children.
|
||||
GameplayClock = new GameplayClock(userOffsetClock);
|
||||
localGameplayClock = new LocalGameplayClock(userOffsetClock);
|
||||
|
||||
GameplayClock.IsPaused.BindTo(IsPaused);
|
||||
}
|
||||
@ -200,11 +203,26 @@ namespace osu.Game.Screens.Play
|
||||
protected override void Update()
|
||||
{
|
||||
if (!IsPaused.Value)
|
||||
{
|
||||
userOffsetClock.ProcessFrame();
|
||||
}
|
||||
|
||||
base.Update();
|
||||
}
|
||||
|
||||
private double getTrueGameplayRate()
|
||||
{
|
||||
double baseRate = track.Rate;
|
||||
|
||||
if (speedAdjustmentsApplied)
|
||||
{
|
||||
baseRate /= UserPlaybackRate.Value;
|
||||
baseRate /= pauseFreqAdjust.Value;
|
||||
}
|
||||
|
||||
return baseRate;
|
||||
}
|
||||
|
||||
private bool speedAdjustmentsApplied;
|
||||
|
||||
private void updateRate()
|
||||
@ -215,6 +233,9 @@ namespace osu.Game.Screens.Play
|
||||
track.AddAdjustment(AdjustableProperty.Frequency, pauseFreqAdjust);
|
||||
track.AddAdjustment(AdjustableProperty.Tempo, UserPlaybackRate);
|
||||
|
||||
localGameplayClock.MutableNonGameplayAdjustments.Add(pauseFreqAdjust);
|
||||
localGameplayClock.MutableNonGameplayAdjustments.Add(UserPlaybackRate);
|
||||
|
||||
speedAdjustmentsApplied = true;
|
||||
}
|
||||
|
||||
@ -231,9 +252,24 @@ namespace osu.Game.Screens.Play
|
||||
track.RemoveAdjustment(AdjustableProperty.Frequency, pauseFreqAdjust);
|
||||
track.RemoveAdjustment(AdjustableProperty.Tempo, UserPlaybackRate);
|
||||
|
||||
localGameplayClock.MutableNonGameplayAdjustments.Remove(pauseFreqAdjust);
|
||||
localGameplayClock.MutableNonGameplayAdjustments.Remove(UserPlaybackRate);
|
||||
|
||||
speedAdjustmentsApplied = false;
|
||||
}
|
||||
|
||||
public class LocalGameplayClock : GameplayClock
|
||||
{
|
||||
public readonly List<Bindable<double>> MutableNonGameplayAdjustments = new List<Bindable<double>>();
|
||||
|
||||
public override IEnumerable<Bindable<double>> NonGameplayAdjustments => MutableNonGameplayAdjustments;
|
||||
|
||||
public LocalGameplayClock(FramedOffsetClock underlyingClock)
|
||||
: base(underlyingClock)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private class HardwareCorrectionOffsetClock : FramedOffsetClock
|
||||
{
|
||||
// we always want to apply the same real-time offset, so it should be adjusted by the difference in playback rate (from realtime) to achieve this.
|
||||
|
Loading…
Reference in New Issue
Block a user