mirror of
https://github.com/ppy/osu.git
synced 2025-02-19 11:23:23 +08:00
commit
452506d982
@ -6,7 +6,6 @@ using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Timing;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Osu.Judgements;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||
using OpenTK;
|
||||
@ -110,10 +109,7 @@ namespace osu.Desktop.Tests.Visual
|
||||
h.Depth = depth++;
|
||||
|
||||
if (auto)
|
||||
{
|
||||
h.State = ArmedState.Hit;
|
||||
h.Judgement = new OsuJudgement { Result = HitResult.Hit };
|
||||
}
|
||||
|
||||
playfieldContainer.Add(h);
|
||||
var proxyable = h as IDrawableHitObjectWithProxiedApproach;
|
||||
|
@ -57,11 +57,10 @@ namespace osu.Desktop.Tests.Visual
|
||||
|
||||
var note = new DrawableNote(new Note { Column = col }, ManiaAction.Key1)
|
||||
{
|
||||
Judgement = new ManiaJudgement { Result = HitResult.Hit },
|
||||
AccentColour = playfield.Columns.ElementAt(col).AccentColour
|
||||
};
|
||||
|
||||
playfield.OnJudgement(note);
|
||||
playfield.OnJudgement(note, new ManiaJudgement { Result = HitResult.Perfect });
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -72,7 +72,7 @@ namespace osu.Desktop.Tests.Visual
|
||||
[Test]
|
||||
public void TestSpeedAdjustmentOrdering()
|
||||
{
|
||||
var hitObjectContainer = new ScrollingPlayfield<TestHitObject, TestJudgement>.ScrollingHitObjectContainer(Axes.X);
|
||||
var hitObjectContainer = new ScrollingPlayfield.ScrollingHitObjectContainer(Axes.X);
|
||||
|
||||
var speedAdjustments = new[]
|
||||
{
|
||||
@ -129,7 +129,7 @@ namespace osu.Desktop.Tests.Visual
|
||||
Assert.IsTrue(hitObjectContainer.SpeedAdjustments[3].Contains(hitObjects[1]));
|
||||
}
|
||||
|
||||
private class TestRulesetContainer : ScrollingRulesetContainer<TestPlayfield, TestHitObject, TestJudgement>
|
||||
private class TestRulesetContainer : ScrollingRulesetContainer<TestPlayfield, TestHitObject>
|
||||
{
|
||||
private readonly Axes scrollingAxes;
|
||||
|
||||
@ -147,14 +147,14 @@ namespace osu.Desktop.Tests.Visual
|
||||
|
||||
protected override BeatmapConverter<TestHitObject> CreateBeatmapConverter() => new TestBeatmapConverter();
|
||||
|
||||
protected override Playfield<TestHitObject, TestJudgement> CreatePlayfield() => new TestPlayfield(scrollingAxes);
|
||||
protected override Playfield CreatePlayfield() => new TestPlayfield(scrollingAxes);
|
||||
|
||||
protected override DrawableHitObject<TestHitObject, TestJudgement> GetVisualRepresentation(TestHitObject h) => new DrawableTestHitObject(scrollingAxes, h);
|
||||
protected override DrawableHitObject<TestHitObject> GetVisualRepresentation(TestHitObject h) => new DrawableTestHitObject(scrollingAxes, h);
|
||||
}
|
||||
|
||||
private class TestScoreProcessor : ScoreProcessor<TestHitObject, TestJudgement>
|
||||
private class TestScoreProcessor : ScoreProcessor<TestHitObject>
|
||||
{
|
||||
protected override void OnNewJudgement(TestJudgement judgement)
|
||||
protected override void OnNewJudgement(Judgement judgement)
|
||||
{
|
||||
}
|
||||
}
|
||||
@ -169,7 +169,7 @@ namespace osu.Desktop.Tests.Visual
|
||||
}
|
||||
}
|
||||
|
||||
private class DrawableTestHitObject : DrawableScrollingHitObject<TestHitObject, TestJudgement>
|
||||
private class DrawableTestHitObject : DrawableScrollingHitObject<TestHitObject>
|
||||
{
|
||||
public DrawableTestHitObject(Axes scrollingAxes, TestHitObject hitObject)
|
||||
: base(hitObject)
|
||||
@ -185,14 +185,12 @@ namespace osu.Desktop.Tests.Visual
|
||||
});
|
||||
}
|
||||
|
||||
protected override TestJudgement CreateJudgement() => new TestJudgement();
|
||||
|
||||
protected override void UpdateState(ArmedState state)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private class TestPlayfield : ScrollingPlayfield<TestHitObject, TestJudgement>
|
||||
private class TestPlayfield : ScrollingPlayfield
|
||||
{
|
||||
protected override Container<Drawable> Content => content;
|
||||
private readonly Container<Drawable> content;
|
||||
@ -218,11 +216,5 @@ namespace osu.Desktop.Tests.Visual
|
||||
private class TestHitObject : HitObject
|
||||
{
|
||||
}
|
||||
|
||||
private class TestJudgement : Judgement
|
||||
{
|
||||
public override string ResultString { get { throw new NotImplementedException(); } }
|
||||
public override string MaxResultString { get { throw new NotImplementedException(); } }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -128,7 +128,7 @@ namespace osu.Desktop.Tests.Visual
|
||||
|
||||
private void addHitJudgement(bool kiai)
|
||||
{
|
||||
TaikoHitResult hitResult = RNG.Next(2) == 0 ? TaikoHitResult.Good : TaikoHitResult.Great;
|
||||
HitResult hitResult = RNG.Next(2) == 0 ? HitResult.Good : HitResult.Great;
|
||||
|
||||
var cpi = new ControlPointInfo();
|
||||
cpi.EffectPoints.Add(new EffectControlPoint
|
||||
@ -139,36 +139,20 @@ namespace osu.Desktop.Tests.Visual
|
||||
Hit hit = new Hit();
|
||||
hit.ApplyDefaults(cpi, new BeatmapDifficulty());
|
||||
|
||||
var h = new DrawableTestHit(hit)
|
||||
{
|
||||
X = RNG.NextSingle(hitResult == TaikoHitResult.Good ? -0.1f : -0.05f, hitResult == TaikoHitResult.Good ? 0.1f : 0.05f),
|
||||
Judgement = new TaikoJudgement
|
||||
{
|
||||
Result = HitResult.Hit,
|
||||
TaikoResult = hitResult,
|
||||
TimeOffset = 0
|
||||
}
|
||||
};
|
||||
var h = new DrawableTestHit(hit) { X = RNG.NextSingle(hitResult == HitResult.Good ? -0.1f : -0.05f, hitResult == HitResult.Good ? 0.1f : 0.05f) };
|
||||
|
||||
rulesetContainer.Playfield.OnJudgement(h);
|
||||
rulesetContainer.Playfield.OnJudgement(h, new TaikoJudgement { Result = hitResult });
|
||||
|
||||
if (RNG.Next(10) == 0)
|
||||
{
|
||||
h.Judgement.SecondHit = true;
|
||||
rulesetContainer.Playfield.OnJudgement(h);
|
||||
rulesetContainer.Playfield.OnJudgement(h, new TaikoJudgement { Result = hitResult });
|
||||
rulesetContainer.Playfield.OnJudgement(h, new TaikoStrongHitJudgement());
|
||||
}
|
||||
}
|
||||
|
||||
private void addMissJudgement()
|
||||
{
|
||||
rulesetContainer.Playfield.OnJudgement(new DrawableTestHit(new Hit())
|
||||
{
|
||||
Judgement = new TaikoJudgement
|
||||
{
|
||||
Result = HitResult.Miss,
|
||||
TimeOffset = 0
|
||||
}
|
||||
});
|
||||
rulesetContainer.Playfield.OnJudgement(new DrawableTestHit(new Hit()), new TaikoJudgement { Result = HitResult.Miss });
|
||||
}
|
||||
|
||||
private void addBarLine(bool major, double delay = scroll_time)
|
||||
@ -230,15 +214,13 @@ namespace osu.Desktop.Tests.Visual
|
||||
rulesetContainer.Playfield.Add(new DrawableRimHit(h));
|
||||
}
|
||||
|
||||
private class DrawableTestHit : DrawableHitObject<TaikoHitObject, TaikoJudgement>
|
||||
private class DrawableTestHit : DrawableHitObject<TaikoHitObject>
|
||||
{
|
||||
public DrawableTestHit(TaikoHitObject hitObject)
|
||||
: base(hitObject)
|
||||
{
|
||||
}
|
||||
|
||||
protected override TaikoJudgement CreateJudgement() => new TaikoJudgement();
|
||||
|
||||
protected override void UpdateState(ArmedState state)
|
||||
{
|
||||
}
|
||||
|
@ -7,8 +7,6 @@ namespace osu.Game.Rulesets.Catch.Judgements
|
||||
{
|
||||
public class CatchJudgement : Judgement
|
||||
{
|
||||
public override string ResultString => string.Empty;
|
||||
|
||||
public override string MaxResultString => string.Empty;
|
||||
// todo: wangs
|
||||
}
|
||||
}
|
||||
|
@ -9,14 +9,14 @@ using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Rulesets.Catch.Judgements;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
{
|
||||
public class DrawableFruit : DrawableScrollingHitObject<CatchBaseHit, CatchJudgement>
|
||||
public class DrawableFruit : DrawableScrollingHitObject<CatchBaseHit>
|
||||
{
|
||||
private const float pulp_size = 30;
|
||||
|
||||
@ -98,14 +98,12 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
};
|
||||
}
|
||||
|
||||
protected override CatchJudgement CreateJudgement() => new CatchJudgement();
|
||||
|
||||
private const float preempt = 1000;
|
||||
|
||||
protected override void CheckJudgement(bool userTriggered)
|
||||
protected override void CheckForJudgements(bool userTriggered, double timeOffset)
|
||||
{
|
||||
if (Judgement.TimeOffset > 0)
|
||||
Judgement.Result = CheckPosition?.Invoke(HitObject) ?? false ? HitResult.Hit : HitResult.Miss;
|
||||
if (timeOffset > 0)
|
||||
AddJudgement(new Judgement { Result = CheckPosition?.Invoke(HitObject) ?? false ? HitResult.Perfect : HitResult.Miss });
|
||||
}
|
||||
|
||||
protected override void UpdateState(ArmedState state)
|
||||
|
@ -1,20 +1,20 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Game.Rulesets.Catch.Judgements;
|
||||
using osu.Game.Rulesets.Catch.Objects;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Rulesets.UI;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Scoring
|
||||
{
|
||||
internal class CatchScoreProcessor : ScoreProcessor<CatchBaseHit, CatchJudgement>
|
||||
internal class CatchScoreProcessor : ScoreProcessor<CatchBaseHit>
|
||||
{
|
||||
public CatchScoreProcessor()
|
||||
{
|
||||
}
|
||||
|
||||
public CatchScoreProcessor(RulesetContainer<CatchBaseHit, CatchJudgement> rulesetContainer)
|
||||
public CatchScoreProcessor(RulesetContainer<CatchBaseHit> rulesetContainer)
|
||||
: base(rulesetContainer)
|
||||
{
|
||||
}
|
||||
@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Catch.Scoring
|
||||
Accuracy.Value = 1;
|
||||
}
|
||||
|
||||
protected override void OnNewJudgement(CatchJudgement judgement)
|
||||
protected override void OnNewJudgement(Judgement judgement)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
@ -2,17 +2,16 @@
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Rulesets.Catch.Objects;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using OpenTK;
|
||||
using osu.Game.Rulesets.Catch.Judgements;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Rulesets.Catch.Objects.Drawable;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.UI
|
||||
{
|
||||
public class CatchPlayfield : ScrollingPlayfield<CatchBaseHit, CatchJudgement>
|
||||
public class CatchPlayfield : ScrollingPlayfield
|
||||
{
|
||||
protected override Container<Drawable> Content => content;
|
||||
private readonly Container<Drawable> content;
|
||||
@ -44,7 +43,7 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
};
|
||||
}
|
||||
|
||||
public override void Add(DrawableHitObject<CatchBaseHit, CatchJudgement> h)
|
||||
public override void Add(DrawableHitObject h)
|
||||
{
|
||||
base.Add(h);
|
||||
|
||||
@ -53,13 +52,13 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
fruit.OnJudgement += Fruit_OnJudgement;
|
||||
}
|
||||
|
||||
private void Fruit_OnJudgement(DrawableHitObject<CatchBaseHit, CatchJudgement> obj)
|
||||
private void Fruit_OnJudgement(DrawableHitObject judgedObject, Judgement judgement)
|
||||
{
|
||||
if (obj.Judgement.Result == HitResult.Hit)
|
||||
if (judgement.IsHit)
|
||||
{
|
||||
Vector2 screenPosition = obj.ScreenSpaceDrawQuad.Centre;
|
||||
Remove(obj);
|
||||
catcherArea.Add(obj, screenPosition);
|
||||
Vector2 screenPosition = judgedObject.ScreenSpaceDrawQuad.Centre;
|
||||
Remove(judgedObject);
|
||||
catcherArea.Add(judgedObject, screenPosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,6 @@ using osu.Framework.Input;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Beatmaps;
|
||||
using osu.Game.Rulesets.Catch.Beatmaps;
|
||||
using osu.Game.Rulesets.Catch.Judgements;
|
||||
using osu.Game.Rulesets.Catch.Objects;
|
||||
using osu.Game.Rulesets.Catch.Objects.Drawable;
|
||||
using osu.Game.Rulesets.Catch.Scoring;
|
||||
@ -15,7 +14,7 @@ using osu.Game.Rulesets.UI;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.UI
|
||||
{
|
||||
public class CatchRulesetContainer : ScrollingRulesetContainer<CatchPlayfield, CatchBaseHit, CatchJudgement>
|
||||
public class CatchRulesetContainer : ScrollingRulesetContainer<CatchPlayfield, CatchBaseHit>
|
||||
{
|
||||
public CatchRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap, bool isForCurrentRuleset)
|
||||
: base(ruleset, beatmap, isForCurrentRuleset)
|
||||
@ -26,11 +25,11 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
|
||||
protected override BeatmapConverter<CatchBaseHit> CreateBeatmapConverter() => new CatchBeatmapConverter();
|
||||
|
||||
protected override Playfield<CatchBaseHit, CatchJudgement> CreatePlayfield() => new CatchPlayfield();
|
||||
protected override Playfield CreatePlayfield() => new CatchPlayfield();
|
||||
|
||||
public override PassThroughInputManager CreateInputManager() => new CatchInputManager(Ruleset.RulesetInfo);
|
||||
|
||||
protected override DrawableHitObject<CatchBaseHit, CatchJudgement> GetVisualRepresentation(CatchBaseHit h)
|
||||
protected override DrawableHitObject<CatchBaseHit> GetVisualRepresentation(CatchBaseHit h)
|
||||
{
|
||||
if (h is Fruit)
|
||||
return new DrawableFruit(h);
|
||||
|
@ -10,7 +10,6 @@ using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.Input.Bindings;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Game.Rulesets.Catch.Judgements;
|
||||
using osu.Game.Rulesets.Catch.Objects;
|
||||
using osu.Game.Rulesets.Catch.Objects.Drawable;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
@ -22,7 +21,7 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
{
|
||||
private Catcher catcher;
|
||||
|
||||
public void Add(DrawableHitObject<CatchBaseHit, CatchJudgement> fruit, Vector2 screenPosition) => catcher.AddToStack(fruit, screenPosition);
|
||||
public void Add(DrawableHitObject fruit, Vector2 screenPosition) => catcher.AddToStack(fruit, screenPosition);
|
||||
|
||||
public bool CheckIfWeCanCatch(CatchBaseHit obj) => Math.Abs(catcher.Position.X - obj.Position) < catcher.DrawSize.X / DrawSize.X / 2;
|
||||
|
||||
@ -152,7 +151,7 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
X = (float)MathHelper.Clamp(X + Math.Sign(currentDirection) * Clock.ElapsedFrameTime / 1800 * speed, 0, 1);
|
||||
}
|
||||
|
||||
public void AddToStack(DrawableHitObject<CatchBaseHit, CatchJudgement> fruit, Vector2 absolutePosition)
|
||||
public void AddToStack(DrawableHitObject fruit, Vector2 absolutePosition)
|
||||
{
|
||||
fruit.RelativePositionAxes = Axes.None;
|
||||
fruit.Position = new Vector2(ToLocalSpace(absolutePosition).X - DrawSize.X / 2, 0);
|
||||
@ -161,7 +160,6 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
fruit.Origin = Anchor.BottomCentre;
|
||||
fruit.Scale *= 0.7f;
|
||||
fruit.LifetimeEnd = double.MaxValue;
|
||||
fruit.Depth = (float)Time.Current;
|
||||
|
||||
float distance = fruit.DrawSize.X / 2 * fruit.Scale.X;
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Judgements
|
||||
{
|
||||
@ -145,18 +146,18 @@ namespace osu.Game.Rulesets.Mania.Judgements
|
||||
/// </summary>
|
||||
/// <param name="hitOffset">The time offset.</param>
|
||||
/// <returns>The hit result, or null if the time offset results in a miss.</returns>
|
||||
public ManiaHitResult? ResultFor(double hitOffset)
|
||||
public HitResult? ResultFor(double hitOffset)
|
||||
{
|
||||
if (hitOffset <= Perfect / 2)
|
||||
return ManiaHitResult.Perfect;
|
||||
return HitResult.Perfect;
|
||||
if (hitOffset <= Great / 2)
|
||||
return ManiaHitResult.Great;
|
||||
return HitResult.Great;
|
||||
if (hitOffset <= Good / 2)
|
||||
return ManiaHitResult.Good;
|
||||
return HitResult.Good;
|
||||
if (hitOffset <= Ok / 2)
|
||||
return ManiaHitResult.Ok;
|
||||
return HitResult.Ok;
|
||||
if (hitOffset <= Bad / 2)
|
||||
return ManiaHitResult.Bad;
|
||||
return HitResult.Meh;
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,8 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Judgements
|
||||
{
|
||||
public class HoldNoteTailJudgement : ManiaJudgement
|
||||
@ -10,27 +12,27 @@ namespace osu.Game.Rulesets.Mania.Judgements
|
||||
/// </summary>
|
||||
public bool HasBroken;
|
||||
|
||||
public override int NumericResultForScore(ManiaHitResult result)
|
||||
protected override int NumericResultFor(HitResult result)
|
||||
{
|
||||
switch (result)
|
||||
{
|
||||
default:
|
||||
return base.NumericResultForScore(result);
|
||||
case ManiaHitResult.Great:
|
||||
case ManiaHitResult.Perfect:
|
||||
return base.NumericResultForScore(HasBroken ? ManiaHitResult.Good : result);
|
||||
return base.NumericResultFor(result);
|
||||
case HitResult.Great:
|
||||
case HitResult.Perfect:
|
||||
return base.NumericResultFor(HasBroken ? HitResult.Good : result);
|
||||
}
|
||||
}
|
||||
|
||||
public override int NumericResultForAccuracy(ManiaHitResult result)
|
||||
protected override int NumericResultForAccuracy(HitResult result)
|
||||
{
|
||||
switch (result)
|
||||
{
|
||||
default:
|
||||
return base.NumericResultForAccuracy(result);
|
||||
case ManiaHitResult.Great:
|
||||
case ManiaHitResult.Perfect:
|
||||
return base.NumericResultForAccuracy(HasBroken ? ManiaHitResult.Good : result);
|
||||
case HitResult.Great:
|
||||
case HitResult.Perfect:
|
||||
return base.NumericResultForAccuracy(HasBroken ? HitResult.Good : result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,15 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Judgements
|
||||
{
|
||||
public class HoldNoteTickJudgement : ManiaJudgement
|
||||
{
|
||||
public override bool AffectsCombo => false;
|
||||
|
||||
public override int NumericResultForScore(ManiaHitResult result) => 20;
|
||||
public override int NumericResultForAccuracy(ManiaHitResult result) => 0; // Don't count ticks into accuracy
|
||||
protected override int NumericResultFor(HitResult result) => 20;
|
||||
protected override int NumericResultForAccuracy(HitResult result) => 0; // Don't count ticks into accuracy
|
||||
}
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Judgements
|
||||
{
|
||||
public enum ManiaHitResult
|
||||
{
|
||||
[Description("PERFECT")]
|
||||
Perfect,
|
||||
[Description("GREAT")]
|
||||
Great,
|
||||
[Description("GOOD")]
|
||||
Good,
|
||||
[Description("OK")]
|
||||
Ok,
|
||||
[Description("BAD")]
|
||||
Bad
|
||||
}
|
||||
}
|
@ -1,7 +1,6 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
|
||||
@ -9,73 +8,49 @@ namespace osu.Game.Rulesets.Mania.Judgements
|
||||
{
|
||||
public class ManiaJudgement : Judgement
|
||||
{
|
||||
/// <summary>
|
||||
/// The maximum possible hit result.
|
||||
/// </summary>
|
||||
public const ManiaHitResult MAX_HIT_RESULT = ManiaHitResult.Perfect;
|
||||
|
||||
/// <summary>
|
||||
/// The result value for the combo portion of the score.
|
||||
/// </summary>
|
||||
public int ResultValueForScore => Result == HitResult.Miss ? 0 : NumericResultForScore(ManiaResult);
|
||||
|
||||
/// <summary>
|
||||
/// The result value for the accuracy portion of the score.
|
||||
/// </summary>
|
||||
public int ResultValueForAccuracy => Result == HitResult.Miss ? 0 : NumericResultForAccuracy(ManiaResult);
|
||||
|
||||
/// <summary>
|
||||
/// The maximum result value for the combo portion of the score.
|
||||
/// </summary>
|
||||
public int MaxResultValueForScore => NumericResultForScore(MAX_HIT_RESULT);
|
||||
|
||||
/// <summary>
|
||||
/// The maximum result value for the accuracy portion of the score.
|
||||
/// </summary>
|
||||
public int MaxResultValueForAccuracy => NumericResultForAccuracy(MAX_HIT_RESULT);
|
||||
public int MaxNumericAccuracyResult => NumericResultForAccuracy(HitResult.Perfect);
|
||||
|
||||
public override string ResultString => ManiaResult.GetDescription();
|
||||
|
||||
public override string MaxResultString => MAX_HIT_RESULT.GetDescription();
|
||||
|
||||
/// <summary>
|
||||
/// The hit result.
|
||||
/// </summary>
|
||||
public ManiaHitResult ManiaResult;
|
||||
|
||||
public virtual int NumericResultForScore(ManiaHitResult result)
|
||||
protected override int NumericResultFor(HitResult result)
|
||||
{
|
||||
switch (result)
|
||||
{
|
||||
default:
|
||||
return 0;
|
||||
case ManiaHitResult.Bad:
|
||||
case HitResult.Meh:
|
||||
return 50;
|
||||
case ManiaHitResult.Ok:
|
||||
case HitResult.Ok:
|
||||
return 100;
|
||||
case ManiaHitResult.Good:
|
||||
case HitResult.Good:
|
||||
return 200;
|
||||
case ManiaHitResult.Great:
|
||||
case ManiaHitResult.Perfect:
|
||||
case HitResult.Great:
|
||||
case HitResult.Perfect:
|
||||
return 300;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual int NumericResultForAccuracy(ManiaHitResult result)
|
||||
public int NumericAccuracyResult => NumericResultForAccuracy(Result);
|
||||
|
||||
/// <summary>
|
||||
/// The result value for the accuracy portion of the score.
|
||||
/// </summary>
|
||||
protected virtual int NumericResultForAccuracy(HitResult result)
|
||||
{
|
||||
switch (result)
|
||||
{
|
||||
default:
|
||||
return 0;
|
||||
case ManiaHitResult.Bad:
|
||||
case HitResult.Meh:
|
||||
return 50;
|
||||
case ManiaHitResult.Ok:
|
||||
case HitResult.Ok:
|
||||
return 100;
|
||||
case ManiaHitResult.Good:
|
||||
case HitResult.Good:
|
||||
return 200;
|
||||
case ManiaHitResult.Great:
|
||||
case HitResult.Great:
|
||||
return 300;
|
||||
case ManiaHitResult.Perfect:
|
||||
case HitResult.Perfect:
|
||||
return 305;
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
using osu.Game.Rulesets.Mania.UI;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
@ -24,7 +25,7 @@ namespace osu.Game.Rulesets.Mania.Mods
|
||||
public void ApplyToRulesetContainer(ManiaRulesetContainer rulesetContainer, ref List<SpeedAdjustmentContainer>[] hitObjectTimingChanges, ref List<SpeedAdjustmentContainer> barlineTimingChanges)
|
||||
{
|
||||
// We have to generate one speed adjustment per hit object for gravity
|
||||
foreach (ManiaHitObject obj in rulesetContainer.Objects)
|
||||
foreach (ManiaHitObject obj in rulesetContainer.Objects.OfType<ManiaHitObject>())
|
||||
{
|
||||
MultiplierControlPoint controlPoint = rulesetContainer.CreateControlPointAt(obj.StartTime);
|
||||
// Beat length has too large of an effect for gravity, so we'll force it to a constant value for now
|
||||
|
@ -1,6 +1,8 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
|
||||
@ -154,7 +156,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
holdStartTime = null;
|
||||
|
||||
// If the key has been released too early, the user should not receive full score for the release
|
||||
if (!tail.Judged)
|
||||
if (!tail.AllJudged)
|
||||
hasBroken = true;
|
||||
|
||||
return true;
|
||||
@ -187,12 +189,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
if (!base.OnPressed(action))
|
||||
return false;
|
||||
|
||||
// We only want to trigger a holding state from the head if the head has received a judgement
|
||||
if (!Judged)
|
||||
return false;
|
||||
|
||||
// If the key has been released too early, the user should not receive full score for the release
|
||||
if (Judgement.Result == HitResult.Miss)
|
||||
if (Judgements.Any(j => j.Result == HitResult.Miss))
|
||||
holdNote.hasBroken = true;
|
||||
|
||||
// The head note also handles early hits before the body, but we want accurate early hits to count as the body being held
|
||||
@ -225,17 +223,32 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
GlowPiece.Alpha = 0;
|
||||
}
|
||||
|
||||
protected override ManiaJudgement CreateJudgement() => new HoldNoteTailJudgement();
|
||||
|
||||
protected override void CheckJudgement(bool userTriggered)
|
||||
protected override void CheckForJudgements(bool userTriggered, double timeOffset)
|
||||
{
|
||||
base.CheckJudgement(userTriggered);
|
||||
if (!userTriggered)
|
||||
{
|
||||
if (timeOffset > HitObject.HitWindows.Bad / 2)
|
||||
{
|
||||
AddJudgement(new HoldNoteTailJudgement
|
||||
{
|
||||
Result = HitResult.Miss,
|
||||
HasBroken = holdNote.hasBroken
|
||||
});
|
||||
}
|
||||
|
||||
var tailJudgement = Judgement as HoldNoteTailJudgement;
|
||||
if (tailJudgement == null)
|
||||
return;
|
||||
}
|
||||
|
||||
double offset = Math.Abs(timeOffset);
|
||||
|
||||
if (offset > HitObject.HitWindows.Miss / 2)
|
||||
return;
|
||||
|
||||
tailJudgement.HasBroken = holdNote.hasBroken;
|
||||
AddJudgement(new HoldNoteTailJudgement
|
||||
{
|
||||
Result = HitObject.HitWindows.ResultFor(offset) ?? HitResult.Miss,
|
||||
HasBroken = holdNote.hasBroken
|
||||
});
|
||||
}
|
||||
|
||||
public override bool OnPressed(ManiaAction action) => false; // Tail doesn't handle key down
|
||||
@ -246,9 +259,6 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
if (!holdNote.holdStartTime.HasValue)
|
||||
return false;
|
||||
|
||||
if (Judgement.Result != HitResult.None)
|
||||
return false;
|
||||
|
||||
if (action != Action)
|
||||
return false;
|
||||
|
||||
|
@ -78,9 +78,9 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
}
|
||||
}
|
||||
|
||||
protected override ManiaJudgement CreateJudgement() => new HoldNoteTickJudgement();
|
||||
protected ManiaJudgement CreateJudgement() => new HoldNoteTickJudgement();
|
||||
|
||||
protected override void CheckJudgement(bool userTriggered)
|
||||
protected override void CheckForJudgements(bool userTriggered, double timeOffset)
|
||||
{
|
||||
if (!userTriggered)
|
||||
return;
|
||||
@ -91,8 +91,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
if (HoldStartTime?.Invoke() > HitObject.StartTime)
|
||||
return;
|
||||
|
||||
Judgement.ManiaResult = ManiaHitResult.Perfect;
|
||||
Judgement.Result = HitResult.Hit;
|
||||
AddJudgement(new ManiaJudgement { Result = HitResult.Perfect });
|
||||
}
|
||||
|
||||
protected override void UpdateState(ArmedState state)
|
||||
@ -107,7 +106,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
if (Judgement.Result != HitResult.None)
|
||||
if (AllJudged)
|
||||
return;
|
||||
|
||||
if (HoldStartTime?.Invoke() == null)
|
||||
|
@ -3,12 +3,11 @@
|
||||
|
||||
using osu.Framework.Graphics;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Game.Rulesets.Mania.Judgements;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
{
|
||||
public abstract class DrawableManiaHitObject<TObject> : DrawableScrollingHitObject<ManiaHitObject, ManiaJudgement>
|
||||
public abstract class DrawableManiaHitObject<TObject> : DrawableScrollingHitObject<ManiaHitObject>
|
||||
where TObject : ManiaHitObject
|
||||
{
|
||||
/// <summary>
|
||||
@ -38,7 +37,5 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
base.AccentColour = value;
|
||||
}
|
||||
}
|
||||
|
||||
protected override ManiaJudgement CreateJudgement() => new ManiaJudgement();
|
||||
}
|
||||
}
|
||||
|
@ -58,29 +58,21 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
}
|
||||
}
|
||||
|
||||
protected override void CheckJudgement(bool userTriggered)
|
||||
protected override void CheckForJudgements(bool userTriggered, double timeOffset)
|
||||
{
|
||||
if (!userTriggered)
|
||||
{
|
||||
if (Judgement.TimeOffset > HitObject.HitWindows.Bad / 2)
|
||||
Judgement.Result = HitResult.Miss;
|
||||
if (timeOffset > HitObject.HitWindows.Bad / 2)
|
||||
AddJudgement(new ManiaJudgement { Result = HitResult.Miss });
|
||||
return;
|
||||
}
|
||||
|
||||
double offset = Math.Abs(Judgement.TimeOffset);
|
||||
double offset = Math.Abs(timeOffset);
|
||||
|
||||
if (offset > HitObject.HitWindows.Miss / 2)
|
||||
return;
|
||||
|
||||
ManiaHitResult? tmpResult = HitObject.HitWindows.ResultFor(offset);
|
||||
|
||||
if (tmpResult.HasValue)
|
||||
{
|
||||
Judgement.Result = HitResult.Hit;
|
||||
Judgement.ManiaResult = tmpResult.Value;
|
||||
}
|
||||
else
|
||||
Judgement.Result = HitResult.Miss;
|
||||
AddJudgement(new ManiaJudgement { Result = HitObject.HitWindows.ResultFor(offset) ?? HitResult.Miss });
|
||||
}
|
||||
|
||||
protected override void UpdateState(ArmedState state)
|
||||
|
@ -4,6 +4,7 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Mania.Judgements;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
@ -12,7 +13,7 @@ using osu.Game.Rulesets.UI;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Scoring
|
||||
{
|
||||
internal class ManiaScoreProcessor : ScoreProcessor<ManiaHitObject, ManiaJudgement>
|
||||
internal class ManiaScoreProcessor : ScoreProcessor<ManiaHitObject>
|
||||
{
|
||||
/// <summary>
|
||||
/// The maximum score achievable.
|
||||
@ -155,7 +156,7 @@ namespace osu.Game.Rulesets.Mania.Scoring
|
||||
{
|
||||
}
|
||||
|
||||
public ManiaScoreProcessor(RulesetContainer<ManiaHitObject, ManiaJudgement> rulesetContainer)
|
||||
public ManiaScoreProcessor(RulesetContainer<ManiaHitObject> rulesetContainer)
|
||||
: base(rulesetContainer)
|
||||
{
|
||||
}
|
||||
@ -174,37 +175,19 @@ namespace osu.Game.Rulesets.Mania.Scoring
|
||||
|
||||
if (obj is Note)
|
||||
{
|
||||
AddJudgement(new ManiaJudgement
|
||||
{
|
||||
Result = HitResult.Hit,
|
||||
ManiaResult = ManiaHitResult.Perfect
|
||||
});
|
||||
AddJudgement(new ManiaJudgement { Result = HitResult.Perfect });
|
||||
}
|
||||
else if (holdNote != null)
|
||||
{
|
||||
// Head
|
||||
AddJudgement(new ManiaJudgement
|
||||
{
|
||||
Result = HitResult.Hit,
|
||||
ManiaResult = ManiaJudgement.MAX_HIT_RESULT
|
||||
});
|
||||
AddJudgement(new ManiaJudgement { Result = HitResult.Perfect });
|
||||
|
||||
// Ticks
|
||||
int tickCount = holdNote.Ticks.Count();
|
||||
for (int i = 0; i < tickCount; i++)
|
||||
{
|
||||
AddJudgement(new HoldNoteTickJudgement
|
||||
{
|
||||
Result = HitResult.Hit,
|
||||
ManiaResult = ManiaJudgement.MAX_HIT_RESULT,
|
||||
});
|
||||
}
|
||||
AddJudgement(new HoldNoteTickJudgement { Result = HitResult.Perfect });
|
||||
|
||||
AddJudgement(new HoldNoteTailJudgement
|
||||
{
|
||||
Result = HitResult.Hit,
|
||||
ManiaResult = ManiaJudgement.MAX_HIT_RESULT
|
||||
});
|
||||
AddJudgement(new HoldNoteTailJudgement { Result = HitResult.Perfect });
|
||||
}
|
||||
}
|
||||
|
||||
@ -221,50 +204,50 @@ namespace osu.Game.Rulesets.Mania.Scoring
|
||||
maxComboPortion = comboPortion;
|
||||
}
|
||||
|
||||
protected override void OnNewJudgement(ManiaJudgement judgement)
|
||||
protected override void OnNewJudgement(Judgement judgement)
|
||||
{
|
||||
bool isTick = judgement is HoldNoteTickJudgement;
|
||||
|
||||
if (!isTick)
|
||||
if (isTick)
|
||||
{
|
||||
if (judgement.IsHit)
|
||||
{
|
||||
Health.Value += hpMultiplier * hp_increase_tick;
|
||||
bonusScore += judgement.NumericResult;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
totalHits++;
|
||||
|
||||
switch (judgement.Result)
|
||||
{
|
||||
case HitResult.Miss:
|
||||
Health.Value += hpMissMultiplier * hp_increase_miss;
|
||||
break;
|
||||
case HitResult.Hit:
|
||||
if (isTick)
|
||||
{
|
||||
Health.Value += hpMultiplier * hp_increase_tick;
|
||||
bonusScore += judgement.ResultValueForScore;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (judgement.ManiaResult)
|
||||
{
|
||||
case ManiaHitResult.Bad:
|
||||
Health.Value += hpMultiplier * hp_increase_bad;
|
||||
break;
|
||||
case ManiaHitResult.Ok:
|
||||
Health.Value += hpMultiplier * hp_increase_ok;
|
||||
break;
|
||||
case ManiaHitResult.Good:
|
||||
Health.Value += hpMultiplier * hp_increase_good;
|
||||
break;
|
||||
case ManiaHitResult.Great:
|
||||
Health.Value += hpMultiplier * hp_increase_great;
|
||||
break;
|
||||
case ManiaHitResult.Perfect:
|
||||
Health.Value += hpMultiplier * hp_increase_perfect;
|
||||
break;
|
||||
}
|
||||
switch (judgement.Result)
|
||||
{
|
||||
case HitResult.Miss:
|
||||
Health.Value += hpMissMultiplier * hp_increase_miss;
|
||||
break;
|
||||
case HitResult.Meh:
|
||||
Health.Value += hpMultiplier * hp_increase_bad;
|
||||
break;
|
||||
case HitResult.Ok:
|
||||
Health.Value += hpMultiplier * hp_increase_ok;
|
||||
break;
|
||||
case HitResult.Good:
|
||||
Health.Value += hpMultiplier * hp_increase_good;
|
||||
break;
|
||||
case HitResult.Great:
|
||||
Health.Value += hpMultiplier * hp_increase_great;
|
||||
break;
|
||||
case HitResult.Perfect:
|
||||
Health.Value += hpMultiplier * hp_increase_perfect;
|
||||
break;
|
||||
}
|
||||
|
||||
// A factor that is applied to make higher combos more relevant
|
||||
double comboRelevance = Math.Min(Math.Max(0.5, Math.Log(Combo.Value, combo_base)), Math.Log(combo_relevance_cap, combo_base));
|
||||
comboPortion += judgement.ResultValueForScore * comboRelevance;
|
||||
}
|
||||
break;
|
||||
if (judgement.IsHit)
|
||||
{
|
||||
// A factor that is applied to make higher combos more relevant
|
||||
double comboRelevance = Math.Min(Math.Max(0.5, Math.Log(Combo.Value, combo_base)), Math.Log(combo_relevance_cap, combo_base));
|
||||
comboPortion += judgement.NumericResult * comboRelevance;
|
||||
}
|
||||
}
|
||||
|
||||
int scoreForAccuracy = 0;
|
||||
@ -272,8 +255,10 @@ namespace osu.Game.Rulesets.Mania.Scoring
|
||||
|
||||
foreach (var j in Judgements)
|
||||
{
|
||||
scoreForAccuracy += j.ResultValueForAccuracy;
|
||||
maxScoreForAccuracy += j.MaxResultValueForAccuracy;
|
||||
var maniaJudgement = (ManiaJudgement)j;
|
||||
|
||||
scoreForAccuracy += maniaJudgement.NumericAccuracyResult;
|
||||
maxScoreForAccuracy += maniaJudgement.MaxNumericAccuracyResult;
|
||||
}
|
||||
|
||||
Accuracy.Value = (double)scoreForAccuracy / maxScoreForAccuracy;
|
||||
|
@ -13,12 +13,11 @@ using osu.Game.Rulesets.Objects.Drawables;
|
||||
using System;
|
||||
using osu.Framework.Input.Bindings;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
using osu.Game.Rulesets.Mania.Judgements;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.UI
|
||||
{
|
||||
public class Column : ScrollingPlayfield<ManiaHitObject, ManiaJudgement>, IHasAccentColour
|
||||
public class Column : ScrollingPlayfield, IHasAccentColour
|
||||
{
|
||||
private const float key_icon_size = 10;
|
||||
private const float key_icon_corner_radius = 3;
|
||||
@ -42,6 +41,9 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
protected override Container<Drawable> Content => content;
|
||||
private readonly Container<Drawable> content;
|
||||
|
||||
private const float opacity_released = 0.1f;
|
||||
private const float opacity_pressed = 0.25f;
|
||||
|
||||
public Column()
|
||||
: base(Axes.Y)
|
||||
{
|
||||
@ -51,9 +53,9 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
{
|
||||
background = new Box
|
||||
{
|
||||
Name = "Foreground",
|
||||
Name = "Background",
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Alpha = 0.2f
|
||||
Alpha = opacity_released
|
||||
},
|
||||
new Container
|
||||
{
|
||||
@ -199,15 +201,15 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
/// Adds a DrawableHitObject to this Playfield.
|
||||
/// </summary>
|
||||
/// <param name="hitObject">The DrawableHitObject to add.</param>
|
||||
public override void Add(DrawableHitObject<ManiaHitObject, ManiaJudgement> hitObject)
|
||||
public override void Add(DrawableHitObject hitObject)
|
||||
{
|
||||
hitObject.AccentColour = AccentColour;
|
||||
HitObjects.Add(hitObject);
|
||||
}
|
||||
|
||||
public override void OnJudgement(DrawableHitObject<ManiaHitObject, ManiaJudgement> judgedObject)
|
||||
public override void OnJudgement(DrawableHitObject judgedObject, Judgement judgement)
|
||||
{
|
||||
if (judgedObject.Judgement.Result != HitResult.Hit)
|
||||
if (!judgement.IsHit)
|
||||
return;
|
||||
|
||||
explosionContainer.Add(new HitExplosion(judgedObject));
|
||||
@ -217,7 +219,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
{
|
||||
if (action == Action)
|
||||
{
|
||||
background.FadeTo(0.6f, 50, Easing.OutQuint);
|
||||
background.FadeTo(opacity_pressed, 50, Easing.OutQuint);
|
||||
keyIcon.ScaleTo(1.4f, 50, Easing.OutQuint);
|
||||
}
|
||||
|
||||
@ -228,7 +230,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
{
|
||||
if (action == Action)
|
||||
{
|
||||
background.FadeTo(0.2f, 800, Easing.OutQuart);
|
||||
background.FadeTo(opacity_released, 800, Easing.OutQuart);
|
||||
keyIcon.ScaleTo(1f, 400, Easing.OutQuart);
|
||||
}
|
||||
|
||||
|
@ -3,14 +3,12 @@
|
||||
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Mania.Judgements;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.UI
|
||||
{
|
||||
internal class DrawableManiaJudgement : DrawableJudgement<ManiaJudgement>
|
||||
internal class DrawableManiaJudgement : DrawableJudgement
|
||||
{
|
||||
public DrawableManiaJudgement(ManiaJudgement judgement)
|
||||
public DrawableManiaJudgement(Judgement judgement)
|
||||
: base(judgement)
|
||||
{
|
||||
JudgementText.TextSize = 25;
|
||||
@ -22,14 +20,12 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
|
||||
this.FadeInFromZero(50, Easing.OutQuint);
|
||||
|
||||
switch (Judgement.Result)
|
||||
if (Judgement.IsHit)
|
||||
{
|
||||
case HitResult.Hit:
|
||||
this.ScaleTo(0.8f);
|
||||
this.ScaleTo(1, 250, Easing.OutElastic);
|
||||
this.ScaleTo(0.8f);
|
||||
this.ScaleTo(1, 250, Easing.OutElastic);
|
||||
|
||||
this.Delay(50).FadeOut(200).ScaleTo(0.75f, 250);
|
||||
break;
|
||||
this.Delay(50).FadeOut(200).ScaleTo(0.75f, 250);
|
||||
}
|
||||
|
||||
Expire();
|
||||
|
@ -6,8 +6,6 @@ using OpenTK.Graphics;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Rulesets.Mania.Judgements;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
|
||||
@ -17,7 +15,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
{
|
||||
private readonly Box inner;
|
||||
|
||||
public HitExplosion(DrawableHitObject<ManiaHitObject, ManiaJudgement> judgedObject)
|
||||
public HitExplosion(DrawableHitObject judgedObject)
|
||||
{
|
||||
bool isTick = judgedObject is DrawableHoldNoteTick;
|
||||
|
||||
|
@ -6,7 +6,6 @@ using osu.Game.Rulesets.Mania.Objects;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Game.Rulesets.Mania.Judgements;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using System;
|
||||
using osu.Game.Graphics;
|
||||
@ -17,10 +16,11 @@ using osu.Framework.Configuration;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.UI
|
||||
{
|
||||
public class ManiaPlayfield : ScrollingPlayfield<ManiaHitObject, ManiaJudgement>
|
||||
public class ManiaPlayfield : ScrollingPlayfield
|
||||
{
|
||||
public const float HIT_TARGET_POSITION = 50;
|
||||
|
||||
@ -192,12 +192,13 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnJudgement(DrawableHitObject<ManiaHitObject, ManiaJudgement> judgedObject)
|
||||
public override void OnJudgement(DrawableHitObject judgedObject, Judgement judgement)
|
||||
{
|
||||
columns[judgedObject.HitObject.Column].OnJudgement(judgedObject);
|
||||
var maniaObject = (ManiaHitObject)judgedObject.HitObject;
|
||||
columns[maniaObject.Column].OnJudgement(judgedObject, judgement);
|
||||
|
||||
judgements.Clear();
|
||||
judgements.Add(new DrawableManiaJudgement(judgedObject.Judgement)
|
||||
judgements.Add(new DrawableManiaJudgement(judgement)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
@ -223,7 +224,8 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
}
|
||||
}
|
||||
|
||||
public override void Add(DrawableHitObject<ManiaHitObject, ManiaJudgement> h) => Columns.ElementAt(h.HitObject.Column).Add(h);
|
||||
public override void Add(DrawableHitObject h) => Columns.ElementAt(((ManiaHitObject)h.HitObject).Column).Add(h);
|
||||
|
||||
public void Add(DrawableBarLine barline) => HitObjects.Add(barline);
|
||||
|
||||
protected override void Update()
|
||||
|
@ -15,7 +15,6 @@ using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Rulesets.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.Judgements;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Mania.Replays;
|
||||
@ -30,7 +29,7 @@ using osu.Game.Rulesets.UI;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.UI
|
||||
{
|
||||
public class ManiaRulesetContainer : ScrollingRulesetContainer<ManiaPlayfield, ManiaHitObject, ManiaJudgement>
|
||||
public class ManiaRulesetContainer : ScrollingRulesetContainer<ManiaPlayfield, ManiaHitObject>
|
||||
{
|
||||
/// <summary>
|
||||
/// The number of columns which the <see cref="ManiaPlayfield"/> should display, and which
|
||||
@ -77,7 +76,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
BarLines.ForEach(Playfield.Add);
|
||||
}
|
||||
|
||||
protected sealed override Playfield<ManiaHitObject, ManiaJudgement> CreatePlayfield() => new ManiaPlayfield(AvailableColumns)
|
||||
protected sealed override Playfield CreatePlayfield() => new ManiaPlayfield(AvailableColumns)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
@ -107,7 +106,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
return new ManiaBeatmapConverter(IsForCurrentRuleset, AvailableColumns);
|
||||
}
|
||||
|
||||
protected override DrawableHitObject<ManiaHitObject, ManiaJudgement> GetVisualRepresentation(ManiaHitObject h)
|
||||
protected override DrawableHitObject<ManiaHitObject> GetVisualRepresentation(ManiaHitObject h)
|
||||
{
|
||||
ManiaAction action = Playfield.Columns.ElementAt(h.Column).Action;
|
||||
|
||||
|
@ -60,7 +60,6 @@
|
||||
<Compile Include="Judgements\HitWindows.cs" />
|
||||
<Compile Include="Judgements\HoldNoteTailJudgement.cs" />
|
||||
<Compile Include="Judgements\HoldNoteTickJudgement.cs" />
|
||||
<Compile Include="Judgements\ManiaHitResult.cs" />
|
||||
<Compile Include="Judgements\ManiaJudgement.cs" />
|
||||
<Compile Include="ManiaDifficultyCalculator.cs" />
|
||||
<Compile Include="Mods\IGenerateSpeedAdjustments.cs" />
|
||||
|
@ -4,10 +4,14 @@
|
||||
using OpenTK;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Judgements
|
||||
{
|
||||
public class SliderTickJudgement : OsuJudgement
|
||||
{
|
||||
}
|
||||
|
||||
public class OsuJudgement : Judgement
|
||||
{
|
||||
/// <summary>
|
||||
@ -15,38 +19,18 @@ namespace osu.Game.Rulesets.Osu.Judgements
|
||||
/// </summary>
|
||||
public Vector2 PositionOffset;
|
||||
|
||||
/// <summary>
|
||||
/// The score the user achieved.
|
||||
/// </summary>
|
||||
public OsuScoreResult Score;
|
||||
|
||||
/// <summary>
|
||||
/// The score which would be achievable on a perfect hit.
|
||||
/// </summary>
|
||||
public OsuScoreResult MaxScore = OsuScoreResult.Hit300;
|
||||
|
||||
public override string ResultString => Score.GetDescription();
|
||||
|
||||
public override string MaxResultString => MaxScore.GetDescription();
|
||||
|
||||
public int ScoreValue => scoreToInt(Score);
|
||||
|
||||
public int MaxScoreValue => scoreToInt(MaxScore);
|
||||
|
||||
private int scoreToInt(OsuScoreResult result)
|
||||
protected override int NumericResultFor(HitResult result)
|
||||
{
|
||||
switch (result)
|
||||
{
|
||||
default:
|
||||
return 0;
|
||||
case OsuScoreResult.Hit50:
|
||||
case HitResult.Meh:
|
||||
return 50;
|
||||
case OsuScoreResult.Hit100:
|
||||
case HitResult.Good:
|
||||
return 100;
|
||||
case OsuScoreResult.Hit300:
|
||||
case HitResult.Great:
|
||||
return 300;
|
||||
case OsuScoreResult.SliderTick:
|
||||
return 10;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@ using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
|
||||
using OpenTK;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Rulesets.Osu.Judgements;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
{
|
||||
@ -38,9 +39,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
Colour = AccentColour,
|
||||
Hit = () =>
|
||||
{
|
||||
if (Judgement.Result != HitResult.None) return false;
|
||||
if (AllJudged)
|
||||
return false;
|
||||
|
||||
Judgement.PositionOffset = Vector2.Zero; //todo: set to correct value
|
||||
UpdateJudgement(true);
|
||||
return true;
|
||||
},
|
||||
@ -65,24 +66,20 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
Size = circle.DrawSize;
|
||||
}
|
||||
|
||||
protected override void CheckJudgement(bool userTriggered)
|
||||
protected override void CheckForJudgements(bool userTriggered, double timeOffset)
|
||||
{
|
||||
if (!userTriggered)
|
||||
{
|
||||
if (Judgement.TimeOffset > HitObject.HitWindowFor(OsuScoreResult.Hit50))
|
||||
Judgement.Result = HitResult.Miss;
|
||||
if (timeOffset > HitObject.HitWindowFor(HitResult.Meh))
|
||||
AddJudgement(new OsuJudgement { Result = HitResult.Miss });
|
||||
return;
|
||||
}
|
||||
|
||||
double hitOffset = Math.Abs(Judgement.TimeOffset);
|
||||
|
||||
if (hitOffset < HitObject.HitWindowFor(OsuScoreResult.Hit50))
|
||||
AddJudgement(new OsuJudgement
|
||||
{
|
||||
Judgement.Result = HitResult.Hit;
|
||||
Judgement.Score = HitObject.ScoreResultForOffset(hitOffset);
|
||||
}
|
||||
else
|
||||
Judgement.Result = HitResult.Miss;
|
||||
Result = HitObject.ScoreResultForOffset(Math.Abs(timeOffset)),
|
||||
PositionOffset = Vector2.Zero //todo: set to correct value
|
||||
});
|
||||
}
|
||||
|
||||
protected override void UpdateInitialState()
|
||||
|
@ -3,12 +3,12 @@
|
||||
|
||||
using System.ComponentModel;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Osu.Judgements;
|
||||
using osu.Framework.Graphics;
|
||||
using System.Linq;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
{
|
||||
public class DrawableOsuHitObject : DrawableHitObject<OsuHitObject, OsuJudgement>
|
||||
public class DrawableOsuHitObject : DrawableHitObject<OsuHitObject>
|
||||
{
|
||||
public const float TIME_PREEMPT = 600;
|
||||
public const float TIME_FADEIN = 400;
|
||||
@ -21,8 +21,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
Alpha = 0;
|
||||
}
|
||||
|
||||
protected override OsuJudgement CreateJudgement() => new OsuJudgement { MaxScore = OsuScoreResult.Hit300 };
|
||||
|
||||
protected sealed override void UpdateState(ArmedState state)
|
||||
{
|
||||
FinishTransforms();
|
||||
@ -33,7 +31,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
|
||||
UpdatePreemptState();
|
||||
|
||||
using (BeginDelayedSequence(TIME_PREEMPT + Judgement.TimeOffset, true))
|
||||
using (BeginDelayedSequence(TIME_PREEMPT + (Judgements.FirstOrDefault()?.TimeOffset ?? 0), true))
|
||||
UpdateCurrentState(state);
|
||||
}
|
||||
}
|
||||
@ -65,18 +63,4 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
[Description(@"Amazing")]
|
||||
Perfect
|
||||
}
|
||||
|
||||
public enum OsuScoreResult
|
||||
{
|
||||
[Description(@"Miss")]
|
||||
Miss,
|
||||
[Description(@"50")]
|
||||
Hit50,
|
||||
[Description(@"100")]
|
||||
Hit100,
|
||||
[Description(@"300")]
|
||||
Hit300,
|
||||
[Description(@"10")]
|
||||
SliderTick
|
||||
}
|
||||
}
|
||||
|
@ -9,9 +9,10 @@ using osu.Game.Rulesets.Judgements;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
{
|
||||
public class DrawableOsuJudgement : DrawableJudgement<OsuJudgement>
|
||||
public class DrawableOsuJudgement : DrawableJudgement
|
||||
{
|
||||
public DrawableOsuJudgement(OsuJudgement judgement) : base(judgement)
|
||||
public DrawableOsuJudgement(OsuJudgement judgement)
|
||||
: base(judgement)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,7 @@ using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Rulesets.Osu.Judgements;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
{
|
||||
@ -114,33 +115,31 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
bouncer2.Position = slider.Curve.PositionAt(body.SnakedEnd ?? 0);
|
||||
|
||||
//todo: we probably want to reconsider this before adding scoring, but it looks and feels nice.
|
||||
if (initialCircle.Judgement?.Result != HitResult.Hit)
|
||||
if (!initialCircle.Judgements.Any(j => j.IsHit))
|
||||
initialCircle.Position = slider.Curve.PositionAt(progress);
|
||||
|
||||
foreach (var c in components) c.UpdateProgress(progress, repeat);
|
||||
foreach (var t in ticks.Children) t.Tracking = ball.Tracking;
|
||||
}
|
||||
|
||||
protected override void CheckJudgement(bool userTriggered)
|
||||
protected override void CheckForJudgements(bool userTriggered, double timeOffset)
|
||||
{
|
||||
if (!userTriggered && Time.Current >= slider.EndTime)
|
||||
{
|
||||
var ticksCount = ticks.Children.Count + 1;
|
||||
var ticksHit = ticks.Children.Count(t => t.Judgement.Result == HitResult.Hit);
|
||||
if (initialCircle.Judgement.Result == HitResult.Hit)
|
||||
var ticksHit = ticks.Children.Count(t => t.Judgements.Any(j => j.IsHit));
|
||||
if (initialCircle.Judgements.Any(j => j.IsHit))
|
||||
ticksHit++;
|
||||
|
||||
var hitFraction = (double)ticksHit / ticksCount;
|
||||
if (hitFraction == 1 && initialCircle.Judgement.Score == OsuScoreResult.Hit300)
|
||||
Judgement.Score = OsuScoreResult.Hit300;
|
||||
else if (hitFraction >= 0.5 && initialCircle.Judgement.Score >= OsuScoreResult.Hit100)
|
||||
Judgement.Score = OsuScoreResult.Hit100;
|
||||
if (hitFraction == 1 && initialCircle.Judgements.Any(j => j.Result == HitResult.Great))
|
||||
AddJudgement(new OsuJudgement { Result = HitResult.Great });
|
||||
else if (hitFraction >= 0.5 && initialCircle.Judgements.Any(j => j.Result >= HitResult.Good))
|
||||
AddJudgement(new OsuJudgement { Result = HitResult.Good });
|
||||
else if (hitFraction > 0)
|
||||
Judgement.Score = OsuScoreResult.Hit50;
|
||||
AddJudgement(new OsuJudgement { Result = HitResult.Meh });
|
||||
else
|
||||
Judgement.Score = OsuScoreResult.Miss;
|
||||
|
||||
Judgement.Result = Judgement.Score != OsuScoreResult.Miss ? HitResult.Hit : HitResult.Miss;
|
||||
AddJudgement(new OsuJudgement { Result = HitResult.Miss });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,10 +4,10 @@
|
||||
using System;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Osu.Judgements;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Rulesets.Osu.Judgements;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
{
|
||||
@ -22,8 +22,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
|
||||
public override bool RemoveWhenNotAlive => false;
|
||||
|
||||
protected override OsuJudgement CreateJudgement() => new OsuJudgement { MaxScore = OsuScoreResult.SliderTick };
|
||||
|
||||
public DrawableSliderTick(SliderTick sliderTick) : base(sliderTick)
|
||||
{
|
||||
this.sliderTick = sliderTick;
|
||||
@ -49,13 +47,10 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
};
|
||||
}
|
||||
|
||||
protected override void CheckJudgement(bool userTriggered)
|
||||
protected override void CheckForJudgements(bool userTriggered, double timeOffset)
|
||||
{
|
||||
if (Judgement.TimeOffset >= 0)
|
||||
{
|
||||
Judgement.Result = Tracking ? HitResult.Hit : HitResult.Miss;
|
||||
Judgement.Score = Tracking ? OsuScoreResult.SliderTick : OsuScoreResult.Miss;
|
||||
}
|
||||
if (timeOffset >= 0)
|
||||
AddJudgement(new SliderTickJudgement { Result = Tracking ? HitResult.Perfect : HitResult.Miss });
|
||||
}
|
||||
|
||||
protected override void UpdatePreemptState()
|
||||
|
@ -11,6 +11,7 @@ using OpenTK.Graphics;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Game.Rulesets.Osu.Judgements;
|
||||
using osu.Game.Screens.Ranking;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
@ -107,7 +108,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
|
||||
public float Progress => MathHelper.Clamp(disc.RotationAbsolute / 360 / spinner.SpinsRequired, 0, 1);
|
||||
|
||||
protected override void CheckJudgement(bool userTriggered)
|
||||
protected override void CheckForJudgements(bool userTriggered, double timeOffset)
|
||||
{
|
||||
if (Time.Current < HitObject.StartTime) return;
|
||||
|
||||
@ -129,26 +130,13 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
if (!userTriggered && Time.Current >= spinner.EndTime)
|
||||
{
|
||||
if (Progress >= 1)
|
||||
{
|
||||
Judgement.Score = OsuScoreResult.Hit300;
|
||||
Judgement.Result = HitResult.Hit;
|
||||
}
|
||||
AddJudgement(new OsuJudgement { Result = HitResult.Great });
|
||||
else if (Progress > .9)
|
||||
{
|
||||
Judgement.Score = OsuScoreResult.Hit100;
|
||||
Judgement.Result = HitResult.Hit;
|
||||
}
|
||||
AddJudgement(new OsuJudgement { Result = HitResult.Good });
|
||||
else if (Progress > .75)
|
||||
{
|
||||
Judgement.Score = OsuScoreResult.Hit50;
|
||||
Judgement.Result = HitResult.Hit;
|
||||
}
|
||||
else
|
||||
{
|
||||
Judgement.Score = OsuScoreResult.Miss;
|
||||
if (Time.Current >= spinner.EndTime)
|
||||
Judgement.Result = HitResult.Miss;
|
||||
}
|
||||
AddJudgement(new OsuJudgement { Result = HitResult.Meh });
|
||||
else if (Time.Current >= spinner.EndTime)
|
||||
AddJudgement(new OsuJudgement { Result = HitResult.Miss });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,10 +4,10 @@
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using OpenTK;
|
||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Objects
|
||||
{
|
||||
@ -42,30 +42,30 @@ namespace osu.Game.Rulesets.Osu.Objects
|
||||
public virtual bool NewCombo { get; set; }
|
||||
public int ComboIndex { get; set; }
|
||||
|
||||
public double HitWindowFor(OsuScoreResult result)
|
||||
public double HitWindowFor(HitResult result)
|
||||
{
|
||||
switch (result)
|
||||
{
|
||||
default:
|
||||
return 300;
|
||||
case OsuScoreResult.Hit50:
|
||||
case HitResult.Meh:
|
||||
return 150;
|
||||
case OsuScoreResult.Hit100:
|
||||
case HitResult.Good:
|
||||
return 80;
|
||||
case OsuScoreResult.Hit300:
|
||||
case HitResult.Great:
|
||||
return 30;
|
||||
}
|
||||
}
|
||||
|
||||
public OsuScoreResult ScoreResultForOffset(double offset)
|
||||
public HitResult ScoreResultForOffset(double offset)
|
||||
{
|
||||
if (offset < HitWindowFor(OsuScoreResult.Hit300))
|
||||
return OsuScoreResult.Hit300;
|
||||
if (offset < HitWindowFor(OsuScoreResult.Hit100))
|
||||
return OsuScoreResult.Hit100;
|
||||
if (offset < HitWindowFor(OsuScoreResult.Hit50))
|
||||
return OsuScoreResult.Hit50;
|
||||
return OsuScoreResult.Miss;
|
||||
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;
|
||||
}
|
||||
|
||||
public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
|
||||
|
@ -9,6 +9,7 @@ using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Rulesets.Replays;
|
||||
|
||||
@ -89,20 +90,20 @@ namespace osu.Game.Rulesets.Osu.Replays
|
||||
double endTime = (prev as IHasEndTime)?.EndTime ?? prev.StartTime;
|
||||
|
||||
// Make the cursor stay at a hitObject as long as possible (mainly for autopilot).
|
||||
if (h.StartTime - h.HitWindowFor(OsuScoreResult.Miss) > endTime + h.HitWindowFor(OsuScoreResult.Hit50) + 50)
|
||||
if (h.StartTime - h.HitWindowFor(HitResult.Miss) > endTime + h.HitWindowFor(HitResult.Meh) + 50)
|
||||
{
|
||||
if (!(prev is Spinner) && h.StartTime - endTime < 1000) AddFrameToReplay(new ReplayFrame(endTime + h.HitWindowFor(OsuScoreResult.Hit50), prev.StackedEndPosition.X, prev.StackedEndPosition.Y, ReplayButtonState.None));
|
||||
if (!(h is Spinner)) AddFrameToReplay(new ReplayFrame(h.StartTime - h.HitWindowFor(OsuScoreResult.Miss), h.StackedPosition.X, h.StackedPosition.Y, ReplayButtonState.None));
|
||||
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 (!(h is Spinner)) AddFrameToReplay(new ReplayFrame(h.StartTime - h.HitWindowFor(HitResult.Miss), h.StackedPosition.X, h.StackedPosition.Y, ReplayButtonState.None));
|
||||
}
|
||||
else if (h.StartTime - h.HitWindowFor(OsuScoreResult.Hit50) > endTime + h.HitWindowFor(OsuScoreResult.Hit50) + 50)
|
||||
else if (h.StartTime - h.HitWindowFor(HitResult.Meh) > endTime + h.HitWindowFor(HitResult.Meh) + 50)
|
||||
{
|
||||
if (!(prev is Spinner) && h.StartTime - endTime < 1000) AddFrameToReplay(new ReplayFrame(endTime + h.HitWindowFor(OsuScoreResult.Hit50), prev.StackedEndPosition.X, prev.StackedEndPosition.Y, ReplayButtonState.None));
|
||||
if (!(h is Spinner)) AddFrameToReplay(new ReplayFrame(h.StartTime - h.HitWindowFor(OsuScoreResult.Hit50), h.StackedPosition.X, h.StackedPosition.Y, ReplayButtonState.None));
|
||||
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 (!(h is Spinner)) AddFrameToReplay(new ReplayFrame(h.StartTime - h.HitWindowFor(HitResult.Meh), h.StackedPosition.X, h.StackedPosition.Y, ReplayButtonState.None));
|
||||
}
|
||||
else if (h.StartTime - h.HitWindowFor(OsuScoreResult.Hit100) > endTime + h.HitWindowFor(OsuScoreResult.Hit100) + 50)
|
||||
else if (h.StartTime - h.HitWindowFor(HitResult.Good) > endTime + h.HitWindowFor(HitResult.Good) + 50)
|
||||
{
|
||||
if (!(prev is Spinner) && h.StartTime - endTime < 1000) AddFrameToReplay(new ReplayFrame(endTime + h.HitWindowFor(OsuScoreResult.Hit100), prev.StackedEndPosition.X, prev.StackedEndPosition.Y, ReplayButtonState.None));
|
||||
if (!(h is Spinner)) AddFrameToReplay(new ReplayFrame(h.StartTime - h.HitWindowFor(OsuScoreResult.Hit100), h.StackedPosition.X, h.StackedPosition.Y, ReplayButtonState.None));
|
||||
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 (!(h is Spinner)) AddFrameToReplay(new ReplayFrame(h.StartTime - h.HitWindowFor(HitResult.Good), h.StackedPosition.X, h.StackedPosition.Y, ReplayButtonState.None));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@ using System.Collections.Generic;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Osu.Judgements;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
@ -15,7 +16,7 @@ using osu.Game.Rulesets.UI;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Scoring
|
||||
{
|
||||
internal class OsuScoreProcessor : ScoreProcessor<OsuHitObject, OsuJudgement>
|
||||
internal class OsuScoreProcessor : ScoreProcessor<OsuHitObject>
|
||||
{
|
||||
public readonly Bindable<ScoringMode> Mode = new Bindable<ScoringMode>(ScoringMode.Exponential);
|
||||
|
||||
@ -23,7 +24,7 @@ namespace osu.Game.Rulesets.Osu.Scoring
|
||||
{
|
||||
}
|
||||
|
||||
public OsuScoreProcessor(RulesetContainer<OsuHitObject, OsuJudgement> rulesetContainer)
|
||||
public OsuScoreProcessor(RulesetContainer<OsuHitObject> rulesetContainer)
|
||||
: base(rulesetContainer)
|
||||
{
|
||||
}
|
||||
@ -32,7 +33,7 @@ namespace osu.Game.Rulesets.Osu.Scoring
|
||||
|
||||
private int totalAccurateJudgements;
|
||||
|
||||
private readonly Dictionary<OsuScoreResult, int> scoreResultCounts = new Dictionary<OsuScoreResult, int>();
|
||||
private readonly Dictionary<HitResult, int> scoreResultCounts = new Dictionary<HitResult, int>();
|
||||
private readonly Dictionary<ComboResult, int> comboResultCounts = new Dictionary<ComboResult, int>();
|
||||
|
||||
private double comboMaxScore;
|
||||
@ -42,18 +43,10 @@ namespace osu.Game.Rulesets.Osu.Scoring
|
||||
hpDrainRate = beatmap.BeatmapInfo.Difficulty.DrainRate;
|
||||
totalAccurateJudgements = beatmap.HitObjects.Count;
|
||||
|
||||
foreach (var h in beatmap.HitObjects)
|
||||
foreach (var unused in beatmap.HitObjects)
|
||||
{
|
||||
if (h != null)
|
||||
{
|
||||
// TODO: add support for other object types.
|
||||
AddJudgement(new OsuJudgement
|
||||
{
|
||||
MaxScore = OsuScoreResult.Hit300,
|
||||
Score = OsuScoreResult.Hit300,
|
||||
Result = HitResult.Hit
|
||||
});
|
||||
}
|
||||
// TODO: add support for other object types.
|
||||
AddJudgement(new OsuJudgement { Result = HitResult.Great });
|
||||
}
|
||||
}
|
||||
|
||||
@ -72,44 +65,43 @@ namespace osu.Game.Rulesets.Osu.Scoring
|
||||
{
|
||||
base.PopulateScore(score);
|
||||
|
||||
score.Statistics[@"300"] = scoreResultCounts.GetOrDefault(OsuScoreResult.Hit300);
|
||||
score.Statistics[@"100"] = scoreResultCounts.GetOrDefault(OsuScoreResult.Hit100);
|
||||
score.Statistics[@"50"] = scoreResultCounts.GetOrDefault(OsuScoreResult.Hit50);
|
||||
score.Statistics[@"x"] = scoreResultCounts.GetOrDefault(OsuScoreResult.Miss);
|
||||
score.Statistics[@"300"] = scoreResultCounts.GetOrDefault(HitResult.Great);
|
||||
score.Statistics[@"100"] = scoreResultCounts.GetOrDefault(HitResult.Good);
|
||||
score.Statistics[@"50"] = scoreResultCounts.GetOrDefault(HitResult.Meh);
|
||||
score.Statistics[@"x"] = scoreResultCounts.GetOrDefault(HitResult.Miss);
|
||||
}
|
||||
|
||||
protected override void OnNewJudgement(OsuJudgement judgement)
|
||||
protected override void OnNewJudgement(Judgement judgement)
|
||||
{
|
||||
if (judgement != null)
|
||||
var osuJudgement = (OsuJudgement)judgement;
|
||||
|
||||
if (judgement.Result != HitResult.None)
|
||||
{
|
||||
if (judgement.Result != HitResult.None)
|
||||
{
|
||||
scoreResultCounts[judgement.Score] = scoreResultCounts.GetOrDefault(judgement.Score) + 1;
|
||||
comboResultCounts[judgement.Combo] = comboResultCounts.GetOrDefault(judgement.Combo) + 1;
|
||||
}
|
||||
scoreResultCounts[judgement.Result] = scoreResultCounts.GetOrDefault(judgement.Result) + 1;
|
||||
comboResultCounts[osuJudgement.Combo] = comboResultCounts.GetOrDefault(osuJudgement.Combo) + 1;
|
||||
}
|
||||
|
||||
switch (judgement.Score)
|
||||
{
|
||||
case OsuScoreResult.Hit300:
|
||||
Health.Value += (10.2 - hpDrainRate) * 0.02;
|
||||
break;
|
||||
switch (judgement.Result)
|
||||
{
|
||||
case HitResult.Great:
|
||||
Health.Value += (10.2 - hpDrainRate) * 0.02;
|
||||
break;
|
||||
|
||||
case OsuScoreResult.Hit100:
|
||||
Health.Value += (8 - hpDrainRate) * 0.02;
|
||||
break;
|
||||
case HitResult.Good:
|
||||
Health.Value += (8 - hpDrainRate) * 0.02;
|
||||
break;
|
||||
|
||||
case OsuScoreResult.Hit50:
|
||||
Health.Value += (4 - hpDrainRate) * 0.02;
|
||||
break;
|
||||
case HitResult.Meh:
|
||||
Health.Value += (4 - hpDrainRate) * 0.02;
|
||||
break;
|
||||
|
||||
case OsuScoreResult.SliderTick:
|
||||
Health.Value += Math.Max(7 - hpDrainRate, 0) * 0.01;
|
||||
break;
|
||||
/*case HitResult.SliderTick:
|
||||
Health.Value += Math.Max(7 - hpDrainRate, 0) * 0.01;
|
||||
break;*/
|
||||
|
||||
case OsuScoreResult.Miss:
|
||||
Health.Value -= hpDrainRate * 0.04;
|
||||
break;
|
||||
}
|
||||
case HitResult.Miss:
|
||||
Health.Value -= hpDrainRate * 0.04;
|
||||
break;
|
||||
}
|
||||
|
||||
calculateScore();
|
||||
@ -124,10 +116,10 @@ namespace osu.Game.Rulesets.Osu.Scoring
|
||||
|
||||
foreach (var j in Judgements)
|
||||
{
|
||||
baseScore += j.ScoreValue;
|
||||
baseMaxScore += j.MaxScoreValue;
|
||||
baseScore += j.NumericResult;
|
||||
baseMaxScore += j.MaxNumericResult;
|
||||
|
||||
comboScore += j.ScoreValue * (1 + Combo.Value / 10d);
|
||||
comboScore += j.NumericResult * (1 + Combo.Value / 10d);
|
||||
}
|
||||
|
||||
Accuracy.Value = (double)baseScore / baseMaxScore;
|
||||
|
@ -10,12 +10,13 @@ using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Osu.Objects.Drawables.Connections;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using System.Linq;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Osu.Judgements;
|
||||
using osu.Game.Rulesets.Osu.UI.Cursor;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.UI
|
||||
{
|
||||
public class OsuPlayfield : Playfield<OsuHitObject, OsuJudgement>
|
||||
public class OsuPlayfield : Playfield
|
||||
{
|
||||
private readonly Container approachCircles;
|
||||
private readonly Container judgementLayer;
|
||||
@ -67,11 +68,9 @@ namespace osu.Game.Rulesets.Osu.UI
|
||||
AddInternal(new GameplayCursor());
|
||||
}
|
||||
|
||||
public override void Add(DrawableHitObject<OsuHitObject, OsuJudgement> h)
|
||||
public override void Add(DrawableHitObject h)
|
||||
{
|
||||
h.Depth = (float)h.HitObject.StartTime;
|
||||
|
||||
IDrawableHitObjectWithProxiedApproach c = h as IDrawableHitObjectWithProxiedApproach;
|
||||
var c = h as IDrawableHitObjectWithProxiedApproach;
|
||||
if (c != null)
|
||||
approachCircles.Add(c.ProxiedLayer.CreateProxy());
|
||||
|
||||
@ -85,12 +84,15 @@ namespace osu.Game.Rulesets.Osu.UI
|
||||
.OrderBy(h => h.StartTime).OfType<OsuHitObject>();
|
||||
}
|
||||
|
||||
public override void OnJudgement(DrawableHitObject<OsuHitObject, OsuJudgement> judgedObject)
|
||||
public override void OnJudgement(DrawableHitObject judgedObject, Judgement judgement)
|
||||
{
|
||||
DrawableOsuJudgement explosion = new DrawableOsuJudgement(judgedObject.Judgement)
|
||||
var osuJudgement = (OsuJudgement)judgement;
|
||||
var osuObject = (OsuHitObject)judgedObject.HitObject;
|
||||
|
||||
DrawableOsuJudgement explosion = new DrawableOsuJudgement(osuJudgement)
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Position = judgedObject.HitObject.StackedEndPosition + judgedObject.Judgement.PositionOffset
|
||||
Position = osuObject.StackedEndPosition + osuJudgement.PositionOffset
|
||||
};
|
||||
|
||||
judgementLayer.Add(explosion);
|
||||
|
@ -7,7 +7,6 @@ using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Beatmaps;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Osu.Beatmaps;
|
||||
using osu.Game.Rulesets.Osu.Judgements;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Osu.Replays;
|
||||
@ -18,7 +17,7 @@ using osu.Game.Rulesets.Replays;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.UI
|
||||
{
|
||||
public class OsuRulesetContainer : RulesetContainer<OsuHitObject, OsuJudgement>
|
||||
public class OsuRulesetContainer : RulesetContainer<OsuHitObject>
|
||||
{
|
||||
public OsuRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap, bool isForCurrentRuleset)
|
||||
: base(ruleset, beatmap, isForCurrentRuleset)
|
||||
@ -31,11 +30,11 @@ namespace osu.Game.Rulesets.Osu.UI
|
||||
|
||||
protected override BeatmapProcessor<OsuHitObject> CreateBeatmapProcessor() => new OsuBeatmapProcessor();
|
||||
|
||||
protected override Playfield<OsuHitObject, OsuJudgement> CreatePlayfield() => new OsuPlayfield();
|
||||
protected override Playfield CreatePlayfield() => new OsuPlayfield();
|
||||
|
||||
public override PassThroughInputManager CreateInputManager() => new OsuInputManager(Ruleset.RulesetInfo);
|
||||
|
||||
protected override DrawableHitObject<OsuHitObject, OsuJudgement> GetVisualRepresentation(OsuHitObject h)
|
||||
protected override DrawableHitObject<OsuHitObject> GetVisualRepresentation(OsuHitObject h)
|
||||
{
|
||||
var circle = h as HitCircle;
|
||||
if (circle != null)
|
||||
|
@ -1,34 +1,26 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Judgements
|
||||
{
|
||||
public class TaikoDrumRollTickJudgement : TaikoJudgement
|
||||
{
|
||||
/// <summary>
|
||||
/// Drum roll ticks don't display judgement text.
|
||||
/// </summary>
|
||||
public override string ResultString => string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Drum roll ticks don't display judgement text.
|
||||
/// </summary>
|
||||
public override string MaxResultString => string.Empty;
|
||||
|
||||
public override bool AffectsCombo => false;
|
||||
|
||||
protected override int NumericResultForScore(TaikoHitResult result)
|
||||
protected override int NumericResultFor(HitResult result)
|
||||
{
|
||||
switch (result)
|
||||
{
|
||||
default:
|
||||
return 0;
|
||||
case TaikoHitResult.Great:
|
||||
case HitResult.Great:
|
||||
return 200;
|
||||
}
|
||||
}
|
||||
|
||||
protected override int NumericResultForAccuracy(TaikoHitResult result)
|
||||
protected override int NumericResultForAccuracy(HitResult result)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,15 +0,0 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Judgements
|
||||
{
|
||||
public enum TaikoHitResult
|
||||
{
|
||||
[Description("GOOD")]
|
||||
Good,
|
||||
[Description("GREAT")]
|
||||
Great
|
||||
}
|
||||
}
|
@ -2,86 +2,56 @@
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Judgements
|
||||
{
|
||||
public class TaikoJudgement : Judgement
|
||||
{
|
||||
/// <summary>
|
||||
/// The maximum result.
|
||||
/// </summary>
|
||||
public const TaikoHitResult MAX_HIT_RESULT = TaikoHitResult.Great;
|
||||
|
||||
/// <summary>
|
||||
/// The result.
|
||||
/// </summary>
|
||||
public TaikoHitResult TaikoResult;
|
||||
|
||||
/// <summary>
|
||||
/// The result value for the combo portion of the score.
|
||||
/// </summary>
|
||||
public int ResultValueForScore => Result == HitResult.Miss ? 0 : NumericResultForScore(TaikoResult);
|
||||
|
||||
/// <summary>
|
||||
/// The result value for the accuracy portion of the score.
|
||||
/// </summary>
|
||||
public int ResultValueForAccuracy => Result == HitResult.Miss ? 0 : NumericResultForAccuracy(TaikoResult);
|
||||
|
||||
/// <summary>
|
||||
/// The maximum result value for the combo portion of the score.
|
||||
/// </summary>
|
||||
public int MaxResultValueForScore => NumericResultForScore(MAX_HIT_RESULT);
|
||||
public int ResultNumericForAccuracy => Result == HitResult.Miss ? 0 : NumericResultForAccuracy(Result);
|
||||
|
||||
/// <summary>
|
||||
/// The maximum result value for the accuracy portion of the score.
|
||||
/// </summary>
|
||||
public int MaxResultValueForAccuracy => NumericResultForAccuracy(MAX_HIT_RESULT);
|
||||
|
||||
public override string ResultString => TaikoResult.GetDescription();
|
||||
|
||||
public override string MaxResultString => MAX_HIT_RESULT.GetDescription();
|
||||
|
||||
/// <summary>
|
||||
/// Whether this Judgement has a secondary hit in the case of strong hits.
|
||||
/// </summary>
|
||||
public virtual bool SecondHit { get; set; }
|
||||
public int MaxResultValueForAccuracy => NumericResultForAccuracy(HitResult.Great);
|
||||
|
||||
/// <summary>
|
||||
/// Computes the numeric result value for the combo portion of the score.
|
||||
/// For the accuracy portion of the score (including accuracy percentage), see <see cref="NumericResultForAccuracy(TaikoHitResult)"/>.
|
||||
/// For the accuracy portion of the score (including accuracy percentage), see <see cref="NumericResultForAccuracy(HitResult)"/>.
|
||||
/// </summary>
|
||||
/// <param name="result">The result to compute the value for.</param>
|
||||
/// <returns>The numeric result value.</returns>
|
||||
protected virtual int NumericResultForScore(TaikoHitResult result)
|
||||
protected override int NumericResultFor(HitResult result)
|
||||
{
|
||||
switch (result)
|
||||
{
|
||||
default:
|
||||
return 0;
|
||||
case TaikoHitResult.Good:
|
||||
case HitResult.Good:
|
||||
return 100;
|
||||
case TaikoHitResult.Great:
|
||||
case HitResult.Great:
|
||||
return 300;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Computes the numeric result value for the accuracy portion of the score.
|
||||
/// For the combo portion of the score, see <see cref="NumericResultForScore(TaikoHitResult)"/>.
|
||||
/// For the combo portion of the score, see <see cref="NumericResultFor(HitResult)"/>.
|
||||
/// </summary>
|
||||
/// <param name="result">The result to compute the value for.</param>
|
||||
/// <returns>The numeric result value.</returns>
|
||||
protected virtual int NumericResultForAccuracy(TaikoHitResult result)
|
||||
protected virtual int NumericResultForAccuracy(HitResult result)
|
||||
{
|
||||
switch (result)
|
||||
{
|
||||
default:
|
||||
return 0;
|
||||
case TaikoHitResult.Good:
|
||||
case HitResult.Good:
|
||||
return 150;
|
||||
case TaikoHitResult.Great:
|
||||
case HitResult.Great:
|
||||
return 300;
|
||||
}
|
||||
}
|
||||
|
@ -1,25 +1,17 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Judgements
|
||||
{
|
||||
public class TaikoStrongHitJudgement : TaikoJudgement, IPartialJudgement
|
||||
public class TaikoStrongHitJudgement : TaikoJudgement
|
||||
{
|
||||
public bool Changed { get; set; }
|
||||
|
||||
public override bool SecondHit
|
||||
public TaikoStrongHitJudgement()
|
||||
{
|
||||
get { return base.SecondHit; }
|
||||
set
|
||||
{
|
||||
if (base.SecondHit == value)
|
||||
return;
|
||||
base.SecondHit = value;
|
||||
|
||||
Changed = true;
|
||||
}
|
||||
base.Result = HitResult.Perfect;
|
||||
}
|
||||
|
||||
public new HitResult Result => base.Result;
|
||||
}
|
||||
}
|
||||
|
@ -5,14 +5,13 @@ using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using OpenTK;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Taiko.Judgements;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
||||
{
|
||||
/// <summary>
|
||||
/// A line that scrolls alongside hit objects in the playfield and visualises control points.
|
||||
/// </summary>
|
||||
public class DrawableBarLine : DrawableScrollingHitObject<TaikoHitObject, TaikoJudgement>
|
||||
public class DrawableBarLine : DrawableScrollingHitObject<TaikoHitObject>
|
||||
{
|
||||
/// <summary>
|
||||
/// The width of the line tracker.
|
||||
@ -58,8 +57,6 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
||||
};
|
||||
}
|
||||
|
||||
protected override TaikoJudgement CreateJudgement() => null;
|
||||
|
||||
protected override void UpdateState(ArmedState state)
|
||||
{
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ using OpenTK.Graphics;
|
||||
using osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
||||
{
|
||||
@ -52,8 +53,6 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
||||
}
|
||||
}
|
||||
|
||||
protected override TaikoJudgement CreateJudgement() => new TaikoJudgement { SecondHit = HitObject.IsStrong };
|
||||
|
||||
protected override TaikoPiece CreateMainPiece() => new ElongatedCirclePiece();
|
||||
|
||||
public override bool OnPressed(TaikoAction action) => false;
|
||||
@ -65,9 +64,9 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
||||
accentDarkColour = colours.YellowDarker;
|
||||
}
|
||||
|
||||
private void onTickJudgement(DrawableHitObject<TaikoHitObject, TaikoJudgement> obj)
|
||||
private void onTickJudgement(DrawableHitObject obj, Judgement judgement)
|
||||
{
|
||||
if (obj.Judgement.Result == HitResult.Hit)
|
||||
if (judgement.Result > HitResult.Miss)
|
||||
rollingHits++;
|
||||
else
|
||||
rollingHits--;
|
||||
@ -78,23 +77,24 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
||||
MainPiece.FadeAccent(newAccent, 100);
|
||||
}
|
||||
|
||||
protected override void CheckJudgement(bool userTriggered)
|
||||
protected override void CheckForJudgements(bool userTriggered, double timeOffset)
|
||||
{
|
||||
if (userTriggered)
|
||||
return;
|
||||
|
||||
if (Judgement.TimeOffset < 0)
|
||||
if (timeOffset < 0)
|
||||
return;
|
||||
|
||||
int countHit = NestedHitObjects.Count(o => o.Judgement.Result == HitResult.Hit);
|
||||
int countHit = NestedHitObjects.Count(o => o.AllJudged);
|
||||
|
||||
if (countHit > HitObject.RequiredGoodHits)
|
||||
{
|
||||
Judgement.Result = HitResult.Hit;
|
||||
Judgement.TaikoResult = countHit >= HitObject.RequiredGreatHits ? TaikoHitResult.Great : TaikoHitResult.Good;
|
||||
AddJudgement(new TaikoJudgement { Result = countHit >= HitObject.RequiredGreatHits ? HitResult.Great : HitResult.Good });
|
||||
if (HitObject.IsStrong)
|
||||
AddJudgement(new TaikoStrongHitJudgement());
|
||||
}
|
||||
else
|
||||
Judgement.Result = HitResult.Miss;
|
||||
AddJudgement(new TaikoJudgement { Result = HitResult.Miss });
|
||||
}
|
||||
|
||||
protected override void UpdateState(ArmedState state)
|
||||
|
@ -34,18 +34,17 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
||||
Filled = HitObject.FirstTick
|
||||
};
|
||||
|
||||
protected override TaikoJudgement CreateJudgement() => new TaikoDrumRollTickJudgement { SecondHit = HitObject.IsStrong };
|
||||
|
||||
protected override void CheckJudgement(bool userTriggered)
|
||||
protected override void CheckForJudgements(bool userTriggered, double timeOffset)
|
||||
{
|
||||
if (!userTriggered)
|
||||
return;
|
||||
|
||||
if (Math.Abs(Judgement.TimeOffset) < HitObject.HitWindow)
|
||||
{
|
||||
Judgement.Result = HitResult.Hit;
|
||||
Judgement.TaikoResult = TaikoHitResult.Great;
|
||||
}
|
||||
if (!(Math.Abs(timeOffset) < HitObject.HitWindow))
|
||||
return;
|
||||
|
||||
AddJudgement(new TaikoDrumRollTickJudgement { Result = HitResult.Great });
|
||||
if (HitObject.IsStrong)
|
||||
AddJudgement(new TaikoStrongHitJudgement());
|
||||
}
|
||||
|
||||
protected override void UpdateState(ArmedState state)
|
||||
@ -58,9 +57,6 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
||||
}
|
||||
}
|
||||
|
||||
public override bool OnPressed(TaikoAction action)
|
||||
{
|
||||
return Judgement.Result == HitResult.None && UpdateJudgement(true);
|
||||
}
|
||||
public override bool OnPressed(TaikoAction action) => UpdateJudgement(true);
|
||||
}
|
||||
}
|
||||
|
@ -28,36 +28,30 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
||||
FillMode = FillMode.Fit;
|
||||
}
|
||||
|
||||
protected override void CheckJudgement(bool userTriggered)
|
||||
protected override void CheckForJudgements(bool userTriggered, double timeOffset)
|
||||
{
|
||||
if (!userTriggered)
|
||||
{
|
||||
if (Judgement.TimeOffset > HitObject.HitWindowGood)
|
||||
Judgement.Result = HitResult.Miss;
|
||||
if (timeOffset > HitObject.HitWindowGood)
|
||||
AddJudgement(new TaikoJudgement { Result = HitResult.Miss });
|
||||
return;
|
||||
}
|
||||
|
||||
double hitOffset = Math.Abs(Judgement.TimeOffset);
|
||||
double hitOffset = Math.Abs(timeOffset);
|
||||
|
||||
if (hitOffset > HitObject.HitWindowMiss)
|
||||
return;
|
||||
|
||||
if (!validKeyPressed)
|
||||
Judgement.Result = HitResult.Miss;
|
||||
AddJudgement(new TaikoJudgement { Result = HitResult.Miss });
|
||||
else if (hitOffset < HitObject.HitWindowGood)
|
||||
{
|
||||
Judgement.Result = HitResult.Hit;
|
||||
Judgement.TaikoResult = hitOffset < HitObject.HitWindowGreat ? TaikoHitResult.Great : TaikoHitResult.Good;
|
||||
}
|
||||
AddJudgement(new TaikoJudgement { Result = hitOffset < HitObject.HitWindowGreat ? HitResult.Great : HitResult.Good });
|
||||
else
|
||||
Judgement.Result = HitResult.Miss;
|
||||
AddJudgement(new TaikoJudgement { Result = HitResult.Miss });
|
||||
}
|
||||
|
||||
public override bool OnPressed(TaikoAction action)
|
||||
{
|
||||
if (Judgement.Result != HitResult.None)
|
||||
return false;
|
||||
|
||||
validKeyPressed = HitActions.Contains(action);
|
||||
|
||||
return UpdateJudgement(true);
|
||||
@ -75,7 +69,8 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
||||
var circlePiece = MainPiece as CirclePiece;
|
||||
circlePiece?.FlashBox.FinishTransforms();
|
||||
|
||||
using (BeginDelayedSequence(HitObject.StartTime - Time.Current + Judgement.TimeOffset, true))
|
||||
var offset = !AllJudged ? 0 : Time.Current - HitObject.StartTime;
|
||||
using (BeginDelayedSequence(HitObject.StartTime - Time.Current + offset, true))
|
||||
{
|
||||
switch (State)
|
||||
{
|
||||
|
@ -3,7 +3,6 @@
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Taiko.Judgements;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
||||
@ -25,13 +24,14 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
||||
{
|
||||
}
|
||||
|
||||
protected override TaikoJudgement CreateJudgement() => new TaikoStrongHitJudgement();
|
||||
private bool processedSecondHit;
|
||||
public override bool AllJudged => processedSecondHit && base.AllJudged;
|
||||
|
||||
protected override void CheckJudgement(bool userTriggered)
|
||||
protected override void CheckForJudgements(bool userTriggered, double timeOffset)
|
||||
{
|
||||
if (Judgement.Result == HitResult.None)
|
||||
if (!base.AllJudged)
|
||||
{
|
||||
base.CheckJudgement(userTriggered);
|
||||
base.CheckForJudgements(userTriggered, timeOffset);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -41,7 +41,10 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
||||
// If we get here, we're assured that the key pressed is the correct secondary key
|
||||
|
||||
if (Math.Abs(firstHitTime - Time.Current) < second_hit_window)
|
||||
Judgement.SecondHit = true;
|
||||
{
|
||||
AddJudgement(new TaikoStrongHitJudgement());
|
||||
processedSecondHit = true;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool OnReleased(TaikoAction action)
|
||||
@ -54,7 +57,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
||||
public override bool OnPressed(TaikoAction action)
|
||||
{
|
||||
// Check if we've handled the first key
|
||||
if (Judgement.Result == HitResult.None)
|
||||
if (!base.AllJudged)
|
||||
{
|
||||
// First key hasn't been handled yet, attempt to handle it
|
||||
bool handled = base.OnPressed(action);
|
||||
@ -70,7 +73,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
||||
}
|
||||
|
||||
// If we've already hit the second key, don't handle this object any further
|
||||
if (Judgement.SecondHit)
|
||||
if (processedSecondHit)
|
||||
return false;
|
||||
|
||||
// Don't handle represses of the first key
|
||||
|
@ -9,11 +9,11 @@ using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Taiko.Judgements;
|
||||
using osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Rulesets.Taiko.Judgements;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
||||
{
|
||||
@ -135,7 +135,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
||||
Width *= Parent.RelativeChildSize.X;
|
||||
}
|
||||
|
||||
protected override void CheckJudgement(bool userTriggered)
|
||||
protected override void CheckForJudgements(bool userTriggered, double timeOffset)
|
||||
{
|
||||
if (userTriggered)
|
||||
{
|
||||
@ -153,24 +153,17 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
||||
expandingRing.ScaleTo(1f + Math.Min(target_ring_scale - 1f, (target_ring_scale - 1f) * completion * 1.3f), 260, Easing.OutQuint);
|
||||
|
||||
if (userHits == HitObject.RequiredHits)
|
||||
{
|
||||
Judgement.Result = HitResult.Hit;
|
||||
Judgement.TaikoResult = TaikoHitResult.Great;
|
||||
}
|
||||
AddJudgement(new TaikoJudgement { Result = HitResult.Great });
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Judgement.TimeOffset < 0)
|
||||
if (timeOffset < 0)
|
||||
return;
|
||||
|
||||
//TODO: THIS IS SHIT AND CAN'T EXIST POST-TAIKO WORLD CUP
|
||||
if (userHits > HitObject.RequiredHits / 2)
|
||||
{
|
||||
Judgement.Result = HitResult.Hit;
|
||||
Judgement.TaikoResult = TaikoHitResult.Good;
|
||||
}
|
||||
else
|
||||
Judgement.Result = HitResult.Miss;
|
||||
AddJudgement(userHits > HitObject.RequiredHits / 2
|
||||
? new TaikoJudgement { Result = HitResult.Good }
|
||||
: new TaikoJudgement { Result = HitResult.Miss });
|
||||
}
|
||||
}
|
||||
|
||||
@ -180,7 +173,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
||||
const float out_transition_time = 300;
|
||||
|
||||
double untilStartTime = HitObject.StartTime - Time.Current;
|
||||
double untilJudgement = untilStartTime + Judgement.TimeOffset + HitObject.Duration;
|
||||
double untilJudgement = untilStartTime + (Judgements.FirstOrDefault()?.TimeOffset ?? 0) + HitObject.Duration;
|
||||
|
||||
targetRing.Delay(untilStartTime - preempt).ScaleTo(target_ring_scale, preempt * 4, Easing.OutQuint);
|
||||
this.Delay(untilJudgement).FadeOut(out_transition_time, Easing.Out);
|
||||
@ -214,9 +207,6 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
||||
|
||||
public override bool OnPressed(TaikoAction action)
|
||||
{
|
||||
if (Judgement.Result != HitResult.None)
|
||||
return false;
|
||||
|
||||
// Don't handle keys before the swell starts
|
||||
if (Time.Current < HitObject.StartTime)
|
||||
return false;
|
||||
|
@ -4,15 +4,13 @@
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Input.Bindings;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Taiko.Judgements;
|
||||
using osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces;
|
||||
using OpenTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
||||
{
|
||||
public abstract class DrawableTaikoHitObject<TaikoHitType>
|
||||
: DrawableScrollingHitObject<TaikoHitObject, TaikoJudgement>, IKeyBindingHandler<TaikoAction>
|
||||
where TaikoHitType : TaikoHitObject
|
||||
public abstract class DrawableTaikoHitObject<TaikoHitType> : DrawableScrollingHitObject<TaikoHitObject>, IKeyBindingHandler<TaikoAction>
|
||||
where TaikoHitType : TaikoHitObject
|
||||
{
|
||||
public override Vector2 OriginPosition => new Vector2(DrawHeight / 2);
|
||||
|
||||
@ -37,8 +35,6 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
||||
MainPiece.KiaiMode = HitObject.Kiai;
|
||||
}
|
||||
|
||||
protected override TaikoJudgement CreateJudgement() => new TaikoJudgement();
|
||||
|
||||
protected virtual TaikoPiece CreateMainPiece() => new CirclePiece();
|
||||
|
||||
public abstract bool OnPressed(TaikoAction action);
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
using System;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Rulesets.Taiko.Judgements;
|
||||
@ -12,7 +13,7 @@ using OpenTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Scoring
|
||||
{
|
||||
internal class TaikoScoreProcessor : ScoreProcessor<TaikoHitObject, TaikoJudgement>
|
||||
internal class TaikoScoreProcessor : ScoreProcessor<TaikoHitObject>
|
||||
{
|
||||
/// <summary>
|
||||
/// The maximum score achievable.
|
||||
@ -36,12 +37,12 @@ namespace osu.Game.Rulesets.Taiko.Scoring
|
||||
private const double combo_base = 4;
|
||||
|
||||
/// <summary>
|
||||
/// The HP awarded by a <see cref="TaikoHitResult.Great"/> hit.
|
||||
/// The HP awarded by a <see cref="HitResult.Great"/> hit.
|
||||
/// </summary>
|
||||
private const double hp_hit_great = 0.03;
|
||||
|
||||
/// <summary>
|
||||
/// The HP awarded for a <see cref="TaikoHitResult.Good"/> hit.
|
||||
/// The HP awarded for a <see cref="HitResult.Good"/> hit.
|
||||
/// </summary>
|
||||
private const double hp_hit_good = 0.011;
|
||||
|
||||
@ -113,7 +114,7 @@ namespace osu.Game.Rulesets.Taiko.Scoring
|
||||
{
|
||||
}
|
||||
|
||||
public TaikoScoreProcessor(RulesetContainer<TaikoHitObject, TaikoJudgement> rulesetContainer)
|
||||
public TaikoScoreProcessor(RulesetContainer<TaikoHitObject> rulesetContainer)
|
||||
: base(rulesetContainer)
|
||||
{
|
||||
}
|
||||
@ -138,39 +139,28 @@ namespace osu.Game.Rulesets.Taiko.Scoring
|
||||
{
|
||||
if (obj is Hit)
|
||||
{
|
||||
AddJudgement(new TaikoJudgement
|
||||
{
|
||||
Result = HitResult.Hit,
|
||||
TaikoResult = TaikoHitResult.Great,
|
||||
SecondHit = obj.IsStrong
|
||||
});
|
||||
AddJudgement(new TaikoJudgement { Result = HitResult.Great });
|
||||
if (obj.IsStrong)
|
||||
AddJudgement(new TaikoStrongHitJudgement());
|
||||
}
|
||||
else if (obj is DrumRoll)
|
||||
{
|
||||
for (int i = 0; i < ((DrumRoll)obj).TotalTicks; i++)
|
||||
{
|
||||
AddJudgement(new TaikoDrumRollTickJudgement
|
||||
{
|
||||
Result = HitResult.Hit,
|
||||
TaikoResult = TaikoHitResult.Great,
|
||||
SecondHit = obj.IsStrong
|
||||
});
|
||||
AddJudgement(new TaikoDrumRollTickJudgement { Result = HitResult.Great });
|
||||
|
||||
if (obj.IsStrong)
|
||||
AddJudgement(new TaikoStrongHitJudgement());
|
||||
}
|
||||
|
||||
AddJudgement(new TaikoJudgement
|
||||
{
|
||||
Result = HitResult.Hit,
|
||||
TaikoResult = TaikoHitResult.Great,
|
||||
SecondHit = obj.IsStrong
|
||||
});
|
||||
AddJudgement(new TaikoJudgement { Result = HitResult.Great });
|
||||
|
||||
if (obj.IsStrong)
|
||||
AddJudgement(new TaikoStrongHitJudgement());
|
||||
}
|
||||
else if (obj is Swell)
|
||||
{
|
||||
AddJudgement(new TaikoJudgement
|
||||
{
|
||||
Result = HitResult.Hit,
|
||||
TaikoResult = TaikoHitResult.Great
|
||||
});
|
||||
AddJudgement(new TaikoJudgement { Result = HitResult.Great });
|
||||
}
|
||||
}
|
||||
|
||||
@ -178,16 +168,40 @@ namespace osu.Game.Rulesets.Taiko.Scoring
|
||||
maxComboPortion = comboPortion;
|
||||
}
|
||||
|
||||
protected override void OnNewJudgement(TaikoJudgement judgement)
|
||||
protected override void OnNewJudgement(Judgement judgement)
|
||||
{
|
||||
bool isStrong = judgement is TaikoStrongHitJudgement;
|
||||
bool isTick = judgement is TaikoDrumRollTickJudgement;
|
||||
|
||||
// Don't consider ticks as a type of hit that counts towards map completion
|
||||
if (!isTick)
|
||||
// Don't consider ticks and strong hits as a type of hit that counts towards map completion
|
||||
if (!isTick && !isStrong)
|
||||
totalHits++;
|
||||
|
||||
// Apply score changes
|
||||
addHitScore(judgement);
|
||||
if (judgement.IsHit)
|
||||
{
|
||||
double baseValue = judgement.NumericResult;
|
||||
|
||||
if (isStrong)
|
||||
{
|
||||
// Add increased score for the previous judgement by hitting a strong hit object with the second key
|
||||
var prevJudgement = Judgements[Judgements.Count - 1];
|
||||
baseValue = prevJudgement.NumericResult * strongHitScale;
|
||||
|
||||
}
|
||||
|
||||
// Add score to portions
|
||||
if (judgement is TaikoDrumRollTickJudgement)
|
||||
bonusScore += baseValue;
|
||||
else
|
||||
{
|
||||
// A relevance factor that needs to be applied to make higher combos more relevant
|
||||
// Value is capped at 400 combo
|
||||
double comboRelevance = Math.Min(Math.Log(400, combo_base), Math.Max(0.5, Math.Log(Combo.Value, combo_base)));
|
||||
|
||||
comboPortion += baseValue * comboRelevance;
|
||||
}
|
||||
}
|
||||
|
||||
// Apply HP changes
|
||||
switch (judgement.Result)
|
||||
@ -197,66 +211,26 @@ namespace osu.Game.Rulesets.Taiko.Scoring
|
||||
if (!isTick)
|
||||
Health.Value += hpIncreaseMiss;
|
||||
break;
|
||||
case HitResult.Hit:
|
||||
switch (judgement.TaikoResult)
|
||||
{
|
||||
case TaikoHitResult.Good:
|
||||
Health.Value += hpIncreaseGood;
|
||||
break;
|
||||
case TaikoHitResult.Great:
|
||||
if (isTick)
|
||||
Health.Value += hpIncreaseTick;
|
||||
else
|
||||
Health.Value += hpIncreaseGreat;
|
||||
break;
|
||||
}
|
||||
case HitResult.Good:
|
||||
Health.Value += hpIncreaseGood;
|
||||
break;
|
||||
case HitResult.Great:
|
||||
if (isTick)
|
||||
Health.Value += hpIncreaseTick;
|
||||
else
|
||||
Health.Value += hpIncreaseGreat;
|
||||
break;
|
||||
}
|
||||
|
||||
calculateScore();
|
||||
}
|
||||
|
||||
protected override void OnJudgementChanged(TaikoJudgement judgement)
|
||||
{
|
||||
// Apply score changes
|
||||
addHitScore(judgement);
|
||||
|
||||
calculateScore();
|
||||
}
|
||||
|
||||
private void addHitScore(TaikoJudgement judgement)
|
||||
{
|
||||
if (judgement.Result != HitResult.Hit)
|
||||
return;
|
||||
|
||||
double baseValue = judgement.ResultValueForScore;
|
||||
|
||||
// Add increased score for hitting a strong hit object with the second key
|
||||
if (judgement.SecondHit)
|
||||
baseValue *= strongHitScale;
|
||||
|
||||
// Add score to portions
|
||||
if (judgement is TaikoDrumRollTickJudgement)
|
||||
bonusScore += baseValue;
|
||||
else
|
||||
{
|
||||
// A relevance factor that needs to be applied to make higher combos more relevant
|
||||
// Value is capped at 400 combo
|
||||
double comboRelevance = Math.Min(Math.Log(400, combo_base), Math.Max(0.5, Math.Log(Combo.Value, combo_base)));
|
||||
|
||||
comboPortion += baseValue * comboRelevance;
|
||||
}
|
||||
}
|
||||
|
||||
private void calculateScore()
|
||||
{
|
||||
int scoreForAccuracy = 0;
|
||||
int maxScoreForAccuracy = 0;
|
||||
|
||||
foreach (var j in Judgements)
|
||||
{
|
||||
scoreForAccuracy += j.ResultValueForAccuracy;
|
||||
maxScoreForAccuracy += j.MaxResultValueForAccuracy;
|
||||
var taikoJudgement = (TaikoJudgement)j;
|
||||
|
||||
scoreForAccuracy += taikoJudgement.ResultNumericForAccuracy;
|
||||
maxScoreForAccuracy += taikoJudgement.MaxResultValueForAccuracy;
|
||||
}
|
||||
|
||||
Accuracy.Value = (double)scoreForAccuracy / maxScoreForAccuracy;
|
||||
|
@ -1,7 +1,6 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Game.Rulesets.Taiko.Judgements;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Game.Graphics;
|
||||
@ -13,15 +12,19 @@ namespace osu.Game.Rulesets.Taiko.UI
|
||||
/// <summary>
|
||||
/// Text that is shown as judgement when a hit object is hit or missed.
|
||||
/// </summary>
|
||||
public class DrawableTaikoJudgement : DrawableJudgement<TaikoJudgement>
|
||||
public class DrawableTaikoJudgement : DrawableJudgement
|
||||
{
|
||||
public readonly DrawableHitObject JudgedObject;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new judgement text.
|
||||
/// </summary>
|
||||
/// <param name="judgedObject">The object which is being judged.</param>
|
||||
/// <param name="judgement">The judgement to visualise.</param>
|
||||
public DrawableTaikoJudgement(TaikoJudgement judgement)
|
||||
public DrawableTaikoJudgement(DrawableHitObject judgedObject, Judgement judgement)
|
||||
: base(judgement)
|
||||
{
|
||||
JudgedObject = judgedObject;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
@ -29,28 +32,19 @@ namespace osu.Game.Rulesets.Taiko.UI
|
||||
{
|
||||
switch (Judgement.Result)
|
||||
{
|
||||
case HitResult.Hit:
|
||||
switch (Judgement.TaikoResult)
|
||||
{
|
||||
case TaikoHitResult.Good:
|
||||
Colour = colours.GreenLight;
|
||||
break;
|
||||
case TaikoHitResult.Great:
|
||||
Colour = colours.BlueLight;
|
||||
break;
|
||||
}
|
||||
case HitResult.Good:
|
||||
Colour = colours.GreenLight;
|
||||
break;
|
||||
case HitResult.Great:
|
||||
Colour = colours.BlueLight;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
switch (Judgement.Result)
|
||||
{
|
||||
case HitResult.Hit:
|
||||
this.MoveToY(-100, 500);
|
||||
break;
|
||||
}
|
||||
if (Judgement.IsHit)
|
||||
this.MoveToY(-100, 500);
|
||||
|
||||
base.LoadComplete();
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Rulesets.Taiko.Judgements;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Taiko.Objects;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.UI
|
||||
@ -18,17 +18,17 @@ namespace osu.Game.Rulesets.Taiko.UI
|
||||
/// </summary>
|
||||
internal class HitExplosion : CircularContainer
|
||||
{
|
||||
public readonly TaikoJudgement Judgement;
|
||||
public readonly DrawableHitObject JudgedObject;
|
||||
|
||||
private readonly Box innerFill;
|
||||
|
||||
private readonly bool isRim;
|
||||
|
||||
public HitExplosion(TaikoJudgement judgement, bool isRim)
|
||||
public HitExplosion(DrawableHitObject judgedObject, bool isRim)
|
||||
{
|
||||
this.isRim = isRim;
|
||||
|
||||
Judgement = judgement;
|
||||
JudgedObject = judgedObject;
|
||||
|
||||
Anchor = Anchor.CentreLeft;
|
||||
Origin = Anchor.Centre;
|
||||
|
@ -7,22 +7,22 @@ using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Rulesets.Taiko.Judgements;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Taiko.Objects;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.UI
|
||||
{
|
||||
public class KiaiHitExplosion : CircularContainer
|
||||
{
|
||||
public readonly TaikoJudgement Judgement;
|
||||
public readonly DrawableHitObject JudgedObject;
|
||||
|
||||
private readonly bool isRim;
|
||||
|
||||
public KiaiHitExplosion(TaikoJudgement judgement, bool isRim)
|
||||
public KiaiHitExplosion(DrawableHitObject judgedObject, bool isRim)
|
||||
{
|
||||
this.isRim = isRim;
|
||||
|
||||
Judgement = judgement;
|
||||
JudgedObject = judgedObject;
|
||||
|
||||
Anchor = Anchor.CentreLeft;
|
||||
Origin = Anchor.Centre;
|
||||
|
@ -14,11 +14,12 @@ using osu.Game.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using System.Linq;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Taiko.Objects.Drawables;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.UI
|
||||
{
|
||||
public class TaikoPlayfield : ScrollingPlayfield<TaikoHitObject, TaikoJudgement>
|
||||
public class TaikoPlayfield : ScrollingPlayfield
|
||||
{
|
||||
/// <summary>
|
||||
/// Default height of a <see cref="TaikoPlayfield"/> when inside a <see cref="TaikoRulesetContainer"/>.
|
||||
@ -202,10 +203,8 @@ namespace osu.Game.Rulesets.Taiko.UI
|
||||
background.Colour = colours.Gray0;
|
||||
}
|
||||
|
||||
public override void Add(DrawableHitObject<TaikoHitObject, TaikoJudgement> h)
|
||||
public override void Add(DrawableHitObject h)
|
||||
{
|
||||
h.Depth = (float)h.HitObject.StartTime;
|
||||
|
||||
base.Add(h);
|
||||
|
||||
var barline = h as DrawableBarLine;
|
||||
@ -218,25 +217,27 @@ namespace osu.Game.Rulesets.Taiko.UI
|
||||
swell.OnStart += () => topLevelHitContainer.Add(swell.CreateProxy());
|
||||
}
|
||||
|
||||
public override void OnJudgement(DrawableHitObject<TaikoHitObject, TaikoJudgement> judgedObject)
|
||||
public override void OnJudgement(DrawableHitObject judgedObject, Judgement judgement)
|
||||
{
|
||||
bool wasHit = judgedObject.Judgement.Result == HitResult.Hit;
|
||||
bool secondHit = judgedObject.Judgement.SecondHit;
|
||||
|
||||
judgementContainer.Add(new DrawableTaikoJudgement(judgedObject.Judgement)
|
||||
if (judgementContainer.FirstOrDefault(j => j.JudgedObject == judgedObject) == null)
|
||||
{
|
||||
Anchor = wasHit ? Anchor.TopLeft : Anchor.CentreLeft,
|
||||
Origin = wasHit ? Anchor.BottomCentre : Anchor.Centre,
|
||||
RelativePositionAxes = Axes.X,
|
||||
X = wasHit ? judgedObject.Position.X : 0,
|
||||
});
|
||||
judgementContainer.Add(new DrawableTaikoJudgement(judgedObject, judgement)
|
||||
{
|
||||
Anchor = judgement.IsHit ? Anchor.TopLeft : Anchor.CentreLeft,
|
||||
Origin = judgement.IsHit ? Anchor.BottomCentre : Anchor.Centre,
|
||||
RelativePositionAxes = Axes.X,
|
||||
X = judgement.IsHit ? judgedObject.Position.X : 0,
|
||||
});
|
||||
}
|
||||
|
||||
if (!wasHit)
|
||||
if (!judgement.IsHit)
|
||||
return;
|
||||
|
||||
bool isRim = judgedObject.HitObject is RimHit;
|
||||
|
||||
if (!secondHit)
|
||||
if (judgement is TaikoStrongHitJudgement)
|
||||
hitExplosionContainer.Children.FirstOrDefault(e => e.JudgedObject == judgedObject)?.VisualiseSecondHit();
|
||||
else
|
||||
{
|
||||
if (judgedObject.X >= -0.05f && judgedObject is DrawableHit)
|
||||
{
|
||||
@ -244,13 +245,11 @@ namespace osu.Game.Rulesets.Taiko.UI
|
||||
topLevelHitContainer.Add(judgedObject.CreateProxy());
|
||||
}
|
||||
|
||||
hitExplosionContainer.Add(new HitExplosion(judgedObject.Judgement, isRim));
|
||||
hitExplosionContainer.Add(new HitExplosion(judgedObject, isRim));
|
||||
|
||||
if (judgedObject.HitObject.Kiai)
|
||||
kiaiExplosionContainer.Add(new KiaiHitExplosion(judgedObject.Judgement, isRim));
|
||||
kiaiExplosionContainer.Add(new KiaiHitExplosion(judgedObject, isRim));
|
||||
}
|
||||
else
|
||||
hitExplosionContainer.Children.FirstOrDefault(e => e.Judgement == judgedObject.Judgement)?.VisualiseSecondHit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,6 @@ using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Rulesets.Replays;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Rulesets.Taiko.Beatmaps;
|
||||
using osu.Game.Rulesets.Taiko.Judgements;
|
||||
using osu.Game.Rulesets.Taiko.Objects;
|
||||
using osu.Game.Rulesets.Taiko.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Taiko.Scoring;
|
||||
@ -22,7 +21,7 @@ using osu.Framework.Input;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.UI
|
||||
{
|
||||
public class TaikoRulesetContainer : ScrollingRulesetContainer<TaikoPlayfield, TaikoHitObject, TaikoJudgement>
|
||||
public class TaikoRulesetContainer : ScrollingRulesetContainer<TaikoPlayfield, TaikoHitObject>
|
||||
{
|
||||
public TaikoRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap, bool isForCurrentRuleset)
|
||||
: base(ruleset, beatmap, isForCurrentRuleset)
|
||||
@ -95,13 +94,13 @@ namespace osu.Game.Rulesets.Taiko.UI
|
||||
|
||||
public override PassThroughInputManager CreateInputManager() => new TaikoInputManager(Ruleset.RulesetInfo);
|
||||
|
||||
protected override Playfield<TaikoHitObject, TaikoJudgement> CreatePlayfield() => new TaikoPlayfield
|
||||
protected override Playfield CreatePlayfield() => new TaikoPlayfield
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft
|
||||
};
|
||||
|
||||
protected override DrawableHitObject<TaikoHitObject, TaikoJudgement> GetVisualRepresentation(TaikoHitObject h)
|
||||
protected override DrawableHitObject<TaikoHitObject> GetVisualRepresentation(TaikoHitObject h)
|
||||
{
|
||||
var centreHit = h as CentreHit;
|
||||
if (centreHit != null)
|
||||
|
@ -52,7 +52,6 @@
|
||||
<Compile Include="Judgements\TaikoDrumRollTickJudgement.cs" />
|
||||
<Compile Include="Judgements\TaikoStrongHitJudgement.cs" />
|
||||
<Compile Include="Judgements\TaikoJudgement.cs" />
|
||||
<Compile Include="Judgements\TaikoHitResult.cs" />
|
||||
<Compile Include="Objects\BarLine.cs" />
|
||||
<Compile Include="Objects\Drawables\DrawableBarLine.cs" />
|
||||
<Compile Include="Objects\Drawables\DrawableBarLineMajor.cs" />
|
||||
|
@ -16,11 +16,9 @@ namespace osu.Game.Rulesets.Judgements
|
||||
/// <summary>
|
||||
/// A drawable object which visualises the hit result of a <see cref="Judgements.Judgement"/>.
|
||||
/// </summary>
|
||||
/// <typeparam name="TJudgement">The type of judgement to visualise.</typeparam>
|
||||
public class DrawableJudgement<TJudgement> : Container
|
||||
where TJudgement : Judgement
|
||||
public class DrawableJudgement : Container
|
||||
{
|
||||
protected readonly TJudgement Judgement;
|
||||
protected readonly Judgement Judgement;
|
||||
|
||||
protected readonly SpriteText JudgementText;
|
||||
|
||||
@ -28,21 +26,19 @@ namespace osu.Game.Rulesets.Judgements
|
||||
/// Creates a drawable which visualises a <see cref="Judgements.Judgement"/>.
|
||||
/// </summary>
|
||||
/// <param name="judgement">The judgement to visualise.</param>
|
||||
public DrawableJudgement(TJudgement judgement)
|
||||
public DrawableJudgement(Judgement judgement)
|
||||
{
|
||||
Judgement = judgement;
|
||||
|
||||
AutoSizeAxes = Axes.Both;
|
||||
|
||||
string resultString = judgement.Result == HitResult.Hit ? judgement.ResultString : judgement.Result.GetDescription();
|
||||
|
||||
Children = new[]
|
||||
{
|
||||
JudgementText = new OsuSpriteText
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Anchor = Anchor.Centre,
|
||||
Text = resultString.ToUpper(),
|
||||
Text = judgement.Result.GetDescription().ToUpper(),
|
||||
Font = @"Venera",
|
||||
TextSize = 16
|
||||
}
|
||||
@ -68,6 +64,8 @@ namespace osu.Game.Rulesets.Judgements
|
||||
|
||||
switch (Judgement.Result)
|
||||
{
|
||||
case HitResult.None:
|
||||
break;
|
||||
case HitResult.Miss:
|
||||
this.ScaleTo(1.6f);
|
||||
this.ScaleTo(1, 100, Easing.In);
|
||||
@ -77,7 +75,7 @@ namespace osu.Game.Rulesets.Judgements
|
||||
|
||||
this.Delay(600).FadeOut(200);
|
||||
break;
|
||||
case HitResult.Hit:
|
||||
default:
|
||||
this.ScaleTo(0.9f);
|
||||
this.ScaleTo(1, 500, Easing.OutElastic);
|
||||
|
||||
|
@ -1,19 +0,0 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
namespace osu.Game.Rulesets.Judgements
|
||||
{
|
||||
/// <summary>
|
||||
/// Inidicates that the judgement this is attached to is a partial judgement and the scoring value may change.
|
||||
/// </summary>
|
||||
public interface IPartialJudgement
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates that this partial judgement has changed and requires reprocessing.
|
||||
/// <para>
|
||||
/// This is set to false once the judgement has been re-processed.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
bool Changed { get; set; }
|
||||
}
|
||||
}
|
@ -5,7 +5,7 @@ using osu.Game.Rulesets.Objects.Drawables;
|
||||
|
||||
namespace osu.Game.Rulesets.Judgements
|
||||
{
|
||||
public abstract class Judgement
|
||||
public class Judgement
|
||||
{
|
||||
/// <summary>
|
||||
/// Whether this judgement is the result of a hit or a miss.
|
||||
@ -13,20 +13,35 @@ namespace osu.Game.Rulesets.Judgements
|
||||
public HitResult Result;
|
||||
|
||||
/// <summary>
|
||||
/// The offset at which this judgement occurred.
|
||||
/// The maximum <see cref="HitResult"/> that can be achieved.
|
||||
/// </summary>
|
||||
public double TimeOffset;
|
||||
public virtual HitResult MaxResult => HitResult.Perfect;
|
||||
|
||||
public bool IsHit => Result > HitResult.Miss;
|
||||
|
||||
/// <summary>
|
||||
/// The offset from a perfect hit at which this judgement occurred.
|
||||
/// Populated when added via <see cref="DrawableHitObject{TObject}.AddJudgement"/>.
|
||||
/// </summary>
|
||||
public double TimeOffset { get; internal set; }
|
||||
|
||||
public virtual bool AffectsCombo => true;
|
||||
|
||||
/// <summary>
|
||||
/// The string representation for the result achieved.
|
||||
/// The numeric representation for the result achieved.
|
||||
/// </summary>
|
||||
public abstract string ResultString { get; }
|
||||
public int NumericResult => NumericResultFor(Result);
|
||||
|
||||
/// <summary>
|
||||
/// The string representation for the max result achievable.
|
||||
/// The numeric representation for the maximum achievable result.
|
||||
/// </summary>
|
||||
public abstract string MaxResultString { get; }
|
||||
public int MaxNumericResult => NumericResultFor(MaxResult);
|
||||
|
||||
/// <summary>
|
||||
/// Convert a <see cref="HitResult"/> to a numeric score representation.
|
||||
/// </summary>
|
||||
/// <param name="result">The value to convert.</param>
|
||||
/// <returns>The number.</returns>
|
||||
protected virtual int NumericResultFor(HitResult result) => result > HitResult.Miss ? 1 : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -34,32 +34,29 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
||||
public abstract class DrawableHitObject<TObject> : DrawableHitObject
|
||||
where TObject : HitObject
|
||||
{
|
||||
public event Action<DrawableHitObject, Judgement> OnJudgement;
|
||||
|
||||
public new readonly TObject HitObject;
|
||||
|
||||
protected DrawableHitObject(TObject hitObject)
|
||||
: base(hitObject)
|
||||
{
|
||||
HitObject = hitObject;
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class DrawableHitObject<TObject, TJudgement> : DrawableHitObject<TObject>
|
||||
where TObject : HitObject
|
||||
where TJudgement : Judgement
|
||||
{
|
||||
public event Action<DrawableHitObject<TObject, TJudgement>> OnJudgement;
|
||||
|
||||
public override bool HandleInput => Interactive;
|
||||
|
||||
public bool Interactive = true;
|
||||
|
||||
public TJudgement Judgement;
|
||||
/// <summary>
|
||||
/// Whether this <see cref="DrawableHitObject"/> can be judged.
|
||||
/// </summary>
|
||||
protected virtual bool ProvidesJudgement => true;
|
||||
|
||||
private readonly List<Judgement> judgements = new List<Judgement>();
|
||||
public IReadOnlyList<Judgement> Judgements => judgements;
|
||||
|
||||
protected List<SampleChannel> Samples = new List<SampleChannel>();
|
||||
|
||||
protected DrawableHitObject(TObject hitObject)
|
||||
: base(hitObject)
|
||||
{
|
||||
HitObject = hitObject;
|
||||
|
||||
Depth = (float)hitObject.StartTime;
|
||||
}
|
||||
|
||||
private ArmedState state;
|
||||
@ -96,69 +93,80 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
||||
UpdateState(State);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether this hit object and all of its nested hit objects have been judged.
|
||||
/// </summary>
|
||||
public bool Judged => (Judgement?.Result ?? HitResult.None) != HitResult.None && (NestedHitObjects?.All(h => h.Judged) ?? true);
|
||||
private bool hasJudgementResult;
|
||||
private bool judgementOccurred;
|
||||
|
||||
/// <summary>
|
||||
/// Process a hit of this hitobject. Carries out judgement.
|
||||
/// Whether this <see cref="DrawableHitObject"/> and all of its nested <see cref="DrawableHitObject"/>s have been judged.
|
||||
/// </summary>
|
||||
/// <returns>Whether a hit was processed.</returns>
|
||||
protected bool UpdateJudgement(bool userTriggered)
|
||||
public virtual bool AllJudged => (!ProvidesJudgement || hasJudgementResult) && (NestedHitObjects?.All(h => h.AllJudged) ?? true);
|
||||
|
||||
/// <summary>
|
||||
/// Notifies that a new judgement has occurred for this <see cref="DrawableHitObject"/>.
|
||||
/// </summary>
|
||||
/// <param name="judgement">The <see cref="Judgement"/>.</param>
|
||||
protected void AddJudgement(Judgement judgement)
|
||||
{
|
||||
if (Judgement == null)
|
||||
return false;
|
||||
hasJudgementResult = judgement.Result >= HitResult.Miss;
|
||||
judgementOccurred = true;
|
||||
|
||||
var partial = Judgement as IPartialJudgement;
|
||||
// Ensure that the judgement is given a valid time offset, because this may not get set by the caller
|
||||
var endTime = (HitObject as IHasEndTime)?.EndTime ?? HitObject.StartTime;
|
||||
judgement.TimeOffset = Time.Current - endTime;
|
||||
|
||||
// Never re-process non-partial hits
|
||||
if (Judgement.Result != HitResult.None && partial == null)
|
||||
return false;
|
||||
judgements.Add(judgement);
|
||||
|
||||
// Update the judgement state
|
||||
double endTime = (HitObject as IHasEndTime)?.EndTime ?? HitObject.StartTime;
|
||||
Judgement.TimeOffset = Time.Current - endTime;
|
||||
|
||||
// Update the judgement state
|
||||
bool hadResult = Judgement.Result != HitResult.None;
|
||||
CheckJudgement(userTriggered);
|
||||
|
||||
// Don't process judgements with no result
|
||||
if (Judgement.Result == HitResult.None)
|
||||
return false;
|
||||
|
||||
// Don't process judgements that previously had results but the results were unchanged
|
||||
if (hadResult && partial?.Changed != true)
|
||||
return false;
|
||||
|
||||
switch (Judgement.Result)
|
||||
switch (judgement.Result)
|
||||
{
|
||||
default:
|
||||
State = ArmedState.Hit;
|
||||
case HitResult.None:
|
||||
break;
|
||||
case HitResult.Miss:
|
||||
State = ArmedState.Miss;
|
||||
break;
|
||||
default:
|
||||
State = ArmedState.Hit;
|
||||
break;
|
||||
}
|
||||
|
||||
OnJudgement?.Invoke(this);
|
||||
|
||||
if (partial != null)
|
||||
partial.Changed = false;
|
||||
|
||||
return true;
|
||||
OnJudgement?.Invoke(this, judgement);
|
||||
}
|
||||
|
||||
protected virtual void CheckJudgement(bool userTriggered)
|
||||
/// <summary>
|
||||
/// Processes this <see cref="DrawableHitObject"/>, checking if any judgements have occurred.
|
||||
/// </summary>
|
||||
/// <param name="userTriggered">Whether the user triggered this process.</param>
|
||||
/// <returns>Whether a judgement has occurred from this <see cref="DrawableHitObject"/> or any nested <see cref="DrawableHitObject"/>s.</returns>
|
||||
protected bool UpdateJudgement(bool userTriggered)
|
||||
{
|
||||
judgementOccurred = false;
|
||||
|
||||
if (AllJudged || State != ArmedState.Idle)
|
||||
return false;
|
||||
|
||||
if (NestedHitObjects != null)
|
||||
{
|
||||
foreach (var d in NestedHitObjects)
|
||||
d.CheckJudgement(userTriggered);
|
||||
judgementOccurred |= d.UpdateJudgement(userTriggered);
|
||||
}
|
||||
|
||||
if (!ProvidesJudgement || hasJudgementResult || judgementOccurred)
|
||||
return judgementOccurred;
|
||||
|
||||
var endTime = (HitObject as IHasEndTime)?.EndTime ?? HitObject.StartTime;
|
||||
CheckForJudgements(userTriggered, Time.Current - endTime);
|
||||
|
||||
return judgementOccurred;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if any judgements have occurred for this <see cref="DrawableHitObject"/>. This method must construct
|
||||
/// all <see cref="Judgement"/>s and notify of them through <see cref="AddJudgement"/>.
|
||||
/// </summary>
|
||||
/// <param name="userTriggered">Whether the user triggered this check.</param>
|
||||
/// <param name="timeOffset">The offset from the <see cref="HitObject"/> end time at which this check occurred. A <paramref name="timeOffset"/> > 0
|
||||
/// implies that this check occurred after the end time of <see cref="HitObject"/>. </param>
|
||||
protected virtual void CheckForJudgements(bool userTriggered, double timeOffset) { }
|
||||
|
||||
protected override void UpdateAfterChildren()
|
||||
{
|
||||
base.UpdateAfterChildren();
|
||||
@ -179,25 +187,20 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
||||
channel.Volume.Value = sample.Volume;
|
||||
Samples.Add(channel);
|
||||
}
|
||||
|
||||
//we may be setting a custom judgement in test cases or what not.
|
||||
if (Judgement == null)
|
||||
Judgement = CreateJudgement();
|
||||
}
|
||||
|
||||
private List<DrawableHitObject<TObject, TJudgement>> nestedHitObjects;
|
||||
protected IEnumerable<DrawableHitObject<TObject, TJudgement>> NestedHitObjects => nestedHitObjects;
|
||||
private List<DrawableHitObject<TObject>> nestedHitObjects;
|
||||
protected IEnumerable<DrawableHitObject<TObject>> NestedHitObjects => nestedHitObjects;
|
||||
|
||||
protected virtual void AddNested(DrawableHitObject<TObject, TJudgement> h)
|
||||
protected virtual void AddNested(DrawableHitObject<TObject> h)
|
||||
{
|
||||
if (nestedHitObjects == null)
|
||||
nestedHitObjects = new List<DrawableHitObject<TObject, TJudgement>>();
|
||||
nestedHitObjects = new List<DrawableHitObject<TObject>>();
|
||||
|
||||
h.OnJudgement += d => OnJudgement?.Invoke(d);
|
||||
h.OnJudgement += (d, j) => OnJudgement?.Invoke(d, j);
|
||||
nestedHitObjects.Add(h);
|
||||
}
|
||||
|
||||
protected abstract TJudgement CreateJudgement();
|
||||
protected abstract void UpdateState(ArmedState state);
|
||||
}
|
||||
}
|
||||
|
@ -3,19 +3,17 @@
|
||||
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
|
||||
namespace osu.Game.Rulesets.Objects.Drawables
|
||||
{
|
||||
/// <summary>
|
||||
/// A basic class that overrides <see cref="DrawableHitObject{TObject, TJudgement}"/> and implements <see cref="IScrollingHitObject"/>.
|
||||
/// A basic class that overrides <see cref="DrawableHitObject{TObject}"/> and implements <see cref="IScrollingHitObject"/>.
|
||||
/// This object does not need to have its <see cref="Drawable.RelativePositionAxes"/> set to be able to scroll, as this will
|
||||
/// will be set by the scrolling container that contains it.
|
||||
/// </summary>
|
||||
public abstract class DrawableScrollingHitObject<TObject, TJudgement> : DrawableHitObject<TObject, TJudgement>, IScrollingHitObject
|
||||
public abstract class DrawableScrollingHitObject<TObject> : DrawableHitObject<TObject>, IScrollingHitObject
|
||||
where TObject : HitObject
|
||||
where TJudgement : Judgement
|
||||
{
|
||||
public BindableDouble LifetimeOffset { get; } = new BindableDouble();
|
||||
|
||||
@ -57,7 +55,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
||||
set { lifetimeEnd = value; }
|
||||
}
|
||||
|
||||
protected override void AddNested(DrawableHitObject<TObject, TJudgement> h)
|
||||
protected override void AddNested(DrawableHitObject<TObject> h)
|
||||
{
|
||||
var scrollingHitObject = h as IScrollingHitObject;
|
||||
scrollingHitObject?.LifetimeOffset.BindTo(LifetimeOffset);
|
||||
|
@ -10,17 +10,34 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
||||
/// <summary>
|
||||
/// Indicates that the object has not been judged yet.
|
||||
/// </summary>
|
||||
[Description("")]
|
||||
[Description(@"")]
|
||||
None,
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that the object has been judged as a miss.
|
||||
/// </summary>
|
||||
[Description(@"Miss")]
|
||||
Miss,
|
||||
|
||||
[Description(@"Meh")]
|
||||
Meh,
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that the object has been judged as a hit.
|
||||
/// Optional judgement.
|
||||
/// </summary>
|
||||
[Description(@"Hit")]
|
||||
Hit,
|
||||
[Description(@"OK")]
|
||||
Ok,
|
||||
|
||||
[Description(@"Good")]
|
||||
Good,
|
||||
|
||||
[Description(@"Great")]
|
||||
Great,
|
||||
|
||||
/// <summary>
|
||||
/// Optional judgement.
|
||||
/// </summary>
|
||||
[Description(@"Perfect")]
|
||||
Perfect,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -135,14 +135,13 @@ namespace osu.Game.Rulesets.Scoring
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class ScoreProcessor<TObject, TJudgement> : ScoreProcessor
|
||||
public abstract class ScoreProcessor<TObject> : ScoreProcessor
|
||||
where TObject : HitObject
|
||||
where TJudgement : Judgement
|
||||
{
|
||||
/// <summary>
|
||||
/// All judgements held by this ScoreProcessor.
|
||||
/// </summary>
|
||||
protected readonly List<TJudgement> Judgements = new List<TJudgement>();
|
||||
protected readonly List<Judgement> Judgements = new List<Judgement>();
|
||||
|
||||
public override bool HasFailed => Health.Value == Health.MinValue;
|
||||
|
||||
@ -150,7 +149,7 @@ namespace osu.Game.Rulesets.Scoring
|
||||
{
|
||||
}
|
||||
|
||||
protected ScoreProcessor(RulesetContainer<TObject, TJudgement> rulesetContainer)
|
||||
protected ScoreProcessor(RulesetContainer<TObject> rulesetContainer)
|
||||
{
|
||||
Judgements.Capacity = rulesetContainer.Beatmap.HitObjects.Count;
|
||||
|
||||
@ -171,7 +170,7 @@ namespace osu.Game.Rulesets.Scoring
|
||||
/// Adds a judgement to this ScoreProcessor.
|
||||
/// </summary>
|
||||
/// <param name="judgement">The judgement to add.</param>
|
||||
protected void AddJudgement(TJudgement judgement)
|
||||
protected void AddJudgement(Judgement judgement)
|
||||
{
|
||||
bool exists = Judgements.Contains(judgement);
|
||||
|
||||
@ -181,10 +180,12 @@ namespace osu.Game.Rulesets.Scoring
|
||||
{
|
||||
switch (judgement.Result)
|
||||
{
|
||||
case HitResult.None:
|
||||
break;
|
||||
case HitResult.Miss:
|
||||
Combo.Value = 0;
|
||||
break;
|
||||
case HitResult.Hit:
|
||||
default:
|
||||
Combo.Value++;
|
||||
break;
|
||||
}
|
||||
@ -195,8 +196,6 @@ namespace osu.Game.Rulesets.Scoring
|
||||
|
||||
NotifyNewJudgement(judgement);
|
||||
}
|
||||
else
|
||||
OnJudgementChanged(judgement);
|
||||
|
||||
UpdateFailed();
|
||||
}
|
||||
@ -210,20 +209,8 @@ namespace osu.Game.Rulesets.Scoring
|
||||
|
||||
/// <summary>
|
||||
/// Updates any values that need post-processing. Invoked when a new judgement has occurred.
|
||||
/// <para>
|
||||
/// This is not triggered when existing judgements are changed - for that see <see cref="OnJudgementChanged(TJudgement)"/>.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <param name="judgement">The judgement that triggered this calculation.</param>
|
||||
protected abstract void OnNewJudgement(TJudgement judgement);
|
||||
|
||||
/// <summary>
|
||||
/// Updates any values that need post-processing. Invoked when an existing judgement has changed.
|
||||
/// <para>
|
||||
/// This is not triggered when a new judgement has occurred - for that see <see cref="OnNewJudgement(TJudgement)"/>.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <param name="judgement">The judgement that triggered this calculation.</param>
|
||||
protected virtual void OnJudgementChanged(TJudgement judgement) { }
|
||||
protected abstract void OnNewJudgement(Judgement judgement);
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,6 @@
|
||||
using System;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using OpenTK;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
@ -14,9 +13,7 @@ using System.Linq;
|
||||
|
||||
namespace osu.Game.Rulesets.UI
|
||||
{
|
||||
public abstract class Playfield<TObject, TJudgement> : Container
|
||||
where TObject : HitObject
|
||||
where TJudgement : Judgement
|
||||
public abstract class Playfield : Container
|
||||
{
|
||||
/// <summary>
|
||||
/// The HitObjects contained in this Playfield.
|
||||
@ -70,7 +67,7 @@ namespace osu.Game.Rulesets.UI
|
||||
public override Axes RelativeSizeAxes
|
||||
{
|
||||
get { return Axes.Both; }
|
||||
set { throw new InvalidOperationException($@"{nameof(Playfield<TObject, TJudgement>)}'s {nameof(RelativeSizeAxes)} should never be changed from {Axes.Both}"); }
|
||||
set { throw new InvalidOperationException($@"{nameof(Playfield)}'s {nameof(RelativeSizeAxes)} should never be changed from {Axes.Both}"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -82,19 +79,20 @@ namespace osu.Game.Rulesets.UI
|
||||
/// Adds a DrawableHitObject to this Playfield.
|
||||
/// </summary>
|
||||
/// <param name="h">The DrawableHitObject to add.</param>
|
||||
public virtual void Add(DrawableHitObject<TObject, TJudgement> h) => HitObjects.Add(h);
|
||||
public virtual void Add(DrawableHitObject h) => HitObjects.Add(h);
|
||||
|
||||
/// <summary>
|
||||
/// Remove a DrawableHitObject from this Playfield.
|
||||
/// </summary>
|
||||
/// <param name="h">The DrawableHitObject to remove.</param>
|
||||
public virtual void Remove(DrawableHitObject<TObject, TJudgement> h) => HitObjects.Remove(h);
|
||||
public virtual void Remove(DrawableHitObject h) => HitObjects.Remove(h);
|
||||
|
||||
/// <summary>
|
||||
/// Triggered when an object's Judgement is updated.
|
||||
/// Triggered when a new <see cref="Judgement"/> occurs on a <see cref="DrawableHitObject"/>.
|
||||
/// </summary>
|
||||
/// <param name="judgedObject">The object that Judgement has been updated for.</param>
|
||||
public virtual void OnJudgement(DrawableHitObject<TObject, TJudgement> judgedObject) { }
|
||||
/// <param name="judgedObject">The object that <paramref name="judgement"/> occured for.</param>
|
||||
/// <param name="judgement">The <see cref="Judgement"/> that occurred.</param>
|
||||
public virtual void OnJudgement(DrawableHitObject judgedObject, Judgement judgement) { }
|
||||
|
||||
public class HitObjectContainer : CompositeDrawable
|
||||
{
|
||||
|
@ -24,7 +24,7 @@ namespace osu.Game.Rulesets.UI
|
||||
/// <summary>
|
||||
/// Base RulesetContainer. Doesn't hold objects.
|
||||
/// <para>
|
||||
/// Should not be derived - derive <see cref="RulesetContainer{TObject,TJudgement}"/> instead.
|
||||
/// Should not be derived - derive <see cref="RulesetContainer{TObject}"/> instead.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public abstract class RulesetContainer : Container
|
||||
@ -35,7 +35,7 @@ namespace osu.Game.Rulesets.UI
|
||||
public event Action OnAllJudged;
|
||||
|
||||
/// <summary>
|
||||
/// Whether to apply adjustments to the child <see cref="Playfield{TObject,TJudgement}"/> based on our own size.
|
||||
/// Whether to apply adjustments to the child <see cref="Playfield"/> based on our own size.
|
||||
/// </summary>
|
||||
public bool AspectAdjust = true;
|
||||
|
||||
@ -116,13 +116,15 @@ namespace osu.Game.Rulesets.UI
|
||||
/// RulesetContainer that applies conversion to Beatmaps. Does not contain a Playfield
|
||||
/// and does not load drawable hit objects.
|
||||
/// <para>
|
||||
/// Should not be derived - derive <see cref="RulesetContainer{TObject,TJudgement}"/> instead.
|
||||
/// Should not be derived - derive <see cref="RulesetContainer{TObject}"/> instead.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <typeparam name="TObject">The type of HitObject contained by this RulesetContainer.</typeparam>
|
||||
public abstract class RulesetContainer<TObject> : RulesetContainer
|
||||
where TObject : HitObject
|
||||
{
|
||||
public event Action<Judgement> OnJudgement;
|
||||
|
||||
/// <summary>
|
||||
/// The Beatmap
|
||||
/// </summary>
|
||||
@ -148,6 +150,20 @@ namespace osu.Game.Rulesets.UI
|
||||
/// </summary>
|
||||
protected readonly bool IsForCurrentRuleset;
|
||||
|
||||
public sealed override bool ProvidingUserCursor => !HasReplayLoaded && Playfield.ProvidingUserCursor;
|
||||
|
||||
protected override bool AllObjectsJudged => drawableObjects.All(h => h.AllJudged);
|
||||
|
||||
/// <summary>
|
||||
/// The playfield.
|
||||
/// </summary>
|
||||
public Playfield Playfield { get; private set; }
|
||||
|
||||
protected override Container<Drawable> Content => content;
|
||||
private Container content;
|
||||
|
||||
private readonly List<DrawableHitObject<TObject>> drawableObjects = new List<DrawableHitObject<TObject>>();
|
||||
|
||||
/// <summary>
|
||||
/// Whether to assume the beatmap passed into this <see cref="RulesetContainer{TObject}"/> is for the current ruleset.
|
||||
/// Creates a hit renderer for a beatmap.
|
||||
@ -155,7 +171,7 @@ namespace osu.Game.Rulesets.UI
|
||||
/// <param name="ruleset">The ruleset being repesented.</param>
|
||||
/// <param name="workingBeatmap">The beatmap to create the hit renderer for.</param>
|
||||
/// <param name="isForCurrentRuleset">Whether to assume the beatmap is for the current ruleset.</param>
|
||||
internal RulesetContainer(Ruleset ruleset, WorkingBeatmap workingBeatmap, bool isForCurrentRuleset)
|
||||
protected RulesetContainer(Ruleset ruleset, WorkingBeatmap workingBeatmap, bool isForCurrentRuleset)
|
||||
: base(ruleset)
|
||||
{
|
||||
Debug.Assert(workingBeatmap != null, "RulesetContainer initialized with a null beatmap.");
|
||||
@ -194,74 +210,6 @@ namespace osu.Game.Rulesets.UI
|
||||
applyMods(Mods);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies the active mods to this RulesetContainer.
|
||||
/// </summary>
|
||||
/// <param name="mods"></param>
|
||||
private void applyMods(IEnumerable<Mod> mods)
|
||||
{
|
||||
if (mods == null)
|
||||
return;
|
||||
|
||||
foreach (var mod in mods.OfType<IApplicableMod<TObject>>())
|
||||
mod.ApplyToRulesetContainer(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a processor to perform post-processing operations
|
||||
/// on HitObjects in converted Beatmaps.
|
||||
/// </summary>
|
||||
/// <returns>The Beatmap processor.</returns>
|
||||
protected virtual BeatmapProcessor<TObject> CreateBeatmapProcessor() => new BeatmapProcessor<TObject>();
|
||||
|
||||
/// <summary>
|
||||
/// Creates a converter to convert Beatmap to a specific mode.
|
||||
/// </summary>
|
||||
/// <returns>The Beatmap converter.</returns>
|
||||
protected abstract BeatmapConverter<TObject> CreateBeatmapConverter();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A derivable RulesetContainer that manages the Playfield and HitObjects.
|
||||
/// </summary>
|
||||
/// <typeparam name="TObject">The type of HitObject contained by this RulesetContainer.</typeparam>
|
||||
/// <typeparam name="TJudgement">The type of Judgement of DrawableHitObjects contained by this RulesetContainer.</typeparam>
|
||||
public abstract class RulesetContainer<TObject, TJudgement> : RulesetContainer<TObject>
|
||||
where TObject : HitObject
|
||||
where TJudgement : Judgement
|
||||
{
|
||||
public event Action<TJudgement> OnJudgement;
|
||||
|
||||
public sealed override bool ProvidingUserCursor => !HasReplayLoaded && Playfield.ProvidingUserCursor;
|
||||
|
||||
/// <summary>
|
||||
/// All the converted hit objects contained by this hit renderer.
|
||||
/// </summary>
|
||||
public new IEnumerable<TObject> Objects => Beatmap.HitObjects;
|
||||
|
||||
protected override bool AllObjectsJudged => drawableObjects.All(h => h.Judged);
|
||||
|
||||
/// <summary>
|
||||
/// The playfield.
|
||||
/// </summary>
|
||||
public Playfield<TObject, TJudgement> Playfield { get; private set; }
|
||||
|
||||
protected override Container<Drawable> Content => content;
|
||||
private Container content;
|
||||
|
||||
private readonly List<DrawableHitObject<TObject, TJudgement>> drawableObjects = new List<DrawableHitObject<TObject, TJudgement>>();
|
||||
|
||||
/// <summary>
|
||||
/// Creates a hit renderer for a beatmap.
|
||||
/// </summary>
|
||||
/// <param name="ruleset">The ruleset being repesented.</param>
|
||||
/// <param name="beatmap">The beatmap to create the hit renderer for.</param>
|
||||
/// <param name="isForCurrentRuleset">Whether to assume the beatmap is for the current ruleset.</param>
|
||||
protected RulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap, bool isForCurrentRuleset)
|
||||
: base(ruleset, beatmap, isForCurrentRuleset)
|
||||
{
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
@ -276,6 +224,19 @@ namespace osu.Game.Rulesets.UI
|
||||
loadObjects();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies the active mods to this RulesetContainer.
|
||||
/// </summary>
|
||||
/// <param name="mods"></param>
|
||||
private void applyMods(IEnumerable<Mod> mods)
|
||||
{
|
||||
if (mods == null)
|
||||
return;
|
||||
|
||||
foreach (var mod in mods.OfType<IApplicableMod<TObject>>())
|
||||
mod.ApplyToRulesetContainer(this);
|
||||
}
|
||||
|
||||
public override void SetReplay(Replay replay)
|
||||
{
|
||||
base.SetReplay(replay);
|
||||
@ -298,7 +259,12 @@ namespace osu.Game.Rulesets.UI
|
||||
if (drawableObject == null)
|
||||
continue;
|
||||
|
||||
drawableObject.OnJudgement += onJudgement;
|
||||
drawableObject.OnJudgement += (d, j) =>
|
||||
{
|
||||
Playfield.OnJudgement(d, j);
|
||||
OnJudgement?.Invoke(j);
|
||||
CheckAllJudged();
|
||||
};
|
||||
|
||||
drawableObjects.Add(drawableObject);
|
||||
Playfield.Add(drawableObject);
|
||||
@ -315,36 +281,36 @@ namespace osu.Game.Rulesets.UI
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// In some cases we want to apply changes to the relative size of our contained <see cref="Playfield{TObject, TJudgement}"/> based on custom conditions.
|
||||
/// Creates a processor to perform post-processing operations
|
||||
/// on HitObjects in converted Beatmaps.
|
||||
/// </summary>
|
||||
/// <returns>The Beatmap processor.</returns>
|
||||
protected virtual BeatmapProcessor<TObject> CreateBeatmapProcessor() => new BeatmapProcessor<TObject>();
|
||||
|
||||
/// <summary>
|
||||
/// In some cases we want to apply changes to the relative size of our contained <see cref="Playfield"/> based on custom conditions.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected virtual Vector2 GetPlayfieldAspectAdjust() => new Vector2(0.75f); //a sane default
|
||||
|
||||
/// <summary>
|
||||
/// Triggered when an object's Judgement is updated.
|
||||
/// Creates a converter to convert Beatmap to a specific mode.
|
||||
/// </summary>
|
||||
/// <param name="judgedObject">The object that Judgement has been updated for.</param>
|
||||
private void onJudgement(DrawableHitObject<TObject, TJudgement> judgedObject)
|
||||
{
|
||||
Playfield.OnJudgement(judgedObject);
|
||||
|
||||
OnJudgement?.Invoke(judgedObject.Judgement);
|
||||
|
||||
CheckAllJudged();
|
||||
}
|
||||
/// <returns>The Beatmap converter.</returns>
|
||||
protected abstract BeatmapConverter<TObject> CreateBeatmapConverter();
|
||||
|
||||
/// <summary>
|
||||
/// Creates a DrawableHitObject from a HitObject.
|
||||
/// </summary>
|
||||
/// <param name="h">The HitObject to make drawable.</param>
|
||||
/// <returns>The DrawableHitObject.</returns>
|
||||
protected abstract DrawableHitObject<TObject, TJudgement> GetVisualRepresentation(TObject h);
|
||||
protected abstract DrawableHitObject<TObject> GetVisualRepresentation(TObject h);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a Playfield.
|
||||
/// </summary>
|
||||
/// <returns>The Playfield.</returns>
|
||||
protected abstract Playfield<TObject, TJudgement> CreatePlayfield();
|
||||
protected abstract Playfield CreatePlayfield();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -352,11 +318,9 @@ namespace osu.Game.Rulesets.UI
|
||||
/// </summary>
|
||||
/// <typeparam name="TPlayfield">The type of Playfield contained by this RulesetContainer.</typeparam>
|
||||
/// <typeparam name="TObject">The type of HitObject contained by this RulesetContainer.</typeparam>
|
||||
/// <typeparam name="TJudgement">The type of Judgement of DrawableHitObjects contained by this RulesetContainer.</typeparam>
|
||||
public abstract class RulesetContainer<TPlayfield, TObject, TJudgement> : RulesetContainer<TObject, TJudgement>
|
||||
public abstract class RulesetContainer<TPlayfield, TObject> : RulesetContainer<TObject>
|
||||
where TObject : HitObject
|
||||
where TJudgement : Judgement
|
||||
where TPlayfield : Playfield<TObject, TJudgement>
|
||||
where TPlayfield : Playfield
|
||||
{
|
||||
/// <summary>
|
||||
/// The playfield.
|
||||
|
@ -11,19 +11,15 @@ using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Transforms;
|
||||
using osu.Framework.Input;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Timing;
|
||||
|
||||
namespace osu.Game.Rulesets.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// A type of <see cref="Playfield{TObject, TJudgement}"/> specialized towards scrolling <see cref="DrawableHitObject"/>s.
|
||||
/// A type of <see cref="Playfield"/> specialized towards scrolling <see cref="DrawableHitObject"/>s.
|
||||
/// </summary>
|
||||
public class ScrollingPlayfield<TObject, TJudgement> : Playfield<TObject, TJudgement>
|
||||
where TObject : HitObject
|
||||
where TJudgement : Judgement
|
||||
public class ScrollingPlayfield : Playfield
|
||||
{
|
||||
/// <summary>
|
||||
/// The default span of time visible by the length of the scrolling axes.
|
||||
@ -65,7 +61,7 @@ namespace osu.Game.Rulesets.UI
|
||||
public new readonly ScrollingHitObjectContainer HitObjects;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="ScrollingPlayfield{TObject, TJudgement}"/>.
|
||||
/// Creates a new <see cref="ScrollingPlayfield"/>.
|
||||
/// </summary>
|
||||
/// <param name="scrollingAxes">The axes on 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>
|
||||
@ -77,21 +73,21 @@ namespace osu.Game.Rulesets.UI
|
||||
HitObjects.Reversed.BindTo(Reversed);
|
||||
}
|
||||
|
||||
private List<ScrollingPlayfield<TObject, TJudgement>> nestedPlayfields;
|
||||
private List<ScrollingPlayfield> nestedPlayfields;
|
||||
/// <summary>
|
||||
/// All the <see cref="ScrollingPlayfield{TObject, TJudgement}"/>s nested inside this playfield.
|
||||
/// All the <see cref="ScrollingPlayfield"/>s nested inside this playfield.
|
||||
/// </summary>
|
||||
public IEnumerable<ScrollingPlayfield<TObject, TJudgement>> NestedPlayfields => nestedPlayfields;
|
||||
public IEnumerable<ScrollingPlayfield> NestedPlayfields => nestedPlayfields;
|
||||
|
||||
/// <summary>
|
||||
/// Adds a <see cref="ScrollingPlayfield{TObject, TJudgement}"/> to this playfield. The nested <see cref="ScrollingPlayfield{TObject, TJudgement}"/>
|
||||
/// Adds a <see cref="ScrollingPlayfield"/> to this playfield. The nested <see cref="ScrollingPlayfield"/>
|
||||
/// will be given all of the same speed adjustments as this playfield.
|
||||
/// </summary>
|
||||
/// <param name="otherPlayfield">The <see cref="ScrollingPlayfield{TObject, TJudgement}"/> to add.</param>
|
||||
protected void AddNested(ScrollingPlayfield<TObject, TJudgement> otherPlayfield)
|
||||
/// <param name="otherPlayfield">The <see cref="ScrollingPlayfield"/> to add.</param>
|
||||
protected void AddNested(ScrollingPlayfield otherPlayfield)
|
||||
{
|
||||
if (nestedPlayfields == null)
|
||||
nestedPlayfields = new List<ScrollingPlayfield<TObject, TJudgement>>();
|
||||
nestedPlayfields = new List<ScrollingPlayfield>();
|
||||
|
||||
nestedPlayfields.Add(otherPlayfield);
|
||||
}
|
||||
@ -119,7 +115,7 @@ namespace osu.Game.Rulesets.UI
|
||||
this.TransformTo(this.PopulateTransform(new TransformVisibleTimeRange(), newTimeRange, duration, easing));
|
||||
}
|
||||
|
||||
private class TransformVisibleTimeRange : Transform<double, ScrollingPlayfield<TObject, TJudgement>>
|
||||
private class TransformVisibleTimeRange : Transform<double, ScrollingPlayfield>
|
||||
{
|
||||
private double valueAt(double time)
|
||||
{
|
||||
@ -131,8 +127,8 @@ namespace osu.Game.Rulesets.UI
|
||||
|
||||
public override string TargetMember => "VisibleTimeRange.Value";
|
||||
|
||||
protected override void Apply(ScrollingPlayfield<TObject, TJudgement> d, double time) => d.VisibleTimeRange.Value = valueAt(time);
|
||||
protected override void ReadIntoStartValue(ScrollingPlayfield<TObject, TJudgement> d) => StartValue = d.VisibleTimeRange.Value;
|
||||
protected override void Apply(ScrollingPlayfield d, double time) => d.VisibleTimeRange.Value = valueAt(time);
|
||||
protected override void ReadIntoStartValue(ScrollingPlayfield d) => StartValue = d.VisibleTimeRange.Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -9,7 +9,6 @@ using osu.Framework.Lists;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.IO.Serialization;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Rulesets.Timing;
|
||||
@ -17,17 +16,16 @@ using osu.Game.Rulesets.Timing;
|
||||
namespace osu.Game.Rulesets.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// A type of <see cref="RulesetContainer{TPlayfield,TObject,TJudgement}"/> that supports a <see cref="ScrollingPlayfield{TObject, TJudgement}"/>.
|
||||
/// <see cref="HitObject"/>s inside this <see cref="RulesetContainer{TPlayfield,TObject,TJudgement}"/> will scroll within the playfield.
|
||||
/// A type of <see cref="RulesetContainer{TPlayfield,TObject}"/> that supports a <see cref="ScrollingPlayfield"/>.
|
||||
/// <see cref="HitObject"/>s inside this <see cref="RulesetContainer{TPlayfield,TObject}"/> will scroll within the playfield.
|
||||
/// </summary>
|
||||
public abstract class ScrollingRulesetContainer<TPlayfield, TObject, TJudgement> : RulesetContainer<TPlayfield, TObject, TJudgement>
|
||||
public abstract class ScrollingRulesetContainer<TPlayfield, TObject> : RulesetContainer<TPlayfield, TObject>
|
||||
where TObject : HitObject
|
||||
where TJudgement : Judgement
|
||||
where TPlayfield : ScrollingPlayfield<TObject, TJudgement>
|
||||
where TPlayfield : ScrollingPlayfield
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides the default <see cref="MultiplierControlPoint"/>s that adjust the scrolling rate of <see cref="HitObject"/>s
|
||||
/// inside this <see cref="RulesetContainer{TPlayfield,TObject,TJudgement}"/>.
|
||||
/// inside this <see cref="RulesetContainer{TPlayfield,TObject}"/>.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected readonly SortedList<MultiplierControlPoint> DefaultControlPoints = new SortedList<MultiplierControlPoint>(Comparer<MultiplierControlPoint>.Default);
|
||||
@ -88,7 +86,7 @@ namespace osu.Game.Rulesets.UI
|
||||
DefaultControlPoints.ForEach(c => applySpeedAdjustment(c, Playfield));
|
||||
}
|
||||
|
||||
private void applySpeedAdjustment(MultiplierControlPoint controlPoint, ScrollingPlayfield<TObject, TJudgement> playfield)
|
||||
private void applySpeedAdjustment(MultiplierControlPoint controlPoint, ScrollingPlayfield playfield)
|
||||
{
|
||||
playfield.HitObjects.AddSpeedAdjustment(CreateSpeedAdjustmentContainer(controlPoint));
|
||||
playfield.NestedPlayfields.ForEach(p => applySpeedAdjustment(controlPoint, p));
|
||||
|
@ -215,7 +215,6 @@
|
||||
<Compile Include="Rulesets\Objects\Types\IHasYPosition.cs" />
|
||||
<Compile Include="Rulesets\Replays\Replay.cs" />
|
||||
<Compile Include="Rulesets\Judgements\DrawableJudgement.cs" />
|
||||
<Compile Include="Rulesets\Judgements\IPartialJudgement.cs" />
|
||||
<Compile Include="Rulesets\Replays\FramedReplayInputHandler.cs" />
|
||||
<Compile Include="Rulesets\Mods\IApplicableMod.cs" />
|
||||
<Compile Include="Rulesets\Mods\ModType.cs" />
|
||||
|
Loading…
Reference in New Issue
Block a user