mirror of
https://github.com/ppy/osu.git
synced 2025-02-21 03:02:54 +08:00
Separate into separate class
This commit is contained in:
parent
ea1bec85ae
commit
10e849d196
@ -120,7 +120,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
|
|
||||||
var result = HitObject.HitWindows.ResultFor(timeOffset);
|
var result = HitObject.HitWindows.ResultFor(timeOffset);
|
||||||
|
|
||||||
if (result == HitResult.None || CheckHittable?.Invoke(this) == false)
|
if (result == HitResult.None || CheckHittable?.Invoke(this, Time.Current) == false)
|
||||||
{
|
{
|
||||||
Shake(Math.Abs(timeOffset) - HitObject.HitWindows.WindowFor(HitResult.Miss));
|
Shake(Math.Abs(timeOffset) - HitObject.HitWindows.WindowFor(HitResult.Miss));
|
||||||
return;
|
return;
|
||||||
|
@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
/// Whether this <see cref="DrawableOsuHitObject"/> can be hit.
|
/// Whether this <see cref="DrawableOsuHitObject"/> can be hit.
|
||||||
/// If non-null, judgements will be ignored (resulting in a shake) whilst the function returns false.
|
/// If non-null, judgements will be ignored (resulting in a shake) whilst the function returns false.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Func<DrawableOsuHitObject, bool> CheckHittable;
|
public Func<DrawableHitObject, double, bool> CheckHittable;
|
||||||
|
|
||||||
protected DrawableOsuHitObject(OsuHitObject hitObject)
|
protected DrawableOsuHitObject(OsuHitObject hitObject)
|
||||||
: base(hitObject)
|
: base(hitObject)
|
||||||
|
104
osu.Game.Rulesets.Osu/UI/OrderedHitPolicy.cs
Normal file
104
osu.Game.Rulesets.Osu/UI/OrderedHitPolicy.cs
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||||
|
using osu.Game.Rulesets.Objects;
|
||||||
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
|
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||||
|
using osu.Game.Rulesets.UI;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Osu.UI
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Ensures that <see cref="HitObject"/>s are hit in-order.
|
||||||
|
/// If a <see cref="HitObject"/> is hit out of order:
|
||||||
|
/// <list type="number">
|
||||||
|
/// <item><description>The hit is blocked if it occurred earlier than the previous <see cref="HitObject"/>'s start time.</description></item>
|
||||||
|
/// <item><description>The hit causes all previous <see cref="HitObject"/>s to missed otherwise.</description></item>
|
||||||
|
/// </list>
|
||||||
|
/// </summary>
|
||||||
|
public class OrderedHitPolicy
|
||||||
|
{
|
||||||
|
private readonly HitObjectContainer hitObjectContainer;
|
||||||
|
|
||||||
|
public OrderedHitPolicy(HitObjectContainer hitObjectContainer)
|
||||||
|
{
|
||||||
|
this.hitObjectContainer = hitObjectContainer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether a <see cref="DrawableHitObject"/> can be hit at a point in time.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hitObject">The <see cref="DrawableHitObject"/> to check.</param>
|
||||||
|
/// <param name="time">The time to check.</param>
|
||||||
|
/// <returns>Whether <paramref name="hitObject"/> can be hit at the given <paramref name="time"/>.</returns>
|
||||||
|
public bool IsHittable(DrawableHitObject hitObject, double time)
|
||||||
|
{
|
||||||
|
DrawableHitObject lastObject = hitObject;
|
||||||
|
|
||||||
|
// Get the last hitobject that can block future hits
|
||||||
|
while ((lastObject = hitObjectContainer.AliveObjects.GetPrevious(lastObject)) != null)
|
||||||
|
{
|
||||||
|
if (canBlockFutureHits(lastObject.HitObject))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there is no previous object alive, allow the hit.
|
||||||
|
if (lastObject == null)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Ensure that either the last object has received a judgement or the hit time occurs at or after the last object's start time.
|
||||||
|
// Simultaneous hitobjects are allowed to be hit at the same time value to account for edge-cases such as Centipede.
|
||||||
|
if (lastObject.Judged || time >= lastObject.HitObject.StartTime)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles a <see cref="HitObject"/> being hit to potentially miss all earlier <see cref="HitObject"/>s.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hitObject">The <see cref="HitObject"/> that was hit.</param>
|
||||||
|
public void HandleHit(HitObject hitObject)
|
||||||
|
{
|
||||||
|
if (!canBlockFutureHits(hitObject))
|
||||||
|
return;
|
||||||
|
|
||||||
|
double minimumTime = hitObject.StartTime;
|
||||||
|
|
||||||
|
foreach (var obj in hitObjectContainer.AliveObjects)
|
||||||
|
{
|
||||||
|
if (obj.HitObject.StartTime >= minimumTime)
|
||||||
|
break;
|
||||||
|
|
||||||
|
switch (obj)
|
||||||
|
{
|
||||||
|
case DrawableHitCircle circle:
|
||||||
|
miss(circle);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DrawableSlider slider:
|
||||||
|
miss(slider.HeadCircle);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void miss(DrawableOsuHitObject obj)
|
||||||
|
{
|
||||||
|
// Hitobjects that have already been judged cannot be missed.
|
||||||
|
if (obj.Judged)
|
||||||
|
return;
|
||||||
|
|
||||||
|
obj.MissForcefully();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether a <see cref="HitObject"/> blocks hits on future <see cref="HitObject"/>s until its start time is reached.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hitObject">The <see cref="HitObject"/> to test.</param>
|
||||||
|
private bool canBlockFutureHits(HitObject hitObject)
|
||||||
|
=> hitObject is HitCircle || hitObject is Slider;
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
@ -11,7 +10,6 @@ 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 osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
using osu.Game.Rulesets.Objects;
|
|
||||||
using osu.Game.Rulesets.Osu.UI.Cursor;
|
using osu.Game.Rulesets.Osu.UI.Cursor;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
|
|
||||||
@ -22,6 +20,7 @@ namespace osu.Game.Rulesets.Osu.UI
|
|||||||
private readonly ApproachCircleProxyContainer approachCircles;
|
private readonly ApproachCircleProxyContainer approachCircles;
|
||||||
private readonly JudgementContainer<DrawableOsuJudgement> judgementLayer;
|
private readonly JudgementContainer<DrawableOsuJudgement> judgementLayer;
|
||||||
private readonly FollowPointRenderer followPoints;
|
private readonly FollowPointRenderer followPoints;
|
||||||
|
private readonly OrderedHitPolicy hitPolicy;
|
||||||
|
|
||||||
public static readonly Vector2 BASE_SIZE = new Vector2(512, 384);
|
public static readonly Vector2 BASE_SIZE = new Vector2(512, 384);
|
||||||
|
|
||||||
@ -53,6 +52,8 @@ namespace osu.Game.Rulesets.Osu.UI
|
|||||||
Depth = -1,
|
Depth = -1,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
hitPolicy = new OrderedHitPolicy(HitObjectContainer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Add(DrawableHitObject h)
|
public override void Add(DrawableHitObject h)
|
||||||
@ -67,7 +68,7 @@ namespace osu.Game.Rulesets.Osu.UI
|
|||||||
base.Add(h);
|
base.Add(h);
|
||||||
|
|
||||||
DrawableOsuHitObject osuHitObject = (DrawableOsuHitObject)h;
|
DrawableOsuHitObject osuHitObject = (DrawableOsuHitObject)h;
|
||||||
osuHitObject.CheckHittable = checkHittable;
|
osuHitObject.CheckHittable = hitPolicy.IsHittable;
|
||||||
|
|
||||||
followPoints.AddFollowPoints(osuHitObject);
|
followPoints.AddFollowPoints(osuHitObject);
|
||||||
}
|
}
|
||||||
@ -82,34 +83,10 @@ namespace osu.Game.Rulesets.Osu.UI
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool checkHittable(DrawableOsuHitObject osuHitObject)
|
|
||||||
{
|
|
||||||
DrawableHitObject lastObject = osuHitObject;
|
|
||||||
|
|
||||||
// Get the last hitobject that can block future hits
|
|
||||||
while ((lastObject = HitObjectContainer.AliveObjects.GetPrevious(lastObject)) != null)
|
|
||||||
{
|
|
||||||
if (canBlockFutureHits(lastObject.HitObject))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If there is no previous object alive, allow the hit.
|
|
||||||
if (lastObject == null)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// Ensure that either the last object has received a judgement or the hit time occurs at or after the last object's start time.
|
|
||||||
// Simultaneous hitobjects are allowed to be hit at the same time value to account for edge-cases such as Centipede.
|
|
||||||
if (lastObject.Judged || Time.Current >= lastObject.HitObject.StartTime)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onNewResult(DrawableHitObject judgedObject, JudgementResult result)
|
private void onNewResult(DrawableHitObject judgedObject, JudgementResult result)
|
||||||
{
|
{
|
||||||
// Hitobjects that block future hits should miss previous hitobjects if they're hit out-of-order.
|
// Hitobjects that block future hits should miss previous hitobjects if they're hit out-of-order.
|
||||||
if (canBlockFutureHits(result.HitObject))
|
hitPolicy.HandleHit(result.HitObject);
|
||||||
missAllEarlierObjects(result.HitObject);
|
|
||||||
|
|
||||||
if (!judgedObject.DisplayResult || !DisplayJudgements.Value)
|
if (!judgedObject.DisplayResult || !DisplayJudgements.Value)
|
||||||
return;
|
return;
|
||||||
@ -124,49 +101,6 @@ namespace osu.Game.Rulesets.Osu.UI
|
|||||||
judgementLayer.Add(explosion);
|
judgementLayer.Add(explosion);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Misses all <see cref="OsuHitObject"/>s occurring earlier than the start time of a judged <see cref="OsuHitObject"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="hitObject">The marker <see cref="HitObject"/>, which all <see cref="HitObject"/>s earlier than will get missed.</param>
|
|
||||||
private void missAllEarlierObjects(HitObject hitObject)
|
|
||||||
{
|
|
||||||
double minimumTime = hitObject.StartTime;
|
|
||||||
|
|
||||||
foreach (var obj in HitObjectContainer.AliveObjects)
|
|
||||||
{
|
|
||||||
if (obj.HitObject.StartTime >= minimumTime)
|
|
||||||
break;
|
|
||||||
|
|
||||||
switch (obj)
|
|
||||||
{
|
|
||||||
case DrawableHitCircle circle:
|
|
||||||
miss(circle);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DrawableSlider slider:
|
|
||||||
miss(slider.HeadCircle);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void miss(DrawableOsuHitObject obj)
|
|
||||||
{
|
|
||||||
// Hitobjects that have already been judged cannot be missed.
|
|
||||||
if (obj.Judged)
|
|
||||||
return;
|
|
||||||
|
|
||||||
obj.MissForcefully();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Whether a <see cref="HitObject"/> can block hits on future <see cref="HitObject"/>s until its start time is reached.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="hitObject">The <see cref="HitObject"/> to test.</param>
|
|
||||||
/// <returns>Whether <paramref name="hitObject"/> can block hits on future <see cref="HitObject"/>s.</returns>
|
|
||||||
private bool canBlockFutureHits(HitObject hitObject)
|
|
||||||
=> hitObject is HitCircle || hitObject is Slider;
|
|
||||||
|
|
||||||
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => HitObjectContainer.ReceivePositionalInputAt(screenSpacePos);
|
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => HitObjectContainer.ReceivePositionalInputAt(screenSpacePos);
|
||||||
|
|
||||||
private class ApproachCircleProxyContainer : LifetimeManagementContainer
|
private class ApproachCircleProxyContainer : LifetimeManagementContainer
|
||||||
|
Loading…
Reference in New Issue
Block a user