1
0
mirror of https://github.com/ppy/osu.git synced 2025-02-03 01:22:58 +08:00

Merge pull request #8524 from smoogipoo/mania-hold-note-skinning

Add mania hold note skinning
This commit is contained in:
Dean Herbert 2020-04-01 10:26:25 +09:00 committed by GitHub
commit b41bf783d0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 174 additions and 82 deletions

View File

@ -7,12 +7,12 @@ using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
namespace osu.Game.Rulesets.Mania.Edit.Blueprints.Components namespace osu.Game.Rulesets.Mania.Edit.Blueprints.Components
{ {
public class EditBodyPiece : BodyPiece public class EditBodyPiece : DefaultBodyPiece
{ {
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuColour colours) private void load(OsuColour colours)
{ {
AccentColour = colours.Yellow; AccentColour.Value = colours.Yellow;
Background.Alpha = 0.5f; Background.Alpha = 0.5f;
Foreground.Alpha = 0; Foreground.Alpha = 0;

View File

@ -4,13 +4,13 @@
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Primitives; using osu.Framework.Graphics.Primitives;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Mania.Objects.Drawables;
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
using osu.Game.Rulesets.UI.Scrolling; using osu.Game.Rulesets.UI.Scrolling;
using osuTK; using osuTK;
using osuTK.Graphics;
namespace osu.Game.Rulesets.Mania.Edit.Blueprints namespace osu.Game.Rulesets.Mania.Edit.Blueprints
{ {
@ -42,11 +42,18 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints
{ {
new HoldNoteNoteSelectionBlueprint(DrawableObject, HoldNotePosition.Start), new HoldNoteNoteSelectionBlueprint(DrawableObject, HoldNotePosition.Start),
new HoldNoteNoteSelectionBlueprint(DrawableObject, HoldNotePosition.End), new HoldNoteNoteSelectionBlueprint(DrawableObject, HoldNotePosition.End),
new BodyPiece new Container
{ {
AccentColour = Color4.Transparent, RelativeSizeAxes = Axes.Both,
BorderColour = colours.Yellow BorderThickness = 1,
}, BorderColour = colours.Yellow,
Child = new Box
{
RelativeSizeAxes = Axes.Both,
Alpha = 0,
AlwaysPresent = true,
}
}
}; };
} }

View File

@ -25,5 +25,6 @@ namespace osu.Game.Rulesets.Mania
Note, Note,
HoldNoteHead, HoldNoteHead,
HoldNoteTail, HoldNoteTail,
HoldNoteBody,
} }
} }

View File

@ -10,6 +10,7 @@ using osu.Game.Rulesets.Objects;
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.UI.Scrolling; using osu.Game.Rulesets.UI.Scrolling;
using osu.Game.Skinning;
namespace osu.Game.Rulesets.Mania.Objects.Drawables namespace osu.Game.Rulesets.Mania.Objects.Drawables
{ {
@ -20,6 +21,10 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
{ {
public override bool DisplayResult => false; public override bool DisplayResult => false;
public IBindable<bool> IsHitting => isHitting;
private readonly Bindable<bool> isHitting = new Bindable<bool>();
public DrawableHoldNoteHead Head => headContainer.Child; public DrawableHoldNoteHead Head => headContainer.Child;
public DrawableHoldNoteTail Tail => tailContainer.Child; public DrawableHoldNoteTail Tail => tailContainer.Child;
@ -27,7 +32,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
private readonly Container<DrawableHoldNoteTail> tailContainer; private readonly Container<DrawableHoldNoteTail> tailContainer;
private readonly Container<DrawableHoldNoteTick> tickContainer; private readonly Container<DrawableHoldNoteTick> tickContainer;
private readonly BodyPiece bodyPiece; private readonly Drawable bodyPiece;
/// <summary> /// <summary>
/// Time at which the user started holding this hold note. Null if the user is not holding this hold note. /// Time at which the user started holding this hold note. Null if the user is not holding this hold note.
@ -44,18 +49,16 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
{ {
RelativeSizeAxes = Axes.X; RelativeSizeAxes = Axes.X;
AddRangeInternal(new Drawable[] AddRangeInternal(new[]
{ {
bodyPiece = new BodyPiece { RelativeSizeAxes = Axes.X }, bodyPiece = new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.HoldNoteBody), _ => new DefaultBodyPiece())
{
RelativeSizeAxes = Axes.X
},
tickContainer = new Container<DrawableHoldNoteTick> { RelativeSizeAxes = Axes.Both }, tickContainer = new Container<DrawableHoldNoteTick> { RelativeSizeAxes = Axes.Both },
headContainer = new Container<DrawableHoldNoteHead> { RelativeSizeAxes = Axes.Both }, headContainer = new Container<DrawableHoldNoteHead> { RelativeSizeAxes = Axes.Both },
tailContainer = new Container<DrawableHoldNoteTail> { RelativeSizeAxes = Axes.Both }, tailContainer = new Container<DrawableHoldNoteTail> { RelativeSizeAxes = Axes.Both },
}); });
AccentColour.BindValueChanged(colour =>
{
bodyPiece.AccentColour = colour.NewValue;
}, true);
} }
protected override void AddNestedHitObject(DrawableHitObject hitObject) protected override void AddNestedHitObject(DrawableHitObject hitObject)
@ -168,7 +171,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
return; return;
HoldStartTime = Time.Current; HoldStartTime = Time.Current;
bodyPiece.Hitting = true; isHitting.Value = true;
} }
public void OnReleased(ManiaAction action) public void OnReleased(ManiaAction action)
@ -194,7 +197,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
private void endHold() private void endHold()
{ {
HoldStartTime = null; HoldStartTime = null;
bodyPiece.Hitting = false; isHitting.Value = false;
} }
} }
} }

View File

@ -2,6 +2,9 @@
// 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 JetBrains.Annotations;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osuTK.Graphics; using osuTK.Graphics;
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
@ -9,26 +12,38 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Layout; using osu.Framework.Layout;
using osu.Game.Graphics; using osu.Game.Rulesets.Objects.Drawables;
namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
{ {
/// <summary> /// <summary>
/// Represents length-wise portion of a hold note. /// Represents length-wise portion of a hold note.
/// </summary> /// </summary>
public class BodyPiece : Container, IHasAccentColour public class DefaultBodyPiece : CompositeDrawable
{ {
private readonly Container subtractionLayer; protected readonly Bindable<Color4> AccentColour = new Bindable<Color4>();
protected readonly Drawable Background; private readonly LayoutValue subtractionCache = new LayoutValue(Invalidation.DrawSize);
protected readonly BufferedContainer Foreground; private readonly IBindable<bool> isHitting = new Bindable<bool>();
private readonly BufferedContainer subtractionContainer;
public BodyPiece() protected Drawable Background { get; private set; }
protected BufferedContainer Foreground { get; private set; }
private BufferedContainer subtractionContainer;
private Container subtractionLayer;
public DefaultBodyPiece()
{ {
RelativeSizeAxes = Axes.Both;
Blending = BlendingParameters.Additive; Blending = BlendingParameters.Additive;
Children = new[] AddLayout(subtractionCache);
}
[BackgroundDependencyLoader(true)]
private void load([CanBeNull] DrawableHitObject drawableObject)
{
InternalChildren = new[]
{ {
Background = new Box { RelativeSizeAxes = Axes.Both }, Background = new Box { RelativeSizeAxes = Axes.Both },
Foreground = new BufferedContainer Foreground = new BufferedContainer
@ -66,43 +81,37 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
} }
}; };
AddLayout(subtractionCache); if (drawableObject != null)
}
protected override void LoadComplete()
{ {
base.LoadComplete(); var holdNote = (DrawableHoldNote)drawableObject;
updateAccentColour(); AccentColour.BindTo(drawableObject.AccentColour);
isHitting.BindTo(holdNote.IsHitting);
} }
private Color4 accentColour; AccentColour.BindValueChanged(onAccentChanged, true);
isHitting.BindValueChanged(_ => onAccentChanged(new ValueChangedEvent<Color4>(AccentColour.Value, AccentColour.Value)), true);
}
public Color4 AccentColour private void onAccentChanged(ValueChangedEvent<Color4> accent)
{ {
get => accentColour; Foreground.Colour = accent.NewValue.Opacity(0.5f);
set Background.Colour = accent.NewValue.Opacity(0.7f);
const float animation_length = 50;
Foreground.ClearTransforms(false, nameof(Foreground.Colour));
if (isHitting.Value)
{ {
if (accentColour == value) // wait for the next sync point
return; double synchronisedOffset = animation_length * 2 - Time.Current % (animation_length * 2);
using (Foreground.BeginDelayedSequence(synchronisedOffset))
accentColour = value; Foreground.FadeColour(accent.NewValue.Lighten(0.2f), animation_length).Then().FadeColour(Foreground.Colour, animation_length).Loop();
updateAccentColour();
}
} }
public bool Hitting subtractionCache.Invalidate();
{
get => hitting;
set
{
hitting = value;
updateAccentColour();
} }
}
private readonly LayoutValue subtractionCache = new LayoutValue(Invalidation.DrawSize);
protected override void Update() protected override void Update()
{ {
@ -125,30 +134,5 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
subtractionCache.Validate(); subtractionCache.Validate();
} }
} }
private bool hitting;
private void updateAccentColour()
{
if (!IsLoaded)
return;
Foreground.Colour = AccentColour.Opacity(0.5f);
Background.Colour = AccentColour.Opacity(0.7f);
const float animation_length = 50;
Foreground.ClearTransforms(false, nameof(Foreground.Colour));
if (hitting)
{
// wait for the next sync point
double synchronisedOffset = animation_length * 2 - Time.Current % (animation_length * 2);
using (Foreground.BeginDelayedSequence(synchronisedOffset))
Foreground.FadeColour(AccentColour.Lighten(0.2f), animation_length).Then().FadeColour(Foreground.Colour, animation_length).Loop();
}
subtractionCache.Invalidate();
}
} }
} }

View File

@ -0,0 +1,93 @@
// 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.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Animations;
using osu.Game.Rulesets.Mania.Objects.Drawables;
using osu.Game.Rulesets.Mania.UI;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.UI.Scrolling;
using osu.Game.Skinning;
using osuTK;
namespace osu.Game.Rulesets.Mania.Skinning
{
public class LegacyBodyPiece : LegacyManiaColumnElement
{
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
private readonly IBindable<bool> isHitting = new Bindable<bool>();
private Drawable sprite;
[Resolved(CanBeNull = true)]
private ManiaStage stage { get; set; }
[Resolved]
private Column column { get; set; }
public LegacyBodyPiece()
{
RelativeSizeAxes = Axes.Both;
}
[BackgroundDependencyLoader]
private void load(ISkinSource skin, IScrollingInfo scrollingInfo, DrawableHitObject drawableObject)
{
string imageName = skin.GetConfig<LegacyManiaSkinConfigurationLookup, string>(
new LegacyManiaSkinConfigurationLookup(stage?.Columns.Count ?? 4, LegacyManiaSkinConfigurationLookups.HoldNoteBodyImage, column.Index))?.Value
?? $"mania-note{FallbackColumnIndex}L";
sprite = skin.GetAnimation(imageName, true, true).With(d =>
{
if (d == null)
return;
if (d is TextureAnimation animation)
animation.IsPlaying = false;
d.Anchor = Anchor.TopCentre;
d.RelativeSizeAxes = Axes.Both;
d.Size = Vector2.One;
d.FillMode = FillMode.Stretch;
// Todo: Wrap
});
if (sprite != null)
InternalChild = sprite;
direction.BindTo(scrollingInfo.Direction);
direction.BindValueChanged(onDirectionChanged, true);
var holdNote = (DrawableHoldNote)drawableObject;
isHitting.BindTo(holdNote.IsHitting);
isHitting.BindValueChanged(onIsHittingChanged, true);
}
private void onIsHittingChanged(ValueChangedEvent<bool> isHitting)
{
if (!(sprite is TextureAnimation animation))
return;
animation.IsPlaying = isHitting.NewValue;
}
private void onDirectionChanged(ValueChangedEvent<ScrollingDirection> direction)
{
if (sprite == null)
return;
if (direction.NewValue == ScrollingDirection.Up)
{
sprite.Origin = Anchor.BottomCentre;
sprite.Scale = new Vector2(1, -1);
}
else
{
sprite.Origin = Anchor.TopCentre;
sprite.Scale = Vector2.One;
}
}
}
}

View File

@ -61,6 +61,9 @@ namespace osu.Game.Rulesets.Mania.Skinning
case ManiaSkinComponents.HoldNoteTail: case ManiaSkinComponents.HoldNoteTail:
return new LegacyHoldNoteTailPiece(); return new LegacyHoldNoteTailPiece();
case ManiaSkinComponents.HoldNoteBody:
return new LegacyBodyPiece();
} }
break; break;

View File

@ -29,6 +29,7 @@ namespace osu.Game.Skinning
KeyImageDown, KeyImageDown,
NoteImage, NoteImage,
HoldNoteHeadImage, HoldNoteHeadImage,
HoldNoteTailImage HoldNoteTailImage,
HoldNoteBodyImage,
} }
} }