1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-07 22:27:25 +08:00

Merge pull request #22873 from peppy/touch-input-distance-travelled

Make osu! touch input aware of the distance travelled of a non-direct touch
This commit is contained in:
Dean Herbert 2023-03-21 18:21:38 +09:00 committed by GitHub
commit 63140c6cb6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 62 additions and 5 deletions

View File

@ -150,6 +150,42 @@ namespace osu.Game.Rulesets.Osu.Tests
assertKeyCounter(1, 1);
}
[Test]
public void TestPositionalTrackingAfterLongDistanceTravelled()
{
// When a single touch has already travelled enough distance on screen, it should remain as the positional
// tracking touch until released (unless a direct touch occurs).
beginTouch(TouchSource.Touch1);
assertKeyCounter(1, 0);
checkPressed(OsuAction.LeftButton);
checkPosition(TouchSource.Touch1);
// cover some distance
beginTouch(TouchSource.Touch1, new Vector2(0));
beginTouch(TouchSource.Touch1, new Vector2(9999));
beginTouch(TouchSource.Touch1, new Vector2(0));
beginTouch(TouchSource.Touch1, new Vector2(9999));
beginTouch(TouchSource.Touch1);
beginTouch(TouchSource.Touch2);
assertKeyCounter(1, 1);
checkNotPressed(OsuAction.LeftButton);
checkPressed(OsuAction.RightButton);
// in this case, touch 2 should not become the positional tracking touch.
checkPosition(TouchSource.Touch1);
// even if the second touch moves on the screen, the original tracking touch is retained.
beginTouch(TouchSource.Touch2, new Vector2(0));
beginTouch(TouchSource.Touch2, new Vector2(9999));
beginTouch(TouchSource.Touch2, new Vector2(0));
beginTouch(TouchSource.Touch2, new Vector2(9999));
checkPosition(TouchSource.Touch1);
}
[Test]
public void TestPositionalInputUpdatesOnlyFromMostRecentTouch()
{

View File

@ -22,6 +22,13 @@ namespace osu.Game.Rulesets.Osu.UI
/// </summary>
private readonly List<TrackedTouch> trackedTouches = new List<TrackedTouch>();
/// <summary>
/// The distance (in local pixels) that a touch must move before being considered a permanent tracking touch.
/// After this distance is covered, any extra touches on the screen will be considered as button inputs, unless
/// a new touch directly interacts with a hit circle.
/// </summary>
private const float distance_before_position_tracking_lock_in = 100;
private TrackedTouch? positionTrackingTouch;
private readonly OsuInputManager osuInputManager;
@ -97,26 +104,32 @@ namespace osu.Game.Rulesets.Osu.UI
return;
}
// ..or if the current position tracking touch was not a direct touch (this one is debatable and may be change in the future, but it's the simplest way to handle)
if (!positionTrackingTouch.DirectTouch)
// ..or if the current position tracking touch was not a direct touch (and didn't travel across the screen too far).
if (!positionTrackingTouch.DirectTouch && positionTrackingTouch.DistanceTravelled < distance_before_position_tracking_lock_in)
{
positionTrackingTouch = newTouch;
return;
}
// In the case the new touch was not used for position tracking, we should also check the previous position tracking touch.
// If it was a direct touch and still has its action pressed, that action should be released.
// If it still has its action pressed, that action should be released.
//
// This is done to allow tracking with the initial touch while still having both Left/Right actions available for alternating with two more touches.
if (positionTrackingTouch.DirectTouch && positionTrackingTouch.Action is OsuAction directTouchAction)
if (positionTrackingTouch.Action is OsuAction touchAction)
{
osuInputManager.KeyBindingContainer.TriggerReleased(directTouchAction);
osuInputManager.KeyBindingContainer.TriggerReleased(touchAction);
positionTrackingTouch.Action = null;
}
}
private void handleTouchMovement(TouchEvent touchEvent)
{
if (touchEvent is TouchMoveEvent moveEvent)
{
var trackedTouch = trackedTouches.Single(t => t.Source == touchEvent.Touch.Source);
trackedTouch.DistanceTravelled += moveEvent.Delta.Length;
}
// Movement should only be tracked for the most recent touch.
if (touchEvent.Touch.Source != positionTrackingTouch?.Source)
return;
@ -148,8 +161,16 @@ namespace osu.Game.Rulesets.Osu.UI
public OsuAction? Action;
/// <summary>
/// Whether the touch was on a hit circle receptor.
/// </summary>
public readonly bool DirectTouch;
/// <summary>
/// The total distance on screen travelled by this touch (in local pixels).
/// </summary>
public float DistanceTravelled;
public TrackedTouch(TouchSource source, OsuAction? action, bool directTouch)
{
Source = source;