Handle key counter rewinding in a better way

Use ElapsedFrameTime rather than storing state data
This commit is contained in:
Dean Herbert
2019-09-12 15:41:53 +09:00
parent cb0cf6e2c5
commit 0cdf125c1e
7 changed files with 50 additions and 84 deletions

View File

@ -7,7 +7,6 @@ using System.Linq;
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Framework.MathUtils;
using osu.Framework.Timing;
using osu.Game.Screens.Play;
using osuTK.Input;
@ -25,14 +24,15 @@ namespace osu.Game.Tests.Visual.Gameplay
public TestSceneKeyCounter()
{
KeyCounterKeyboard rewindTestKeyCounterKeyboard;
KeyCounterKeyboard testCounter;
KeyCounterDisplay kc = new KeyCounterDisplay
{
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
Children = new KeyCounter[]
{
rewindTestKeyCounterKeyboard = new KeyCounterKeyboard(Key.X),
testCounter = new KeyCounterKeyboard(Key.X),
new KeyCounterKeyboard(Key.X),
new KeyCounterMouse(MouseButton.Left),
new KeyCounterMouse(MouseButton.Right),
@ -54,7 +54,7 @@ namespace osu.Game.Tests.Visual.Gameplay
InputManager.ReleaseKey(testKey);
});
AddAssert($"Check {testKey} counter after keypress", () => rewindTestKeyCounterKeyboard.CountPresses == 1);
AddAssert($"Check {testKey} counter after keypress", () => testCounter.CountPresses == 1);
AddStep($"Press {testKey} key", () =>
{
@ -63,39 +63,9 @@ namespace osu.Game.Tests.Visual.Gameplay
time1 = Clock.CurrentTime;
});
AddAssert($"Check {testKey} counter after keypress", () => rewindTestKeyCounterKeyboard.CountPresses == 2);
IFrameBasedClock oldClock = null;
AddStep($"Rewind {testKey} counter once", () =>
{
oldClock = rewindTestKeyCounterKeyboard.Clock;
rewindTestKeyCounterKeyboard.Clock = new FramedOffsetClock(new FixedClock(time1 - 10));
});
AddAssert($"Check {testKey} counter after rewind", () => rewindTestKeyCounterKeyboard.CountPresses == 1);
AddStep($"Rewind {testKey} counter to zero", () => rewindTestKeyCounterKeyboard.Clock = new FramedOffsetClock(new FixedClock(0)));
AddAssert($"Check {testKey} counter after rewind", () => rewindTestKeyCounterKeyboard.CountPresses == 0);
AddStep("Restore clock", () => rewindTestKeyCounterKeyboard.Clock = oldClock);
AddAssert($"Check {testKey} counter after keypress", () => testCounter.CountPresses == 2);
Add(kc);
}
private class FixedClock : IClock
{
private readonly double time;
public FixedClock(double time)
{
this.time = time;
}
public double CurrentTime => time;
public double Rate => 1;
public bool IsRunning => false;
}
}
}

View File

@ -137,9 +137,9 @@ namespace osu.Game.Rulesets.UI
{
}
public bool OnPressed(T action) => Target.Children.OfType<KeyCounterAction<T>>().Any(c => c.OnPressed(action));
public bool OnPressed(T action) => Target.Children.OfType<KeyCounterAction<T>>().Any(c => c.OnPressed(action, Clock.ElapsedFrameTime > 0));
public bool OnReleased(T action) => Target.Children.OfType<KeyCounterAction<T>>().Any(c => c.OnReleased(action));
public bool OnReleased(T action) => Target.Children.OfType<KeyCounterAction<T>>().Any(c => c.OnReleased(action, Clock.ElapsedFrameTime > 0));
}
#endregion

View File

@ -1,8 +1,6 @@
// 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.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
@ -22,9 +20,6 @@ namespace osu.Game.Screens.Play
private Container textLayer;
private SpriteText countSpriteText;
private readonly List<KeyCounterState> states = new List<KeyCounterState>();
private KeyCounterState currentState;
public bool IsCounting { get; set; } = true;
private int countPresses;
@ -52,14 +47,24 @@ namespace osu.Game.Screens.Play
{
isLit = value;
updateGlowSprite(value);
}
}
}
if (value && IsCounting)
public void Increment()
{
if (!IsCounting)
return;
CountPresses++;
saveState();
}
}
}
public void Decrement()
{
if (!IsCounting)
return;
CountPresses--;
}
//further: change default values here and in KeyCounterCollection if needed, instead of passing them in every constructor
@ -143,27 +148,5 @@ namespace osu.Game.Screens.Play
textLayer.FadeColour(KeyUpTextColor, remainingFadeTime, Easing.OutQuint);
}
}
protected override void Update()
{
base.Update();
if (currentState?.Time > Clock.CurrentTime)
restoreStateTo(Clock.CurrentTime);
}
private void saveState()
{
if (currentState == null || currentState.Time < Clock.CurrentTime)
states.Add(currentState = new KeyCounterState(Clock.CurrentTime, CountPresses));
}
private void restoreStateTo(double time)
{
states.RemoveAll(state => state.Time > time);
currentState = states.LastOrDefault();
CountPresses = currentState?.Count ?? 0;
}
}
}

View File

@ -1,11 +1,9 @@
// 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.Input.Bindings;
namespace osu.Game.Screens.Play
{
public class KeyCounterAction<T> : KeyCounter, IKeyBindingHandler<T>
public class KeyCounterAction<T> : KeyCounter
where T : struct
{
public T Action { get; }
@ -16,15 +14,25 @@ namespace osu.Game.Screens.Play
Action = action;
}
public bool OnPressed(T action)
public bool OnPressed(T action, bool forwards)
{
if (action.Equals(Action)) IsLit = true;
if (!action.Equals(Action))
return false;
IsLit = true;
if (forwards)
Increment();
return false;
}
public bool OnReleased(T action)
public bool OnReleased(T action, bool forwards)
{
if (action.Equals(Action)) IsLit = false;
if (!action.Equals(Action))
return false;
IsLit = false;
if (!forwards)
Decrement();
return false;
}
}

View File

@ -102,11 +102,6 @@ namespace osu.Game.Screens.Play
private Receptor receptor;
public Receptor GetReceptor()
{
return receptor ?? (receptor = new Receptor(this));
}
public void SetReceptor(Receptor receptor)
{
if (this.receptor != null)

View File

@ -18,7 +18,12 @@ namespace osu.Game.Screens.Play
protected override bool OnKeyDown(KeyDownEvent e)
{
if (e.Key == Key) IsLit = true;
if (e.Key == Key)
{
IsLit = true;
Increment();
}
return base.OnKeyDown(e);
}

View File

@ -36,7 +36,12 @@ namespace osu.Game.Screens.Play
protected override bool OnMouseDown(MouseDownEvent e)
{
if (e.Button == Button) IsLit = true;
if (e.Button == Button)
{
IsLit = true;
Increment();
}
return base.OnMouseDown(e);
}