1
0
mirror of https://github.com/ppy/osu.git synced 2025-03-12 09:07:19 +08:00

Merge pull request #10956 from ekrctb/palpable-catch-hit-object

Move some members from `CatchHitObject` to `PalpableCatchHitObject` to make it more specific
This commit is contained in:
ekrctb 2020-11-26 15:18:05 +09:00 committed by GitHub
commit 5889b74eba
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 111 additions and 112 deletions

View File

@ -43,7 +43,7 @@ namespace osu.Game.Rulesets.Catch.Tests
hitObject.Scale = 1.5f; hitObject.Scale = 1.5f;
if (hyperdash) if (hyperdash)
hitObject.HyperDashTarget = new Banana(); ((PalpableCatchHitObject)hitObject).HyperDashTarget = new Banana();
d.Anchor = Anchor.Centre; d.Anchor = Anchor.Centre;
d.RelativePositionAxes = Axes.None; d.RelativePositionAxes = Axes.None;

View File

@ -5,11 +5,11 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets.Catch.MathUtils;
using osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Catch.UI; using osu.Game.Rulesets.Catch.UI;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Catch.MathUtils;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects.Types;
namespace osu.Game.Rulesets.Catch.Beatmaps namespace osu.Game.Rulesets.Catch.Beatmaps
{ {
@ -192,24 +192,24 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
private static void initialiseHyperDash(IBeatmap beatmap) private static void initialiseHyperDash(IBeatmap beatmap)
{ {
List<CatchHitObject> objectWithDroplets = new List<CatchHitObject>(); List<PalpableCatchHitObject> palpableObjects = new List<PalpableCatchHitObject>();
foreach (var currentObject in beatmap.HitObjects) foreach (var currentObject in beatmap.HitObjects)
{ {
if (currentObject is Fruit fruitObject) if (currentObject is Fruit fruitObject)
objectWithDroplets.Add(fruitObject); palpableObjects.Add(fruitObject);
if (currentObject is JuiceStream) if (currentObject is JuiceStream)
{ {
foreach (var currentJuiceElement in currentObject.NestedHitObjects) foreach (var juice in currentObject.NestedHitObjects)
{ {
if (!(currentJuiceElement is TinyDroplet)) if (juice is PalpableCatchHitObject palpableObject && !(juice is TinyDroplet))
objectWithDroplets.Add((CatchHitObject)currentJuiceElement); palpableObjects.Add(palpableObject);
} }
} }
} }
objectWithDroplets.Sort((h1, h2) => h1.StartTime.CompareTo(h2.StartTime)); palpableObjects.Sort((h1, h2) => h1.StartTime.CompareTo(h2.StartTime));
double halfCatcherWidth = Catcher.CalculateCatchWidth(beatmap.BeatmapInfo.BaseDifficulty) / 2; double halfCatcherWidth = Catcher.CalculateCatchWidth(beatmap.BeatmapInfo.BaseDifficulty) / 2;
@ -221,10 +221,10 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
int lastDirection = 0; int lastDirection = 0;
double lastExcess = halfCatcherWidth; double lastExcess = halfCatcherWidth;
for (int i = 0; i < objectWithDroplets.Count - 1; i++) for (int i = 0; i < palpableObjects.Count - 1; i++)
{ {
CatchHitObject currentObject = objectWithDroplets[i]; var currentObject = palpableObjects[i];
CatchHitObject nextObject = objectWithDroplets[i + 1]; var nextObject = palpableObjects[i + 1];
// Reset variables in-case values have changed (e.g. after applying HR) // Reset variables in-case values have changed (e.g. after applying HR)
currentObject.HyperDashTarget = null; currentObject.HyperDashTarget = null;

View File

@ -12,9 +12,9 @@ namespace osu.Game.Rulesets.Catch.Difficulty.Preprocessing
{ {
private const float normalized_hitobject_radius = 41.0f; private const float normalized_hitobject_radius = 41.0f;
public new CatchHitObject BaseObject => (CatchHitObject)base.BaseObject; public new PalpableCatchHitObject BaseObject => (PalpableCatchHitObject)base.BaseObject;
public new CatchHitObject LastObject => (CatchHitObject)base.LastObject; public new PalpableCatchHitObject LastObject => (PalpableCatchHitObject)base.LastObject;
public readonly float NormalizedPosition; public readonly float NormalizedPosition;
public readonly float LastNormalizedPosition; public readonly float LastNormalizedPosition;

View File

@ -27,11 +27,6 @@ namespace osu.Game.Rulesets.Catch.Objects
set => x = value; set => x = value;
} }
/// <summary>
/// Whether this object can be placed on the catcher's plate.
/// </summary>
public virtual bool CanBePlated => false;
/// <summary> /// <summary>
/// A random offset applied to <see cref="X"/>, set by the <see cref="CatchBeatmapProcessor"/>. /// A random offset applied to <see cref="X"/>, set by the <see cref="CatchBeatmapProcessor"/>.
/// </summary> /// </summary>
@ -63,13 +58,6 @@ namespace osu.Game.Rulesets.Catch.Objects
set => ComboIndexBindable.Value = value; set => ComboIndexBindable.Value = value;
} }
/// <summary>
/// Difference between the distance to the next object
/// and the distance that would have triggered a hyper dash.
/// A value close to 0 indicates a difficult jump (for difficulty calculation).
/// </summary>
public float DistanceToHyperDash { get; set; }
public Bindable<bool> LastInComboBindable { get; } = new Bindable<bool>(); public Bindable<bool> LastInComboBindable { get; } = new Bindable<bool>();
/// <summary> /// <summary>
@ -83,16 +71,6 @@ namespace osu.Game.Rulesets.Catch.Objects
public float Scale { get; set; } = 1; public float Scale { get; set; } = 1;
/// <summary>
/// Whether this fruit can initiate a hyperdash.
/// </summary>
public bool HyperDash => HyperDashTarget != null;
/// <summary>
/// The target fruit if we are to initiate a hyperdash.
/// </summary>
public CatchHitObject HyperDashTarget;
protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
{ {
base.ApplyDefaultsToSelf(controlPointInfo, difficulty); base.ApplyDefaultsToSelf(controlPointInfo, difficulty);
@ -105,14 +83,6 @@ namespace osu.Game.Rulesets.Catch.Objects
protected override HitWindows CreateHitWindows() => HitWindows.Empty; protected override HitWindows CreateHitWindows() => HitWindows.Empty;
} }
/// <summary>
/// Represents a single object that can be caught by the catcher.
/// </summary>
public abstract class PalpableCatchHitObject : CatchHitObject
{
public override bool CanBePlated => true;
}
public enum FruitVisualRepresentation public enum FruitVisualRepresentation
{ {
Pear, Pear,

View File

@ -2,55 +2,16 @@
// 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 System; using System;
using System.Collections.Generic;
using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Rulesets.Catch.UI; using osu.Game.Rulesets.Catch.UI;
using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Rulesets.Catch.Objects.Drawables namespace osu.Game.Rulesets.Catch.Objects.Drawables
{ {
public abstract class PalpableDrawableCatchHitObject : DrawableCatchHitObject
{
protected Container ScaleContainer { get; private set; }
protected PalpableDrawableCatchHitObject(CatchHitObject hitObject)
: base(hitObject)
{
Origin = Anchor.Centre;
Size = new Vector2(CatchHitObject.OBJECT_RADIUS * 2);
Masking = false;
}
[BackgroundDependencyLoader]
private void load()
{
AddRangeInternal(new Drawable[]
{
ScaleContainer = new Container
{
RelativeSizeAxes = Axes.Both,
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
}
});
ScaleContainer.Scale = new Vector2(HitObject.Scale);
}
protected override Color4 GetComboColour(IReadOnlyList<Color4> comboColours) =>
comboColours[(HitObject.IndexInBeatmap + 1) % comboColours.Count];
}
public abstract class DrawableCatchHitObject : DrawableHitObject<CatchHitObject> public abstract class DrawableCatchHitObject : DrawableHitObject<CatchHitObject>
{ {
protected override double InitialLifetimeOffset => HitObject.TimePreempt; protected override double InitialLifetimeOffset => HitObject.TimePreempt;
public virtual bool StaysOnPlate => HitObject.CanBePlated;
public float DisplayRadius => DrawSize.X / 2 * Scale.X * HitObject.Scale; public float DisplayRadius => DrawSize.X / 2 * Scale.X * HitObject.Scale;
protected override float SamplePlaybackPosition => HitObject.X / CatchPlayfield.WIDTH; protected override float SamplePlaybackPosition => HitObject.X / CatchPlayfield.WIDTH;

View File

@ -8,7 +8,7 @@ using osu.Game.Skinning;
namespace osu.Game.Rulesets.Catch.Objects.Drawables namespace osu.Game.Rulesets.Catch.Objects.Drawables
{ {
public class DrawableDroplet : PalpableDrawableCatchHitObject public class DrawableDroplet : DrawablePalpableCatchHitObject
{ {
public override bool StaysOnPlate => false; public override bool StaysOnPlate => false;

View File

@ -8,7 +8,7 @@ using osu.Game.Skinning;
namespace osu.Game.Rulesets.Catch.Objects.Drawables namespace osu.Game.Rulesets.Catch.Objects.Drawables
{ {
public class DrawableFruit : PalpableDrawableCatchHitObject public class DrawableFruit : DrawablePalpableCatchHitObject
{ {
public DrawableFruit(CatchHitObject h) public DrawableFruit(CatchHitObject h)
: base(h) : base(h)

View File

@ -0,0 +1,47 @@
// 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 System.Collections.Generic;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Rulesets.Catch.Objects.Drawables
{
public abstract class DrawablePalpableCatchHitObject : DrawableCatchHitObject
{
public new PalpableCatchHitObject HitObject => (PalpableCatchHitObject)base.HitObject;
/// <summary>
/// Whether this hit object should stay on the catcher plate when the object is caught by the catcher.
/// </summary>
public virtual bool StaysOnPlate => true;
protected readonly Container ScaleContainer;
protected DrawablePalpableCatchHitObject(CatchHitObject h)
: base(h)
{
Origin = Anchor.Centre;
Size = new Vector2(CatchHitObject.OBJECT_RADIUS * 2);
AddInternal(ScaleContainer = new Container
{
RelativeSizeAxes = Axes.Both,
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
});
}
[BackgroundDependencyLoader]
private void load()
{
ScaleContainer.Scale = new Vector2(HitObject.Scale);
}
protected override Color4 GetComboColour(IReadOnlyList<Color4> comboColours) =>
comboColours[(HitObject.IndexInBeatmap + 1) % comboColours.Count];
}
}

View File

@ -22,8 +22,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(DrawableHitObject drawableObject) private void load(DrawableHitObject drawableObject)
{ {
DrawableCatchHitObject drawableCatchObject = (DrawableCatchHitObject)drawableObject; var drawableCatchObject = (DrawablePalpableCatchHitObject)drawableObject;
var hitObject = drawableCatchObject.HitObject;
InternalChild = new Pulp InternalChild = new Pulp
{ {
@ -31,7 +30,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
AccentColour = { BindTarget = drawableObject.AccentColour } AccentColour = { BindTarget = drawableObject.AccentColour }
}; };
if (hitObject.HyperDash) if (drawableCatchObject.HitObject.HyperDash)
{ {
AddInternal(new Container AddInternal(new Container
{ {

View File

@ -20,7 +20,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
public const float RADIUS_ADJUST = 1.1f; public const float RADIUS_ADJUST = 1.1f;
private Circle border; private Circle border;
private CatchHitObject hitObject; private PalpableCatchHitObject hitObject;
public FruitPiece() public FruitPiece()
{ {
@ -30,12 +30,12 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(DrawableHitObject drawableObject) private void load(DrawableHitObject drawableObject)
{ {
DrawableCatchHitObject drawableCatchObject = (DrawableCatchHitObject)drawableObject; var drawableCatchObject = (DrawablePalpableCatchHitObject)drawableObject;
hitObject = drawableCatchObject.HitObject; hitObject = drawableCatchObject.HitObject;
AddRangeInternal(new[] AddRangeInternal(new[]
{ {
getFruitFor(drawableCatchObject.HitObject.VisualRepresentation), getFruitFor(hitObject.VisualRepresentation),
border = new Circle border = new Circle
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,

View File

@ -0,0 +1,29 @@
// 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.
namespace osu.Game.Rulesets.Catch.Objects
{
/// <summary>
/// Represents a single object that can be caught by the catcher.
/// This includes normal fruits, droplets, and bananas but excludes objects that act only as a container of nested hit objects.
/// </summary>
public abstract class PalpableCatchHitObject : CatchHitObject
{
/// <summary>
/// Difference between the distance to the next object
/// and the distance that would have triggered a hyper dash.
/// A value close to 0 indicates a difficult jump (for difficulty calculation).
/// </summary>
public float DistanceToHyperDash { get; set; }
/// <summary>
/// Whether this fruit can initiate a hyperdash.
/// </summary>
public bool HyperDash => HyperDashTarget != null;
/// <summary>
/// The target fruit if we are to initiate a hyperdash.
/// </summary>
public CatchHitObject HyperDashTarget;
}
}

View File

@ -40,7 +40,7 @@ namespace osu.Game.Rulesets.Catch.Replays
float lastPosition = CatchPlayfield.CENTER_X; float lastPosition = CatchPlayfield.CENTER_X;
double lastTime = 0; double lastTime = 0;
void moveToNext(CatchHitObject h) void moveToNext(PalpableCatchHitObject h)
{ {
float positionChange = Math.Abs(lastPosition - h.X); float positionChange = Math.Abs(lastPosition - h.X);
double timeAvailable = h.StartTime - lastTime; double timeAvailable = h.StartTime - lastTime;
@ -101,23 +101,16 @@ namespace osu.Game.Rulesets.Catch.Replays
foreach (var obj in Beatmap.HitObjects) foreach (var obj in Beatmap.HitObjects)
{ {
switch (obj) if (obj is PalpableCatchHitObject palpableObject)
{ {
case Fruit _: moveToNext(palpableObject);
moveToNext(obj);
break;
} }
foreach (var nestedObj in obj.NestedHitObjects.Cast<CatchHitObject>()) foreach (var nestedObj in obj.NestedHitObjects.Cast<CatchHitObject>())
{ {
switch (nestedObj) if (nestedObj is PalpableCatchHitObject palpableNestedObject)
{ {
case Banana _: moveToNext(palpableNestedObject);
case TinyDroplet _:
case Droplet _:
case Fruit _:
moveToNext(nestedObj);
break;
} }
} }
} }

View File

@ -31,7 +31,7 @@ namespace osu.Game.Rulesets.Catch.Skinning
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(DrawableHitObject drawableObject, ISkinSource skin) private void load(DrawableHitObject drawableObject, ISkinSource skin)
{ {
DrawableCatchHitObject drawableCatchObject = (DrawableCatchHitObject)drawableObject; var drawableCatchObject = (DrawablePalpableCatchHitObject)drawableObject;
accentColour.BindTo(drawableCatchObject.AccentColour); accentColour.BindTo(drawableCatchObject.AccentColour);

View File

@ -220,11 +220,11 @@ namespace osu.Game.Rulesets.Catch.UI
/// <summary> /// <summary>
/// Let the catcher attempt to catch a fruit. /// Let the catcher attempt to catch a fruit.
/// </summary> /// </summary>
/// <param name="fruit">The fruit to catch.</param> /// <param name="hitObject">The fruit to catch.</param>
/// <returns>Whether the catch is possible.</returns> /// <returns>Whether the catch is possible.</returns>
public bool AttemptCatch(CatchHitObject fruit) public bool AttemptCatch(CatchHitObject hitObject)
{ {
if (!fruit.CanBePlated) if (!(hitObject is PalpableCatchHitObject fruit))
return false; return false;
var halfCatchWidth = catchWidth * 0.5f; var halfCatchWidth = catchWidth * 0.5f;

View File

@ -51,7 +51,7 @@ namespace osu.Game.Rulesets.Catch.UI
}; };
} }
public void OnNewResult(DrawableCatchHitObject fruit, JudgementResult result) public void OnNewResult(DrawableCatchHitObject hitObject, JudgementResult result)
{ {
if (!result.Type.IsScorable()) if (!result.Type.IsScorable())
return; return;
@ -69,7 +69,7 @@ namespace osu.Game.Rulesets.Catch.UI
lastPlateableFruit.OnLoadComplete += _ => action(); lastPlateableFruit.OnLoadComplete += _ => action();
} }
if (result.IsHit && fruit.HitObject.CanBePlated) if (result.IsHit && hitObject is DrawablePalpableCatchHitObject fruit)
{ {
// create a new (cloned) fruit to stay on the plate. the original is faded out immediately. // create a new (cloned) fruit to stay on the plate. the original is faded out immediately.
var caughtFruit = (DrawableCatchHitObject)CreateDrawableRepresentation?.Invoke(fruit.HitObject); var caughtFruit = (DrawableCatchHitObject)CreateDrawableRepresentation?.Invoke(fruit.HitObject);
@ -77,7 +77,7 @@ namespace osu.Game.Rulesets.Catch.UI
if (caughtFruit == null) return; if (caughtFruit == null) return;
caughtFruit.RelativePositionAxes = Axes.None; caughtFruit.RelativePositionAxes = Axes.None;
caughtFruit.Position = new Vector2(MovableCatcher.ToLocalSpace(fruit.ScreenSpaceDrawQuad.Centre).X - MovableCatcher.DrawSize.X / 2, 0); caughtFruit.Position = new Vector2(MovableCatcher.ToLocalSpace(hitObject.ScreenSpaceDrawQuad.Centre).X - MovableCatcher.DrawSize.X / 2, 0);
caughtFruit.IsOnPlate = true; caughtFruit.IsOnPlate = true;
caughtFruit.Anchor = Anchor.TopCentre; caughtFruit.Anchor = Anchor.TopCentre;
@ -93,7 +93,7 @@ namespace osu.Game.Rulesets.Catch.UI
runAfterLoaded(() => MovableCatcher.Explode(caughtFruit)); runAfterLoaded(() => MovableCatcher.Explode(caughtFruit));
} }
if (fruit.HitObject.LastInCombo) if (hitObject.HitObject.LastInCombo)
{ {
if (result.Judgement is CatchJudgement catchJudgement && catchJudgement.ShouldExplodeFor(result)) if (result.Judgement is CatchJudgement catchJudgement && catchJudgement.ShouldExplodeFor(result))
runAfterLoaded(() => MovableCatcher.Explode()); runAfterLoaded(() => MovableCatcher.Explode());
@ -101,7 +101,7 @@ namespace osu.Game.Rulesets.Catch.UI
MovableCatcher.Drop(); MovableCatcher.Drop();
} }
comboDisplay.OnNewResult(fruit, result); comboDisplay.OnNewResult(hitObject, result);
} }
public void OnRevertResult(DrawableCatchHitObject fruit, JudgementResult result) public void OnRevertResult(DrawableCatchHitObject fruit, JudgementResult result)