1
0
mirror of https://github.com/ppy/osu.git synced 2026-06-03 02:31:25 +08:00

Merge pull request #34606 from cl8n/sliderpoint

Add skin support for sliderpoint10 and sliderpoint30
This commit is contained in:
Bartłomiej Dach
2025-08-19 15:06:20 +02:00
committed by GitHub
Unverified
10 changed files with 233 additions and 15 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

@@ -0,0 +1,160 @@
// 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.Linq;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Graphics.Sprites;
using osu.Game.Rulesets.Osu.Judgements;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Objects.Drawables;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.UI;
using osuTK;
namespace osu.Game.Rulesets.Osu.Tests
{
public partial class TestSceneDrawableJudgementSliderTicks : OsuSkinnableTestScene
{
private bool classic;
private readonly JudgementPooler<DrawableOsuJudgement>[] judgementPools;
public TestSceneDrawableJudgementSliderTicks()
{
judgementPools = new JudgementPooler<DrawableOsuJudgement>[Rows * Cols];
}
protected override void LoadComplete()
{
base.LoadComplete();
int cellIndex = 0;
SetContents(_ =>
{
var container = new Container
{
RelativeSizeAxes = Axes.Both,
Children = new Drawable[]
{
judgementPools[cellIndex] = new JudgementPooler<DrawableOsuJudgement>(new[]
{
HitResult.Great,
HitResult.Miss,
HitResult.LargeTickHit,
HitResult.SliderTailHit,
HitResult.LargeTickMiss,
HitResult.IgnoreMiss,
}),
new GridContainer
{
Padding = new MarginPadding { Top = 26f },
RelativeSizeAxes = Axes.Both,
RowDimensions = new[] { new Dimension(GridSizeMode.AutoSize) },
ColumnDimensions = new[] { new Dimension(GridSizeMode.AutoSize) },
Content =
new[]
{
new[]
{
Empty(),
new OsuSpriteText
{
Text = "hit",
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre,
},
new OsuSpriteText
{
Text = "miss",
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre,
},
},
}.Concat(new[]
{
"head",
"tick",
"repeat",
"tail",
"slider",
}.Select(label => new Drawable[]
{
new OsuSpriteText
{
Text = label,
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight,
},
new Container<DrawableOsuJudgement> { RelativeSizeAxes = Axes.Both },
new Container<DrawableOsuJudgement> { RelativeSizeAxes = Axes.Both },
})).ToArray(),
},
},
};
cellIndex++;
return container;
});
AddToggleStep("Toggle classic behaviour", c => classic = c);
AddStep("Show judgements", createAllJudgements);
}
private void createAllJudgements()
{
for (int cellIndex = 0; cellIndex < Rows * Cols; cellIndex++)
{
var slider = new Slider { StartTime = Time.Current, ClassicSliderBehaviour = classic };
slider.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
var drawableHitObjects = new DrawableOsuHitObject[]
{
new DrawableSliderHead(new SliderHeadCircle { StartTime = Time.Current, ClassicSliderBehaviour = classic }),
new DrawableSliderTick(new SliderTick { StartTime = Time.Current }),
new DrawableSliderRepeat(new SliderRepeat(slider) { StartTime = Time.Current }),
new DrawableSliderTail(new SliderTailCircle(slider) { StartTime = Time.Current, ClassicSliderBehaviour = classic }),
new DrawableSlider(slider),
};
var containers = Cell(cellIndex).ChildrenOfType<Container<DrawableOsuJudgement>>().ToArray();
for (int i = 0; i < drawableHitObjects.Length; i++)
{
createJudgement(judgementPools[cellIndex], containers[i * 2], drawableHitObjects[i], true);
createJudgement(judgementPools[cellIndex], containers[i * 2 + 1], drawableHitObjects[i], false);
}
}
}
private void createJudgement(JudgementPooler<DrawableOsuJudgement> pool, Container<DrawableOsuJudgement> container, DrawableOsuHitObject drawableHitObject, bool hit)
{
container.Clear(false);
if (!drawableHitObject.DisplayResult)
return;
var hitObject = drawableHitObject.HitObject;
var result = new OsuJudgementResult(hitObject, hitObject.Judgement)
{
Type = hit ? hitObject.Judgement.MaxResult : hitObject.Judgement.MinResult,
};
var judgement = pool.Get(result.Type, d =>
{
d.Anchor = Anchor.Centre;
d.Origin = Anchor.Centre;
d.Scale = new Vector2(0.7f);
d.Apply(result, null);
});
if (judgement != null)
container.Add(judgement);
}
}
}
@@ -21,7 +21,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
[Resolved]
private OsuConfigManager config { get; set; } = null!;
private Vector2 screenSpacePosition;
private Vector2? screenSpacePosition;
[BackgroundDependencyLoader]
private void load()
@@ -65,7 +65,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
Lighting.ResetAnimation();
Lighting.SetColourFrom(this, Result);
Position = Parent!.ToLocalSpace(screenSpacePosition);
if (screenSpacePosition != null)
Position = Parent!.ToLocalSpace(screenSpacePosition.Value);
}
protected override void ApplyHitAnimations()
@@ -87,7 +89,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
base.ApplyHitAnimations();
}
protected override Drawable CreateDefaultJudgement(HitResult result) => new OsuJudgementPiece(result);
protected override Drawable CreateDefaultJudgement(HitResult result) =>
// Tick hits don't show a judgement by default
result.IsHit() && result.IsTick() ? Empty() : new OsuJudgementPiece(result);
private partial class OsuJudgementPiece : DefaultJudgementPiece
{
@@ -16,17 +16,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
public DrawableSlider DrawableSlider => (DrawableSlider)ParentHitObject;
public override bool DisplayResult
{
get
{
if (HitObject?.ClassicSliderBehaviour == true)
return false;
return base.DisplayResult;
}
}
private readonly IBindable<int> pathVersion = new Bindable<int>();
protected override OsuSkinComponents CirclePieceComponent => OsuSkinComponents.SliderHeadHitCircle;
@@ -3,6 +3,7 @@
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Scoring;
using osu.Game.Skinning;
using osuTK.Graphics;
@@ -42,7 +43,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
if (targetJudgement == null || targetResult == null)
Colour = Color4.White;
else
Colour = targetResult.IsHit ? targetJudgement.AccentColour : Color4.Transparent;
Colour = targetResult.IsHit && !targetResult.Type.IsTick() ? targetJudgement.AccentColour : Color4.Transparent;
}
}
}
@@ -29,6 +29,10 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon
switch (result)
{
case HitResult.LargeTickHit:
case HitResult.SliderTailHit:
return null;
case HitResult.IgnoreMiss:
case HitResult.LargeTickMiss:
return new ArgonJudgementPieceSliderTickMiss(result);
@@ -0,0 +1,23 @@
// 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.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Game.Rulesets.Judgements;
using osuTK;
namespace osu.Game.Rulesets.Osu.Skinning.Legacy
{
public partial class LegacyJudgementPieceSliderTickHit : Sprite, IAnimatableJudgement
{
public void PlayAnimation()
{
// https://github.com/peppy/osu-stable-reference/blob/0e91e49bc83fe8b21c3ba5f1eb2d5d06456eae84/osu!/GameModes/Play/Rulesets/Ruleset.cs#L804-L806
this.MoveToOffset(new Vector2(0, -10), 300, Easing.Out)
.Then()
.FadeOut(60);
}
public Drawable GetAboveHitObjectsProxiedContent() => CreateProxy();
}
}
@@ -5,7 +5,9 @@ using System;
using System.Linq;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Textures;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Scoring;
using osu.Game.Screens.Play.HUD;
using osu.Game.Skinning;
using osuTK;
@@ -115,6 +117,39 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
return null;
case SkinComponentLookup<HitResult> resultComponent:
switch (resultComponent.Component)
{
case HitResult.LargeTickHit:
case HitResult.SliderTailHit:
if (getSliderPointTexture(resultComponent.Component) is Texture texture)
return new LegacyJudgementPieceSliderTickHit { Texture = texture };
break;
// If the corresponding hit result displays a judgement and the miss texture isn't provided by this skin, don't look up the miss texture from any further skins.
case HitResult.LargeTickMiss:
case HitResult.IgnoreMiss:
if (getSliderPointTexture(resultComponent.Component == HitResult.LargeTickMiss
? HitResult.LargeTickHit
: HitResult.SliderTailHit) != null)
return base.GetDrawableComponent(lookup) ?? Drawable.Empty();
break;
}
return base.GetDrawableComponent(lookup);
Texture? getSliderPointTexture(HitResult result)
{
// https://github.com/peppy/osu-stable-reference/blob/0e91e49bc83fe8b21c3ba5f1eb2d5d06456eae84/osu!/GameModes/Play/Rulesets/Ruleset.cs#L799
if (GetConfig<SkinConfiguration.LegacySetting, decimal>(SkinConfiguration.LegacySetting.Version)?.Value < 2m)
// Note that osu!stable used sliderpoint30 for heads and repeats, and sliderpoint10 for ticks, but the mapping is intentionally changed here so that each texture represents one type of HitResult.
return GetTexture(result == HitResult.LargeTickHit ? "sliderpoint30" : "sliderpoint10");
return null;
}
case OsuSkinComponentLookup osuComponent:
switch (osuComponent.Component)
{
+2
View File
@@ -81,6 +81,8 @@ namespace osu.Game.Rulesets.Osu.UI
HitResult.Ok,
HitResult.Meh,
HitResult.Miss,
HitResult.LargeTickHit,
HitResult.SliderTailHit,
HitResult.LargeTickMiss,
HitResult.IgnoreMiss,
}, onJudgementLoaded));