Merge pull request #1233 from smoogipooo/mania-holdnote-niceness

Update osu!mania notes + hold notes with glows
This commit is contained in:
Dean Herbert 2017-09-11 17:33:03 +09:00 committed by GitHub
commit 311f4744f6
7 changed files with 222 additions and 22 deletions

View File

@ -41,8 +41,20 @@ namespace osu.Desktop.Tests.Visual
RelativeChildSize = new Vector2(1, 10000), RelativeChildSize = new Vector2(1, 10000),
Children = new[] Children = new[]
{ {
new DrawableNote(new Note { StartTime = 5000 }, ManiaAction.Key1) { AccentColour = Color4.Red }, new DrawableNote(new Note(), ManiaAction.Key1)
new DrawableNote(new Note { StartTime = 6000 }, ManiaAction.Key1) { AccentColour = Color4.Red } {
Y = 5000,
LifetimeStart = double.MinValue,
LifetimeEnd = double.MaxValue,
AccentColour = Color4.Red
},
new DrawableNote(new Note(), ManiaAction.Key1)
{
Y = 6000,
LifetimeStart = double.MinValue,
LifetimeEnd = double.MaxValue,
AccentColour = Color4.Red
}
} }
} }
} }
@ -63,11 +75,14 @@ namespace osu.Desktop.Tests.Visual
RelativeChildSize = new Vector2(1, 10000), RelativeChildSize = new Vector2(1, 10000),
Children = new[] Children = new[]
{ {
new DrawableHoldNote(new HoldNote new DrawableHoldNote(new HoldNote(), ManiaAction.Key1)
{ {
StartTime = 5000, Y = 5000,
Duration = 1000 Height = 1000,
}, ManiaAction.Key1) { AccentColour = Color4.Red } LifetimeStart = double.MinValue,
LifetimeEnd = double.MaxValue,
AccentColour = Color4.Red
}
} }
} }
} }

View File

@ -1,6 +1,7 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Extensions.Color4Extensions;
using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces; using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
@ -9,6 +10,7 @@ using OpenTK;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Game.Rulesets.Mania.Judgements; using osu.Game.Rulesets.Mania.Judgements;
using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Input.Bindings; using osu.Framework.Input.Bindings;
namespace osu.Game.Rulesets.Mania.Objects.Drawables namespace osu.Game.Rulesets.Mania.Objects.Drawables
@ -23,6 +25,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
private readonly BodyPiece bodyPiece; private readonly BodyPiece bodyPiece;
private readonly Container<DrawableHoldNoteTick> tickContainer; private readonly Container<DrawableHoldNoteTick> tickContainer;
private readonly Container glowContainer;
/// <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.
@ -42,13 +45,11 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
AddRange(new Drawable[] AddRange(new Drawable[]
{ {
// For now the body piece covers the entire height of the container
// whereas possibly in the future we don't want to extend under the head/tail.
// This will be fixed when new designs are given or the current design is finalized.
bodyPiece = new BodyPiece bodyPiece = new BodyPiece
{ {
Anchor = Anchor.TopCentre, Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre, Origin = Anchor.TopCentre,
RelativeSizeAxes = Axes.X,
}, },
tickContainer = new Container<DrawableHoldNoteTick> tickContainer = new Container<DrawableHoldNoteTick>
{ {
@ -65,6 +66,19 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
{ {
Anchor = Anchor.BottomCentre, Anchor = Anchor.BottomCentre,
Origin = Anchor.TopCentre Origin = Anchor.TopCentre
},
// The hit object itself cannot be used for the glow because the tail overshoots it
// So a specialized container that is updated to contain the tail height is used
glowContainer = new Container
{
RelativeSizeAxes = Axes.X,
Masking = true,
Child = new Box
{
RelativeSizeAxes = Axes.Both,
Alpha = 0,
AlwaysPresent = true
}
} }
}); });
@ -83,6 +97,13 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
AddNested(tail); AddNested(tail);
} }
protected override void LoadComplete()
{
base.LoadComplete();
updateGlow();
}
public override Color4 AccentColour public override Color4 AccentColour
{ {
get { return base.AccentColour; } get { return base.AccentColour; }
@ -97,13 +118,42 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
bodyPiece.AccentColour = value; bodyPiece.AccentColour = value;
head.AccentColour = value; head.AccentColour = value;
tail.AccentColour = value; tail.AccentColour = value;
updateGlow();
} }
} }
private void updateGlow()
{
if (!IsLoaded)
return;
glowContainer.EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Glow,
Colour = AccentColour.Opacity(0.5f),
Radius = 10,
Hollow = true
};
}
protected override void UpdateState(ArmedState state) protected override void UpdateState(ArmedState state)
{ {
} }
protected override void Update()
{
base.Update();
// Make the body piece not lie under the head note
bodyPiece.Y = head.Height;
bodyPiece.Height = DrawHeight - head.Height;
// Make the glowContainer "contain" the height of the tail note, keeping in mind
// that the tail note overshoots the height of this hit object
glowContainer.Height = DrawHeight + tail.Height;
}
public bool OnPressed(ManiaAction action) public bool OnPressed(ManiaAction action)
{ {
// Make sure the action happened within the body of the hold note // Make sure the action happened within the body of the hold note
@ -153,6 +203,12 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
RelativePositionAxes = Axes.None; RelativePositionAxes = Axes.None;
Y = 0; Y = 0;
// Life time managed by the parent DrawableHoldNote
LifetimeStart = double.MinValue;
LifetimeEnd = double.MaxValue;
ApplyGlow = false;
} }
public override bool OnPressed(ManiaAction action) public override bool OnPressed(ManiaAction action)
@ -190,6 +246,12 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
RelativePositionAxes = Axes.None; RelativePositionAxes = Axes.None;
Y = 0; Y = 0;
// Life time managed by the parent DrawableHoldNote
LifetimeStart = double.MinValue;
LifetimeEnd = double.MaxValue;
ApplyGlow = false;
} }
protected override ManiaJudgement CreateJudgement() => new HoldNoteTailJudgement(); protected override ManiaJudgement CreateJudgement() => new HoldNoteTailJudgement();

View File

@ -23,11 +23,6 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
/// </summary> /// </summary>
public Func<double?> HoldStartTime; public Func<double?> HoldStartTime;
/// <summary>
/// References whether the user is currently holding the hold note.
/// </summary>
public Func<bool> IsHolding;
private readonly Container glowContainer; private readonly Container glowContainer;
public DrawableHoldNoteTick(HoldNoteTick hitObject) public DrawableHoldNoteTick(HoldNoteTick hitObject)
@ -36,9 +31,15 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
Anchor = Anchor.TopCentre; Anchor = Anchor.TopCentre;
Origin = Anchor.TopCentre; Origin = Anchor.TopCentre;
Y = (float)HitObject.StartTime;
RelativeSizeAxes = Axes.X; RelativeSizeAxes = Axes.X;
Size = new Vector2(1); Size = new Vector2(1);
// Life time managed by the parent DrawableHoldNote
LifetimeStart = double.MinValue;
LifetimeEnd = double.MaxValue;
Children = new[] Children = new[]
{ {
glowContainer = new CircularContainer glowContainer = new CircularContainer
@ -112,7 +113,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
if (Judgement.Result != HitResult.None) if (Judgement.Result != HitResult.None)
return; return;
if (IsHolding?.Invoke() != true) if (HoldStartTime?.Invoke() == null)
return; return;
UpdateJudgement(true); UpdateJudgement(true);

View File

@ -1,6 +1,7 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics;
using OpenTK.Graphics; using OpenTK.Graphics;
using osu.Game.Rulesets.Mania.Judgements; using osu.Game.Rulesets.Mania.Judgements;
using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables;
@ -20,6 +21,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
protected DrawableManiaHitObject(TObject hitObject, ManiaAction? action = null) protected DrawableManiaHitObject(TObject hitObject, ManiaAction? action = null)
: base(hitObject) : base(hitObject)
{ {
RelativePositionAxes = Axes.Y;
HitObject = hitObject; HitObject = hitObject;
if (action != null) if (action != null)

View File

@ -2,8 +2,10 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System; using System;
using osu.Framework.Extensions.Color4Extensions;
using OpenTK.Graphics; using OpenTK.Graphics;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Input.Bindings; using osu.Framework.Input.Bindings;
using osu.Game.Rulesets.Mania.Judgements; using osu.Game.Rulesets.Mania.Judgements;
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces; using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
@ -16,13 +18,19 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
/// </summary> /// </summary>
public class DrawableNote : DrawableManiaHitObject<Note>, IKeyBindingHandler<ManiaAction> public class DrawableNote : DrawableManiaHitObject<Note>, IKeyBindingHandler<ManiaAction>
{ {
/// <summary>
/// Gets or sets whether this <see cref="DrawableNote"/> should apply glow to itself.
/// </summary>
protected bool ApplyGlow = true;
private readonly NotePiece headPiece; private readonly NotePiece headPiece;
public DrawableNote(Note hitObject, ManiaAction action) public DrawableNote(Note hitObject, ManiaAction action)
: base(hitObject, action) : base(hitObject, action)
{ {
RelativeSizeAxes = Axes.X; RelativeSizeAxes = Axes.X;
Height = 100; AutoSizeAxes = Axes.Y;
Masking = true;
Add(headPiece = new NotePiece Add(headPiece = new NotePiece
{ {
@ -31,6 +39,13 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
}); });
} }
protected override void LoadComplete()
{
base.LoadComplete();
updateGlow();
}
public override Color4 AccentColour public override Color4 AccentColour
{ {
get { return base.AccentColour; } get { return base.AccentColour; }
@ -41,9 +56,28 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
base.AccentColour = value; base.AccentColour = value;
headPiece.AccentColour = value; headPiece.AccentColour = value;
updateGlow();
} }
} }
private void updateGlow()
{
if (!IsLoaded)
return;
if (!ApplyGlow)
return;
EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Glow,
Colour = AccentColour.Opacity(0.5f),
Radius = 10,
Hollow = true
};
}
protected override void CheckJudgement(bool userTriggered) protected override void CheckJudgement(bool userTriggered)
{ {
if (!userTriggered) if (!userTriggered)

View File

@ -1,7 +1,10 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using osu.Framework.Caching;
using OpenTK.Graphics; using OpenTK.Graphics;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
@ -14,22 +17,61 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
/// </summary> /// </summary>
internal class BodyPiece : Container, IHasAccentColour internal class BodyPiece : Container, IHasAccentColour
{ {
private readonly Box box; private readonly Container subtractionLayer;
private readonly Drawable background;
private readonly BufferedContainer foreground;
private readonly BufferedContainer subtractionContainer;
public BodyPiece() public BodyPiece()
{ {
RelativeSizeAxes = Axes.Both; Blending = BlendingMode.Additive;
Children = new[] Children = new[]
{ {
box = new Box background = new Box { RelativeSizeAxes = Axes.Both },
foreground = new BufferedContainer
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Alpha = 0.3f CacheDrawnFrameBuffer = true,
Children = new Drawable[]
{
new Box { RelativeSizeAxes = Axes.Both },
subtractionContainer = new BufferedContainer
{
RelativeSizeAxes = Axes.Both,
// This is needed because we're blending with another object
BackgroundColour = Color4.White.Opacity(0),
CacheDrawnFrameBuffer = true,
// The 'hole' is achieved by subtracting the result of this container with the parent
Blending = new BlendingParameters { AlphaEquation = BlendingEquation.ReverseSubtract },
Child = subtractionLayer = new CircularContainer
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
// Height computed in Update
Width = 1,
Masking = true,
Child = new Box
{
RelativeSizeAxes = Axes.Both,
Alpha = 0,
AlwaysPresent = true
}
}
}
}
} }
}; };
} }
protected override void LoadComplete()
{
base.LoadComplete();
updateAccentColour();
}
private Color4 accentColour; private Color4 accentColour;
public Color4 AccentColour public Color4 AccentColour
{ {
@ -40,8 +82,51 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
return; return;
accentColour = value; accentColour = value;
box.Colour = accentColour; updateAccentColour();
} }
} }
private Cached subtractionCache = new Cached();
public override bool Invalidate(Invalidation invalidation = Invalidation.All, Drawable source = null, bool shallPropagate = true)
{
if ((invalidation & Invalidation.DrawSize) > 0)
subtractionCache.Invalidate();
return base.Invalidate(invalidation, source, shallPropagate);
}
protected override void Update()
{
base.Update();
if (!subtractionCache.IsValid)
{
subtractionLayer.Width = 5;
subtractionLayer.Height = Math.Max(0, DrawHeight - DrawWidth);
subtractionLayer.EdgeEffect = new EdgeEffectParameters
{
Colour = Color4.White,
Type = EdgeEffectType.Glow,
Radius = DrawWidth
};
foreground.ForceRedraw();
subtractionContainer.ForceRedraw();
subtractionCache.Validate();
}
}
private void updateAccentColour()
{
if (!IsLoaded)
return;
foreground.Colour = AccentColour.Opacity(0.4f);
background.Colour = AccentColour.Opacity(0.2f);
subtractionCache.Invalidate();
}
} }
} }

View File

@ -12,10 +12,11 @@ using osu.Game.Rulesets.Objects.Types;
using OpenTK.Graphics; using OpenTK.Graphics;
using osu.Game.Audio; using osu.Game.Audio;
using System.Linq; using System.Linq;
using osu.Game.Graphics;
namespace osu.Game.Rulesets.Objects.Drawables namespace osu.Game.Rulesets.Objects.Drawables
{ {
public abstract class DrawableHitObject : Container public abstract class DrawableHitObject : Container, IHasAccentColour
{ {
public readonly HitObject HitObject; public readonly HitObject HitObject;