Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow slide bodies to hit as soon as SlideTaps are judged #515

Merged
merged 2 commits into from
Nov 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 22 additions & 4 deletions osu.Game.Rulesets.Sentakki/Objects/Drawables/DrawableSlideBody.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Diagnostics;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Rulesets.Judgements;
Expand All @@ -17,9 +18,13 @@ namespace osu.Game.Rulesets.Sentakki.Objects.Drawables
{
public partial class DrawableSlideBody : DrawableSentakkiLanedHitObject
{
public override bool RemoveWhenNotAlive => false;

private new DrawableSlide ParentHitObject => (DrawableSlide)base.ParentHitObject;
public new SlideBody HitObject => (SlideBody)base.HitObject;

public override bool RemoveWhenNotAlive => false;
// This slide body can only be interacted with iff the slidetap associated with this slide is judged
public bool IsHittable => ParentHitObject is not null && ParentHitObject.SlideTaps.Child.Judged;

public Container<DrawableSlideCheckpoint> SlideCheckpoints { get; private set; } = null!;

Expand Down Expand Up @@ -49,6 +54,9 @@ public virtual float StarProgress
}
}

private static readonly Color4 inactive_color = Color4.LightGray.Darken(0.25f);
private static readonly Color4 active_color = Color4.White;

public DrawableSlideBody()
: this(null)
{
Expand All @@ -69,7 +77,7 @@ private void load()

AddRangeInternal(new Drawable[]
{
Slidepath = new SlideVisual(),
Slidepath = new SlideVisual() { Colour = inactive_color },
SlideStars = new Container<StarPiece>
{
Anchor = Anchor.Centre,
Expand Down Expand Up @@ -136,6 +144,13 @@ private void onRevertResult(DrawableHitObject hitObject, JudgementResult result)
Slidepath.UpdateChevronVisibility();
}

protected override void Update()
{
base.Update();

Slidepath.Colour = IsHittable ? active_color : inactive_color;
}

protected override void UpdateInitialTransforms()
{
base.UpdateInitialTransforms();
Expand Down Expand Up @@ -173,9 +188,10 @@ protected override void CheckForResult(bool userTriggered, double timeOffset)
{
Debug.Assert(HitObject.HitWindows != null);

// Player completed all nodes, we consider this user triggered
// We start with the assumption that the player completed all checkpoints
userTriggered = true;

// If any of the checkpoints aren't complete, we consider the slide to be incomplete
for (int i = 0; i < SlideCheckpoints.Count; ++i)
{
if (!SlideCheckpoints[i].Result.HasResult)
Expand All @@ -184,7 +200,6 @@ protected override void CheckForResult(bool userTriggered, double timeOffset)
break;
}
}

if (!userTriggered)
{
if (!HitObject.HitWindows.CanBeHit(timeOffset))
Expand All @@ -193,6 +208,7 @@ protected override void CheckForResult(bool userTriggered, double timeOffset)
foreach (var checkpoint in SlideCheckpoints)
checkpoint.ForcefullyMiss();

// Apply a leniency if the player almost completed the slide
if (SlideCheckpoints.Count(node => !node.Result.IsHit) <= 2 && SlideCheckpoints.Count > 2)
ApplyResult(HitResult.Ok);
else
Expand All @@ -203,6 +219,8 @@ protected override void CheckForResult(bool userTriggered, double timeOffset)
}

var result = HitObject.HitWindows.ResultFor(timeOffset);

// If the slide was completed before the early windows, just give an OK result
if (result == HitResult.None)
result = HitResult.Ok;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,17 @@ public partial class DrawableSlideCheckpoint : DrawableSentakkiHitObject

public override bool DisplayResult => false;

private DrawableSlideBody parentSlide => (DrawableSlideBody)ParentHitObject;
private new DrawableSlideBody ParentHitObject => (DrawableSlideBody)base.ParentHitObject;

// Used to determine the node order
public int ThisIndex;

// Hits are only possible if this the second node before this one is hit
// If the second node before this one doesn't exist, it is allowed as this is one of the first nodes
// All hits can only be done after the parent StartTime
public bool IsHittable => Time.Current > ParentHitObject.HitObject.StartTime && isPreviousNodeHit();
// All hits can only be done after the slide tap has been judged
public bool IsHittable => ParentHitObject.IsHittable && isPreviousNodeHit();

private bool isPreviousNodeHit() => ThisIndex < 1 || parentSlide.SlideCheckpoints[ThisIndex - 1].IsHit;
private bool isPreviousNodeHit() => ThisIndex < 1 || ParentHitObject.SlideCheckpoints[ThisIndex - 1].IsHit;

private Container<DrawableSlideCheckpointNode> nodes = null!;

Expand Down Expand Up @@ -60,7 +60,7 @@ protected override void OnApply()

// Nodes are applied before being added to the parent playfield, so this node isn't in SlideNodes yet
// Since we know that the node isn't in the container yet, and that the count is always one higher than the topmost element, we can use that as the predicted index
ThisIndex = parentSlide.SlideCheckpoints.Count;
ThisIndex = ParentHitObject.SlideCheckpoints.Count;
}

protected override void CheckForResult(bool userTriggered, double timeOffset)
Expand Down
Loading