Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve osu!mania playability on mobile devices #31368

Open
wants to merge 19 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
7563a18
Allow locking orientation on iOS in certain circumstances
frenzibyte Dec 24, 2024
9d08bc2
Improve osu!mania gameplay scaling on portrait orientation
frenzibyte Dec 29, 2024
d7e4038
Keep game in portrait mode when restarting
frenzibyte Dec 30, 2024
0cd7f1b
Abstractify orientation handling and add Android support
frenzibyte Dec 30, 2024
1e08b3d
Make mania judgements relative to the hit target position
frenzibyte Dec 30, 2024
bea61d2
Replace `ManiaTouchInputArea` with touchable columns
frenzibyte Dec 31, 2024
64e557d
Simplify portrait check
frenzibyte Jan 1, 2025
e5713e5
Fix triangles judgement mispositioned on a miss
frenzibyte Jan 1, 2025
2138982
Fix player no longer handling non-loaded beatmaps
frenzibyte Jan 4, 2025
a241d1f
Fix `DrawableManiaRuleset` not cached as itself in subtypes
frenzibyte Jan 4, 2025
f121b03
Merge branch 'master' into mobile-fix-mania
frenzibyte Jan 12, 2025
f718696
Allow landscape orientation on tablet devices in osu!mania
frenzibyte Jan 12, 2025
c1ac27d
Fix failing tests
frenzibyte Jan 13, 2025
4774d9c
Fix mania fade in test not actually testing the mod
frenzibyte Jan 13, 2025
42e5cb5
Merge branch 'master' into mobile-fix-mania
peppy Jan 16, 2025
daa7921
Mark `IsTablet` with `new` to avoid inspection
peppy Jan 17, 2025
6ec7183
Revert "Fix triangles judgement mispositioned on a miss"
frenzibyte Jan 21, 2025
b63d941
Reapply "Fix triangles judgement mispositioned on a miss"
frenzibyte Jan 21, 2025
56a611b
Merge branch 'master' into mobile-fix-mania
peppy Jan 24, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions osu.Android/AndroidOrientationManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// 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 Android.Content.PM;
using Android.Content.Res;
using osu.Framework.Allocation;
using osu.Game.Mobile;

namespace osu.Android
{
public partial class AndroidOrientationManager : OrientationManager
{
[Resolved]
private OsuGameActivity gameActivity { get; set; } = null!;

protected override bool IsCurrentOrientationPortrait => gameActivity.Resources!.Configuration!.Orientation == Orientation.Portrait;
protected override bool IsTablet => gameActivity.IsTablet;

protected override void SetAllowedOrientations(GameOrientation? orientation)
=> gameActivity.RequestedOrientation = orientation == null ? gameActivity.DefaultOrientation : toScreenOrientation(orientation.Value);

private static ScreenOrientation toScreenOrientation(GameOrientation orientation)
{
if (orientation == GameOrientation.Locked)
return ScreenOrientation.Locked;

if (orientation == GameOrientation.Portrait)
return ScreenOrientation.Portrait;

if (orientation == GameOrientation.Landscape)
return ScreenOrientation.Landscape;

if (orientation == GameOrientation.FullPortrait)
return ScreenOrientation.SensorPortrait;

return ScreenOrientation.SensorLandscape;
}
}
}
34 changes: 0 additions & 34 deletions osu.Android/GameplayScreenRotationLocker.cs

This file was deleted.

6 changes: 4 additions & 2 deletions osu.Android/OsuGameActivity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ public class OsuGameActivity : AndroidGameActivity
/// <remarks>Adjusted on startup to match expected UX for the current device type (phone/tablet).</remarks>
public ScreenOrientation DefaultOrientation = ScreenOrientation.Unspecified;

public new bool IsTablet { get; private set; }

private readonly OsuGameAndroid game;

private bool gameCreated;
Expand Down Expand Up @@ -89,9 +91,9 @@ protected override void OnCreate(Bundle? savedInstanceState)
WindowManager.DefaultDisplay.GetSize(displaySize);
#pragma warning restore CA1422
float smallestWidthDp = Math.Min(displaySize.X, displaySize.Y) / Resources.DisplayMetrics.Density;
bool isTablet = smallestWidthDp >= 600f;
IsTablet = smallestWidthDp >= 600f;

RequestedOrientation = DefaultOrientation = isTablet ? ScreenOrientation.FullUser : ScreenOrientation.SensorLandscape;
RequestedOrientation = DefaultOrientation = IsTablet ? ScreenOrientation.FullUser : ScreenOrientation.SensorLandscape;

// Currently (SDK 6.0.200), BundleAssemblies is not runnable for net6-android.
// The assembly files are not available as files either after native AOT.
Expand Down
2 changes: 1 addition & 1 deletion osu.Android/OsuGameAndroid.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ public override Version AssemblyVersion
protected override void LoadComplete()
{
base.LoadComplete();
LoadComponentAsync(new GameplayScreenRotationLocker(), Add);
LoadComponentAsync(new AndroidOrientationManager(), Add);
}

public override void SetHost(GameHost host)
Expand Down
10 changes: 5 additions & 5 deletions osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModFadeIn.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public void TestMinCoverageFullWidth()
{
CreateModTest(new ModTestData
{
Mod = new ManiaModHidden(),
Mod = new ManiaModFadeIn(),
PassCondition = () => checkCoverage(ManiaModHidden.MIN_COVERAGE)
});
}
Expand All @@ -36,7 +36,7 @@ public void TestMinCoverageHalfWidth()
{
CreateModTest(new ModTestData
{
Mod = new ManiaModHidden(),
Mod = new ManiaModFadeIn(),
PassCondition = () => checkCoverage(ManiaModHidden.MIN_COVERAGE)
});

Expand All @@ -48,7 +48,7 @@ public void TestMaxCoverageFullWidth()
{
CreateModTest(new ModTestData
{
Mod = new ManiaModHidden(),
Mod = new ManiaModFadeIn(),
PassCondition = () => checkCoverage(ManiaModHidden.MAX_COVERAGE)
});

Expand All @@ -60,7 +60,7 @@ public void TestMaxCoverageHalfWidth()
{
CreateModTest(new ModTestData
{
Mod = new ManiaModHidden(),
Mod = new ManiaModFadeIn(),
PassCondition = () => checkCoverage(ManiaModHidden.MAX_COVERAGE)
});

Expand All @@ -73,7 +73,7 @@ public void TestNoCoverageDuringBreak()
{
CreateModTest(new ModTestData
{
Mod = new ManiaModHidden(),
Mod = new ManiaModFadeIn(),
CreateBeatmap = () => new Beatmap
{
HitObjects = Enumerable.Range(1, 100).Select(i => (HitObject)new Note { StartTime = 1000 + 200 * i }).ToList(),
Expand Down
68 changes: 68 additions & 0 deletions osu.Game.Rulesets.Mania.Tests/TestSceneManiaTouchInput.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// 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.Linq;
using NUnit.Framework;
using osu.Framework.Input;
using osu.Framework.Testing;
using osu.Game.Rulesets.Mania.UI;
using osu.Game.Tests.Visual;

namespace osu.Game.Rulesets.Mania.Tests
{
public partial class TestSceneManiaTouchInput : PlayerTestScene
{
protected override Ruleset CreatePlayerRuleset() => new ManiaRuleset();

[Test]
public void TestTouchInput()
{
for (int i = 0; i < 4; i++)
{
int index = i;

AddStep($"touch column {index}", () => InputManager.BeginTouch(new Touch(TouchSource.Touch1, getColumn(index).ScreenSpaceDrawQuad.Centre)));

AddAssert("action sent",
() => this.ChildrenOfType<ManiaInputManager>().SelectMany(m => m.KeyBindingContainer.PressedActions),
() => Does.Contain(getColumn(index).Action.Value));

AddStep($"release column {index}", () => InputManager.EndTouch(new Touch(TouchSource.Touch1, getColumn(index).ScreenSpaceDrawQuad.Centre)));

AddAssert("action released",
() => this.ChildrenOfType<ManiaInputManager>().SelectMany(m => m.KeyBindingContainer.PressedActions),
() => Does.Not.Contain(getColumn(index).Action.Value));
}
}

[Test]
public void TestOneColumnMultipleTouches()
{
AddStep("touch column 0", () => InputManager.BeginTouch(new Touch(TouchSource.Touch1, getColumn(0).ScreenSpaceDrawQuad.Centre)));

AddAssert("action sent",
() => this.ChildrenOfType<ManiaInputManager>().SelectMany(m => m.KeyBindingContainer.PressedActions),
() => Does.Contain(getColumn(0).Action.Value));

AddStep("touch another finger", () => InputManager.BeginTouch(new Touch(TouchSource.Touch2, getColumn(0).ScreenSpaceDrawQuad.Centre)));

AddAssert("action still pressed",
() => this.ChildrenOfType<ManiaInputManager>().SelectMany(m => m.KeyBindingContainer.PressedActions),
() => Does.Contain(getColumn(0).Action.Value));

AddStep("release first finger", () => InputManager.EndTouch(new Touch(TouchSource.Touch1, getColumn(0).ScreenSpaceDrawQuad.Centre)));

AddAssert("action still pressed",
() => this.ChildrenOfType<ManiaInputManager>().SelectMany(m => m.KeyBindingContainer.PressedActions),
() => Does.Contain(getColumn(0).Action.Value));

AddStep("release second finger", () => InputManager.EndTouch(new Touch(TouchSource.Touch2, getColumn(0).ScreenSpaceDrawQuad.Centre)));

AddAssert("action released",
() => this.ChildrenOfType<ManiaInputManager>().SelectMany(m => m.KeyBindingContainer.PressedActions),
() => Does.Not.Contain(getColumn(0).Action.Value));
}

private Column getColumn(int index) => this.ChildrenOfType<Column>().ElementAt(index);
}
}
49 changes: 0 additions & 49 deletions osu.Game.Rulesets.Mania.Tests/TestSceneManiaTouchInputArea.cs

This file was deleted.

6 changes: 3 additions & 3 deletions osu.Game.Rulesets.Mania/Mods/ManiaModWithPlayfieldCover.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
using System.Linq;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mania.UI;
using osu.Game.Rulesets.Mania.UI.Components;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.UI;
Expand All @@ -34,8 +34,8 @@ public virtual void ApplyToDrawableRuleset(DrawableRuleset<ManiaHitObject> drawa

foreach (Column column in maniaPlayfield.Stages.SelectMany(stage => stage.Columns))
{
HitObjectContainer hoc = column.HitObjectArea.HitObjectContainer;
Container hocParent = (Container)hoc.Parent!;
HitObjectContainer hoc = column.HitObjectContainer;
ColumnHitObjectArea hocParent = (ColumnHitObjectArea)hoc.Parent!;

hocParent.Remove(hoc, false);
hocParent.Add(CreateCover(hoc).With(c =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon
{
public partial class ArgonJudgementPiece : TextJudgementPiece, IAnimatableJudgement
{
private const float judgement_y_position = 160;
private const float judgement_y_position = -180f;

private RingExplosion? ringExplosion;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
using osu.Framework.Graphics.Containers;
using osu.Framework.Utils;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Mania.UI;
using osu.Game.Rulesets.Scoring;
using osu.Game.Skinning;

Expand All @@ -23,7 +22,7 @@ public LegacyManiaJudgementPiece(HitResult result, Drawable animation)
this.result = result;
this.animation = animation;

Anchor = Anchor.Centre;
Anchor = Anchor.BottomCentre;
Origin = Anchor.Centre;

AutoSizeAxes = Axes.Both;
Expand All @@ -32,12 +31,11 @@ public LegacyManiaJudgementPiece(HitResult result, Drawable animation)
[BackgroundDependencyLoader]
private void load(ISkinSource skin)
{
float? scorePosition = skin.GetManiaSkinConfig<float>(LegacyManiaSkinConfigurationLookups.ScorePosition)?.Value;
float hitPosition = skin.GetManiaSkinConfig<float>(LegacyManiaSkinConfigurationLookups.HitPosition)?.Value ?? 0;
float scorePosition = skin.GetManiaSkinConfig<float>(LegacyManiaSkinConfigurationLookups.ScorePosition)?.Value ?? 0;

if (scorePosition != null)
scorePosition -= Stage.HIT_TARGET_POSITION + 150;

Y = scorePosition ?? 0;
float absoluteHitPosition = 480f * LegacyManiaSkinConfiguration.POSITION_SCALE_FACTOR - hitPosition;
Y = scorePosition - absoluteHitPosition;

InternalChild = animation.With(d =>
{
Expand Down
24 changes: 24 additions & 0 deletions osu.Game.Rulesets.Mania/UI/Column.cs
Original file line number Diff line number Diff line change
Expand Up @@ -180,5 +180,29 @@ public void OnReleased(KeyBindingReleaseEvent<ManiaAction> e)
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos)
// This probably shouldn't exist as is, but the columns in the stage are separated by a 1px border
=> DrawRectangle.Inflate(new Vector2(Stage.COLUMN_SPACING / 2, 0)).Contains(ToLocalSpace(screenSpacePos));

#region Touch Input

[Resolved(canBeNull: true)]
private ManiaInputManager maniaInputManager { get; set; }

private int touchActivationCount;

protected override bool OnTouchDown(TouchDownEvent e)
{
maniaInputManager.KeyBindingContainer.TriggerPressed(Action.Value);
touchActivationCount++;
return true;
}

protected override void OnTouchUp(TouchUpEvent e)
{
touchActivationCount--;

if (touchActivationCount == 0)
maniaInputManager.KeyBindingContainer.TriggerReleased(Action.Value);
}

#endregion
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

namespace osu.Game.Rulesets.Mania.UI.Components
{
public partial class ColumnHitObjectArea : HitObjectArea
public partial class ColumnHitObjectArea : HitPositionPaddedContainer
{
public readonly Container Explosions;

Expand Down
Loading
Loading