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

Change Taiko Classic HD, HR and HDHR to better match stable #27136

Open
wants to merge 19 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
Prev Previous commit
Next Next commit
Classic hidden
  • Loading branch information
vunyunt committed Feb 4, 2024
commit c75ce34f758f14448f682c138359e11921bbd1d8
48 changes: 48 additions & 0 deletions osu.Game.Rulesets.Taiko/Mods/TaikoModClassic.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
// 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;
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Taiko.Objects;
Expand All @@ -12,18 +17,61 @@ namespace osu.Game.Rulesets.Taiko.Mods
{
public class TaikoModClassic : ModClassic, IApplicableToDrawableRuleset<TaikoHitObject>, IApplicableToDrawableHitObject
{
private IReadOnlyList<Mod> mods = Array.Empty<Mod>();

private const float default_hidden_fade_out_duration = 0.375f;

private const float default_hidden_initial_alpha = 0.75f;

private const float hidden_base_aspect = 4f / 3f;

private readonly BindableFloat hiddenFadeOutDuration = new BindableFloat(default_hidden_fade_out_duration);

private readonly BindableFloat hiddenInitialAlpha = new BindableFloat(default_hidden_initial_alpha);


public void ApplyToDrawableRuleset(DrawableRuleset<TaikoHitObject> drawableRuleset)
{
var drawableTaikoRuleset = (DrawableTaikoRuleset)drawableRuleset;

// drawableRuleset.Mods should always be non-null here, but just in case.
mods = drawableRuleset.Mods ?? mods;

drawableTaikoRuleset.MaximumAspect.Value = 22f / 9f;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The upper limit used to be 16:9, why has this been increased?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is to match stable with classic mod, stable allows a wider aspect ratio range

Copy link
Collaborator

@bdach bdach Feb 21, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How was this upper limit determined though?

I'm asking because I can't find anything like this in stable source.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the notes fade in at some point, and while you can't see the fade in with 16:9, you can see it with a higher aspect ratio

Copy link
Collaborator

@bdach bdach Feb 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean sure but that's not evidence of there being a aspect ratio lock on stable, right? That is also consistent with there not being any lock in stable, isn't it? Which we had set already but this PR removes?

As far as I can tell "if you go wider than 16:9 more is shown" means either:

  • The upper bound of the lock is above 16:9.
  • The upper bound of the lock doesn't exist.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have access to stable's code. But I'm guessing for stable, while there isn't an explicit aspect ratio upper bound for the playfield itself, it still effectively limits the time rage to a ~2:1 aspect ratio equivalent by hiding notes beyond that point (fading them in. Without this high sv will lose most of their difficulty since player can in theory stretch the window and have indefinitely long time range.

if you go wider than 16:9 more is shown

For stable nm, it seems to start fading notes in beyond ~2:1. 16:9 doesn't seem to be a cutoff point for stable nm.

With this PR it is done by trimming the playfield instead. This way we can reuse the trim mechanism used by classic HD, while keeping the upper bound of time range.

Copy link
Collaborator

@bdach bdach Feb 28, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it still effectively limits the time rage to a ~2:1 aspect ratio equivalent by hiding notes beyond that point (fading them in

Now we're getting somewhere...

I have experimentally confirmed this on a single taiko map. Graphs are here: https://www.desmos.com/calculator/cdmlh4lm3u

But that generally makes me nervous as to whether it's valid to simulate the fadeout limit by clamping aspect ratio in the first place. Clamping ratio is a hard cutoff, it doesn't emulate limited visibility of the objects as they move onto the playfield, so I don't know that this should be done? Maybe the objects should just actually be fading in instead to match stable.

Note that this affects overlapping scroll too / SVs. If the fade-in is solely in the time domain (which it appears to be on stable), then this means that a fast-moving SV-accelerated circle is going to spend more of its active time fading in on screen than a normal circle would.

@ppy/team-client would appreciate thoughts on this spectacle if you can because I'm feeling increasingly out of my depth here in making shot calls as to how this should behave

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this means that a fast-moving SV-accelerated circle is going to spend more of its active time fading in on screen than a normal circle would

Never really noticed this previously when playing normally, but I can confirm that this is true. When SV on stable nomod is high enough, it will still be fading in even with 16:9 aspect ratio

With this insight it does seem better to actually implement the fade in (trim was used under the assumption that notes take a fixed amount of space to fade in, which has proven to be false)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't have access to my local branch right now, but fade in has been implemented. I'll be pushing it & posting comparison videos either tonight or some time tomorrow

drawableTaikoRuleset.MinimumAspect.Value = 5f / 4f;
drawableTaikoRuleset.TrimOnOverflow.Value = true;

TaikoModHidden? hidden = mods.OfType<TaikoModHidden>().FirstOrDefault();
if (hidden != null)
{
// Stable limits the aspect ratio to 4:3
drawableTaikoRuleset.MaximumAspect.Value = hidden_base_aspect;

// Enable aspect ratio adjustment for hidden (see adjustHidden)
hiddenInitialAlpha.BindTo(hidden.InitialAlpha);
hiddenFadeOutDuration.BindTo(hidden.FadeOutDuration);
drawableRuleset.OnUpdate += adjustHidden;
}
}

public void ApplyToDrawableHitObject(DrawableHitObject drawable)
{
if (drawable is DrawableTaikoHitObject hit)
hit.SnapJudgementLocation = true;
}

// Compensate for aspect ratios narrower than 4:3 by scaling the fade out duration and initial alpha
private void adjustHidden(Drawable drawableRuleset)
{
var drawableTaikoRuleset = (DrawableTaikoRuleset)drawableRuleset;

if (drawableTaikoRuleset.CurrentAspect.Value < hidden_base_aspect)
{
hiddenFadeOutDuration.Value =
default_hidden_fade_out_duration * (drawableTaikoRuleset.CurrentAspect.Value / hidden_base_aspect);
hiddenInitialAlpha.Value =
default_hidden_initial_alpha * (drawableTaikoRuleset.CurrentAspect.Value / hidden_base_aspect);
}
}
}
}
19 changes: 17 additions & 2 deletions osu.Game.Rulesets.Taiko/Mods/TaikoModHidden.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// 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.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Localisation;
using osu.Game.Rulesets.Mods;
Expand Down Expand Up @@ -29,7 +30,20 @@ public class TaikoModHidden : ModHidden, IApplicableToDrawableRuleset<TaikoHitOb
/// How long hitobjects take to fade out, in terms of the scrolling length.
/// Range: [0, 1]
/// </summary>
private const float fade_out_duration = 0.375f;
public readonly BindableFloat FadeOutDuration = new BindableFloat(0.375f)
{
MinValue = 0f,
MaxValue = 1f
};

/// <summary>
/// The initial alpha of hitobjects when they appear.
/// </summary>
public readonly BindableFloat InitialAlpha = new BindableFloat(1f)
{
MinValue = 0f,
MaxValue = 1f
};

private DrawableTaikoRuleset drawableRuleset = null!;

Expand All @@ -51,7 +65,8 @@ protected override void ApplyNormalVisibilityState(DrawableHitObject hitObject,
case DrawableHit:
double preempt = drawableRuleset.TimeRange.Value / drawableRuleset.ControlPointAt(hitObject.HitObject.StartTime).Multiplier;
double start = hitObject.HitObject.StartTime - preempt * fade_out_start_time;
double duration = preempt * fade_out_duration;
double duration = preempt * FadeOutDuration.Value;
hitObject.Alpha = InitialAlpha.Value;

using (hitObject.BeginAbsoluteSequence(start))
{
Expand Down
5 changes: 4 additions & 1 deletion osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ public partial class DrawableTaikoRuleset : DrawableScrollingRuleset<TaikoHitObj

public readonly BindableBool TrimOnOverflow = new BindableBool(false);

public readonly BindableFloat CurrentAspect = new BindableFloat(16f / 9f);
bdach marked this conversation as resolved.
Show resolved Hide resolved

public new TaikoInputManager KeyBindingInputManager => (TaikoInputManager)base.KeyBindingInputManager;

protected new TaikoPlayfieldAdjustmentContainer PlayfieldAdjustmentContainer => (TaikoPlayfieldAdjustmentContainer)base.PlayfieldAdjustmentContainer;
Expand Down Expand Up @@ -95,7 +97,8 @@ public MultiplierControlPoint ControlPointAt(double time)
{
MaximumAspect = { BindTarget = MaximumAspect },
MinimumAspect = { BindTarget = MinimumAspect },
TrimOnOverflow = { BindTarget = TrimOnOverflow }
TrimOnOverflow = { BindTarget = TrimOnOverflow },
CurrentAspect = { BindTarget = CurrentAspect }
};

protected override PassThroughInputManager CreateInputManager() => new TaikoInputManager(Ruleset.RulesetInfo);
Expand Down
14 changes: 8 additions & 6 deletions osu.Game.Rulesets.Taiko/UI/TaikoPlayfieldAdjustmentContainer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ public partial class TaikoPlayfieldAdjustmentContainer : PlayfieldAdjustmentCont

public BindableFloat MinimumAspect = new BindableFloat(5f / 4f);

public BindableFloat CurrentAspect = new BindableFloat(16f / 9f);

public BindableBool TrimOnOverflow = new BindableBool(false);

public TaikoPlayfieldAdjustmentContainer()
Expand Down Expand Up @@ -45,22 +47,22 @@ protected override void Update()
//
// As a middle-ground, the aspect ratio can still be adjusted in the downwards direction but has a maximum limit.
// This is still a bit weird, because readability changes with window size, but it is what it is.
float currentAspect = Parent!.ChildSize.X / Parent!.ChildSize.Y;
CurrentAspect.Value = Parent!.ChildSize.X / Parent!.ChildSize.Y;

if (currentAspect > MaximumAspect.Value)
if (CurrentAspect.Value > MaximumAspect.Value)
{
if (TrimOnOverflow.Value)
{
widthScale = MaximumAspect.Value / currentAspect;
widthScale = MaximumAspect.Value / CurrentAspect.Value;
}
else
{
relativeHeight *= currentAspect / MaximumAspect.Value;
relativeHeight *= CurrentAspect.Value / MaximumAspect.Value;
}
}
else if (currentAspect < MinimumAspect.Value)
else if (CurrentAspect.Value < MinimumAspect.Value)
{
relativeHeight *= currentAspect / MinimumAspect.Value;
relativeHeight *= CurrentAspect.Value / MinimumAspect.Value;
}


Expand Down