mirror of
https://github.com/ppy/osu.git
synced 2024-12-14 15:33:05 +08:00
Merge remote-tracking branch 'origin/master' into editor-pattern-adjustments
This commit is contained in:
commit
87baa6febd
@ -1,200 +0,0 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
|
||||||
|
|
||||||
using osu.Game.Beatmaps;
|
|
||||||
using osu.Game.Rulesets.Scoring;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Judgements
|
|
||||||
{
|
|
||||||
public class HitWindows
|
|
||||||
{
|
|
||||||
#region Constants
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// PERFECT hit window at OD = 10.
|
|
||||||
/// </summary>
|
|
||||||
private const double perfect_min = 27.8;
|
|
||||||
/// <summary>
|
|
||||||
/// PERFECT hit window at OD = 5.
|
|
||||||
/// </summary>
|
|
||||||
private const double perfect_mid = 38.8;
|
|
||||||
/// <summary>
|
|
||||||
/// PERFECT hit window at OD = 0.
|
|
||||||
/// </summary>
|
|
||||||
private const double perfect_max = 44.8;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// GREAT hit window at OD = 10.
|
|
||||||
/// </summary>
|
|
||||||
private const double great_min = 68;
|
|
||||||
/// <summary>
|
|
||||||
/// GREAT hit window at OD = 5.
|
|
||||||
/// </summary>
|
|
||||||
private const double great_mid = 98;
|
|
||||||
/// <summary>
|
|
||||||
/// GREAT hit window at OD = 0.
|
|
||||||
/// </summary>
|
|
||||||
private const double great_max = 128;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// GOOD hit window at OD = 10.
|
|
||||||
/// </summary>
|
|
||||||
private const double good_min = 134;
|
|
||||||
/// <summary>
|
|
||||||
/// GOOD hit window at OD = 5.
|
|
||||||
/// </summary>
|
|
||||||
private const double good_mid = 164;
|
|
||||||
/// <summary>
|
|
||||||
/// GOOD hit window at OD = 0.
|
|
||||||
/// </summary>
|
|
||||||
private const double good_max = 194;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// OK hit window at OD = 10.
|
|
||||||
/// </summary>
|
|
||||||
private const double ok_min = 194;
|
|
||||||
/// <summary>
|
|
||||||
/// OK hit window at OD = 5.
|
|
||||||
/// </summary>
|
|
||||||
private const double ok_mid = 224;
|
|
||||||
/// <summary>
|
|
||||||
/// OK hit window at OD = 0.
|
|
||||||
/// </summary>
|
|
||||||
private const double ok_max = 254;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// BAD hit window at OD = 10.
|
|
||||||
/// </summary>
|
|
||||||
private const double bad_min = 242;
|
|
||||||
/// <summary>
|
|
||||||
/// BAD hit window at OD = 5.
|
|
||||||
/// </summary>
|
|
||||||
private const double bad_mid = 272;
|
|
||||||
/// <summary>
|
|
||||||
/// BAD hit window at OD = 0.
|
|
||||||
/// </summary>
|
|
||||||
private const double bad_max = 302;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// MISS hit window at OD = 10.
|
|
||||||
/// </summary>
|
|
||||||
private const double miss_min = 316;
|
|
||||||
/// <summary>
|
|
||||||
/// MISS hit window at OD = 5.
|
|
||||||
/// </summary>
|
|
||||||
private const double miss_mid = 346;
|
|
||||||
/// <summary>
|
|
||||||
/// MISS hit window at OD = 0.
|
|
||||||
/// </summary>
|
|
||||||
private const double miss_max = 376;
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Hit window for a PERFECT hit.
|
|
||||||
/// </summary>
|
|
||||||
public double Perfect = perfect_mid;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Hit window for a GREAT hit.
|
|
||||||
/// </summary>
|
|
||||||
public double Great = great_mid;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Hit window for a GOOD hit.
|
|
||||||
/// </summary>
|
|
||||||
public double Good = good_mid;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Hit window for an OK hit.
|
|
||||||
/// </summary>
|
|
||||||
public double Ok = ok_mid;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Hit window for a BAD hit.
|
|
||||||
/// </summary>
|
|
||||||
public double Bad = bad_mid;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Hit window for a MISS hit.
|
|
||||||
/// </summary>
|
|
||||||
public double Miss = miss_mid;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Constructs default hit windows.
|
|
||||||
/// </summary>
|
|
||||||
public HitWindows()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Constructs hit windows by fitting a parameter to a 2-part piecewise linear function for each hit window.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="difficulty">The parameter.</param>
|
|
||||||
public HitWindows(double difficulty)
|
|
||||||
{
|
|
||||||
Perfect = BeatmapDifficulty.DifficultyRange(difficulty, perfect_max, perfect_mid, perfect_min);
|
|
||||||
Great = BeatmapDifficulty.DifficultyRange(difficulty, great_max, great_mid, great_min);
|
|
||||||
Good = BeatmapDifficulty.DifficultyRange(difficulty, good_max, good_mid, good_min);
|
|
||||||
Ok = BeatmapDifficulty.DifficultyRange(difficulty, ok_max, ok_mid, ok_min);
|
|
||||||
Bad = BeatmapDifficulty.DifficultyRange(difficulty, bad_max, bad_mid, bad_min);
|
|
||||||
Miss = BeatmapDifficulty.DifficultyRange(difficulty, miss_max, miss_mid, miss_min);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Retrieves the hit result for a time offset.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="hitOffset">The time offset.</param>
|
|
||||||
/// <returns>The hit result, or null if the time offset results in a miss.</returns>
|
|
||||||
public HitResult? ResultFor(double hitOffset)
|
|
||||||
{
|
|
||||||
if (hitOffset <= Perfect / 2)
|
|
||||||
return HitResult.Perfect;
|
|
||||||
if (hitOffset <= Great / 2)
|
|
||||||
return HitResult.Great;
|
|
||||||
if (hitOffset <= Good / 2)
|
|
||||||
return HitResult.Good;
|
|
||||||
if (hitOffset <= Ok / 2)
|
|
||||||
return HitResult.Ok;
|
|
||||||
if (hitOffset <= Bad / 2)
|
|
||||||
return HitResult.Meh;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Constructs new hit windows which have been multiplied by a value.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="windows">The original hit windows.</param>
|
|
||||||
/// <param name="value">The value to multiply each hit window by.</param>
|
|
||||||
public static HitWindows operator *(HitWindows windows, double value)
|
|
||||||
{
|
|
||||||
return new HitWindows
|
|
||||||
{
|
|
||||||
Perfect = windows.Perfect * value,
|
|
||||||
Great = windows.Great * value,
|
|
||||||
Good = windows.Good * value,
|
|
||||||
Ok = windows.Ok * value,
|
|
||||||
Bad = windows.Bad * value,
|
|
||||||
Miss = windows.Miss * value
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Constructs new hit windows which have been divided by a value.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="windows">The original hit windows.</param>
|
|
||||||
/// <param name="value">The value to divide each hit window by.</param>
|
|
||||||
public static HitWindows operator /(HitWindows windows, double value)
|
|
||||||
{
|
|
||||||
return new HitWindows
|
|
||||||
{
|
|
||||||
Perfect = windows.Perfect / value,
|
|
||||||
Great = windows.Great / value,
|
|
||||||
Good = windows.Good / value,
|
|
||||||
Ok = windows.Ok / value,
|
|
||||||
Bad = windows.Bad / value,
|
|
||||||
Miss = windows.Miss / value
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,7 +1,6 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
@ -212,7 +211,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
{
|
{
|
||||||
if (!userTriggered)
|
if (!userTriggered)
|
||||||
{
|
{
|
||||||
if (timeOffset > HitObject.HitWindows.Bad / 2)
|
if (!HitObject.HitWindows.CanBeHit(timeOffset))
|
||||||
{
|
{
|
||||||
AddJudgement(new HoldNoteTailJudgement
|
AddJudgement(new HoldNoteTailJudgement
|
||||||
{
|
{
|
||||||
@ -224,14 +223,13 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
double offset = Math.Abs(timeOffset);
|
var result = HitObject.HitWindows.ResultFor(timeOffset);
|
||||||
|
if (result == HitResult.None)
|
||||||
if (offset > HitObject.HitWindows.Miss / 2)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
AddJudgement(new HoldNoteTailJudgement
|
AddJudgement(new HoldNoteTailJudgement
|
||||||
{
|
{
|
||||||
Result = HitObject.HitWindows.ResultFor(offset) ?? HitResult.Miss,
|
Result = result,
|
||||||
HasBroken = holdNote.hasBroken
|
HasBroken = holdNote.hasBroken
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
using System;
|
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Input.Bindings;
|
using osu.Framework.Input.Bindings;
|
||||||
@ -63,17 +62,16 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
{
|
{
|
||||||
if (!userTriggered)
|
if (!userTriggered)
|
||||||
{
|
{
|
||||||
if (timeOffset > HitObject.HitWindows.Bad / 2)
|
if (!HitObject.HitWindows.CanBeHit(timeOffset))
|
||||||
AddJudgement(new ManiaJudgement { Result = HitResult.Miss });
|
AddJudgement(new ManiaJudgement { Result = HitResult.Miss });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
double offset = Math.Abs(timeOffset);
|
var result = HitObject.HitWindows.ResultFor(timeOffset);
|
||||||
|
if (result == HitResult.None)
|
||||||
if (offset > HitObject.HitWindows.Miss / 2)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
AddJudgement(new ManiaJudgement { Result = HitObject.HitWindows.ResultFor(offset) ?? HitResult.Miss });
|
AddJudgement(new ManiaJudgement { Result = result });
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void UpdateState(ArmedState state)
|
protected override void UpdateState(ArmedState state)
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Rulesets.Mania.Objects.Types;
|
using osu.Game.Rulesets.Mania.Objects.Types;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
|
|
||||||
@ -9,5 +11,13 @@ namespace osu.Game.Rulesets.Mania.Objects
|
|||||||
public abstract class ManiaHitObject : HitObject, IHasColumn
|
public abstract class ManiaHitObject : HitObject, IHasColumn
|
||||||
{
|
{
|
||||||
public virtual int Column { get; set; }
|
public virtual int Column { get; set; }
|
||||||
|
|
||||||
|
protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
|
||||||
|
{
|
||||||
|
base.ApplyDefaultsToSelf(controlPointInfo, difficulty);
|
||||||
|
|
||||||
|
HitWindows.AllowsPerfect = true;
|
||||||
|
HitWindows.AllowsOk = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,6 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using osu.Game.Beatmaps;
|
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
|
||||||
using osu.Game.Rulesets.Mania.Judgements;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Objects
|
namespace osu.Game.Rulesets.Mania.Objects
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -13,17 +8,5 @@ namespace osu.Game.Rulesets.Mania.Objects
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class Note : ManiaHitObject
|
public class Note : ManiaHitObject
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// The key-press hit window for this note.
|
|
||||||
/// </summary>
|
|
||||||
[JsonIgnore]
|
|
||||||
public HitWindows HitWindows { get; protected set; } = new HitWindows();
|
|
||||||
|
|
||||||
protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
|
|
||||||
{
|
|
||||||
base.ApplyDefaultsToSelf(controlPointInfo, difficulty);
|
|
||||||
|
|
||||||
HitWindows = new HitWindows(difficulty.OverallDifficulty);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,7 +64,6 @@
|
|||||||
<Compile Include="Beatmaps\Patterns\Pattern.cs" />
|
<Compile Include="Beatmaps\Patterns\Pattern.cs" />
|
||||||
<Compile Include="Configuration\ManiaConfigManager.cs" />
|
<Compile Include="Configuration\ManiaConfigManager.cs" />
|
||||||
<Compile Include="MathUtils\FastRandom.cs" />
|
<Compile Include="MathUtils\FastRandom.cs" />
|
||||||
<Compile Include="Judgements\HitWindows.cs" />
|
|
||||||
<Compile Include="Judgements\HoldNoteTailJudgement.cs" />
|
<Compile Include="Judgements\HoldNoteTailJudgement.cs" />
|
||||||
<Compile Include="Judgements\HoldNoteTickJudgement.cs" />
|
<Compile Include="Judgements\HoldNoteTickJudgement.cs" />
|
||||||
<Compile Include="Judgements\ManiaJudgement.cs" />
|
<Compile Include="Judgements\ManiaJudgement.cs" />
|
||||||
|
@ -72,14 +72,18 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
{
|
{
|
||||||
if (!userTriggered)
|
if (!userTriggered)
|
||||||
{
|
{
|
||||||
if (timeOffset > HitObject.HitWindowFor(HitResult.Meh))
|
if (!HitObject.HitWindows.CanBeHit(timeOffset))
|
||||||
AddJudgement(new OsuJudgement { Result = HitResult.Miss });
|
AddJudgement(new OsuJudgement { Result = HitResult.Miss });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var result = HitObject.HitWindows.ResultFor(timeOffset);
|
||||||
|
if (result == HitResult.None)
|
||||||
|
return;
|
||||||
|
|
||||||
AddJudgement(new OsuJudgement
|
AddJudgement(new OsuJudgement
|
||||||
{
|
{
|
||||||
Result = HitObject.ScoreResultForOffset(Math.Abs(timeOffset)),
|
Result = result,
|
||||||
PositionOffset = Vector2.Zero //todo: set to correct value
|
PositionOffset = Vector2.Zero //todo: set to correct value
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -104,7 +108,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
Expire(true);
|
Expire(true);
|
||||||
|
|
||||||
// override lifetime end as FadeIn may have been changed externally, causing out expiration to be too early.
|
// override lifetime end as FadeIn may have been changed externally, causing out expiration to be too early.
|
||||||
LifetimeEnd = HitObject.StartTime + HitObject.HitWindowFor(HitResult.Miss);
|
LifetimeEnd = HitObject.StartTime + HitObject.HitWindows.HalfWindowFor(HitResult.Miss);
|
||||||
break;
|
break;
|
||||||
case ArmedState.Miss:
|
case ArmedState.Miss:
|
||||||
ApproachCircle.FadeOut(50);
|
ApproachCircle.FadeOut(50);
|
||||||
|
@ -7,7 +7,6 @@ using OpenTK;
|
|||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Rulesets.Scoring;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Objects
|
namespace osu.Game.Rulesets.Osu.Objects
|
||||||
{
|
{
|
||||||
@ -15,11 +14,6 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
{
|
{
|
||||||
public const double OBJECT_RADIUS = 64;
|
public const double OBJECT_RADIUS = 64;
|
||||||
|
|
||||||
private const double hittable_range = 300;
|
|
||||||
public double HitWindow50 = 150;
|
|
||||||
public double HitWindow100 = 80;
|
|
||||||
public double HitWindow300 = 30;
|
|
||||||
|
|
||||||
public double TimePreempt = 600;
|
public double TimePreempt = 600;
|
||||||
public double TimeFadein = 400;
|
public double TimeFadein = 400;
|
||||||
|
|
||||||
@ -45,32 +39,6 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
public virtual bool NewCombo { get; set; }
|
public virtual bool NewCombo { get; set; }
|
||||||
public int IndexInCurrentCombo { get; set; }
|
public int IndexInCurrentCombo { get; set; }
|
||||||
|
|
||||||
public double HitWindowFor(HitResult result)
|
|
||||||
{
|
|
||||||
switch (result)
|
|
||||||
{
|
|
||||||
default:
|
|
||||||
return hittable_range;
|
|
||||||
case HitResult.Meh:
|
|
||||||
return HitWindow50;
|
|
||||||
case HitResult.Good:
|
|
||||||
return HitWindow100;
|
|
||||||
case HitResult.Great:
|
|
||||||
return HitWindow300;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public HitResult ScoreResultForOffset(double offset)
|
|
||||||
{
|
|
||||||
if (offset < HitWindowFor(HitResult.Great))
|
|
||||||
return HitResult.Great;
|
|
||||||
if (offset < HitWindowFor(HitResult.Good))
|
|
||||||
return HitResult.Good;
|
|
||||||
if (offset < HitWindowFor(HitResult.Meh))
|
|
||||||
return HitResult.Meh;
|
|
||||||
return HitResult.Miss;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
|
protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
|
||||||
{
|
{
|
||||||
base.ApplyDefaultsToSelf(controlPointInfo, difficulty);
|
base.ApplyDefaultsToSelf(controlPointInfo, difficulty);
|
||||||
@ -78,10 +46,6 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
TimePreempt = (float)BeatmapDifficulty.DifficultyRange(difficulty.ApproachRate, 1800, 1200, 450);
|
TimePreempt = (float)BeatmapDifficulty.DifficultyRange(difficulty.ApproachRate, 1800, 1200, 450);
|
||||||
TimeFadein = (float)BeatmapDifficulty.DifficultyRange(difficulty.ApproachRate, 1200, 800, 300);
|
TimeFadein = (float)BeatmapDifficulty.DifficultyRange(difficulty.ApproachRate, 1200, 800, 300);
|
||||||
|
|
||||||
HitWindow50 = BeatmapDifficulty.DifficultyRange(difficulty.OverallDifficulty, 200, 150, 100);
|
|
||||||
HitWindow100 = BeatmapDifficulty.DifficultyRange(difficulty.OverallDifficulty, 140, 100, 60);
|
|
||||||
HitWindow300 = BeatmapDifficulty.DifficultyRange(difficulty.OverallDifficulty, 80, 50, 20);
|
|
||||||
|
|
||||||
Scale = (1.0f - 0.7f * (difficulty.CircleSize - 5) / 5) / 2;
|
Scale = (1.0f - 0.7f * (difficulty.CircleSize - 5) / 5) / 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -89,20 +89,20 @@ namespace osu.Game.Rulesets.Osu.Replays
|
|||||||
double endTime = (prev as IHasEndTime)?.EndTime ?? prev.StartTime;
|
double endTime = (prev as IHasEndTime)?.EndTime ?? prev.StartTime;
|
||||||
|
|
||||||
// Make the cursor stay at a hitObject as long as possible (mainly for autopilot).
|
// Make the cursor stay at a hitObject as long as possible (mainly for autopilot).
|
||||||
if (h.StartTime - h.HitWindowFor(HitResult.Miss) > endTime + h.HitWindowFor(HitResult.Meh) + 50)
|
if (h.StartTime - h.HitWindows.HalfWindowFor(HitResult.Miss) > endTime + h.HitWindows.HalfWindowFor(HitResult.Meh) + 50)
|
||||||
{
|
{
|
||||||
if (!(prev is Spinner) && h.StartTime - endTime < 1000) AddFrameToReplay(new ReplayFrame(endTime + h.HitWindowFor(HitResult.Meh), prev.StackedEndPosition.X, prev.StackedEndPosition.Y, ReplayButtonState.None));
|
if (!(prev is Spinner) && h.StartTime - endTime < 1000) AddFrameToReplay(new ReplayFrame(endTime + h.HitWindows.HalfWindowFor(HitResult.Meh), prev.StackedEndPosition.X, prev.StackedEndPosition.Y, ReplayButtonState.None));
|
||||||
if (!(h is Spinner)) AddFrameToReplay(new ReplayFrame(h.StartTime - h.HitWindowFor(HitResult.Miss), h.StackedPosition.X, h.StackedPosition.Y, ReplayButtonState.None));
|
if (!(h is Spinner)) AddFrameToReplay(new ReplayFrame(h.StartTime - h.HitWindows.HalfWindowFor(HitResult.Meh), h.StackedPosition.X, h.StackedPosition.Y, ReplayButtonState.None));
|
||||||
}
|
}
|
||||||
else if (h.StartTime - h.HitWindowFor(HitResult.Meh) > endTime + h.HitWindowFor(HitResult.Meh) + 50)
|
else if (h.StartTime - h.HitWindows.HalfWindowFor(HitResult.Meh) > endTime + h.HitWindows.HalfWindowFor(HitResult.Meh) + 50)
|
||||||
{
|
{
|
||||||
if (!(prev is Spinner) && h.StartTime - endTime < 1000) AddFrameToReplay(new ReplayFrame(endTime + h.HitWindowFor(HitResult.Meh), prev.StackedEndPosition.X, prev.StackedEndPosition.Y, ReplayButtonState.None));
|
if (!(prev is Spinner) && h.StartTime - endTime < 1000) AddFrameToReplay(new ReplayFrame(endTime + h.HitWindows.HalfWindowFor(HitResult.Meh), prev.StackedEndPosition.X, prev.StackedEndPosition.Y, ReplayButtonState.None));
|
||||||
if (!(h is Spinner)) AddFrameToReplay(new ReplayFrame(h.StartTime - h.HitWindowFor(HitResult.Meh), h.StackedPosition.X, h.StackedPosition.Y, ReplayButtonState.None));
|
if (!(h is Spinner)) AddFrameToReplay(new ReplayFrame(h.StartTime - h.HitWindows.HalfWindowFor(HitResult.Meh), h.StackedPosition.X, h.StackedPosition.Y, ReplayButtonState.None));
|
||||||
}
|
}
|
||||||
else if (h.StartTime - h.HitWindowFor(HitResult.Good) > endTime + h.HitWindowFor(HitResult.Good) + 50)
|
else if (h.StartTime - h.HitWindows.HalfWindowFor(HitResult.Meh) > endTime + h.HitWindows.HalfWindowFor(HitResult.Meh) + 50)
|
||||||
{
|
{
|
||||||
if (!(prev is Spinner) && h.StartTime - endTime < 1000) AddFrameToReplay(new ReplayFrame(endTime + h.HitWindowFor(HitResult.Good), prev.StackedEndPosition.X, prev.StackedEndPosition.Y, ReplayButtonState.None));
|
if (!(prev is Spinner) && h.StartTime - endTime < 1000) AddFrameToReplay(new ReplayFrame(endTime + h.HitWindows.HalfWindowFor(HitResult.Meh), prev.StackedEndPosition.X, prev.StackedEndPosition.Y, ReplayButtonState.None));
|
||||||
if (!(h is Spinner)) AddFrameToReplay(new ReplayFrame(h.StartTime - h.HitWindowFor(HitResult.Good), h.StackedPosition.X, h.StackedPosition.Y, ReplayButtonState.None));
|
if (!(h is Spinner)) AddFrameToReplay(new ReplayFrame(h.StartTime - h.HitWindows.HalfWindowFor(HitResult.Meh), h.StackedPosition.X, h.StackedPosition.Y, ReplayButtonState.None));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
@ -38,30 +37,27 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
{
|
{
|
||||||
if (!userTriggered)
|
if (!userTriggered)
|
||||||
{
|
{
|
||||||
if (timeOffset > HitObject.HitWindowGood)
|
if (!HitObject.HitWindows.CanBeHit(timeOffset))
|
||||||
AddJudgement(new TaikoJudgement { Result = HitResult.Miss });
|
AddJudgement(new TaikoJudgement { Result = HitResult.Miss });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
double hitOffset = Math.Abs(timeOffset);
|
var result = HitObject.HitWindows.ResultFor(timeOffset);
|
||||||
|
if (result == HitResult.None)
|
||||||
if (hitOffset > HitObject.HitWindowMiss)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!validKeyPressed)
|
if (!validKeyPressed || result == HitResult.Miss)
|
||||||
AddJudgement(new TaikoJudgement { Result = HitResult.Miss });
|
AddJudgement(new TaikoJudgement { Result = HitResult.Miss });
|
||||||
else if (hitOffset < HitObject.HitWindowGood)
|
else
|
||||||
{
|
{
|
||||||
AddJudgement(new TaikoJudgement
|
AddJudgement(new TaikoJudgement
|
||||||
{
|
{
|
||||||
Result = hitOffset < HitObject.HitWindowGreat ? HitResult.Great : HitResult.Good,
|
Result = result,
|
||||||
Final = !HitObject.IsStrong
|
Final = !HitObject.IsStrong
|
||||||
});
|
});
|
||||||
|
|
||||||
SecondHitAllowed = true;
|
SecondHitAllowed = true;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
AddJudgement(new TaikoJudgement { Result = HitResult.Miss });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool OnPressed(TaikoAction action)
|
public override bool OnPressed(TaikoAction action)
|
||||||
@ -90,7 +86,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
switch (State.Value)
|
switch (State.Value)
|
||||||
{
|
{
|
||||||
case ArmedState.Idle:
|
case ArmedState.Idle:
|
||||||
this.Delay(HitObject.HitWindowMiss).Expire();
|
this.Delay(HitObject.HitWindows.HalfWindowFor(HitResult.Miss)).Expire();
|
||||||
break;
|
break;
|
||||||
case ArmedState.Miss:
|
case ArmedState.Miss:
|
||||||
this.FadeOut(100)
|
this.FadeOut(100)
|
||||||
|
@ -1,35 +1,9 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
using osu.Game.Beatmaps;
|
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Taiko.Objects
|
namespace osu.Game.Rulesets.Taiko.Objects
|
||||||
{
|
{
|
||||||
public class Hit : TaikoHitObject
|
public class Hit : TaikoHitObject
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// The hit window that results in a "GREAT" hit.
|
|
||||||
/// </summary>
|
|
||||||
public double HitWindowGreat = 35;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The hit window that results in a "GOOD" hit.
|
|
||||||
/// </summary>
|
|
||||||
public double HitWindowGood = 80;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The hit window that results in a "MISS".
|
|
||||||
/// </summary>
|
|
||||||
public double HitWindowMiss = 95;
|
|
||||||
|
|
||||||
protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
|
|
||||||
{
|
|
||||||
base.ApplyDefaultsToSelf(controlPointInfo, difficulty);
|
|
||||||
|
|
||||||
HitWindowGreat = BeatmapDifficulty.DifficultyRange(difficulty.OverallDifficulty, 50, 35, 20);
|
|
||||||
HitWindowGood = BeatmapDifficulty.DifficultyRange(difficulty.OverallDifficulty, 120, 80, 50);
|
|
||||||
HitWindowMiss = BeatmapDifficulty.DifficultyRange(difficulty.OverallDifficulty, 135, 95, 70);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,5 +40,17 @@ namespace osu.Game.Beatmaps
|
|||||||
return mid - (mid - min) * (5 - difficulty) / 5;
|
return mid - (mid - min) * (5 - difficulty) / 5;
|
||||||
return mid;
|
return mid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Maps a difficulty value [0, 10] to a two-piece linear range of values.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="difficulty">The difficulty value to be mapped.</param>
|
||||||
|
/// <param name="range">The values that define the two linear ranges.</param>
|
||||||
|
/// <param name="range.od0">Minimum of the resulting range which will be achieved by a difficulty value of 0.</param>
|
||||||
|
/// <param name="range.od5">Midpoint of the resulting range which will be achieved by a difficulty value of 5.</param>
|
||||||
|
/// <param name="range.od10">Maximum of the resulting range which will be achieved by a difficulty value of 10.</param>
|
||||||
|
/// <returns>Value to which the difficulty value maps in the specified range.</returns>
|
||||||
|
public static double DifficultyRange(double difficulty, (double od0, double od5, double od10) range)
|
||||||
|
=> DifficultyRange(difficulty, range.od0, range.od5, range.od10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,6 +49,19 @@ namespace osu.Game.Rulesets.Objects
|
|||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public bool Kiai { get; private set; }
|
public bool Kiai { get; private set; }
|
||||||
|
|
||||||
|
private float overallDifficulty = BeatmapDifficulty.DEFAULT_DIFFICULTY;
|
||||||
|
|
||||||
|
private HitWindows hitWindows;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The hit windows for this <see cref="HitObject"/>.
|
||||||
|
/// </summary>
|
||||||
|
public HitWindows HitWindows
|
||||||
|
{
|
||||||
|
get => hitWindows ?? (hitWindows = new HitWindows(overallDifficulty));
|
||||||
|
protected set => hitWindows = value;
|
||||||
|
}
|
||||||
|
|
||||||
private readonly SortedList<HitObject> nestedHitObjects = new SortedList<HitObject>((h1, h2) => h1.StartTime.CompareTo(h2.StartTime));
|
private readonly SortedList<HitObject> nestedHitObjects = new SortedList<HitObject>((h1, h2) => h1.StartTime.CompareTo(h2.StartTime));
|
||||||
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
@ -75,6 +88,9 @@ namespace osu.Game.Rulesets.Objects
|
|||||||
|
|
||||||
Kiai = effectPoint.KiaiMode;
|
Kiai = effectPoint.KiaiMode;
|
||||||
SampleControlPoint = samplePoint;
|
SampleControlPoint = samplePoint;
|
||||||
|
|
||||||
|
overallDifficulty = difficulty.OverallDifficulty;
|
||||||
|
hitWindows = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void CreateNestedHitObjects()
|
protected virtual void CreateNestedHitObjects()
|
||||||
|
173
osu.Game/Rulesets/Objects/HitWindows.cs
Normal file
173
osu.Game/Rulesets/Objects/HitWindows.cs
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Objects
|
||||||
|
{
|
||||||
|
public class HitWindows
|
||||||
|
{
|
||||||
|
private static readonly IReadOnlyDictionary<HitResult, (double od0, double od5, double od10)> base_ranges = new Dictionary<HitResult, (double, double, double)>
|
||||||
|
{
|
||||||
|
{ HitResult.Perfect, (44.8, 38.8, 27.8) },
|
||||||
|
{ HitResult.Great, (128, 98, 68 ) },
|
||||||
|
{ HitResult.Good, (194, 164, 134) },
|
||||||
|
{ HitResult.Ok, (254, 224, 194) },
|
||||||
|
{ HitResult.Meh, (302, 272, 242) },
|
||||||
|
{ HitResult.Miss, (376, 346, 316) },
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Hit window for a <see cref="HitResult.Perfect"/> result.
|
||||||
|
/// The user can only achieve receive this result if <see cref="AllowsPerfect"/> is true.
|
||||||
|
/// </summary>
|
||||||
|
public double Perfect { get; protected set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Hit window for a <see cref="HitResult.Great"/> result.
|
||||||
|
/// </summary>
|
||||||
|
public double Great { get; protected set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Hit window for a <see cref="HitResult.Good"/> result.
|
||||||
|
/// </summary>
|
||||||
|
public double Good { get; protected set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Hit window for an <see cref="HitResult.Ok"/> result.
|
||||||
|
/// The user can only achieve this result if <see cref="AllowsOk"/> is true.
|
||||||
|
/// </summary>
|
||||||
|
public double Ok { get; protected set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Hit window for a <see cref="HitResult.Meh"/> result.
|
||||||
|
/// </summary>
|
||||||
|
public double Meh { get; protected set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Hit window for a <see cref="HitResult.Miss"/> result.
|
||||||
|
/// </summary>
|
||||||
|
public double Miss { get; protected set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether it's possible to achieve a <see cref="HitResult.Perfect"/> result.
|
||||||
|
/// </summary>
|
||||||
|
public bool AllowsPerfect;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether it's possible to achieve a <see cref="HitResult.Ok"/> result.
|
||||||
|
/// </summary>
|
||||||
|
public bool AllowsOk;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constructs hit windows by fitting a parameter to a 2-part piecewise linear function for each hit window.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="difficulty">The parameter.</param>
|
||||||
|
public HitWindows(double difficulty)
|
||||||
|
{
|
||||||
|
Perfect = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Perfect]);
|
||||||
|
Great = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Great]);
|
||||||
|
Good = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Good]);
|
||||||
|
Ok = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Ok]);
|
||||||
|
Meh = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Meh]);
|
||||||
|
Miss = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Miss]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves the <see cref="HitResult"/> for a time offset.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="timeOffset">The time offset.</param>
|
||||||
|
/// <returns>The hit result, or <see cref="HitResult.None"/> if <paramref name="timeOffset"/> doesn't result in a judgement.</returns>
|
||||||
|
public HitResult ResultFor(double timeOffset)
|
||||||
|
{
|
||||||
|
timeOffset = Math.Abs(timeOffset);
|
||||||
|
|
||||||
|
if (AllowsPerfect && timeOffset <= HalfWindowFor(HitResult.Perfect))
|
||||||
|
return HitResult.Perfect;
|
||||||
|
if (timeOffset <= HalfWindowFor(HitResult.Great))
|
||||||
|
return HitResult.Great;
|
||||||
|
if (timeOffset <= HalfWindowFor(HitResult.Good))
|
||||||
|
return HitResult.Good;
|
||||||
|
if (AllowsOk && timeOffset <= HalfWindowFor(HitResult.Ok))
|
||||||
|
return HitResult.Ok;
|
||||||
|
if (timeOffset <= HalfWindowFor(HitResult.Meh))
|
||||||
|
return HitResult.Meh;
|
||||||
|
if (timeOffset <= HalfWindowFor(HitResult.Miss))
|
||||||
|
return HitResult.Miss;
|
||||||
|
|
||||||
|
return HitResult.None;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves half the hit window for a <see cref="HitResult"/>.
|
||||||
|
/// This is useful if the hit window for one half of the hittable range of a <see cref="HitObject"/> is required.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="result">The expected <see cref="HitResult"/>.</param>
|
||||||
|
/// <returns>One half of the hit window for <paramref name="result"/>.</returns>
|
||||||
|
public double HalfWindowFor(HitResult result)
|
||||||
|
{
|
||||||
|
switch (result)
|
||||||
|
{
|
||||||
|
case HitResult.Perfect:
|
||||||
|
return Perfect / 2;
|
||||||
|
case HitResult.Great:
|
||||||
|
return Great / 2;
|
||||||
|
case HitResult.Good:
|
||||||
|
return Good / 2;
|
||||||
|
case HitResult.Ok:
|
||||||
|
return Ok / 2;
|
||||||
|
case HitResult.Meh:
|
||||||
|
return Meh / 2;
|
||||||
|
case HitResult.Miss:
|
||||||
|
return Miss / 2;
|
||||||
|
default:
|
||||||
|
throw new ArgumentException(nameof(result));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Given a time offset, whether the <see cref="HitObject"/> can ever be hit in the future with a non-<see cref="HitResult.Miss"/> result.
|
||||||
|
/// This happens if <paramref name="timeOffset"/> is less than what is required for a <see cref="Meh"/> result.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="timeOffset">The time offset.</param>
|
||||||
|
/// <returns>Whether the <see cref="HitObject"/> can be hit at any point in the future from this time offset.</returns>
|
||||||
|
public bool CanBeHit(double timeOffset) => timeOffset <= HalfWindowFor(HitResult.Meh);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Multiplies all hit windows by a value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="windows">The hit windows to multiply.</param>
|
||||||
|
/// <param name="value">The value to multiply each hit window by.</param>
|
||||||
|
public static HitWindows operator *(HitWindows windows, double value)
|
||||||
|
{
|
||||||
|
windows.Perfect *= value;
|
||||||
|
windows.Great *= value;
|
||||||
|
windows.Good *= value;
|
||||||
|
windows.Ok *= value;
|
||||||
|
windows.Meh *= value;
|
||||||
|
windows.Miss *= value;
|
||||||
|
|
||||||
|
return windows;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Divides all hit windows by a value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="windows">The hit windows to divide.</param>
|
||||||
|
/// <param name="value">The value to divide each hit window by.</param>
|
||||||
|
public static HitWindows operator /(HitWindows windows, double value)
|
||||||
|
{
|
||||||
|
windows.Perfect /= value;
|
||||||
|
windows.Great /= value;
|
||||||
|
windows.Good /= value;
|
||||||
|
windows.Ok /= value;
|
||||||
|
windows.Meh /= value;
|
||||||
|
windows.Miss /= value;
|
||||||
|
|
||||||
|
return windows;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -35,6 +35,7 @@ namespace osu.Game.Rulesets.Objects.Types
|
|||||||
/// Ranges from [0, 1] where 0 is the beginning of the curve and 1 is the end of the curve.
|
/// Ranges from [0, 1] where 0 is the beginning of the curve and 1 is the end of the curve.
|
||||||
/// </para>
|
/// </para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="obj">The curve.</param>
|
||||||
/// <param name="progress">[0, 1] where 0 is the beginning of the curve and 1 is the end of the curve.</param>
|
/// <param name="progress">[0, 1] where 0 is the beginning of the curve and 1 is the end of the curve.</param>
|
||||||
public static Vector2 PositionAt(this IHasCurve obj, double progress)
|
public static Vector2 PositionAt(this IHasCurve obj, double progress)
|
||||||
=> obj.Curve.PositionAt(obj.ProgressAt(progress));
|
=> obj.Curve.PositionAt(obj.ProgressAt(progress));
|
||||||
@ -42,6 +43,7 @@ namespace osu.Game.Rulesets.Objects.Types
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Finds the progress along the curve, accounting for repeat logic.
|
/// Finds the progress along the curve, accounting for repeat logic.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="obj">The curve.</param>
|
||||||
/// <param name="progress">[0, 1] where 0 is the beginning of the curve and 1 is the end of the curve.</param>
|
/// <param name="progress">[0, 1] where 0 is the beginning of the curve and 1 is the end of the curve.</param>
|
||||||
/// <returns>[0, 1] where 0 is the beginning of the curve and 1 is the end of the curve.</returns>
|
/// <returns>[0, 1] where 0 is the beginning of the curve and 1 is the end of the curve.</returns>
|
||||||
public static double ProgressAt(this IHasCurve obj, double progress)
|
public static double ProgressAt(this IHasCurve obj, double progress)
|
||||||
@ -55,6 +57,7 @@ namespace osu.Game.Rulesets.Objects.Types
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines which span of the curve the progress point is on.
|
/// Determines which span of the curve the progress point is on.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="obj">The curve.</param>
|
||||||
/// <param name="progress">[0, 1] where 0 is the beginning of the curve and 1 is the end of the curve.</param>
|
/// <param name="progress">[0, 1] where 0 is the beginning of the curve and 1 is the end of the curve.</param>
|
||||||
/// <returns>[0, SpanCount) where 0 is the first run.</returns>
|
/// <returns>[0, SpanCount) where 0 is the first run.</returns>
|
||||||
public static int SpanAt(this IHasCurve obj, double progress)
|
public static int SpanAt(this IHasCurve obj, double progress)
|
||||||
|
@ -52,7 +52,7 @@ namespace osu.Game.Rulesets.UI.Scrolling
|
|||||||
protected virtual bool UserScrollSpeedAdjustment => true;
|
protected virtual bool UserScrollSpeedAdjustment => true;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The container that contains the <see cref="SpeedAdjustmentContainer"/>s and <see cref="DrawableHitObject"/>s.
|
/// The container that contains the <see cref="DrawableHitObject"/>s.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public new ScrollingHitObjectContainer HitObjects => (ScrollingHitObjectContainer)base.HitObjects;
|
public new ScrollingHitObjectContainer HitObjects => (ScrollingHitObjectContainer)base.HitObjects;
|
||||||
|
|
||||||
@ -61,7 +61,7 @@ namespace osu.Game.Rulesets.UI.Scrolling
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new <see cref="ScrollingPlayfield"/>.
|
/// Creates a new <see cref="ScrollingPlayfield"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="scrollingAxes">The axes on which <see cref="DrawableHitObject"/>s in this container should scroll.</param>
|
/// <param name="direction">The direction in which <see cref="DrawableHitObject"/>s in this container should scroll.</param>
|
||||||
/// <param name="customWidth">Whether we want our internal coordinate system to be scaled to a specified width</param>
|
/// <param name="customWidth">Whether we want our internal coordinate system to be scaled to a specified width</param>
|
||||||
protected ScrollingPlayfield(ScrollingDirection direction, float? customWidth = null)
|
protected ScrollingPlayfield(ScrollingDirection direction, float? customWidth = null)
|
||||||
: base(customWidth)
|
: base(customWidth)
|
||||||
|
@ -56,19 +56,19 @@ namespace osu.Game.Users
|
|||||||
public int? Id;
|
public int? Id;
|
||||||
}
|
}
|
||||||
|
|
||||||
[JsonProperty(@"isAdmin")]
|
[JsonProperty(@"is_admin")]
|
||||||
public bool IsAdmin;
|
public bool IsAdmin;
|
||||||
|
|
||||||
[JsonProperty(@"isSupporter")]
|
[JsonProperty(@"is_supporter")]
|
||||||
public bool IsSupporter;
|
public bool IsSupporter;
|
||||||
|
|
||||||
[JsonProperty(@"isGMT")]
|
[JsonProperty(@"is_gmt")]
|
||||||
public bool IsGMT;
|
public bool IsGMT;
|
||||||
|
|
||||||
[JsonProperty(@"isQAT")]
|
[JsonProperty(@"is_qat")]
|
||||||
public bool IsQAT;
|
public bool IsQAT;
|
||||||
|
|
||||||
[JsonProperty(@"isBNG")]
|
[JsonProperty(@"is_bng")]
|
||||||
public bool IsBNG;
|
public bool IsBNG;
|
||||||
|
|
||||||
[JsonProperty(@"is_active")]
|
[JsonProperty(@"is_active")]
|
||||||
@ -107,7 +107,7 @@ namespace osu.Game.Users
|
|||||||
[JsonProperty(@"playmode")]
|
[JsonProperty(@"playmode")]
|
||||||
public string PlayMode;
|
public string PlayMode;
|
||||||
|
|
||||||
[JsonProperty(@"profileOrder")]
|
[JsonProperty(@"profile_order")]
|
||||||
public string[] ProfileOrder;
|
public string[] ProfileOrder;
|
||||||
|
|
||||||
[JsonProperty(@"kudosu")]
|
[JsonProperty(@"kudosu")]
|
||||||
|
@ -340,6 +340,7 @@
|
|||||||
<Compile Include="Overlays\Social\SocialListPanel.cs" />
|
<Compile Include="Overlays\Social\SocialListPanel.cs" />
|
||||||
<Compile Include="Overlays\Social\SocialPanel.cs" />
|
<Compile Include="Overlays\Social\SocialPanel.cs" />
|
||||||
<Compile Include="Rulesets\Mods\IApplicableToDrawableHitObject.cs" />
|
<Compile Include="Rulesets\Mods\IApplicableToDrawableHitObject.cs" />
|
||||||
|
<Compile Include="Rulesets\Objects\HitWindows.cs" />
|
||||||
<Compile Include="Screens\Play\PlayerSettings\VisualSettings.cs" />
|
<Compile Include="Screens\Play\PlayerSettings\VisualSettings.cs" />
|
||||||
<Compile Include="Rulesets\Objects\CatmullApproximator.cs" />
|
<Compile Include="Rulesets\Objects\CatmullApproximator.cs" />
|
||||||
<Compile Include="Rulesets\UI\HitObjectContainer.cs" />
|
<Compile Include="Rulesets\UI\HitObjectContainer.cs" />
|
||||||
|
Loading…
Reference in New Issue
Block a user