1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-13 15:27:30 +08:00

Implement toggling visibility of pass and fail storyboard layers

Closes https://github.com/ppy/osu/issues/6842.

This is a rather barebones implementation, just to get this in place
somehow at least. The logic is simple - 50% health or above shows pass
layer, anything below shows fail layer.

This does not match stable logic all across the board because I have
no idea how to package that. Stable defines "passing" in like fifty
ways:

- in mania it's >80% HP
  (bb57924c15/osu!/GameModes/Play/Rulesets/Mania/RulesetMania.cs#L333-L336)
- in taiko it's >80% *accuracy*
  (bb57924c15/osu!/GameModes/Play/Rulesets/Taiko/RulesetTaiko.cs#L486-L492)
- there's also the part where "geki additions" will unconditionally set
  passing state
  (bb57924c15/osu!/GameModes/Play/Player.cs#L3561-L3564)
- and also the part where at the end of the map, the final passing state
  is determined by checking whether the user passed more sections than
  failed
  (bb57924c15/osu!/GameModes/Play/Player.cs#L3320)

The biggest issues of these are probably the first two, and they can
*probably* be fixed, but would require a new member on `Ruleset` and I'm
not sure how to make one look, so I'm not doing that at this time
pending collection of ideas on how to do that.
This commit is contained in:
Bartłomiej Dach 2024-06-14 13:36:40 +02:00
parent 2d4121b14a
commit 67ca7e4135
No known key found for this signature in database
5 changed files with 37 additions and 25 deletions

View File

@ -14,8 +14,11 @@ using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Formats;
using osu.Game.IO;
using osu.Game.Overlays;
using osu.Game.Rulesets.Osu;
using osu.Game.Screens.Play;
using osu.Game.Storyboards;
using osu.Game.Storyboards.Drawables;
using osu.Game.Tests.Gameplay;
using osu.Game.Tests.Resources;
using osuTK.Graphics;
@ -28,14 +31,14 @@ namespace osu.Game.Tests.Visual.Gameplay
private DrawableStoryboard? storyboard;
[Cached]
private GameplayState testGameplayState = TestGameplayState.Create(new OsuRuleset());
[Test]
public void TestStoryboard()
{
AddStep("Restart", restart);
AddToggleStep("Passing", passing =>
{
if (storyboard != null) storyboard.Passing = passing;
});
AddToggleStep("Toggle passing state", passing => testGameplayState.HealthProcessor.Health.Value = passing ? 1 : 0);
}
[Test]
@ -109,7 +112,6 @@ namespace osu.Game.Tests.Visual.Gameplay
storyboardContainer.Clock = new FramedClock(Beatmap.Value.Track);
storyboard = toLoad.CreateDrawable(SelectedMods.Value);
storyboard.Passing = false;
storyboardContainer.Add(storyboard);
}

View File

@ -40,6 +40,7 @@ namespace osu.Game.Screens.Play
public readonly Score Score;
public readonly ScoreProcessor ScoreProcessor;
public readonly HealthProcessor HealthProcessor;
/// <summary>
/// The storyboard associated with the beatmap.
@ -68,7 +69,14 @@ namespace osu.Game.Screens.Play
private readonly Bindable<JudgementResult> lastJudgementResult = new Bindable<JudgementResult>();
public GameplayState(IBeatmap beatmap, Ruleset ruleset, IReadOnlyList<Mod>? mods = null, Score? score = null, ScoreProcessor? scoreProcessor = null, Storyboard? storyboard = null)
public GameplayState(
IBeatmap beatmap,
Ruleset ruleset,
IReadOnlyList<Mod>? mods = null,
Score? score = null,
ScoreProcessor? scoreProcessor = null,
HealthProcessor? healthProcessor = null,
Storyboard? storyboard = null)
{
Beatmap = beatmap;
Ruleset = ruleset;
@ -82,6 +90,7 @@ namespace osu.Game.Screens.Play
};
Mods = mods ?? Array.Empty<Mod>();
ScoreProcessor = scoreProcessor ?? ruleset.CreateScoreProcessor();
HealthProcessor = healthProcessor ?? ruleset.CreateHealthProcessor(beatmap.HitObjects[0].StartTime);
Storyboard = storyboard ?? new Storyboard();
}

View File

@ -260,7 +260,7 @@ namespace osu.Game.Screens.Play
Score.ScoreInfo.Ruleset = ruleset.RulesetInfo;
Score.ScoreInfo.Mods = gameplayMods;
dependencies.CacheAs(GameplayState = new GameplayState(playableBeatmap, ruleset, gameplayMods, Score, ScoreProcessor, Beatmap.Value.Storyboard));
dependencies.CacheAs(GameplayState = new GameplayState(playableBeatmap, ruleset, gameplayMods, Score, ScoreProcessor, HealthProcessor, Beatmap.Value.Storyboard));
var rulesetSkinProvider = new RulesetSkinProvidingContainer(ruleset, playableBeatmap, Beatmap.Value.Skin);

View File

@ -37,20 +37,6 @@ namespace osu.Game.Storyboards.Drawables
protected override Vector2 DrawScale => new Vector2(Parent!.DrawHeight / 480);
private bool passing = true;
public bool Passing
{
get => passing;
set
{
if (passing == value) return;
passing = value;
updateLayerVisibility();
}
}
public override bool RemoveCompletedTransforms => false;
private double? lastEventEndTime;
@ -66,6 +52,9 @@ namespace osu.Game.Storyboards.Drawables
private DependencyContainer dependencies = null!;
private BindableNumber<double> health = null!;
private readonly BindableBool passing = new BindableBool(true);
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) =>
dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
@ -91,8 +80,8 @@ namespace osu.Game.Storyboards.Drawables
});
}
[BackgroundDependencyLoader(true)]
private void load(IGameplayClock? clock, CancellationToken? cancellationToken)
[BackgroundDependencyLoader]
private void load(IGameplayClock? clock, CancellationToken? cancellationToken, GameplayState? gameplayState)
{
if (clock != null)
Clock = clock;
@ -110,6 +99,16 @@ namespace osu.Game.Storyboards.Drawables
}
lastEventEndTime = Storyboard.LatestEventTime;
health = gameplayState?.HealthProcessor.Health.GetBoundCopy() ?? new BindableDouble(1);
}
protected override void LoadComplete()
{
base.LoadComplete();
health.BindValueChanged(val => passing.Value = val.NewValue >= 0.5, true);
passing.BindValueChanged(_ => updateLayerVisibility(), true);
}
protected virtual IResourceStore<byte[]> CreateResourceLookupStore() => new StoryboardResourceLookupStore(Storyboard, realm, host);
@ -125,7 +124,7 @@ namespace osu.Game.Storyboards.Drawables
private void updateLayerVisibility()
{
foreach (var layer in Children)
layer.Enabled = passing ? layer.Layer.VisibleWhenPassing : layer.Layer.VisibleWhenFailing;
layer.Enabled = passing.Value ? layer.Layer.VisibleWhenPassing : layer.Layer.VisibleWhenFailing;
}
private class StoryboardResourceLookupStore : IResourceStore<byte[]>

View File

@ -27,7 +27,9 @@ namespace osu.Game.Tests.Gameplay
var scoreProcessor = ruleset.CreateScoreProcessor();
scoreProcessor.ApplyBeatmap(playableBeatmap);
return new GameplayState(playableBeatmap, ruleset, mods, score, scoreProcessor);
var healthProcessor = ruleset.CreateHealthProcessor(beatmap.HitObjects[0].StartTime);
return new GameplayState(playableBeatmap, ruleset, mods, score, scoreProcessor, healthProcessor);
}
}
}