1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-15 07:22:55 +08:00

Major rsefinements to taiko drawable classes.

This commit is contained in:
Dean Herbert 2017-04-05 10:01:40 +09:00
parent 6dc03c1cc4
commit 028e941ab2
No known key found for this signature in database
GPG Key ID: 46D71BF4958ABB49
21 changed files with 316 additions and 275 deletions

View File

@ -37,7 +37,7 @@ namespace osu.Desktop.VisualTests.Tests
}
});
Add(new StrongCirclePiece
Add(new CirclePiece(true)
{
Position = new Vector2(350, 100),
AccentColour = Color4.DarkRed,
@ -59,7 +59,7 @@ namespace osu.Desktop.VisualTests.Tests
}
});
Add(new StrongCirclePiece
Add(new CirclePiece(true)
{
Position = new Vector2(350, 300),
AccentColour = Color4.DarkBlue,
@ -89,7 +89,7 @@ namespace osu.Desktop.VisualTests.Tests
KiaiMode = kiai,
});
Add(new StrongCirclePiece
Add(new CirclePiece(true)
{
Position = new Vector2(575, 300),
Width = 0.25f,

View File

@ -108,11 +108,12 @@ namespace osu.Desktop.VisualTests.Tests
var d = new DrumRoll
{
StartTime = Time.Current + 1000,
IsStrong = strong,
Distance = 1000,
PreEmpt = 1000,
};
playfield.Add(strong ? new DrawableStrongDrumRoll(d) : new DrawableDrumRoll(d));
playfield.Add(new DrawableDrumRoll(d));
}
private void addCentreHit(bool strong)

View File

@ -15,13 +15,13 @@ namespace osu.Game.Modes.Taiko.Objects.Drawables
public DrawableCentreHit(Hit hit)
: base(hit)
{
Circle.Add(new CentreHitSymbolPiece());
MainPiece.Add(new CentreHitSymbolPiece());
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
Circle.AccentColour = colours.PinkDarker;
MainPiece.AccentColour = colours.PinkDarker;
}
}
}

View File

@ -3,28 +3,23 @@
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.MathUtils;
using osu.Game.Graphics;
using osu.Game.Modes.Objects.Drawables;
using osu.Game.Modes.Taiko.Judgements;
using osu.Game.Modes.Taiko.Objects.Drawables.Pieces;
using OpenTK;
using OpenTK.Graphics;
using osu.Game.Modes.Taiko.Objects.Drawables.Pieces;
namespace osu.Game.Modes.Taiko.Objects.Drawables
{
public class DrawableDrumRoll : DrawableTaikoHitObject
public class DrawableDrumRoll : DrawableTaikoHitObject<DrumRoll>
{
/// <summary>
/// Number of rolling hits required to reach the dark/final accent colour.
/// </summary>
private const int rolling_hits_for_dark_accent = 5;
private readonly DrumRoll drumRoll;
private readonly CirclePiece circle;
private Color4 accentDarkColour;
/// <summary>
@ -35,14 +30,6 @@ namespace osu.Game.Modes.Taiko.Objects.Drawables
public DrawableDrumRoll(DrumRoll drumRoll)
: base(drumRoll)
{
this.drumRoll = drumRoll;
RelativeSizeAxes = Axes.X;
Width = (float)(drumRoll.Duration / drumRoll.PreEmpt);
Add(circle = CreateCirclePiece());
circle.KiaiMode = HitObject.Kiai;
foreach (var tick in drumRoll.Ticks)
{
var newTick = new DrawableDrumRollTick(tick)
@ -53,14 +40,22 @@ namespace osu.Game.Modes.Taiko.Objects.Drawables
newTick.OnJudgement += onTickJudgement;
AddNested(newTick);
Add(newTick);
MainPiece.Add(newTick);
}
}
protected override TaikoJudgement CreateJudgement() => new TaikoJudgement { SecondHit = HitObject.IsStrong };
protected override TaikoPiece CreateMainPiece() => new ElongatedCirclePiece(HitObject.IsStrong)
{
Length = (float)(HitObject.Duration / HitObject.PreEmpt),
PlayfieldLengthReference = () => Parent.DrawSize.X
};
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
circle.AccentColour = AccentColour = colours.YellowDark;
MainPiece.AccentColour = AccentColour = colours.YellowDark;
accentDarkColour = colours.YellowDarker;
}
@ -72,7 +67,7 @@ namespace osu.Game.Modes.Taiko.Objects.Drawables
// is further than mid point of the play field, so the time taken to scroll in should always
// be greater than the time taken to scroll out to the left of the screen.
// Thus, using PreEmpt here is enough for the drum roll to completely scroll out.
LifetimeEnd = drumRoll.EndTime + drumRoll.PreEmpt;
LifetimeEnd = HitObject.EndTime + HitObject.PreEmpt;
}
private void onTickJudgement(DrawableHitObject<TaikoHitObject, TaikoJudgement> obj)
@ -85,7 +80,7 @@ namespace osu.Game.Modes.Taiko.Objects.Drawables
rollingHits = MathHelper.Clamp(rollingHits, 0, rolling_hits_for_dark_accent);
Color4 newAccent = Interpolation.ValueAt((float)rollingHits / rolling_hits_for_dark_accent, AccentColour, accentDarkColour, 0, 1);
circle.FadeAccent(newAccent, 100);
MainPiece.FadeAccent(newAccent, 100);
}
protected override void CheckJudgement(bool userTriggered)
@ -98,10 +93,10 @@ namespace osu.Game.Modes.Taiko.Objects.Drawables
int countHit = NestedHitObjects.Count(o => o.Judgement.Result == HitResult.Hit);
if (countHit > drumRoll.RequiredGoodHits)
if (countHit > HitObject.RequiredGoodHits)
{
Judgement.Result = HitResult.Hit;
Judgement.TaikoResult = countHit >= drumRoll.RequiredGreatHits ? TaikoHitResult.Great : TaikoHitResult.Good;
Judgement.TaikoResult = countHit >= HitObject.RequiredGreatHits ? TaikoHitResult.Great : TaikoHitResult.Good;
}
else
Judgement.Result = HitResult.Miss;

View File

@ -3,79 +3,37 @@
using System;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Game.Modes.Objects.Drawables;
using osu.Game.Modes.Taiko.Judgements;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Input;
using osu.Game.Modes.Taiko.Objects.Drawables.Pieces;
namespace osu.Game.Modes.Taiko.Objects.Drawables
{
public class DrawableDrumRollTick : DrawableTaikoHitObject
public class DrawableDrumRollTick : DrawableTaikoHitObject<DrumRollTick>
{
/// <summary>
/// The size of a tick.
/// </summary>
private const float tick_size = TaikoHitObject.CIRCLE_RADIUS / 2;
/// <summary>
/// Any tick that is not the first for a drumroll is not filled, but is instead displayed
/// as a hollow circle. This is what controls the border width of that circle.
/// </summary>
private const float tick_border_width = tick_size / 4;
private readonly DrumRollTick tick;
private readonly CircularContainer bodyContainer;
public DrawableDrumRollTick(DrumRollTick tick)
: base(tick)
{
this.tick = tick;
Anchor = Anchor.CentreLeft;
Origin = Anchor.Centre;
RelativePositionAxes = Axes.X;
Size = new Vector2(tick_size);
Children = new[]
{
bodyContainer = new CircularContainer
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Masking = true,
BorderThickness = tick_border_width,
BorderColour = Color4.White,
Children = new[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Alpha = tick.FirstTick ? 1 : 0,
AlwaysPresent = true
}
}
}
};
}
protected override TaikoJudgement CreateJudgement() => new TaikoDrumRollTickJudgement { SecondHit = tick.IsStrong };
protected override TaikoPiece CreateMainPiece() => new TickPiece
{
Filled = HitObject.FirstTick
};
protected override TaikoJudgement CreateJudgement() => new TaikoDrumRollTickJudgement { SecondHit = HitObject.IsStrong };
protected override void CheckJudgement(bool userTriggered)
{
if (!userTriggered)
{
if (Judgement.TimeOffset > tick.HitWindow)
if (Judgement.TimeOffset > HitObject.HitWindow)
Judgement.Result = HitResult.Miss;
return;
}
if (Math.Abs(Judgement.TimeOffset) < tick.HitWindow)
if (Math.Abs(Judgement.TimeOffset) < HitObject.HitWindow)
{
Judgement.Result = HitResult.Hit;
Judgement.TaikoResult = TaikoHitResult.Great;
@ -87,7 +45,7 @@ namespace osu.Game.Modes.Taiko.Objects.Drawables
switch (state)
{
case ArmedState.Hit:
bodyContainer.ScaleTo(0, 100, EasingTypes.OutQuint);
Content.ScaleTo(0, 100, EasingTypes.OutQuint);
break;
}
}

View File

@ -4,29 +4,19 @@
using System;
using System.Linq;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Modes.Objects.Drawables;
using osu.Game.Modes.Taiko.Judgements;
using osu.Game.Modes.Taiko.Objects.Drawables.Pieces;
using OpenTK.Input;
namespace osu.Game.Modes.Taiko.Objects.Drawables
{
public abstract class DrawableHit : DrawableTaikoHitObject
public abstract class DrawableHit : DrawableTaikoHitObject<Hit>
{
/// <summary>
/// A list of keys which can result in hits for this HitObject.
/// </summary>
protected abstract Key[] HitKeys { get; }
protected override Container<Drawable> Content => bodyContainer;
protected readonly CirclePiece Circle;
private readonly Hit hit;
private readonly Container bodyContainer;
/// <summary>
/// Whether the last key pressed is a valid hit key.
/// </summary>
@ -35,41 +25,28 @@ namespace osu.Game.Modes.Taiko.Objects.Drawables
protected DrawableHit(Hit hit)
: base(hit)
{
this.hit = hit;
AddInternal(bodyContainer = new Container
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Children = new[]
{
Circle = CreateCirclePiece()
}
});
Circle.KiaiMode = HitObject.Kiai;
}
protected override void CheckJudgement(bool userTriggered)
{
if (!userTriggered)
{
if (Judgement.TimeOffset > hit.HitWindowGood)
if (Judgement.TimeOffset > HitObject.HitWindowGood)
Judgement.Result = HitResult.Miss;
return;
}
double hitOffset = Math.Abs(Judgement.TimeOffset);
if (hitOffset > hit.HitWindowMiss)
if (hitOffset > HitObject.HitWindowMiss)
return;
if (!validKeyPressed)
Judgement.Result = HitResult.Miss;
else if (hitOffset < hit.HitWindowGood)
else if (hitOffset < HitObject.HitWindowGood)
{
Judgement.Result = HitResult.Hit;
Judgement.TaikoResult = hitOffset < hit.HitWindowGreat ? TaikoHitResult.Great : TaikoHitResult.Good;
Judgement.TaikoResult = hitOffset < HitObject.HitWindowGreat ? TaikoHitResult.Great : TaikoHitResult.Good;
}
else
Judgement.Result = HitResult.Miss;
@ -92,16 +69,16 @@ namespace osu.Game.Modes.Taiko.Objects.Drawables
switch (State)
{
case ArmedState.Idle:
Delay(hit.HitWindowMiss);
Delay(HitObject.HitWindowMiss);
break;
case ArmedState.Miss:
FadeOut(100);
break;
case ArmedState.Hit:
bodyContainer.ScaleTo(0.8f, 400, EasingTypes.OutQuad);
bodyContainer.MoveToY(-200, 250, EasingTypes.Out);
bodyContainer.Delay(250);
bodyContainer.MoveToY(0, 500, EasingTypes.In);
Content.ScaleTo(0.8f, 400, EasingTypes.OutQuad);
Content.MoveToY(-200, 250, EasingTypes.Out);
Content.Delay(250);
Content.MoveToY(0, 500, EasingTypes.In);
FadeOut(600);
break;

View File

@ -15,13 +15,13 @@ namespace osu.Game.Modes.Taiko.Objects.Drawables
public DrawableRimHit(Hit hit)
: base(hit)
{
Circle.Add(new RimHitSymbolPiece());
MainPiece.Add(new RimHitSymbolPiece());
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
Circle.AccentColour = colours.BlueDarker;
MainPiece.AccentColour = colours.BlueDarker;
}
}
}

View File

@ -15,13 +15,13 @@ namespace osu.Game.Modes.Taiko.Objects.Drawables
public DrawableStrongCentreHit(Hit hit)
: base(hit)
{
Circle.Add(new CentreHitSymbolPiece());
MainPiece.Add(new CentreHitSymbolPiece());
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
Circle.AccentColour = colours.PinkDarker;
MainPiece.AccentColour = colours.PinkDarker;
}
}
}

View File

@ -1,20 +0,0 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Modes.Taiko.Judgements;
using osu.Game.Modes.Taiko.Objects.Drawables.Pieces;
namespace osu.Game.Modes.Taiko.Objects.Drawables
{
public class DrawableStrongDrumRoll : DrawableDrumRoll
{
public DrawableStrongDrumRoll(DrumRoll drumRoll)
: base(drumRoll)
{
}
protected override TaikoJudgement CreateJudgement() => new TaikoJudgement { SecondHit = true };
protected override CirclePiece CreateCirclePiece() => new StrongCirclePiece();
}
}

View File

@ -6,8 +6,8 @@ using System.Linq;
using osu.Framework.Input;
using osu.Game.Modes.Objects.Drawables;
using osu.Game.Modes.Taiko.Judgements;
using osu.Game.Modes.Taiko.Objects.Drawables.Pieces;
using OpenTK.Input;
using osu.Game.Modes.Taiko.Objects.Drawables.Pieces;
namespace osu.Game.Modes.Taiko.Objects.Drawables
{
@ -28,9 +28,9 @@ namespace osu.Game.Modes.Taiko.Objects.Drawables
{
}
protected override TaikoJudgement CreateJudgement() => new TaikoStrongHitJudgement();
protected override TaikoPiece CreateMainPiece() => new CirclePiece(true);
protected override CirclePiece CreateCirclePiece() => new StrongCirclePiece();
protected override TaikoJudgement CreateJudgement() => new TaikoStrongHitJudgement();
protected override void CheckJudgement(bool userTriggered)
{

View File

@ -15,13 +15,13 @@ namespace osu.Game.Modes.Taiko.Objects.Drawables
public DrawableStrongRimHit(Hit hit)
: base(hit)
{
Circle.Add(new RimHitSymbolPiece());
MainPiece.Add(new RimHitSymbolPiece());
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
Circle.AccentColour = colours.BlueDarker;
MainPiece.AccentColour = colours.BlueDarker;
}
}
}

View File

@ -18,7 +18,7 @@ using OpenTK.Input;
namespace osu.Game.Modes.Taiko.Objects.Drawables
{
public class DrawableSwell : DrawableTaikoHitObject
public class DrawableSwell : DrawableTaikoHitObject<Swell>
{
/// <summary>
/// Invoked when the swell has reached the hit target, i.e. when CurrentTime >= StartTime.
@ -31,8 +31,6 @@ namespace osu.Game.Modes.Taiko.Objects.Drawables
private const float target_ring_scale = 5f;
private const float inner_ring_alpha = 0.65f;
private readonly Swell swell;
private readonly Container bodyContainer;
private readonly CircularContainer targetRing;
private readonly CircularContainer expandingRing;
@ -54,12 +52,11 @@ namespace osu.Game.Modes.Taiko.Objects.Drawables
public DrawableSwell(Swell swell)
: base(swell)
{
this.swell = swell;
Children = new Drawable[]
{
bodyContainer = new Container
{
AutoSizeAxes = Axes.Both,
Children = new Drawable[]
{
expandingRing = new CircularContainer
@ -120,6 +117,8 @@ namespace osu.Game.Modes.Taiko.Objects.Drawables
},
circlePiece = new CirclePiece
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Children = new []
{
symbol = new SwellSymbolPiece()
@ -146,18 +145,18 @@ namespace osu.Game.Modes.Taiko.Objects.Drawables
{
userHits++;
var completion = (float)userHits / swell.RequiredHits;
var completion = (float)userHits / HitObject.RequiredHits;
expandingRing.FadeTo(expandingRing.Alpha + MathHelper.Clamp(completion / 16, 0.1f, 0.6f), 50);
expandingRing.Delay(50);
expandingRing.FadeTo(completion / 8, 2000, EasingTypes.OutQuint);
expandingRing.DelayReset();
symbol.RotateTo((float)(completion * swell.Duration / 8), 4000, EasingTypes.OutQuint);
symbol.RotateTo((float)(completion * HitObject.Duration / 8), 4000, EasingTypes.OutQuint);
expandingRing.ScaleTo(1f + Math.Min(target_ring_scale - 1f, (target_ring_scale - 1f) * completion * 1.3f), 260, EasingTypes.OutQuint);
if (userHits == swell.RequiredHits)
if (userHits == HitObject.RequiredHits)
{
Judgement.Result = HitResult.Hit;
Judgement.TaikoResult = TaikoHitResult.Great;
@ -169,7 +168,7 @@ namespace osu.Game.Modes.Taiko.Objects.Drawables
return;
//TODO: THIS IS SHIT AND CAN'T EXIST POST-TAIKO WORLD CUP
if (userHits > swell.RequiredHits / 2)
if (userHits > HitObject.RequiredHits / 2)
{
Judgement.Result = HitResult.Hit;
Judgement.TaikoResult = TaikoHitResult.Good;
@ -189,7 +188,7 @@ namespace osu.Game.Modes.Taiko.Objects.Drawables
Delay(preempt, true);
Delay(Judgement.TimeOffset + swell.Duration, true);
Delay(Judgement.TimeOffset + HitObject.Duration, true);
const float out_transition_time = 300;

View File

@ -3,15 +3,18 @@
using System.Collections.Generic;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Input;
using osu.Game.Modes.Objects.Drawables;
using osu.Game.Modes.Taiko.Judgements;
using osu.Game.Modes.Taiko.Objects.Drawables.Pieces;
using OpenTK;
using OpenTK.Input;
namespace osu.Game.Modes.Taiko.Objects.Drawables
{
public abstract class DrawableTaikoHitObject : DrawableHitObject<TaikoHitObject, TaikoJudgement>
public abstract class DrawableTaikoHitObject<TaikoHitType> : DrawableHitObject<TaikoHitObject, TaikoJudgement>
where TaikoHitType : TaikoHitObject
{
/// <summary>
/// A list of keys which this hit object will accept. These are the standard Taiko keys for now.
@ -19,35 +22,56 @@ namespace osu.Game.Modes.Taiko.Objects.Drawables
/// </summary>
private readonly List<Key> validKeys = new List<Key>(new[] { Key.D, Key.F, Key.J, Key.K });
protected DrawableTaikoHitObject(TaikoHitObject hitObject)
public override Vector2 OriginPosition => new Vector2(DrawHeight / 2);
protected override Container<Drawable> Content => bodyContainer;
protected readonly TaikoPiece MainPiece;
private readonly Container bodyContainer;
public new TaikoHitType HitObject;
protected DrawableTaikoHitObject(TaikoHitType hitObject)
: base(hitObject)
{
HitObject = hitObject;
Anchor = Anchor.CentreLeft;
Origin = Anchor.CentreLeft;
Origin = Anchor.Custom;
AutoSizeAxes = Axes.Both;
RelativePositionAxes = Axes.X;
AddInternal(bodyContainer = new Container
{
AutoSizeAxes = Axes.Both,
Children = new[]
{
MainPiece = CreateMainPiece()
}
});
MainPiece.KiaiMode = HitObject.Kiai;
}
protected override void LoadComplete()
{
LifetimeStart = HitObject.StartTime - HitObject.PreEmpt * 2;
base.LoadComplete();
}
protected override TaikoJudgement CreateJudgement() => new TaikoJudgement();
protected virtual CirclePiece CreateCirclePiece() => new CirclePiece();
protected virtual TaikoPiece CreateMainPiece() => new CirclePiece(HitObject.IsStrong);
/// <summary>
/// Sets the scroll position of the DrawableHitObject relative to the offset between
/// a time value and the HitObject's StartTime.
/// </summary>
/// <param name="time"></param>
protected virtual void UpdateScrollPosition(double time)
{
MoveToX((float)((HitObject.StartTime - time) / HitObject.PreEmpt));
}
protected virtual void UpdateScrollPosition(double time) => MoveToX((float)((HitObject.StartTime - time) / HitObject.PreEmpt));
protected override void Update()
{

View File

@ -1,12 +1,10 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics;
using osu.Game.Graphics.Backgrounds;
using OpenTK.Graphics;
@ -15,26 +13,30 @@ namespace osu.Game.Modes.Taiko.Objects.Drawables.Pieces
/// <summary>
/// A circle piece which is used uniformly through osu!taiko to visualise hitobjects.
/// <para>
/// The body of this piece will overshoot its parent by <see cref="CirclePiece.Height"/> to form
/// a rounded (_[-Width-]_) figure such that a regular "circle" is the result of a parent with Width = 0.
/// Note that this can actually be non-circle if the width is changed. See <see cref="ElongatedCirclePiece"/>
/// for a usage example.
/// </para>
/// </summary>
public class CirclePiece : Container, IHasAccentColour
public class CirclePiece : TaikoPiece
{
public const float SYMBOL_SIZE = TaikoHitObject.CIRCLE_RADIUS * 2f * 0.45f;
public const float SYMBOL_BORDER = 8;
public const float SYMBOL_INNER_SIZE = SYMBOL_SIZE - 2 * SYMBOL_BORDER;
private Color4 accentColour;
/// <summary>
/// The amount to scale up the base circle to show it as a "strong" piece.
/// </summary>
private const float strong_scale = 1.5f;
/// <summary>
/// The colour of the inner circle and outer glows.
/// </summary>
public Color4 AccentColour
public override Color4 AccentColour
{
get { return accentColour; }
get { return base.AccentColour; }
set
{
accentColour = value;
base.AccentColour = value;
background.Colour = AccentColour;
@ -42,107 +44,92 @@ namespace osu.Game.Modes.Taiko.Objects.Drawables.Pieces
}
}
private bool kiaiMode;
/// <summary>
/// Whether Kiai mode effects are enabled for this circle piece.
/// </summary>
public bool KiaiMode
public override bool KiaiMode
{
get { return kiaiMode; }
get { return base.KiaiMode; }
set
{
kiaiMode = value;
base.KiaiMode = value;
resetEdgeEffects();
}
}
public override Anchor Origin
{
get { return Anchor.CentreLeft; }
set { throw new InvalidOperationException($"{nameof(CirclePiece)} must always use CentreLeft origin."); }
}
protected override Container<Drawable> Content => content;
protected override Container<Drawable> Content => SymbolContainer;
protected readonly Container SymbolContainer;
private readonly Container content;
private readonly Container background;
private readonly Container innerLayer;
public CirclePiece()
public CirclePiece(bool isStrong = false)
{
RelativeSizeAxes = Axes.X;
Height = TaikoHitObject.CIRCLE_RADIUS * 2;
// The "inner layer" is the body of the CirclePiece that overshoots it by Height/2 px on both sides
AddInternal(innerLayer = new Container
AddInternal(new Drawable[]
{
Name = "Inner Layer",
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Y,
Children = new Drawable[]
background = new CircularContainer
{
background = new CircularContainer
Name = "Background",
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Masking = true,
Children = new Drawable[]
{
Name = "Background",
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Masking = true,
Children = new Drawable[]
new Box
{
new Box
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
},
new Triangles
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
ColourLight = Color4.White,
ColourDark = Color4.White.Darken(0.1f)
}
}
},
new CircularContainer
{
Name = "Ring",
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
BorderThickness = 8,
BorderColour = Color4.White,
Masking = true,
Children = new[]
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
},
new Triangles
{
new Box
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Alpha = 0,
AlwaysPresent = true
}
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
ColourLight = Color4.White,
ColourDark = Color4.White.Darken(0.1f)
}
},
SymbolContainer = new Container
{
Name = "Symbol",
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
}
},
new CircularContainer
{
Name = "Ring",
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
BorderThickness = 8,
BorderColour = Color4.White,
Masking = true,
Children = new[]
{
new Box
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Alpha = 0,
AlwaysPresent = true
}
}
},
content = new Container
{
RelativeSizeAxes = Axes.Both,
Name = "Symbol",
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
}
});
}
protected override void Update()
{
// Add the overshoot to compensate for corner radius
innerLayer.Width = DrawWidth + DrawHeight;
if (isStrong)
{
Size *= strong_scale;
//for symbols etc.
Content.Scale *= strong_scale;
}
}
private void resetEdgeEffects()

View File

@ -0,0 +1,41 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using osu.Framework.Graphics.Primitives;
using osu.Game.Modes.Taiko.UI;
namespace osu.Game.Modes.Taiko.Objects.Drawables.Pieces
{
public class ElongatedCirclePiece : CirclePiece
{
/// <summary>
/// As we are being used to define the absolute size of hits, we need to be given a relative reference of our containing <see cref="TaikoPlayfield"/>.
/// </summary>
public Func<float> PlayfieldLengthReference;
/// <summary>
/// The length of this piece as a multiple of the value returned by <see cref="PlayfieldLengthReference"/>
/// </summary>
public float Length;
public ElongatedCirclePiece(bool isStrong = false) : base(isStrong)
{
}
protected override void Update()
{
base.Update();
var contentPadding = DrawHeight / 2 * Content.Scale.X;
Content.Padding = new MarginPadding
{
Left = contentPadding,
Right = contentPadding,
};
Width = (PlayfieldLengthReference?.Invoke() ?? 0) * Length + DrawHeight;
}
}
}

View File

@ -1,25 +0,0 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
namespace osu.Game.Modes.Taiko.Objects.Drawables.Pieces
{
/// <summary>
/// A type of circle piece which is drawn at a higher scale to represent a "strong" piece.
/// </summary>
public class StrongCirclePiece : CirclePiece
{
/// <summary>
/// The amount to scale up the base circle to show it as a "strong" piece.
/// </summary>
private const float strong_scale = 1.5f;
public StrongCirclePiece()
{
SymbolContainer.Scale = new Vector2(strong_scale);
}
public override Vector2 Size => new Vector2(base.Size.X, base.Size.Y * strong_scale);
}
}

View File

@ -0,0 +1,45 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics.Containers;
using osu.Game.Graphics;
using OpenTK;
using OpenTK.Graphics;
namespace osu.Game.Modes.Taiko.Objects.Drawables.Pieces
{
public class TaikoPiece : Container, IHasAccentColour
{
private Color4 accentColour;
/// <summary>
/// The colour of the inner circle and outer glows.
/// </summary>
public virtual Color4 AccentColour
{
get { return accentColour; }
set
{
accentColour = value;
}
}
private bool kiaiMode;
/// <summary>
/// Whether Kiai mode effects are enabled for this circle piece.
/// </summary>
public virtual bool KiaiMode
{
get { return kiaiMode; }
set
{
kiaiMode = value;
}
}
public TaikoPiece()
{
//just a default
Size = new Vector2(TaikoHitObject.CIRCLE_RADIUS * 2);
}
}
}

View File

@ -0,0 +1,60 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using OpenTK;
using OpenTK.Graphics;
namespace osu.Game.Modes.Taiko.Objects.Drawables.Pieces
{
public class TickPiece : TaikoPiece
{
/// <summary>
/// Any tick that is not the first for a drumroll is not filled, but is instead displayed
/// as a hollow circle. This is what controls the border width of that circle.
/// </summary>
private const float tick_border_width = TaikoHitObject.CIRCLE_RADIUS / 2 / 4;
/// <summary>
/// The size of a tick.
/// </summary>
private const float tick_size = TaikoHitObject.CIRCLE_RADIUS / 2;
private bool filled;
public bool Filled
{
get { return filled; }
set
{
filled = value;
fillBox.Alpha = filled ? 1 : 0;
}
}
private readonly Box fillBox;
public TickPiece()
{
Size = new Vector2(tick_size);
Add(new CircularContainer
{
RelativeSizeAxes = Axes.Both,
Masking = true,
BorderThickness = tick_border_width,
BorderColour = Color4.White,
Children = new[]
{
fillBox = new Box
{
RelativeSizeAxes = Axes.Both,
Alpha = 0,
AlwaysPresent = true
}
}
});
}
}
}

View File

@ -25,7 +25,7 @@ namespace osu.Game.Modes.Taiko.Objects
public float VelocityMultiplier = 1;
/// <summary>
/// The time to scroll in the HitObject.
/// The time from the initial right (off-screen) spawn position to the centre of the hit target.
/// </summary>
public double PreEmpt;

View File

@ -133,8 +133,6 @@ namespace osu.Game.Modes.Taiko.UI
var drumRoll = h as DrumRoll;
if (drumRoll != null)
{
if (h.IsStrong)
return new DrawableStrongDrumRoll(drumRoll);
return new DrawableDrumRoll(drumRoll);
}

View File

@ -61,18 +61,19 @@
<Compile Include="Objects\Drawables\DrawableStrongRimHit.cs" />
<Compile Include="Objects\Drawables\DrawableCentreHit.cs" />
<Compile Include="Objects\Drawables\DrawableHit.cs" />
<Compile Include="Objects\Drawables\DrawableStrongDrumRoll.cs" />
<Compile Include="Objects\Drawables\DrawableStrongCentreHit.cs" />
<Compile Include="Objects\Drawables\DrawableStrongHit.cs" />
<Compile Include="Objects\Drawables\Pieces\ElongatedCirclePiece.cs" />
<Compile Include="Objects\Drawables\Pieces\CentreHitSymbolPiece.cs" />
<Compile Include="Objects\Drawables\DrawableDrumRoll.cs" />
<Compile Include="Objects\Drawables\DrawableDrumRollTick.cs" />
<Compile Include="Objects\Drawables\DrawableSwell.cs" />
<Compile Include="Objects\Drawables\DrawableTaikoHitObject.cs" />
<Compile Include="Objects\Drawables\Pieces\RimHitSymbolPiece.cs" />
<Compile Include="Objects\Drawables\Pieces\StrongCirclePiece.cs" />
<Compile Include="Objects\Drawables\Pieces\CirclePiece.cs" />
<Compile Include="Objects\Drawables\Pieces\SwellSymbolPiece.cs" />
<Compile Include="Objects\Drawables\Pieces\TaikoPiece.cs" />
<Compile Include="Objects\Drawables\Pieces\TickPiece.cs" />
<Compile Include="Objects\DrumRoll.cs" />
<Compile Include="Objects\DrumRollTick.cs" />
<Compile Include="Objects\Hit.cs" />