Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Taiko swell drawing #567

Merged
merged 18 commits into from Mar 31, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
45 changes: 9 additions & 36 deletions osu.Desktop.VisualTests/Tests/TestCaseTaikoHitObjects.cs
Expand Up @@ -4,7 +4,6 @@
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Testing;
using osu.Game.Graphics;
Expand Down Expand Up @@ -76,20 +75,16 @@ public override void Reset()
}
});

Add(new SwellCircle(new CirclePiece
{
KiaiMode = kiai
})
{
Position = new Vector2(100, 500)
});

Add(new SwellCircle(new StrongCirclePiece
{
KiaiMode = kiai
})
Add(new CirclePiece
{
Position = new Vector2(350, 500)
Position = new Vector2(100, 500),
Width = 0,
AccentColour = Color4.Orange,
KiaiMode = kiai,
Children = new[]
{
new SwellSymbolPiece()
}
});

Add(new DrumRollCircle(new CirclePiece
Expand All @@ -111,28 +106,6 @@ public override void Reset()
});
}

private class SwellCircle : BaseCircle
{
public SwellCircle(CirclePiece piece)
: base(piece)
{
Piece.Add(new TextAwesome
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
TextSize = CirclePiece.SYMBOL_INNER_SIZE,
Icon = FontAwesome.fa_asterisk,
Shadow = false
});
}

[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
Piece.AccentColour = colours.YellowDark;
}
}

private class DrumRollCircle : BaseCircle
{
public DrumRollCircle(CirclePiece piece)
Expand Down
11 changes: 11 additions & 0 deletions osu.Desktop.VisualTests/Tests/TestCaseTaikoPlayfield.cs
Expand Up @@ -26,6 +26,7 @@ public override void Reset()

AddButton("Hit!", addHitJudgement);
AddButton("Miss :(", addMissJudgement);
AddButton("Swell", addSwell);
AddButton("Centre", () => addCentreHit(false));
AddButton("Strong Centre", () => addCentreHit(true));
AddButton("Rim", () => addRimHit(false));
Expand Down Expand Up @@ -74,6 +75,16 @@ private void addMissJudgement()
});
}

private void addSwell()
{
playfield.Add(new DrawableSwell(new Swell
{
StartTime = Time.Current + 1000,
EndTime = Time.Current + 5000,
PreEmpt = 1000
}));
}

private void addCentreHit(bool strong)
{
Hit h = new Hit
Expand Down
177 changes: 172 additions & 5 deletions osu.Game.Modes.Taiko/Objects/Drawable/DrawableSwell.cs
@@ -1,37 +1,160 @@
// 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;
using OpenTK.Graphics;
using OpenTK.Input;
using osu.Framework.Allocation;
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.Modes.Objects.Drawables;
using osu.Game.Modes.Taiko.Judgements;
using osu.Game.Modes.Taiko.Objects.Drawable.Pieces;
using System;
using System.Linq;

namespace osu.Game.Modes.Taiko.Objects.Drawable
{
public class DrawableSwell : DrawableTaikoHitObject
{
/// <summary>
/// Invoked when the swell has reached the hit target, i.e. when CurrentTime >= StartTime.
/// This is only ever invoked once.
/// </summary>
public event Action OnStart;

private const float target_ring_thick_border = 1.4f;
private const float target_ring_thin_border = 1f;
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;

private readonly CirclePiece circlePiece;

private readonly Key[] rimKeys = { Key.D, Key.K };
private readonly Key[] centreKeys = { Key.F, Key.J };
private Key[] lastKeySet;

/// <summary>
/// The amount of times the user has hit this swell.
/// </summary>
private int userHits;

private readonly Swell swell;
private bool hasStarted;
private readonly SwellSymbolPiece symbol;

public DrawableSwell(Swell swell)
: base(swell)
{
this.swell = swell;

Children = new Framework.Graphics.Drawable[]
{
bodyContainer = new Container
{
Children = new Framework.Graphics.Drawable[]
{
expandingRing = new CircularContainer
{
Name = "Expanding ring",
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Alpha = 0,
Size = new Vector2(TaikoHitObject.CIRCLE_RADIUS * 2),
BlendingMode = BlendingMode.Additive,
Masking = true,
Children = new []
{
new Box
{
RelativeSizeAxes = Axes.Both,
Alpha = inner_ring_alpha,
}
}
},
targetRing = new CircularContainer
{
Name = "Target ring (thick border)",
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(TaikoHitObject.CIRCLE_RADIUS * 2),
Masking = true,
BorderThickness = target_ring_thick_border,
BlendingMode = BlendingMode.Additive,
Children = new Framework.Graphics.Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Alpha = 0,
AlwaysPresent = true
},
new CircularContainer
{
Name = "Target ring (thin border)",
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Masking = true,
BorderThickness = target_ring_thin_border,
BorderColour = Color4.White,
Children = new[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Alpha = 0,
AlwaysPresent = true
}
}
}
}
},
circlePiece = new CirclePiece
{
Children = new []
{
symbol = new SwellSymbolPiece()
}
}
}
}
};
}

[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
circlePiece.AccentColour = colours.YellowDark;
expandingRing.Colour = colours.YellowLight;
targetRing.BorderColour = colours.YellowDark.Opacity(0.25f);
}

protected override void CheckJudgement(bool userTriggered)
{
if (userTriggered)
{
if (Time.Current < HitObject.StartTime)
return;

userHits++;

var completion = (float)userHits / swell.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);

expandingRing.ScaleTo(1f + Math.Min(target_ring_scale - 1f, (target_ring_scale - 1f) * completion * 1.3f), 260, EasingTypes.OutQuint);

if (userHits == swell.RequiredHits)
{
Judgement.Result = HitResult.Hit;
Expand All @@ -43,6 +166,7 @@ protected override void CheckJudgement(bool userTriggered)
if (Judgement.TimeOffset < 0)
return;

//TODO: THIS IS SHIT AND CAN'T EXIST POST-TAIKO WORLD CUP
if (userHits > swell.RequiredHits / 2)
{
Judgement.Result = HitResult.Hit;
Expand All @@ -55,18 +179,61 @@ protected override void CheckJudgement(bool userTriggered)

protected override void UpdateState(ArmedState state)
{
const float preempt = 100;

Delay(HitObject.StartTime - Time.Current - preempt, true);

targetRing.ScaleTo(target_ring_scale, preempt * 4, EasingTypes.OutQuint);

Delay(preempt, true);

Delay(Judgement.TimeOffset + swell.Duration, true);

const float out_transition_time = 300;

switch (state)
{
case ArmedState.Hit:
bodyContainer.ScaleTo(1.4f, out_transition_time);
break;
}

FadeOut(out_transition_time, EasingTypes.Out);

Expire();
}

protected override void UpdateScrollPosition(double time)
{
base.UpdateScrollPosition(Math.Min(time, HitObject.StartTime));
// Make the swell stop at the hit target
double t = Math.Min(HitObject.StartTime, time);

if (t == HitObject.StartTime && !hasStarted)
{
OnStart?.Invoke();
hasStarted = true;
}

base.UpdateScrollPosition(t);
}

protected override bool HandleKeyPress(Key key)
{
if (Judgement.Result.HasValue)
return false;

// Don't handle keys before the swell starts
if (Time.Current < HitObject.StartTime)
return false;

// Find the keyset which this key corresponds to
var keySet = rimKeys.Contains(key) ? rimKeys : centreKeys;

// Ensure alternating keysets
if (keySet == lastKeySet)
return false;
lastKeySet = keySet;

UpdateJudgement(true);

return true;
Expand Down
24 changes: 24 additions & 0 deletions osu.Game.Modes.Taiko/Objects/Drawable/Pieces/SwellSymbolPiece.cs
@@ -0,0 +1,24 @@
// 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.Graphics;
using osu.Framework.Graphics;

namespace osu.Game.Modes.Taiko.Objects.Drawable.Pieces
{
/// <summary>
/// The symbol used for swell pieces.
/// </summary>
public class SwellSymbolPiece : TextAwesome
{
public SwellSymbolPiece()
{
Anchor = Anchor.Centre;
Origin = Anchor.Centre;
UseFullGlyphHeight = true;
TextSize = CirclePiece.SYMBOL_INNER_SIZE;
Icon = FontAwesome.fa_asterisk;
Shadow = false;
}
}
}
2 changes: 1 addition & 1 deletion osu.Game.Modes.Taiko/Objects/Swell.cs
Expand Up @@ -17,7 +17,7 @@ public class Swell : TaikoHitObject, IHasEndTime
/// <summary>
/// The number of hits required to complete the swell successfully.
/// </summary>
public int RequiredHits { get; protected set; }
public int RequiredHits { get; protected set; } = 10;

public override void ApplyDefaults(TimingInfo timing, BeatmapDifficulty difficulty)
{
Expand Down