mirror of
https://github.com/ppy/osu.git
synced 2024-11-11 11:20:04 +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);
|
||||
|
||||
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));
|
||||
return;
|
||||
|
@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
/// Whether this <see cref="DrawableOsuHitObject"/> can be hit.
|
||||
/// If non-null, judgements will be ignored (resulting in a shake) whilst the function returns false.
|
||||
/// </summary>
|
||||
public Func<DrawableOsuHitObject, bool> CheckHittable;
|
||||
public Func<DrawableHitObject, double, bool> CheckHittable;
|
||||
|
||||
protected DrawableOsuHitObject(OsuHitObject 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.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||
using osuTK;
|
||||
using osu.Framework.Graphics;
|
||||
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.UI;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Osu.UI.Cursor;
|
||||
using osu.Game.Skinning;
|
||||
|
||||
@ -22,6 +20,7 @@ namespace osu.Game.Rulesets.Osu.UI
|
||||
private readonly ApproachCircleProxyContainer approachCircles;
|
||||
private readonly JudgementContainer<DrawableOsuJudgement> judgementLayer;
|
||||
private readonly FollowPointRenderer followPoints;
|
||||
private readonly OrderedHitPolicy hitPolicy;
|
||||
|
||||
public static readonly Vector2 BASE_SIZE = new Vector2(512, 384);
|
||||
|
||||
@ -53,6 +52,8 @@ namespace osu.Game.Rulesets.Osu.UI
|
||||
Depth = -1,
|
||||
},
|
||||
};
|
||||
|
||||
hitPolicy = new OrderedHitPolicy(HitObjectContainer);
|
||||
}
|
||||
|
||||
public override void Add(DrawableHitObject h)
|
||||
@ -67,7 +68,7 @@ namespace osu.Game.Rulesets.Osu.UI
|
||||
base.Add(h);
|
||||
|
||||
DrawableOsuHitObject osuHitObject = (DrawableOsuHitObject)h;
|
||||
osuHitObject.CheckHittable = checkHittable;
|
||||
osuHitObject.CheckHittable = hitPolicy.IsHittable;
|
||||
|
||||
followPoints.AddFollowPoints(osuHitObject);
|
||||
}
|
||||
@ -82,34 +83,10 @@ namespace osu.Game.Rulesets.Osu.UI
|
||||
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)
|
||||
{
|
||||
// Hitobjects that block future hits should miss previous hitobjects if they're hit out-of-order.
|
||||
if (canBlockFutureHits(result.HitObject))
|
||||
missAllEarlierObjects(result.HitObject);
|
||||
hitPolicy.HandleHit(result.HitObject);
|
||||
|
||||
if (!judgedObject.DisplayResult || !DisplayJudgements.Value)
|
||||
return;
|
||||
@ -124,49 +101,6 @@ namespace osu.Game.Rulesets.Osu.UI
|
||||
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);
|
||||
|
||||
private class ApproachCircleProxyContainer : LifetimeManagementContainer
|
||||
|
Loading…
Reference in New Issue
Block a user