Skip to content

Commit

Permalink
Merge pull request #515 from LumpBloom7/Slide-pop-in
Browse files Browse the repository at this point in the history
Allow slide bodies to hit as soon as SlideTaps are judged
  • Loading branch information
LumpBloom7 authored Nov 30, 2023
2 parents ec13e1c + 6a516f7 commit b616c7a
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 9 deletions.
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

0 comments on commit b616c7a

Please sign in to comment.