mirror of
https://github.com/osukey/osukey.git
synced 2025-08-07 00:23:59 +09:00
Merge pull request #10268 from bdach/taiko-explosion-rework
Rework legacy taiko strong explosions to not require frame-perfect hits to show
This commit is contained in:
@ -1,21 +1,64 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System.Linq;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
|
using osu.Game.Rulesets.Taiko.Objects.Drawables;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Taiko.Skinning
|
namespace osu.Game.Rulesets.Taiko.Skinning
|
||||||
{
|
{
|
||||||
public class LegacyHitExplosion : CompositeDrawable
|
public class LegacyHitExplosion : CompositeDrawable
|
||||||
{
|
{
|
||||||
public LegacyHitExplosion(Drawable sprite)
|
private readonly Drawable sprite;
|
||||||
{
|
private readonly Drawable strongSprite;
|
||||||
InternalChild = sprite;
|
|
||||||
|
|
||||||
|
private DrawableStrongNestedHit nestedStrongHit;
|
||||||
|
private bool switchedToStrongSprite;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new legacy hit explosion.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Contrary to stable's, this implementation doesn't require a frame-perfect hit
|
||||||
|
/// for the strong sprite to be displayed.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="sprite">The normal legacy explosion sprite.</param>
|
||||||
|
/// <param name="strongSprite">The strong legacy explosion sprite.</param>
|
||||||
|
public LegacyHitExplosion(Drawable sprite, Drawable strongSprite = null)
|
||||||
|
{
|
||||||
|
this.sprite = sprite;
|
||||||
|
this.strongSprite = strongSprite;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(DrawableHitObject judgedObject)
|
||||||
|
{
|
||||||
Anchor = Anchor.Centre;
|
Anchor = Anchor.Centre;
|
||||||
Origin = Anchor.Centre;
|
Origin = Anchor.Centre;
|
||||||
|
|
||||||
AutoSizeAxes = Axes.Both;
|
AutoSizeAxes = Axes.Both;
|
||||||
|
|
||||||
|
AddInternal(sprite.With(s =>
|
||||||
|
{
|
||||||
|
s.Anchor = Anchor.Centre;
|
||||||
|
s.Origin = Anchor.Centre;
|
||||||
|
}));
|
||||||
|
|
||||||
|
if (strongSprite != null)
|
||||||
|
{
|
||||||
|
AddInternal(strongSprite.With(s =>
|
||||||
|
{
|
||||||
|
s.Alpha = 0;
|
||||||
|
s.Anchor = Anchor.Centre;
|
||||||
|
s.Origin = Anchor.Centre;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (judgedObject is DrawableHit hit)
|
||||||
|
nestedStrongHit = hit.NestedHitObjects.SingleOrDefault() as DrawableStrongNestedHit;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
@ -33,5 +76,25 @@ namespace osu.Game.Rulesets.Taiko.Skinning
|
|||||||
|
|
||||||
Expire(true);
|
Expire(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void Update()
|
||||||
|
{
|
||||||
|
base.Update();
|
||||||
|
|
||||||
|
if (shouldSwitchToStrongSprite() && !switchedToStrongSprite)
|
||||||
|
{
|
||||||
|
sprite.FadeOut(50, Easing.OutQuint);
|
||||||
|
strongSprite.FadeIn(50, Easing.OutQuint);
|
||||||
|
switchedToStrongSprite = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool shouldSwitchToStrongSprite()
|
||||||
|
{
|
||||||
|
if (nestedStrongHit == null || strongSprite == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return nestedStrongHit.IsHit;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -74,15 +74,23 @@ namespace osu.Game.Rulesets.Taiko.Skinning
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
case TaikoSkinComponents.TaikoExplosionGood:
|
|
||||||
case TaikoSkinComponents.TaikoExplosionGoodStrong:
|
|
||||||
case TaikoSkinComponents.TaikoExplosionGreat:
|
|
||||||
case TaikoSkinComponents.TaikoExplosionGreatStrong:
|
|
||||||
case TaikoSkinComponents.TaikoExplosionMiss:
|
case TaikoSkinComponents.TaikoExplosionMiss:
|
||||||
|
|
||||||
var sprite = this.GetAnimation(getHitName(taikoComponent.Component), true, false);
|
var missSprite = this.GetAnimation(getHitName(taikoComponent.Component), true, false);
|
||||||
if (sprite != null)
|
if (missSprite != null)
|
||||||
return new LegacyHitExplosion(sprite);
|
return new LegacyHitExplosion(missSprite);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
|
||||||
|
case TaikoSkinComponents.TaikoExplosionGood:
|
||||||
|
case TaikoSkinComponents.TaikoExplosionGreat:
|
||||||
|
|
||||||
|
var hitName = getHitName(taikoComponent.Component);
|
||||||
|
var hitSprite = this.GetAnimation(hitName, true, false);
|
||||||
|
var strongHitSprite = this.GetAnimation($"{hitName}k", true, false);
|
||||||
|
|
||||||
|
if (hitSprite != null)
|
||||||
|
return new LegacyHitExplosion(hitSprite, strongHitSprite);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
@ -109,17 +117,11 @@ namespace osu.Game.Rulesets.Taiko.Skinning
|
|||||||
case TaikoSkinComponents.TaikoExplosionGood:
|
case TaikoSkinComponents.TaikoExplosionGood:
|
||||||
return "taiko-hit100";
|
return "taiko-hit100";
|
||||||
|
|
||||||
case TaikoSkinComponents.TaikoExplosionGoodStrong:
|
|
||||||
return "taiko-hit100k";
|
|
||||||
|
|
||||||
case TaikoSkinComponents.TaikoExplosionGreat:
|
case TaikoSkinComponents.TaikoExplosionGreat:
|
||||||
return "taiko-hit300";
|
return "taiko-hit300";
|
||||||
|
|
||||||
case TaikoSkinComponents.TaikoExplosionGreatStrong:
|
|
||||||
return "taiko-hit300k";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ArgumentOutOfRangeException(nameof(component), "Invalid result type");
|
throw new ArgumentOutOfRangeException(nameof(component), $"Invalid component type: {component}");
|
||||||
}
|
}
|
||||||
|
|
||||||
public override SampleChannel GetSample(ISampleInfo sampleInfo) => Source.GetSample(new LegacyTaikoSampleInfo(sampleInfo));
|
public override SampleChannel GetSample(ISampleInfo sampleInfo) => Source.GetSample(new LegacyTaikoSampleInfo(sampleInfo));
|
||||||
|
@ -17,9 +17,7 @@ namespace osu.Game.Rulesets.Taiko
|
|||||||
BarLine,
|
BarLine,
|
||||||
TaikoExplosionMiss,
|
TaikoExplosionMiss,
|
||||||
TaikoExplosionGood,
|
TaikoExplosionGood,
|
||||||
TaikoExplosionGoodStrong,
|
|
||||||
TaikoExplosionGreat,
|
TaikoExplosionGreat,
|
||||||
TaikoExplosionGreatStrong,
|
|
||||||
Scroller,
|
Scroller,
|
||||||
Mascot,
|
Mascot,
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
// 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.Linq;
|
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
@ -10,7 +9,6 @@ using osu.Framework.Graphics.Containers;
|
|||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Rulesets.Taiko.Objects;
|
using osu.Game.Rulesets.Taiko.Objects;
|
||||||
using osu.Game.Rulesets.Taiko.Objects.Drawables;
|
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Taiko.UI
|
namespace osu.Game.Rulesets.Taiko.UI
|
||||||
@ -50,10 +48,10 @@ namespace osu.Game.Rulesets.Taiko.UI
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
Child = skinnable = new SkinnableDrawable(new TaikoSkinComponent(getComponentName(JudgedObject)), _ => new DefaultHitExplosion(JudgedObject, result));
|
Child = skinnable = new SkinnableDrawable(new TaikoSkinComponent(getComponentName(result)), _ => new DefaultHitExplosion(JudgedObject, result));
|
||||||
}
|
}
|
||||||
|
|
||||||
private TaikoSkinComponents getComponentName(DrawableHitObject judgedObject)
|
private static TaikoSkinComponents getComponentName(HitResult result)
|
||||||
{
|
{
|
||||||
switch (result)
|
switch (result)
|
||||||
{
|
{
|
||||||
@ -61,28 +59,13 @@ namespace osu.Game.Rulesets.Taiko.UI
|
|||||||
return TaikoSkinComponents.TaikoExplosionMiss;
|
return TaikoSkinComponents.TaikoExplosionMiss;
|
||||||
|
|
||||||
case HitResult.Good:
|
case HitResult.Good:
|
||||||
return useStrongExplosion(judgedObject)
|
return TaikoSkinComponents.TaikoExplosionGood;
|
||||||
? TaikoSkinComponents.TaikoExplosionGoodStrong
|
|
||||||
: TaikoSkinComponents.TaikoExplosionGood;
|
|
||||||
|
|
||||||
case HitResult.Great:
|
case HitResult.Great:
|
||||||
return useStrongExplosion(judgedObject)
|
return TaikoSkinComponents.TaikoExplosionGreat;
|
||||||
? TaikoSkinComponents.TaikoExplosionGreatStrong
|
|
||||||
: TaikoSkinComponents.TaikoExplosionGreat;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ArgumentOutOfRangeException(nameof(judgedObject), "Invalid result type");
|
throw new ArgumentOutOfRangeException(nameof(result), $"Invalid result type: {result}");
|
||||||
}
|
|
||||||
|
|
||||||
private bool useStrongExplosion(DrawableHitObject judgedObject)
|
|
||||||
{
|
|
||||||
if (!(judgedObject.HitObject is Hit))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!(judgedObject.NestedHitObjects.SingleOrDefault() is DrawableStrongNestedHit nestedHit))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return judgedObject.Result.Type == nestedHit.Result.Type;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -215,16 +215,12 @@ namespace osu.Game.Rulesets.Taiko.UI
|
|||||||
private void addDrumRollHit(DrawableDrumRollTick drawableTick) =>
|
private void addDrumRollHit(DrawableDrumRollTick drawableTick) =>
|
||||||
drumRollHitContainer.Add(new DrawableFlyingHit(drawableTick));
|
drumRollHitContainer.Add(new DrawableFlyingHit(drawableTick));
|
||||||
|
|
||||||
/// <remarks>
|
private void addExplosion(DrawableHitObject drawableObject, HitResult result, HitType type)
|
||||||
/// As legacy skins have different explosions for singular and double strong hits,
|
|
||||||
/// explosion addition is scheduled to ensure that both hits are processed if they occur on the same frame.
|
|
||||||
/// </remarks>
|
|
||||||
private void addExplosion(DrawableHitObject drawableObject, HitResult result, HitType type) => Schedule(() =>
|
|
||||||
{
|
{
|
||||||
hitExplosionContainer.Add(new HitExplosion(drawableObject, result));
|
hitExplosionContainer.Add(new HitExplosion(drawableObject, result));
|
||||||
if (drawableObject.HitObject.Kiai)
|
if (drawableObject.HitObject.Kiai)
|
||||||
kiaiExplosionContainer.Add(new KiaiHitExplosion(drawableObject, type));
|
kiaiExplosionContainer.Add(new KiaiHitExplosion(drawableObject, type));
|
||||||
});
|
}
|
||||||
|
|
||||||
private class ProxyContainer : LifetimeManagementContainer
|
private class ProxyContainer : LifetimeManagementContainer
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user