1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-19 02:52:55 +08:00

Merge remote-tracking branch 'origin/beatmap-info' into beatmap-info

This commit is contained in:
C0D3 M4513R 2022-11-03 18:55:06 +01:00
commit 21effc5f54
No known key found for this signature in database
GPG Key ID: 3FF32B5F41A39834
51 changed files with 337 additions and 333 deletions

View File

@ -30,23 +30,24 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning
Origin = Anchor.Centre,
}));
AddStep("Rim hit", () => SetContents(_ => new DrawableHit(createHitAtCurrentTime())
AddStep("Rim hit", () => SetContents(_ => new DrawableHit(createHitAtCurrentTime(rim: true))
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
}));
AddStep("Rim hit (strong)", () => SetContents(_ => new DrawableHit(createHitAtCurrentTime(true))
AddStep("Rim hit (strong)", () => SetContents(_ => new DrawableHit(createHitAtCurrentTime(true, true))
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
}));
}
private Hit createHitAtCurrentTime(bool strong = false)
private Hit createHitAtCurrentTime(bool strong = false, bool rim = false)
{
var hit = new Hit
{
Type = rim ? HitType.Rim : HitType.Centre,
IsStrong = strong,
StartTime = Time.Current + 3000,
};

View File

@ -13,6 +13,7 @@ using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.Taiko.Objects;
using osu.Game.Rulesets.Taiko.UI;
using osu.Game.Screens.Ranking;
namespace osu.Game.Rulesets.Taiko.Tests.Skinning
{
@ -49,11 +50,19 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning
// the hit needs to be added to hierarchy in order for nested objects to be created correctly.
// setting zero alpha is supposed to prevent the test from looking broken.
hit.With(h => h.Alpha = 0),
new HitExplosion(hit.Type)
new AspectContainer
{
RelativeSizeAxes = Axes.X,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
}.With(explosion => explosion.Apply(hit))
Child =
new HitExplosion(hit.Type)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
}.With(explosion => explosion.Apply(hit))
}
}
};
}

View File

@ -41,12 +41,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Default
Children = new[]
{
new CircularContainer
{
RelativeSizeAxes = Axes.Both,
Masking = true,
Children = new[] { new Box { RelativeSizeAxes = Axes.Both } }
}
new Circle { RelativeSizeAxes = Axes.Both }
};
}
}

View File

@ -1,9 +1,6 @@
// 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.
#nullable disable
using JetBrains.Annotations;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
@ -12,19 +9,19 @@ using osu.Game.Graphics;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.Taiko.Objects;
using osu.Game.Rulesets.Taiko.UI;
using osuTK.Graphics;
namespace osu.Game.Rulesets.Taiko.UI
namespace osu.Game.Rulesets.Taiko.Skinning.Default
{
internal class DefaultHitExplosion : CircularContainer, IAnimatableHitExplosion
{
private readonly HitResult result;
[CanBeNull]
private Box body;
private Box? body;
[Resolved]
private OsuColour colours { get; set; }
private OsuColour colours { get; set; } = null!;
public DefaultHitExplosion(HitResult result)
{
@ -58,7 +55,7 @@ namespace osu.Game.Rulesets.Taiko.UI
updateColour();
}
private void updateColour([CanBeNull] DrawableHitObject judgedObject = null)
private void updateColour(DrawableHitObject? judgedObject = null)
{
if (body == null)
return;

View File

@ -0,0 +1,181 @@
// 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.
#nullable disable
using System;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
using osu.Framework.Input.Bindings;
using osu.Framework.Input.Events;
using osu.Game.Graphics;
using osu.Game.Screens.Ranking;
using osuTK;
namespace osu.Game.Rulesets.Taiko.Skinning.Default
{
public class DefaultInputDrum : AspectContainer
{
public DefaultInputDrum()
{
RelativeSizeAxes = Axes.Y;
}
[BackgroundDependencyLoader]
private void load()
{
const float middle_split = 0.025f;
InternalChild = new Container
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Scale = new Vector2(0.9f),
Children = new[]
{
new TaikoHalfDrum(false)
{
Name = "Left Half",
Anchor = Anchor.Centre,
Origin = Anchor.CentreRight,
RelativeSizeAxes = Axes.Both,
RelativePositionAxes = Axes.X,
X = -middle_split / 2,
RimAction = TaikoAction.LeftRim,
CentreAction = TaikoAction.LeftCentre
},
new TaikoHalfDrum(true)
{
Name = "Right Half",
Anchor = Anchor.Centre,
Origin = Anchor.CentreLeft,
RelativeSizeAxes = Axes.Both,
RelativePositionAxes = Axes.X,
X = middle_split / 2,
RimAction = TaikoAction.RightRim,
CentreAction = TaikoAction.RightCentre
}
}
};
}
/// <summary>
/// A half-drum. Contains one centre and one rim hit.
/// </summary>
private class TaikoHalfDrum : Container, IKeyBindingHandler<TaikoAction>
{
/// <summary>
/// The key to be used for the rim of the half-drum.
/// </summary>
public TaikoAction RimAction;
/// <summary>
/// The key to be used for the centre of the half-drum.
/// </summary>
public TaikoAction CentreAction;
private readonly Sprite rim;
private readonly Sprite rimHit;
private readonly Sprite centre;
private readonly Sprite centreHit;
public TaikoHalfDrum(bool flipped)
{
Masking = true;
Children = new Drawable[]
{
rim = new Sprite
{
Anchor = flipped ? Anchor.CentreLeft : Anchor.CentreRight,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both
},
rimHit = new Sprite
{
Anchor = flipped ? Anchor.CentreLeft : Anchor.CentreRight,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Alpha = 0,
Blending = BlendingParameters.Additive,
},
centre = new Sprite
{
Anchor = flipped ? Anchor.CentreLeft : Anchor.CentreRight,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Size = new Vector2(0.7f)
},
centreHit = new Sprite
{
Anchor = flipped ? Anchor.CentreLeft : Anchor.CentreRight,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Size = new Vector2(0.7f),
Alpha = 0,
Blending = BlendingParameters.Additive
}
};
}
[BackgroundDependencyLoader]
private void load(TextureStore textures, OsuColour colours)
{
rim.Texture = textures.Get(@"Gameplay/taiko/taiko-drum-outer");
rimHit.Texture = textures.Get(@"Gameplay/taiko/taiko-drum-outer-hit");
centre.Texture = textures.Get(@"Gameplay/taiko/taiko-drum-inner");
centreHit.Texture = textures.Get(@"Gameplay/taiko/taiko-drum-inner-hit");
rimHit.Colour = colours.Blue;
centreHit.Colour = colours.Pink;
}
public bool OnPressed(KeyBindingPressEvent<TaikoAction> e)
{
Drawable target = null;
Drawable back = null;
if (e.Action == CentreAction)
{
target = centreHit;
back = centre;
}
else if (e.Action == RimAction)
{
target = rimHit;
back = rim;
}
if (target != null)
{
const float scale_amount = 0.05f;
const float alpha_amount = 0.5f;
const float down_time = 40;
const float up_time = 1000;
back.ScaleTo(target.Scale.X - scale_amount, down_time, Easing.OutQuint)
.Then()
.ScaleTo(1, up_time, Easing.OutQuint);
target.Animate(
t => t.ScaleTo(target.Scale.X - scale_amount, down_time, Easing.OutQuint),
t => t.FadeTo(Math.Min(target.Alpha + alpha_amount, 1), down_time, Easing.OutQuint)
).Then(
t => t.ScaleTo(1, up_time, Easing.OutQuint),
t => t.FadeOut(up_time, Easing.OutQuint)
);
}
return false;
}
public void OnReleased(KeyBindingReleaseEvent<TaikoAction> e)
{
}
}
}
}

View File

@ -1,9 +1,6 @@
// 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.
#nullable disable
using osuTK;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
@ -11,8 +8,9 @@ using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics;
using osu.Game.Rulesets.Taiko.Objects;
using osuTK;
namespace osu.Game.Rulesets.Taiko.UI
namespace osu.Game.Rulesets.Taiko.Skinning.Default
{
public class DefaultKiaiHitExplosion : CircularContainer
{

View File

@ -1,8 +1,6 @@
// 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.
#nullable disable
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Game.Graphics;

View File

@ -1,8 +1,6 @@
// 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.
#nullable disable
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;

View File

@ -1,8 +1,6 @@
// 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.
#nullable disable
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;

View File

@ -1,8 +1,6 @@
// 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.
#nullable disable
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;

View File

@ -1,8 +1,6 @@
// 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.
#nullable disable
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;

View File

@ -1,8 +1,6 @@
// 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.
#nullable disable
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Animations;
@ -19,7 +17,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy
{
public class LegacyCirclePiece : CompositeDrawable, IHasAccentColour
{
private Drawable backgroundLayer;
private Drawable backgroundLayer = null!;
// required for editor blueprints (not sure why these circle pieces are zero size).
public override Quad ScreenSpaceDrawQuad => backgroundLayer.ScreenSpaceDrawQuad;
@ -32,7 +30,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy
[BackgroundDependencyLoader]
private void load(ISkinSource skin, DrawableHitObject drawableHitObject)
{
Drawable getDrawableFor(string lookup)
Drawable? getDrawableFor(string lookup)
{
const string normal_hit = "taikohit";
const string big_hit = "taikobig";

View File

@ -1,8 +1,6 @@
// 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.
#nullable disable
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
@ -28,11 +26,11 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy
}
}
private LegacyCirclePiece headCircle;
private LegacyCirclePiece headCircle = null!;
private Sprite body;
private Sprite body = null!;
private Sprite tailCircle;
private Sprite tailCircle = null!;
public LegacyDrumRoll()
{

View File

@ -1,8 +1,6 @@
// 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.
#nullable disable
using osu.Framework.Allocation;
using osu.Game.Skinning;
using osuTK.Graphics;

View File

@ -1,9 +1,6 @@
// 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.
#nullable disable
using JetBrains.Annotations;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Animations;
@ -17,8 +14,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy
{
private readonly Drawable sprite;
[CanBeNull]
private readonly Drawable strongSprite;
private readonly Drawable? strongSprite;
/// <summary>
/// Creates a new legacy hit explosion.
@ -29,7 +25,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy
/// </remarks>
/// <param name="sprite">The normal legacy explosion sprite.</param>
/// <param name="strongSprite">The strong legacy explosion sprite.</param>
public LegacyHitExplosion(Drawable sprite, [CanBeNull] Drawable strongSprite = null)
public LegacyHitExplosion(Drawable sprite, Drawable? strongSprite = null)
{
this.sprite = sprite;
this.strongSprite = strongSprite;

View File

@ -1,8 +1,6 @@
// 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.
#nullable disable
using System;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
@ -20,9 +18,9 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy
/// </summary>
internal class LegacyInputDrum : Container
{
private Container content;
private LegacyHalfDrum left;
private LegacyHalfDrum right;
private Container content = null!;
private LegacyHalfDrum left = null!;
private LegacyHalfDrum right = null!;
public LegacyInputDrum()
{
@ -142,7 +140,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy
public bool OnPressed(KeyBindingPressEvent<TaikoAction> e)
{
Drawable target = null;
Drawable? target = null;
if (e.Action == CentreAction)
{

View File

@ -1,8 +1,6 @@
// 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.
#nullable disable
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
@ -27,7 +25,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy
}
[BackgroundDependencyLoader(true)]
private void load(GameplayState gameplayState)
private void load(GameplayState? gameplayState)
{
if (gameplayState != null)
((IBindable<JudgementResult>)LastResult).BindTo(gameplayState.LastJudgementResult);
@ -91,8 +89,8 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy
private class ScrollerSprite : CompositeDrawable
{
private Sprite passingSprite;
private Sprite failingSprite;
private Sprite passingSprite = null!;
private Sprite failingSprite = null!;
private bool passing = true;

View File

@ -1,8 +1,6 @@
// 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.
#nullable disable
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
@ -15,7 +13,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy
{
public class TaikoLegacyHitTarget : CompositeDrawable
{
private Container content;
private Container content = null!;
[BackgroundDependencyLoader]
private void load(ISkinSource skin)

View File

@ -1,8 +1,6 @@
// 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.
#nullable disable
using osu.Framework.Allocation;
using osu.Framework.Audio.Track;
using osu.Framework.Graphics;
@ -16,7 +14,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy
{
public class TaikoLegacyPlayfieldBackgroundRight : BeatSyncedContainer
{
private Sprite kiai;
private Sprite kiai = null!;
private bool kiaiDisplayed;

View File

@ -1,8 +1,6 @@
// 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.
#nullable disable
using osu.Game.Skinning;
namespace osu.Game.Rulesets.Taiko

View File

@ -1,8 +1,6 @@
// 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.
#nullable disable
namespace osu.Game.Rulesets.Taiko
{
public enum TaikoSkinComponents

View File

@ -1,8 +1,6 @@
// 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.
#nullable disable
using osu.Framework.Allocation;
using osu.Game.Rulesets.Taiko.Objects;
using osu.Game.Rulesets.Taiko.Objects.Drawables;

View File

@ -1,8 +1,6 @@
// 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.
#nullable disable
using osu.Framework.Graphics;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Scoring;

View File

@ -1,8 +1,6 @@
// 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.
#nullable disable
using System.Collections.Generic;
using osu.Framework.Allocation;
using osu.Framework.Audio.Track;
@ -24,7 +22,8 @@ namespace osu.Game.Rulesets.Taiko.UI
public readonly Bindable<JudgementResult> LastResult;
private readonly Dictionary<TaikoMascotAnimationState, TaikoMascotAnimation> animations;
private TaikoMascotAnimation currentAnimation;
private TaikoMascotAnimation? currentAnimation;
private bool lastObjectHit = true;
private bool kiaiMode;
@ -40,7 +39,7 @@ namespace osu.Game.Rulesets.Taiko.UI
}
[BackgroundDependencyLoader(true)]
private void load(GameplayState gameplayState)
private void load(GameplayState? gameplayState)
{
InternalChildren = new[]
{

View File

@ -1,8 +1,6 @@
// 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.
#nullable disable
using osu.Game.Rulesets.Taiko.Objects.Drawables;
using osu.Game.Rulesets.UI.Scrolling;

View File

@ -1,8 +1,6 @@
// 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.
#nullable disable
using System;
using osu.Game.Audio;
using osu.Game.Rulesets.Taiko.Objects;

View File

@ -1,10 +1,7 @@
// 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.
#nullable disable
using System;
using JetBrains.Annotations;
using osuTK;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
@ -13,6 +10,7 @@ using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.Taiko.Objects;
using osu.Game.Rulesets.Taiko.Skinning.Default;
using osu.Game.Skinning;
namespace osu.Game.Rulesets.Taiko.UI
@ -29,10 +27,9 @@ namespace osu.Game.Rulesets.Taiko.UI
private double? secondHitTime;
[CanBeNull]
public DrawableHitObject JudgedObject;
public DrawableHitObject? JudgedObject;
private SkinnableDrawable skinnable;
private SkinnableDrawable skinnable = null!;
/// <summary>
/// This constructor only exists to meet the <c>new()</c> type constraint of <see cref="DrawablePool{T}"/>.
@ -62,7 +59,7 @@ namespace osu.Game.Rulesets.Taiko.UI
skinnable.OnSkinChanged += runAnimation;
}
public void Apply([CanBeNull] DrawableHitObject drawableHitObject)
public void Apply(DrawableHitObject? drawableHitObject)
{
JudgedObject = drawableHitObject;
secondHitTime = null;

View File

@ -1,8 +1,6 @@
// 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.
#nullable disable
using osu.Framework.Graphics.Pooling;
using osu.Game.Rulesets.Scoring;

View File

@ -1,8 +1,6 @@
// 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.
#nullable disable
using osu.Game.Rulesets.Objects.Drawables;
namespace osu.Game.Rulesets.Taiko.UI

View File

@ -1,20 +1,11 @@
// 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.
#nullable disable
using System;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
using osu.Framework.Input.Bindings;
using osu.Framework.Input.Events;
using osu.Game.Graphics;
using osu.Game.Screens.Ranking;
using osu.Game.Rulesets.Taiko.Skinning.Default;
using osu.Game.Skinning;
using osuTK;
namespace osu.Game.Rulesets.Taiko.UI
{
@ -23,8 +14,6 @@ namespace osu.Game.Rulesets.Taiko.UI
/// </summary>
internal class InputDrum : Container
{
private const float middle_split = 0.025f;
public InputDrum()
{
AutoSizeAxes = Axes.X;
@ -43,166 +32,5 @@ namespace osu.Game.Rulesets.Taiko.UI
},
};
}
private class DefaultInputDrum : AspectContainer
{
public DefaultInputDrum()
{
RelativeSizeAxes = Axes.Y;
}
[BackgroundDependencyLoader]
private void load()
{
InternalChild = new Container
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Scale = new Vector2(0.9f),
Children = new[]
{
new TaikoHalfDrum(false)
{
Name = "Left Half",
Anchor = Anchor.Centre,
Origin = Anchor.CentreRight,
RelativeSizeAxes = Axes.Both,
RelativePositionAxes = Axes.X,
X = -middle_split / 2,
RimAction = TaikoAction.LeftRim,
CentreAction = TaikoAction.LeftCentre
},
new TaikoHalfDrum(true)
{
Name = "Right Half",
Anchor = Anchor.Centre,
Origin = Anchor.CentreLeft,
RelativeSizeAxes = Axes.Both,
RelativePositionAxes = Axes.X,
X = middle_split / 2,
RimAction = TaikoAction.RightRim,
CentreAction = TaikoAction.RightCentre
}
}
};
}
/// <summary>
/// A half-drum. Contains one centre and one rim hit.
/// </summary>
private class TaikoHalfDrum : Container, IKeyBindingHandler<TaikoAction>
{
/// <summary>
/// The key to be used for the rim of the half-drum.
/// </summary>
public TaikoAction RimAction;
/// <summary>
/// The key to be used for the centre of the half-drum.
/// </summary>
public TaikoAction CentreAction;
private readonly Sprite rim;
private readonly Sprite rimHit;
private readonly Sprite centre;
private readonly Sprite centreHit;
public TaikoHalfDrum(bool flipped)
{
Masking = true;
Children = new Drawable[]
{
rim = new Sprite
{
Anchor = flipped ? Anchor.CentreLeft : Anchor.CentreRight,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both
},
rimHit = new Sprite
{
Anchor = flipped ? Anchor.CentreLeft : Anchor.CentreRight,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Alpha = 0,
Blending = BlendingParameters.Additive,
},
centre = new Sprite
{
Anchor = flipped ? Anchor.CentreLeft : Anchor.CentreRight,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Size = new Vector2(0.7f)
},
centreHit = new Sprite
{
Anchor = flipped ? Anchor.CentreLeft : Anchor.CentreRight,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Size = new Vector2(0.7f),
Alpha = 0,
Blending = BlendingParameters.Additive
}
};
}
[BackgroundDependencyLoader]
private void load(TextureStore textures, OsuColour colours)
{
rim.Texture = textures.Get(@"Gameplay/taiko/taiko-drum-outer");
rimHit.Texture = textures.Get(@"Gameplay/taiko/taiko-drum-outer-hit");
centre.Texture = textures.Get(@"Gameplay/taiko/taiko-drum-inner");
centreHit.Texture = textures.Get(@"Gameplay/taiko/taiko-drum-inner-hit");
rimHit.Colour = colours.Blue;
centreHit.Colour = colours.Pink;
}
public bool OnPressed(KeyBindingPressEvent<TaikoAction> e)
{
Drawable target = null;
Drawable back = null;
if (e.Action == CentreAction)
{
target = centreHit;
back = centre;
}
else if (e.Action == RimAction)
{
target = rimHit;
back = rim;
}
if (target != null)
{
const float scale_amount = 0.05f;
const float alpha_amount = 0.5f;
const float down_time = 40;
const float up_time = 1000;
back.ScaleTo(target.Scale.X - scale_amount, down_time, Easing.OutQuint)
.Then()
.ScaleTo(1, up_time, Easing.OutQuint);
target.Animate(
t => t.ScaleTo(target.Scale.X - scale_amount, down_time, Easing.OutQuint),
t => t.FadeTo(Math.Min(target.Alpha + alpha_amount, 1), down_time, Easing.OutQuint)
).Then(
t => t.ScaleTo(1, up_time, Easing.OutQuint),
t => t.FadeOut(up_time, Easing.OutQuint)
);
}
return false;
}
public void OnReleased(KeyBindingReleaseEvent<TaikoAction> e)
{
}
}
}
}
}

View File

@ -1,13 +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.
#nullable disable
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Taiko.Objects;
using osu.Game.Rulesets.Taiko.Skinning.Default;
using osu.Game.Skinning;
using osuTK;
@ -22,7 +21,7 @@ namespace osu.Game.Rulesets.Taiko.UI
private readonly HitType hitType;
private SkinnableDrawable skinnable;
private SkinnableDrawable skinnable = null!;
public override double LifetimeStart => skinnable.Drawable.LifetimeStart;

View File

@ -1,8 +1,6 @@
// 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.
#nullable disable
using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;

View File

@ -1,8 +1,6 @@
// 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.
#nullable disable
using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;

View File

@ -1,8 +1,6 @@
// 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.
#nullable disable
using osuTK;
using osuTK.Graphics;
using osu.Framework.Graphics;

View File

@ -1,8 +1,6 @@
// 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.
#nullable disable
using System;
using osu.Framework.Allocation;
using osu.Framework.Audio.Track;
@ -89,7 +87,7 @@ namespace osu.Game.Rulesets.Taiko.UI
[BackgroundDependencyLoader]
private void load(ISkinSource source)
{
ISkin skin = source.FindProvider(s => getAnimationFrame(s, state, 0) != null);
ISkin? skin = source.FindProvider(s => getAnimationFrame(s, state, 0) != null);
if (skin == null) return;
@ -120,7 +118,7 @@ namespace osu.Game.Rulesets.Taiko.UI
[BackgroundDependencyLoader]
private void load(ISkinSource source)
{
ISkin skin = source.FindProvider(s => getAnimationFrame(s, TaikoMascotAnimationState.Clear, 0) != null);
ISkin? skin = source.FindProvider(s => getAnimationFrame(s, TaikoMascotAnimationState.Clear, 0) != null);
if (skin == null) return;
@ -137,7 +135,7 @@ namespace osu.Game.Rulesets.Taiko.UI
}
}
private static Texture getAnimationFrame(ISkin skin, TaikoMascotAnimationState state, int frameIndex)
private static Texture? getAnimationFrame(ISkin skin, TaikoMascotAnimationState state, int frameIndex)
{
var texture = skin.GetTexture($"pippidon{state.ToString().ToLowerInvariant()}{frameIndex}");

View File

@ -1,8 +1,6 @@
// 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.
#nullable disable
namespace osu.Game.Rulesets.Taiko.UI
{
public enum TaikoMascotAnimationState

View File

@ -1,8 +1,6 @@
// 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.
#nullable disable
using System;
using osu.Framework.Bindables;
using osu.Framework.Graphics;

View File

@ -1,8 +1,6 @@
// 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.
#nullable disable
using System.Collections.Generic;
using osu.Game.Rulesets.Replays;
using osu.Game.Rulesets.Taiko.Replays;

View File

@ -59,8 +59,9 @@ namespace osu.Game.Tests.Visual.Beatmaps
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(25f, 50f),
Scale = new Vector2(2f),
State = { Value = DownloadState.NotDownloaded },
Scale = new Vector2(2)
};
});
}

View File

@ -37,7 +37,11 @@ namespace osu.Game.Tests.Visual.Beatmaps
beatmapSetInfo = CreateAPIBeatmapSet(Ruleset.Value);
beatmapSetInfo.HasFavourited = favourited;
});
AddStep("create button", () => Child = button = new FavouriteButton(beatmapSetInfo) { Scale = new Vector2(2) });
AddStep("create button", () => Child = button = new FavouriteButton(beatmapSetInfo)
{
Size = new Vector2(25f, 50f),
Scale = new Vector2(2f),
});
assertCorrectIcon(favourited);
AddAssert("correct tooltip text", () => button.TooltipText == (favourited ? BeatmapsetsStrings.ShowDetailsUnfavourite : BeatmapsetsStrings.ShowDetailsFavourite));
@ -51,7 +55,11 @@ namespace osu.Game.Tests.Visual.Beatmaps
BeatmapFavouriteAction? lastRequestAction = null;
AddStep("create beatmap set", () => beatmapSetInfo = CreateAPIBeatmapSet(Ruleset.Value));
AddStep("create button", () => Child = button = new FavouriteButton(beatmapSetInfo) { Scale = new Vector2(2) });
AddStep("create button", () => Child = button = new FavouriteButton(beatmapSetInfo)
{
Size = new Vector2(25f, 50f),
Scale = new Vector2(2f),
});
assertCorrectIcon(false);

View File

@ -93,6 +93,15 @@ namespace osu.Game.Tests.Visual.Gameplay
checkRequestCount(1);
}
[Test]
public void TestAutomaticSkipActuatesOnce()
{
createTest();
AddStep("start automated skip", () => skip.SkipWhenReady());
AddUntilStep("wait for button disabled", () => !skip.IsButtonVisible);
checkRequestCount(1);
}
[Test]
public void TestClickOnlyActuatesOnce()
{
@ -110,6 +119,16 @@ namespace osu.Game.Tests.Visual.Gameplay
checkRequestCount(1);
}
[Test]
public void TestAutomaticSkipActuatesMultipleTimes()
{
createTest();
AddStep("set increment lower", () => increment = 3000);
AddStep("start automated skip", () => skip.SkipWhenReady());
AddUntilStep("wait for button disabled", () => !skip.IsButtonVisible);
checkRequestCount(2);
}
[Test]
public void TestClickOnlyActuatesMultipleTimes()
{
@ -137,8 +156,11 @@ namespace osu.Game.Tests.Visual.Gameplay
checkRequestCount(0);
}
private void checkRequestCount(int expected) =>
AddAssert($"request count is {expected}", () => requestCount == expected);
private void checkRequestCount(int expected)
{
AddAssert($"skip count is {expected}", () => skip.SkipCount, () => Is.EqualTo(expected));
AddAssert($"request count is {expected}", () => requestCount, () => Is.EqualTo(expected));
}
private class TestSkipOverlay : SkipOverlay
{

View File

@ -18,7 +18,7 @@ namespace osu.Game.Tournament.Models
public Bindable<int> Seed = new BindableInt
{
MinValue = 1,
MaxValue = 64
MaxValue = 256
};
}
}

View File

@ -17,7 +17,7 @@ namespace osu.Game.Tournament.Models
public Bindable<int> Seed = new BindableInt
{
MinValue = 1,
MaxValue = 64
MaxValue = 256
};
}
}

View File

@ -54,7 +54,7 @@ namespace osu.Game.Tournament.Models
public Bindable<int> LastYearPlacing = new BindableInt
{
MinValue = 1,
MaxValue = 64
MaxValue = 256
};
[JsonProperty]

View File

@ -81,7 +81,6 @@ namespace osu.Game.Beatmaps.Drawables.Cards
FavouriteState = { BindTarget = FavouriteState },
ButtonsCollapsedWidth = CORNER_RADIUS,
ButtonsExpandedWidth = 30,
ButtonsPadding = new MarginPadding { Vertical = 35 },
Children = new Drawable[]
{
new FillFlowContainer

View File

@ -82,7 +82,6 @@ namespace osu.Game.Beatmaps.Drawables.Cards
FavouriteState = { BindTarget = FavouriteState },
ButtonsCollapsedWidth = CORNER_RADIUS,
ButtonsExpandedWidth = 30,
ButtonsPadding = new MarginPadding { Vertical = 17.5f },
Children = new Drawable[]
{
new FillFlowContainer

View File

@ -4,13 +4,16 @@
#nullable disable
using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Input.Events;
using osu.Game.Graphics.Containers;
using osu.Game.Overlays;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Beatmaps.Drawables.Cards.Buttons
{
@ -59,6 +62,7 @@ namespace osu.Game.Beatmaps.Drawables.Cards.Buttons
protected override Container<Drawable> Content => content;
private readonly Container content;
private readonly Box hover;
protected BeatmapCardIconButton()
{
@ -69,19 +73,27 @@ namespace osu.Game.Beatmaps.Drawables.Cards.Buttons
{
RelativeSizeAxes = Axes.Both,
Masking = true,
CornerRadius = BeatmapCard.CORNER_RADIUS,
Scale = new Vector2(0.8f),
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
Children = new Drawable[]
{
hover = new Box
{
RelativeSizeAxes = Axes.Both,
Colour = Color4.White.Opacity(0.1f),
Blending = BlendingParameters.Additive,
},
Icon = new SpriteIcon
{
Origin = Anchor.Centre,
Anchor = Anchor.Centre
}
Anchor = Anchor.Centre,
Scale = new Vector2(1.2f),
},
}
});
Size = new Vector2(24);
IconSize = 12;
}
@ -116,8 +128,9 @@ namespace osu.Game.Beatmaps.Drawables.Cards.Buttons
{
bool isHovered = IsHovered && Enabled.Value;
content.ScaleTo(isHovered ? 1.2f : 1, 500, Easing.OutQuint);
content.FadeColour(isHovered ? HoverColour : IdleColour, BeatmapCard.TRANSITION_DURATION, Easing.OutQuint);
hover.FadeTo(isHovered ? 1f : 0f, 500, Easing.OutQuint);
content.ScaleTo(isHovered ? 1 : 0.8f, 500, Easing.OutQuint);
Icon.FadeColour(isHovered ? HoverColour : IdleColour, BeatmapCard.TRANSITION_DURATION, Easing.OutQuint);
}
}
}

View File

@ -48,12 +48,6 @@ namespace osu.Game.Beatmaps.Drawables.Cards
}
}
public MarginPadding ButtonsPadding
{
get => buttons.Padding;
set => buttons.Padding = value;
}
protected override Container<Drawable> Content => mainContent;
private readonly Container background;
@ -86,9 +80,6 @@ namespace osu.Game.Beatmaps.Drawables.Cards
RelativeSizeAxes = Axes.Both,
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight,
// workaround for masking artifacts at the top & bottom of card,
// which become especially visible on downloaded beatmaps (when the icon area has a lime background).
Padding = new MarginPadding { Vertical = 1 },
Child = new Box
{
RelativeSizeAxes = Axes.Both,
@ -104,25 +95,34 @@ namespace osu.Game.Beatmaps.Drawables.Cards
Child = buttons = new Container<BeatmapCardIconButton>
{
RelativeSizeAxes = Axes.Both,
// Padding of 4 avoids touching the card borders when in the expanded (ie. showing difficulties) state.
// Left override allows the buttons to visually be wider and look better.
Padding = new MarginPadding(4) { Left = 2 },
Children = new BeatmapCardIconButton[]
{
new FavouriteButton(beatmapSet)
{
Current = FavouriteState,
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre
Origin = Anchor.TopCentre,
RelativeSizeAxes = Axes.Both,
Height = 0.48f,
},
new DownloadButton(beatmapSet)
{
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre,
State = { BindTarget = downloadTracker.State }
State = { BindTarget = downloadTracker.State },
RelativeSizeAxes = Axes.Both,
Height = 0.48f,
},
new GoToBeatmapButton(beatmapSet)
{
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre,
State = { BindTarget = downloadTracker.State }
State = { BindTarget = downloadTracker.State },
RelativeSizeAxes = Axes.Both,
Height = 0.48f,
}
}
}

View File

@ -57,15 +57,13 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts
private void updateRelativeChildSize()
{
// the track may not be loaded completely (only has a length once it is).
if (!beatmap.Value.Track.IsLoaded)
{
content.RelativeChildSize = Vector2.One;
Schedule(updateRelativeChildSize);
return;
}
// If the track is not loaded, assign a default sane length otherwise relative positioning becomes meaningless.
double trackLength = beatmap.Value.Track.IsLoaded ? beatmap.Value.Track.Length : 60000;
content.RelativeChildSize = new Vector2((float)Math.Max(1, trackLength), 1);
content.RelativeChildSize = new Vector2((float)Math.Max(1, beatmap.Value.Track.Length), 1);
// The track may not be loaded completely (only has a length once it is).
if (!beatmap.Value.Track.IsLoaded)
Schedule(updateRelativeChildSize);
}
protected virtual void LoadBeatmap(EditorBeatmap beatmap)

View File

@ -27,7 +27,7 @@ namespace osu.Game.Screens.Edit
private readonly Bindable<Track> track = new Bindable<Track>();
public double TrackLength => track.Value?.Length ?? 60000;
public double TrackLength => track.Value?.IsLoaded == true ? track.Value.Length : 60000;
public ControlPointInfo ControlPointInfo => Beatmap.ControlPointInfo;

View File

@ -27,6 +27,11 @@ namespace osu.Game.Screens.Play
{
public class SkipOverlay : CompositeDrawable, IKeyBindingHandler<GlobalAction>
{
/// <summary>
/// The total number of successful skips performed by this overlay.
/// </summary>
public int SkipCount { get; private set; }
private readonly double startTime;
public Action RequestSkip;
@ -124,23 +129,36 @@ namespace osu.Game.Screens.Play
return;
}
button.Action = () => RequestSkip?.Invoke();
button.Action = () =>
{
SkipCount++;
RequestSkip?.Invoke();
};
fadeContainer.TriggerShow();
if (skipQueued)
{
Scheduler.AddDelayed(() => button.TriggerClick(), 200);
skipQueued = false;
}
}
/// <summary>
/// Triggers an "automated" skip to happen as soon as available.
/// </summary>
public void SkipWhenReady()
{
if (IsLoaded)
if (skipQueued) return;
skipQueued = true;
attemptNextSkip();
void attemptNextSkip() => Scheduler.AddDelayed(() =>
{
if (!button.Enabled.Value)
{
skipQueued = false;
return;
}
button.TriggerClick();
else
skipQueued = true;
attemptNextSkip();
}, 200);
}
protected override void Update()