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