1
0
mirror of https://github.com/ppy/osu.git synced 2024-05-14 18:10:23 +08:00

Merge pull request #21153 from peppy/argon-taiko

First pass osu!taiko "argon" skin
This commit is contained in:
Dean Herbert 2022-11-12 14:41:55 +09:00 committed by GitHub
commit 3c9fbdb4cf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 1138 additions and 9 deletions

View File

@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning
var cont = new Container
{
RelativeSizeAxes = Axes.Both,
Height = 0.8f,
Height = 0.2f,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Children = new Drawable[]
@ -63,7 +63,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning
var cont = new Container
{
RelativeSizeAxes = Axes.Both,
Height = 0.8f,
Height = 0.2f,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Children = new Drawable[]
@ -88,7 +88,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning
var barLine = new BarLine
{
Major = major,
StartTime = Time.Current + 2000,
StartTime = Time.Current + 5000,
};
var cpi = new ControlPointInfo();

View File

@ -4,6 +4,7 @@
#nullable disable
using System;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics;
@ -25,11 +26,10 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning
TimeRange = { Value = 5000 },
};
public TestSceneTaikoPlayfield()
[SetUpSteps]
public void SetUpSteps()
{
TaikoBeatmap beatmap;
bool kiai = false;
AddStep("set beatmap", () =>
{
Beatmap.Value = CreateWorkingBeatmap(beatmap = new TaikoBeatmap());
@ -41,12 +41,28 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning
AddStep("Load playfield", () => SetContents(_ => new TaikoPlayfield
{
Height = 0.2f,
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Height = 0.6f,
}));
}
[Test]
public void TestBasic()
{
AddStep("do nothing", () => { });
}
[Test]
public void TestHeightChanges()
{
AddRepeatStep("change height", () => this.ChildrenOfType<TaikoPlayfield>().ForEach(p => p.Height = Math.Max(0.2f, (p.Height + 0.2f) % 1f)), 50);
}
[Test]
public void TestKiai()
{
bool kiai = false;
AddStep("Toggle kiai", () =>
{

View File

@ -74,7 +74,8 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
switch (state)
{
case ArmedState.Hit:
this.ScaleTo(0, 100, Easing.OutQuint);
this.ScaleTo(1.4f, 200, Easing.OutQuint);
this.FadeOut(200, Easing.OutQuint);
break;
}
}

View File

@ -133,6 +133,8 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
protected override void OnApply()
{
base.OnApply();
// TODO: THIS CANNOT BE HERE, it makes pooling pointless (see https://github.com/ppy/osu/issues/21072).
RecreatePieces();
}

View File

@ -0,0 +1,83 @@
// 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.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Taiko.Objects.Drawables;
using osuTK;
namespace osu.Game.Rulesets.Taiko.Skinning.Argon
{
public class ArgonBarLine : CompositeDrawable
{
private Container majorEdgeContainer = null!;
private Bindable<bool> major = null!;
[BackgroundDependencyLoader]
private void load(DrawableHitObject drawableHitObject)
{
RelativeSizeAxes = Axes.Both;
const float line_offset = 8;
var majorPieceSize = new Vector2(6, 20);
InternalChildren = new Drawable[]
{
line = new Box
{
RelativeSizeAxes = Axes.Both,
EdgeSmoothness = new Vector2(0.5f, 0),
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
},
majorEdgeContainer = new Container
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Children = new[]
{
new Circle
{
Name = "Top line",
Anchor = Anchor.TopCentre,
Origin = Anchor.BottomCentre,
Size = majorPieceSize,
Y = -line_offset,
},
new Circle
{
Name = "Bottom line",
Anchor = Anchor.BottomCentre,
Origin = Anchor.TopCentre,
Size = majorPieceSize,
Y = line_offset,
},
}
}
};
major = ((DrawableBarLine)drawableHitObject).Major.GetBoundCopy();
}
protected override void LoadComplete()
{
base.LoadComplete();
major.BindValueChanged(updateMajor, true);
}
private Box line = null!;
private void updateMajor(ValueChangedEvent<bool> major)
{
line.Alpha = major.NewValue ? 1f : 0.5f;
line.Width = major.NewValue ? 1 : 0.5f;
majorEdgeContainer.Alpha = major.NewValue ? 1 : 0;
}
}
}

View File

@ -0,0 +1,34 @@
// 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.Colour;
using osu.Framework.Graphics.Sprites;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Rulesets.Taiko.Skinning.Argon
{
public class ArgonCentreCirclePiece : ArgonCirclePiece
{
[BackgroundDependencyLoader]
private void load()
{
AccentColour = ColourInfo.GradientVertical(
new Color4(241, 0, 0, 255),
new Color4(167, 0, 0, 255)
);
AddInternal(new SpriteIcon
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Icon = FontAwesome.Solid.AngleLeft,
Size = new Vector2(ICON_SIZE),
Scale = new Vector2(0.8f, 1)
});
}
}
}

View File

@ -0,0 +1,112 @@
// 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.Audio.Track;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Shapes;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Graphics.Containers;
using osu.Game.Rulesets.Objects.Drawables;
using osuTK.Graphics;
namespace osu.Game.Rulesets.Taiko.Skinning.Argon
{
public abstract class ArgonCirclePiece : BeatSyncedContainer
{
public const float ICON_SIZE = 20 / 70f;
private const double pre_beat_transition_time = 80;
private const float flash_opacity = 0.3f;
private ColourInfo accentColour;
/// <summary>
/// The colour of the inner circle and outer glows.
/// </summary>
public ColourInfo AccentColour
{
get => accentColour;
set
{
accentColour = value;
ring.Colour = AccentColour.MultiplyAlpha(0.5f);
ring2.Colour = AccentColour;
}
}
[Resolved]
private DrawableHitObject drawableHitObject { get; set; } = null!;
private readonly Drawable flash;
private readonly RingPiece ring;
private readonly RingPiece ring2;
protected ArgonCirclePiece()
{
RelativeSizeAxes = Axes.Both;
EarlyActivationMilliseconds = pre_beat_transition_time;
AddRangeInternal(new[]
{
new Circle
{
RelativeSizeAxes = Axes.Both,
Colour = new Color4(0, 0, 0, 190)
},
ring = new RingPiece(20 / 70f),
ring2 = new RingPiece(5 / 70f),
flash = new Circle
{
Name = "Flash layer",
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Blending = BlendingParameters.Additive,
Alpha = 0,
},
});
}
protected override void LoadComplete()
{
base.LoadComplete();
drawableHitObject.ApplyCustomUpdateState += updateStateTransforms;
updateStateTransforms(drawableHitObject, drawableHitObject.State.Value);
}
private void updateStateTransforms(DrawableHitObject drawableHitObject, ArmedState state)
{
switch (state)
{
case ArmedState.Hit:
using (BeginAbsoluteSequence(drawableHitObject.HitStateUpdateTime))
{
flash.FadeTo(0.9f).FadeOut(500, Easing.OutQuint);
}
break;
}
}
protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes)
{
if (!effectPoint.KiaiMode)
return;
if (drawableHitObject.State.Value == ArmedState.Idle)
{
flash
.FadeTo(flash_opacity)
.Then()
.FadeOut(timingPoint.BeatLength * 0.75, Easing.OutSine);
}
}
}
}

View File

@ -0,0 +1,33 @@
// 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.Colour;
using osuTK.Graphics;
namespace osu.Game.Rulesets.Taiko.Skinning.Argon
{
public class ArgonElongatedCirclePiece : ArgonCirclePiece
{
public ArgonElongatedCirclePiece()
{
RelativeSizeAxes = Axes.Y;
}
[BackgroundDependencyLoader]
private void load()
{
AccentColour = ColourInfo.GradientVertical(
new Color4(241, 161, 0, 255),
new Color4(167, 111, 0, 255)
);
}
protected override void Update()
{
base.Update();
Width = Parent.DrawSize.X + DrawHeight;
}
}
}

View File

@ -0,0 +1,87 @@
// 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.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Taiko.Objects;
using osu.Game.Rulesets.Taiko.UI;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Rulesets.Taiko.Skinning.Argon
{
public class ArgonHitExplosion : CompositeDrawable, IAnimatableHitExplosion
{
private readonly TaikoSkinComponents component;
private readonly Circle outer;
public ArgonHitExplosion(TaikoSkinComponents component)
{
this.component = component;
RelativeSizeAxes = Axes.Both;
InternalChildren = new Drawable[]
{
outer = new Circle
{
Name = "Outer circle",
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Colour = ColourInfo.GradientVertical(
new Color4(255, 227, 236, 255),
new Color4(255, 198, 211, 255)
),
Masking = true,
},
new Circle
{
Name = "Inner circle",
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Colour = Color4.White,
Size = new Vector2(0.85f),
EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Glow,
Colour = new Color4(255, 132, 191, 255).Opacity(0.5f),
Radius = 45,
},
Masking = true,
},
};
}
public void Animate(DrawableHitObject drawableHitObject)
{
this.FadeOut();
switch (component)
{
case TaikoSkinComponents.TaikoExplosionGreat:
this.FadeIn(30, Easing.In)
.Then()
.FadeOut(450, Easing.OutQuint);
break;
case TaikoSkinComponents.TaikoExplosionOk:
this.FadeTo(0.2f, 30, Easing.In)
.Then()
.FadeOut(200, Easing.OutQuint);
break;
}
}
public void AnimateSecondHit()
{
outer.ResizeTo(new Vector2(TaikoStrongableHitObject.STRONG_SCALE), 500, Easing.OutQuint);
}
}
}

View File

@ -0,0 +1,72 @@
// 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;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Rulesets.Taiko.Objects;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Rulesets.Taiko.Skinning.Argon
{
public class ArgonHitTarget : CompositeDrawable
{
/// <summary>
/// Thickness of all drawn line pieces.
/// </summary>
public ArgonHitTarget()
{
RelativeSizeAxes = Axes.Both;
Masking = true;
const float border_thickness = 4f;
InternalChildren = new Drawable[]
{
new Circle
{
Name = "Bar Upper",
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Y = -border_thickness,
RelativeSizeAxes = Axes.Y,
Size = new Vector2(border_thickness, (1 - TaikoStrongableHitObject.DEFAULT_STRONG_SIZE)),
},
new Circle
{
Name = "Outer circle",
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Colour = Color4.White,
Blending = BlendingParameters.Additive,
Alpha = 0.1f,
Size = new Vector2(TaikoHitObject.DEFAULT_SIZE),
Masking = true,
},
new Circle
{
Name = "Inner circle",
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Colour = Color4.White,
Blending = BlendingParameters.Additive,
Alpha = 0.1f,
Size = new Vector2(TaikoHitObject.DEFAULT_SIZE * 0.85f),
Masking = true,
},
new Circle
{
Name = "Bar Lower",
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre,
RelativeSizeAxes = Axes.Y,
Y = border_thickness,
Size = new Vector2(border_thickness, (1 - TaikoStrongableHitObject.DEFAULT_STRONG_SIZE)),
},
};
}
}
}

View File

@ -0,0 +1,218 @@
// 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 osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Input.Bindings;
using osu.Framework.Input.Events;
using osu.Game.Graphics;
using osu.Game.Screens.Ranking;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Rulesets.Taiko.Skinning.Argon
{
public class ArgonInputDrum : AspectContainer
{
private const float rim_size = 0.3f;
public ArgonInputDrum()
{
RelativeSizeAxes = Axes.Y;
}
[BackgroundDependencyLoader]
private void load()
{
const float middle_split = 6;
InternalChild = new Container
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Scale = new Vector2(0.9f),
Children = new Drawable[]
{
new TaikoHalfDrum(false)
{
Name = "Left Half",
Anchor = Anchor.Centre,
Origin = Anchor.CentreRight,
RelativeSizeAxes = Axes.Both,
RimAction = TaikoAction.LeftRim,
CentreAction = TaikoAction.LeftCentre
},
new TaikoHalfDrum(true)
{
Name = "Right Half",
Anchor = Anchor.Centre,
Origin = Anchor.CentreLeft,
RelativeSizeAxes = Axes.Both,
RimAction = TaikoAction.RightRim,
CentreAction = TaikoAction.RightCentre
},
new CircularContainer
{
RelativeSizeAxes = Axes.Both,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Masking = true,
Children = new Drawable[]
{
new Box
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Colour = OsuColour.Gray(38 / 255f),
Width = middle_split,
RelativeSizeAxes = Axes.Y,
},
new Box
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Colour = OsuColour.Gray(48 / 255f),
Width = middle_split,
Height = 1 - rim_size,
RelativeSizeAxes = Axes.Y,
},
},
}
}
};
}
/// <summary>
/// A half-drum. Contains one centre and one rim hit.
/// </summary>
private class TaikoHalfDrum : CompositeDrawable, 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 Drawable rimHit;
private readonly Drawable centreHit;
public TaikoHalfDrum(bool flipped)
{
Anchor anchor = flipped ? Anchor.CentreLeft : Anchor.CentreRight;
Masking = true;
Anchor = anchor;
Origin = anchor;
RelativeSizeAxes = Axes.Both;
// Extend maskable region for glow.
Height = 2f;
InternalChildren = new Drawable[]
{
new Container
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Height = 0.5f,
Children = new[]
{
new Circle
{
Anchor = anchor,
Colour = OsuColour.Gray(51 / 255f),
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both
},
rimHit = new Circle
{
Anchor = anchor,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Colour = ColourInfo.GradientHorizontal(
new Color4(227, 248, 255, 255),
new Color4(198, 245, 255, 255)
),
EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Glow,
Colour = new Color4(126, 215, 253, 170),
Radius = 50,
},
Alpha = 0,
},
new Circle
{
Anchor = anchor,
Origin = Anchor.Centre,
Colour = OsuColour.Gray(64 / 255f),
RelativeSizeAxes = Axes.Both,
Size = new Vector2(1 - rim_size)
},
centreHit = new Circle
{
Anchor = anchor,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Colour = ColourInfo.GradientHorizontal(
new Color4(255, 227, 236, 255),
new Color4(255, 198, 211, 255)
),
EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Glow,
Colour = new Color4(255, 147, 199, 255),
Radius = 50,
},
Size = new Vector2(1 - rim_size),
Alpha = 0,
}
},
},
};
}
public bool OnPressed(KeyBindingPressEvent<TaikoAction> e)
{
Drawable? target = null;
if (e.Action == CentreAction)
target = centreHit;
else if (e.Action == RimAction)
target = rimHit;
if (target != null)
{
const float alpha_amount = 0.5f;
const float down_time = 40;
const float up_time = 750;
target.Animate(
t => t.FadeTo(Math.Min(target.Alpha + alpha_amount, 1), down_time, Easing.OutQuint)
).Then(
t => t.FadeOut(up_time, Easing.OutQuint)
);
}
return false;
}
public void OnReleased(KeyBindingReleaseEvent<TaikoAction> e)
{
}
}
}
}

View File

@ -0,0 +1,198 @@
// 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 osu.Framework.Allocation;
using osu.Framework.Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Utils;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Scoring;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Rulesets.Taiko.Skinning.Argon
{
public class ArgonJudgementPiece : CompositeDrawable, IAnimatableJudgement
{
protected readonly HitResult Result;
protected SpriteText JudgementText { get; private set; } = null!;
private RingExplosion? ringExplosion;
[Resolved]
private OsuColour colours { get; set; } = null!;
public ArgonJudgementPiece(HitResult result)
{
Result = result;
RelativePositionAxes = Axes.Both;
RelativeSizeAxes = Axes.Both;
}
[BackgroundDependencyLoader]
private void load()
{
InternalChildren = new Drawable[]
{
JudgementText = new OsuSpriteText
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Text = Result.GetDescription().ToUpperInvariant(),
Colour = colours.ForHitResult(Result),
Blending = BlendingParameters.Additive,
Spacing = new Vector2(10, 0),
RelativePositionAxes = Axes.Both,
Font = OsuFont.Default.With(size: 20, weight: FontWeight.Regular),
},
};
if (Result.IsHit())
{
AddInternal(ringExplosion = new RingExplosion(Result)
{
Colour = colours.ForHitResult(Result),
RelativePositionAxes = Axes.Y,
});
}
}
/// <summary>
/// Plays the default animation for this judgement piece.
/// </summary>
/// <remarks>
/// The base implementation only handles fade (for all result types) and misses.
/// Individual rulesets are recommended to implement their appropriate hit animations.
/// </remarks>
public virtual void PlayAnimation()
{
const double duration = 800;
switch (Result)
{
default:
JudgementText.MoveToY(-0.6f)
.MoveToY(-1.0f, duration, Easing.OutQuint);
JudgementText
.ScaleTo(Vector2.One)
.ScaleTo(new Vector2(1.4f), duration, Easing.OutQuint);
break;
case HitResult.Miss:
this.ScaleTo(1.6f);
this.ScaleTo(1, 100, Easing.In);
JudgementText.MoveTo(Vector2.Zero);
JudgementText.MoveToOffset(new Vector2(0, 100), duration, Easing.InQuint);
this.RotateTo(0);
this.RotateTo(40, duration, Easing.InQuint);
break;
}
this.FadeOutFromOne(duration, Easing.OutQuint);
ringExplosion?.PlayAnimation();
}
public Drawable? GetAboveHitObjectsProxiedContent() => null;
private class RingExplosion : CompositeDrawable
{
private readonly float travel = 58;
public RingExplosion(HitResult result)
{
const float thickness = 4;
const float small_size = 9;
const float large_size = 14;
Anchor = Anchor.Centre;
Origin = Anchor.Centre;
Blending = BlendingParameters.Additive;
int countSmall = 0;
int countLarge = 0;
switch (result)
{
case HitResult.Meh:
countSmall = 3;
travel *= 0.3f;
break;
case HitResult.Ok:
case HitResult.Good:
countSmall = 4;
travel *= 0.6f;
break;
case HitResult.Great:
case HitResult.Perfect:
countSmall = 4;
countLarge = 4;
break;
}
for (int i = 0; i < countSmall; i++)
AddInternal(new RingPiece(thickness) { Size = new Vector2(small_size) });
for (int i = 0; i < countLarge; i++)
AddInternal(new RingPiece(thickness) { Size = new Vector2(large_size) });
}
public void PlayAnimation()
{
foreach (var c in InternalChildren)
{
const float start_position_ratio = 0.6f;
float direction = RNG.NextSingle(0, 360);
float distance = RNG.NextSingle(travel / 2, travel);
c.MoveTo(new Vector2(
MathF.Cos(direction) * distance * start_position_ratio,
MathF.Sin(direction) * distance * start_position_ratio
));
c.MoveTo(new Vector2(
MathF.Cos(direction) * distance,
MathF.Sin(direction) * distance
), 600, Easing.OutQuint);
}
this.FadeOutFromOne(1000, Easing.OutQuint);
}
public class RingPiece : CircularContainer
{
public RingPiece(float thickness = 9)
{
Anchor = Anchor.Centre;
Origin = Anchor.Centre;
Masking = true;
BorderThickness = thickness;
BorderColour = Color4.White;
Child = new Box
{
AlwaysPresent = true,
Alpha = 0,
RelativeSizeAxes = Axes.Both
};
}
}
}
}
}

View File

@ -0,0 +1,27 @@
// 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;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osuTK.Graphics;
namespace osu.Game.Rulesets.Taiko.Skinning.Argon
{
public class ArgonPlayfieldBackgroundLeft : CompositeDrawable
{
public ArgonPlayfieldBackgroundLeft()
{
RelativeSizeAxes = Axes.Both;
InternalChildren = new Drawable[]
{
new Box
{
Colour = Color4.Black,
RelativeSizeAxes = Axes.Both,
},
};
}
}
}

View File

@ -0,0 +1,28 @@
// 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;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osuTK.Graphics;
namespace osu.Game.Rulesets.Taiko.Skinning.Argon
{
public class ArgonPlayfieldBackgroundRight : CompositeDrawable
{
public ArgonPlayfieldBackgroundRight()
{
RelativeSizeAxes = Axes.Both;
InternalChildren = new Drawable[]
{
new Box
{
Colour = Color4.Black,
Alpha = 0.7f,
RelativeSizeAxes = Axes.Both,
},
};
}
}
}

View File

@ -0,0 +1,34 @@
// 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.Colour;
using osu.Framework.Graphics.Sprites;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Rulesets.Taiko.Skinning.Argon
{
public class ArgonRimCirclePiece : ArgonCirclePiece
{
[BackgroundDependencyLoader]
private void load()
{
AccentColour = ColourInfo.GradientVertical(
new Color4(0, 161, 241, 255),
new Color4(0, 111, 167, 255)
);
AddInternal(new SpriteIcon
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Icon = FontAwesome.Solid.AngleLeft,
Size = new Vector2(ICON_SIZE),
Scale = new Vector2(0.8f, 1)
});
}
}
}

View File

@ -0,0 +1,68 @@
// 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.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Taiko.Objects;
using osu.Game.Rulesets.Taiko.Objects.Drawables;
using osuTK;
namespace osu.Game.Rulesets.Taiko.Skinning.Argon
{
public class ArgonTickPiece : CompositeDrawable
{
private readonly Bindable<bool> isFirstTick = new Bindable<bool>();
public ArgonTickPiece()
{
const float tick_size = 1 / TaikoHitObject.DEFAULT_SIZE * ArgonCirclePiece.ICON_SIZE;
Anchor = Anchor.Centre;
Origin = Anchor.Centre;
RelativeSizeAxes = Axes.Both;
FillMode = FillMode.Fit;
Size = new Vector2(tick_size);
}
[Resolved]
private DrawableHitObject drawableHitObject { get; set; } = null!;
protected override void LoadComplete()
{
base.LoadComplete();
if (drawableHitObject is DrawableDrumRollTick drumRollTick)
isFirstTick.BindTo(drumRollTick.IsFirstTick);
isFirstTick.BindValueChanged(first =>
{
if (first.NewValue)
{
InternalChild = new Circle
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both
};
}
else
{
InternalChild = new SpriteIcon
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Icon = FontAwesome.Solid.AngleLeft,
Scale = new Vector2(0.8f, 1)
};
}
}, true);
}
}
}

View File

@ -0,0 +1,40 @@
// 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;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osuTK.Graphics;
namespace osu.Game.Rulesets.Taiko.Skinning.Argon
{
public class RingPiece : CircularContainer
{
private readonly float relativeBorderThickness;
public RingPiece(float relativeBorderThickness)
{
this.relativeBorderThickness = relativeBorderThickness;
RelativeSizeAxes = Axes.Both;
Anchor = Anchor.Centre;
Origin = Anchor.Centre;
Masking = true;
BorderColour = Color4.White;
Child = new Box
{
AlwaysPresent = true,
Alpha = 0,
RelativeSizeAxes = Axes.Both
};
}
protected override void Update()
{
base.Update();
BorderThickness = relativeBorderThickness * DrawSize.Y;
}
}
}

View File

@ -0,0 +1,71 @@
// 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;
using osu.Game.Rulesets.Scoring;
using osu.Game.Skinning;
namespace osu.Game.Rulesets.Taiko.Skinning.Argon
{
public class TaikoArgonSkinTransformer : SkinTransformer
{
public TaikoArgonSkinTransformer(ISkin skin)
: base(skin)
{
}
public override Drawable? GetDrawableComponent(ISkinComponentLookup component)
{
switch (component)
{
case GameplaySkinComponentLookup<HitResult> resultComponent:
return new ArgonJudgementPiece(resultComponent.Component);
case TaikoSkinComponentLookup taikoComponent:
// TODO: Once everything is finalised, consider throwing UnsupportedSkinComponentException on missing entries.
switch (taikoComponent.Component)
{
case TaikoSkinComponents.CentreHit:
return new ArgonCentreCirclePiece();
case TaikoSkinComponents.RimHit:
return new ArgonRimCirclePiece();
case TaikoSkinComponents.PlayfieldBackgroundLeft:
return new ArgonPlayfieldBackgroundLeft();
case TaikoSkinComponents.PlayfieldBackgroundRight:
return new ArgonPlayfieldBackgroundRight();
case TaikoSkinComponents.InputDrum:
return new ArgonInputDrum();
case TaikoSkinComponents.HitTarget:
return new ArgonHitTarget();
case TaikoSkinComponents.BarLine:
return new ArgonBarLine();
case TaikoSkinComponents.DrumRollBody:
return new ArgonElongatedCirclePiece();
case TaikoSkinComponents.DrumRollTick:
return new ArgonTickPiece();
case TaikoSkinComponents.TaikoExplosionKiai:
// the drawable needs to expire as soon as possible to avoid accumulating empty drawables on the playfield.
return Drawable.Empty().With(d => d.Expire());
case TaikoSkinComponents.TaikoExplosionGreat:
case TaikoSkinComponents.TaikoExplosionMiss:
case TaikoSkinComponents.TaikoExplosionOk:
return new ArgonHitExplosion(taikoComponent.Component);
}
break;
}
return base.GetDrawableComponent(component);
}
}
}

View File

@ -10,6 +10,7 @@ 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;
using osuTK.Graphics;
namespace osu.Game.Rulesets.Taiko.Skinning.Default
@ -74,6 +75,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Default
public void AnimateSecondHit()
{
this.ResizeTo(new Vector2(TaikoStrongableHitObject.STRONG_SCALE), 50);
}
}
}

View File

@ -24,6 +24,7 @@ using osu.Game.Rulesets.Taiko.Mods;
using osu.Game.Rulesets.Taiko.Objects;
using osu.Game.Rulesets.Taiko.Replays;
using osu.Game.Rulesets.Taiko.Scoring;
using osu.Game.Rulesets.Taiko.Skinning.Argon;
using osu.Game.Rulesets.Taiko.Skinning.Legacy;
using osu.Game.Rulesets.Taiko.UI;
using osu.Game.Rulesets.UI;
@ -47,6 +48,9 @@ namespace osu.Game.Rulesets.Taiko
{
switch (skin)
{
case ArgonSkin:
return new TaikoArgonSkinTransformer(skin);
case LegacySkin:
return new TaikoLegacySkinTransformer(skin);
}

View File

@ -90,7 +90,6 @@ namespace osu.Game.Rulesets.Taiko.UI
{
using (BeginAbsoluteSequence(secondHitTime.Value))
{
this.ResizeTo(new Vector2(TaikoStrongableHitObject.DEFAULT_STRONG_SIZE), 50);
(skinnable.Drawable as IAnimatableHitExplosion)?.AnimateSecondHit();
}
}