1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-14 09:32:55 +08:00

Merge pull request #13379 from ekrctb/catcher-sprite

Refactor osu!catch catcher sprite to factor out skinning logic
This commit is contained in:
Dean Herbert 2021-06-10 16:52:17 +09:00 committed by GitHub
commit 05b46b4743
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 204 additions and 126 deletions

View File

@ -8,9 +8,7 @@ namespace osu.Game.Rulesets.Catch
Fruit,
Banana,
Droplet,
CatcherIdle,
CatcherFail,
CatcherKiai,
Catcher,
CatchComboCounter
}
}

View File

@ -0,0 +1,54 @@
// 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.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
using osu.Game.Rulesets.Catch.UI;
namespace osu.Game.Rulesets.Catch.Skinning.Default
{
public class DefaultCatcher : CompositeDrawable, ICatcherSprite
{
public Bindable<CatcherAnimationState> CurrentState { get; } = new Bindable<CatcherAnimationState>();
public Texture CurrentTexture => sprite.Texture;
private readonly Sprite sprite;
private readonly Dictionary<CatcherAnimationState, Texture> textures = new Dictionary<CatcherAnimationState, Texture>();
public DefaultCatcher()
{
RelativeSizeAxes = Axes.Both;
InternalChild = sprite = new Sprite
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
RelativeSizeAxes = Axes.Both,
FillMode = FillMode.Fit
};
}
[BackgroundDependencyLoader]
private void load(TextureStore store, Bindable<CatcherAnimationState> currentState)
{
CurrentState.BindTo(currentState);
textures[CatcherAnimationState.Idle] = store.Get(@"Gameplay/catch/fruit-catcher-idle");
textures[CatcherAnimationState.Fail] = store.Get(@"Gameplay/catch/fruit-catcher-fail");
textures[CatcherAnimationState.Kiai] = store.Get(@"Gameplay/catch/fruit-catcher-kiai");
}
protected override void LoadComplete()
{
base.LoadComplete();
CurrentState.BindValueChanged(state => sprite.Texture = textures[state.NewValue], true);
}
}
}

View File

@ -0,0 +1,12 @@
// 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.Textures;
namespace osu.Game.Rulesets.Catch.Skinning
{
public interface ICatcherSprite
{
Texture CurrentTexture { get; }
}
}

View File

@ -65,17 +65,21 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy
return null;
case CatchSkinComponents.CatcherIdle:
return this.GetAnimation("fruit-catcher-idle", true, true, true) ??
this.GetAnimation("fruit-ryuuta", true, true, true);
case CatchSkinComponents.Catcher:
var version = Source.GetConfig<LegacySkinConfiguration.LegacySetting, decimal>(LegacySkinConfiguration.LegacySetting.Version)?.Value ?? 1;
case CatchSkinComponents.CatcherFail:
return this.GetAnimation("fruit-catcher-fail", true, true, true) ??
this.GetAnimation("fruit-ryuuta", true, true, true);
if (version < 2.3m)
{
if (GetTexture(@"fruit-ryuuta") != null ||
GetTexture(@"fruit-ryuuta-0") != null)
return new LegacyCatcherOld();
}
case CatchSkinComponents.CatcherKiai:
return this.GetAnimation("fruit-catcher-kiai", true, true, true) ??
this.GetAnimation("fruit-ryuuta", true, true, true);
if (GetTexture(@"fruit-catcher-idle") != null ||
GetTexture(@"fruit-catcher-idle-0") != null)
return new LegacyCatcherNew();
return null;
case CatchSkinComponents.CatchComboCounter:
if (providesComboCounter)

View File

@ -0,0 +1,73 @@
// 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;
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Animations;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
using osu.Game.Rulesets.Catch.UI;
using osu.Game.Skinning;
using osuTK;
namespace osu.Game.Rulesets.Catch.Skinning.Legacy
{
public class LegacyCatcherNew : CompositeDrawable, ICatcherSprite
{
[Resolved]
private Bindable<CatcherAnimationState> currentState { get; set; }
public Texture CurrentTexture => (currentDrawable as TextureAnimation)?.CurrentFrame ?? (currentDrawable as Sprite)?.Texture;
private readonly Dictionary<CatcherAnimationState, Drawable> drawables = new Dictionary<CatcherAnimationState, Drawable>();
private Drawable currentDrawable;
public LegacyCatcherNew()
{
RelativeSizeAxes = Axes.Both;
}
[BackgroundDependencyLoader]
private void load(ISkinSource skin)
{
foreach (var state in Enum.GetValues(typeof(CatcherAnimationState)).Cast<CatcherAnimationState>())
{
AddInternal(drawables[state] = getDrawableFor(state).With(d =>
{
d.Anchor = Anchor.TopCentre;
d.Origin = Anchor.TopCentre;
d.RelativeSizeAxes = Axes.Both;
d.Size = Vector2.One;
d.FillMode = FillMode.Fit;
d.Alpha = 0;
}));
}
currentDrawable = drawables[CatcherAnimationState.Idle];
Drawable getDrawableFor(CatcherAnimationState state) =>
skin.GetAnimation(@$"fruit-catcher-{state.ToString().ToLowerInvariant()}", true, true, true) ??
skin.GetAnimation(@"fruit-catcher-idle", true, true, true);
}
protected override void LoadComplete()
{
base.LoadComplete();
currentState.BindValueChanged(state =>
{
currentDrawable.Alpha = 0;
currentDrawable = drawables[state.NewValue];
currentDrawable.Alpha = 1;
(currentDrawable as IFramedAnimation)?.GotoFrame(0);
}, true);
}
}
}

View File

@ -0,0 +1,37 @@
// 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.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Animations;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
using osu.Game.Skinning;
using osuTK;
namespace osu.Game.Rulesets.Catch.Skinning.Legacy
{
public class LegacyCatcherOld : CompositeDrawable, ICatcherSprite
{
public Texture CurrentTexture => (InternalChild as TextureAnimation)?.CurrentFrame ?? (InternalChild as Sprite)?.Texture;
public LegacyCatcherOld()
{
RelativeSizeAxes = Axes.Both;
}
[BackgroundDependencyLoader]
private void load(ISkinSource skin)
{
InternalChild = skin.GetAnimation(@"fruit-ryuuta", true, true, true).With(d =>
{
d.Anchor = Anchor.TopCentre;
d.Origin = Anchor.TopCentre;
d.RelativeSizeAxes = Axes.Both;
d.Size = Vector2.One;
d.FillMode = FillMode.Fit;
});
}
}
}

View File

@ -7,9 +7,9 @@ using JetBrains.Annotations;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Animations;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Pooling;
using osu.Framework.Graphics.Textures;
using osu.Framework.Input.Bindings;
using osu.Framework.Utils;
using osu.Game.Beatmaps;
@ -18,6 +18,7 @@ using osu.Game.Rulesets.Catch.Judgements;
using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Catch.Objects.Drawables;
using osu.Game.Rulesets.Catch.Skinning;
using osu.Game.Rulesets.Catch.Skinning.Default;
using osu.Game.Rulesets.Judgements;
using osu.Game.Skinning;
using osuTK;
@ -78,17 +79,17 @@ namespace osu.Game.Rulesets.Catch.UI
/// </summary>
private readonly Container<CaughtObject> droppedObjectTarget;
public CatcherAnimationState CurrentState { get; private set; }
[Cached]
protected readonly Bindable<CatcherAnimationState> CurrentStateBindable = new Bindable<CatcherAnimationState>();
public CatcherAnimationState CurrentState => CurrentStateBindable.Value;
/// <summary>
/// The width of the catcher which can receive fruit. Equivalent to "catchMargin" in osu-stable.
/// </summary>
public const float ALLOWED_CATCH_RANGE = 0.8f;
/// <summary>
/// The drawable catcher for <see cref="CurrentState"/>.
/// </summary>
internal Drawable CurrentDrawableCatcher => currentCatcher.Drawable;
internal Texture CurrentTexture => ((ICatcherSprite)currentCatcher.Drawable).CurrentTexture;
private bool dashing;
@ -110,11 +111,7 @@ namespace osu.Game.Rulesets.Catch.UI
/// </summary>
private readonly float catchWidth;
private readonly CatcherSprite catcherIdle;
private readonly CatcherSprite catcherKiai;
private readonly CatcherSprite catcherFail;
private CatcherSprite currentCatcher;
private readonly SkinnableDrawable currentCatcher;
private Color4 hyperDashColour = DEFAULT_HYPER_DASH_COLOUR;
private Color4 hyperDashEndGlowColour = DEFAULT_HYPER_DASH_COLOUR;
@ -156,20 +153,12 @@ namespace osu.Game.Rulesets.Catch.UI
Anchor = Anchor.TopCentre,
Origin = Anchor.BottomCentre,
},
catcherIdle = new CatcherSprite(CatcherAnimationState.Idle)
currentCatcher = new SkinnableDrawable(
new CatchSkinComponent(CatchSkinComponents.Catcher),
_ => new DefaultCatcher())
{
Anchor = Anchor.TopCentre,
Alpha = 0,
},
catcherKiai = new CatcherSprite(CatcherAnimationState.Kiai)
{
Anchor = Anchor.TopCentre,
Alpha = 0,
},
catcherFail = new CatcherSprite(CatcherAnimationState.Fail)
{
Anchor = Anchor.TopCentre,
Alpha = 0,
OriginPosition = new Vector2(0.5f, 0.06f) * CatcherArea.CATCHER_SIZE
},
hitExplosionContainer = new HitExplosionContainer
{
@ -184,8 +173,6 @@ namespace osu.Game.Rulesets.Catch.UI
{
hitLighting = config.GetBindable<bool>(OsuSetting.HitLighting);
trails = new CatcherTrailDisplay(this);
updateCatcher();
}
protected override void LoadComplete()
@ -436,36 +423,12 @@ namespace osu.Game.Rulesets.Catch.UI
}
}
private void updateCatcher()
{
currentCatcher?.Hide();
switch (CurrentState)
{
default:
currentCatcher = catcherIdle;
break;
case CatcherAnimationState.Fail:
currentCatcher = catcherFail;
break;
case CatcherAnimationState.Kiai:
currentCatcher = catcherKiai;
break;
}
currentCatcher.Show();
(currentCatcher.Drawable as IFramedAnimation)?.GotoFrame(0);
}
private void updateState(CatcherAnimationState state)
{
if (CurrentState == state)
return;
CurrentState = state;
updateCatcher();
CurrentStateBindable.Value = state;
}
private void placeCaughtObject(DrawablePalpableCatchHitObject drawableObject, Vector2 position)

View File

@ -1,59 +0,0 @@
// 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.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
using osu.Game.Skinning;
using osuTK;
namespace osu.Game.Rulesets.Catch.UI
{
public class CatcherSprite : SkinnableDrawable
{
protected override bool ApplySizeRestrictionsToDefault => true;
public CatcherSprite(CatcherAnimationState state)
: base(new CatchSkinComponent(componentFromState(state)), _ =>
new DefaultCatcherSprite(state), confineMode: ConfineMode.ScaleToFit)
{
RelativeSizeAxes = Axes.None;
Size = new Vector2(CatcherArea.CATCHER_SIZE);
// Sets the origin roughly to the centre of the catcher's plate to allow for correct scaling.
OriginPosition = new Vector2(0.5f, 0.06f) * CatcherArea.CATCHER_SIZE;
}
private static CatchSkinComponents componentFromState(CatcherAnimationState state)
{
switch (state)
{
case CatcherAnimationState.Fail:
return CatchSkinComponents.CatcherFail;
case CatcherAnimationState.Kiai:
return CatchSkinComponents.CatcherKiai;
default:
return CatchSkinComponents.CatcherIdle;
}
}
private class DefaultCatcherSprite : Sprite
{
private readonly CatcherAnimationState state;
public DefaultCatcherSprite(CatcherAnimationState state)
{
this.state = state;
}
[BackgroundDependencyLoader]
private void load(TextureStore textures)
{
Texture = textures.Get($"Gameplay/catch/fruit-catcher-{state.ToString().ToLower()}");
}
}
}
}

View File

@ -4,10 +4,8 @@
using System;
using JetBrains.Annotations;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Animations;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Pooling;
using osu.Framework.Graphics.Sprites;
using osuTK;
using osuTK.Graphics;
@ -120,11 +118,9 @@ namespace osu.Game.Rulesets.Catch.UI
private CatcherTrailSprite createTrailSprite(Container<CatcherTrailSprite> target)
{
var texture = (catcher.CurrentDrawableCatcher as TextureAnimation)?.CurrentFrame ?? ((Sprite)catcher.CurrentDrawableCatcher).Texture;
CatcherTrailSprite sprite = trailPool.Get();
sprite.Texture = texture;
sprite.Texture = catcher.CurrentTexture;
sprite.Anchor = catcher.Anchor;
sprite.Scale = catcher.Scale;
sprite.Blending = BlendingParameters.Additive;