1
0
mirror of https://github.com/ppy/osu.git synced 2025-02-16 18:32:56 +08:00

Merge pull request #656 from smoogipooo/taiko-fixes

Taiko fixes
This commit is contained in:
Dean Herbert 2017-04-20 20:10:29 +09:00 committed by GitHub
commit 6e3125e115
12 changed files with 99 additions and 37 deletions

View File

@ -138,8 +138,7 @@ namespace osu.Game.Rulesets.Osu
if (h is Spinner) if (h is Spinner)
{ {
targetPosition.X = Frames[Frames.Count - 1].MouseX; targetPosition = Frames[Frames.Count - 1].Position;
targetPosition.Y = Frames[Frames.Count - 1].MouseY;
Vector2 difference = spinner_centre - targetPosition; Vector2 difference = spinner_centre - targetPosition;
@ -193,7 +192,7 @@ namespace osu.Game.Rulesets.Osu
addFrameToReplay(lastFrame); addFrameToReplay(lastFrame);
} }
Vector2 lastPosition = new Vector2(lastFrame.MouseX, lastFrame.MouseY); Vector2 lastPosition = lastFrame.Position;
double timeDifference = applyModsToTime(h.StartTime - lastFrame.Time); double timeDifference = applyModsToTime(h.StartTime - lastFrame.Time);

View File

@ -98,11 +98,11 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
double osuDuration = distance / osuVelocity; double osuDuration = distance / osuVelocity;
// If the drum roll is to be split into hit circles, assume the ticks are 1/8 spaced within the duration of one beat // If the drum roll is to be split into hit circles, assume the ticks are 1/8 spaced within the duration of one beat
double tickSpacing = Math.Min(speedAdjustedBeatLength / beatmap.BeatmapInfo.Difficulty.SliderTickRate, taikoDuration / repeats) / 8; double tickSpacing = Math.Min(speedAdjustedBeatLength / beatmap.BeatmapInfo.Difficulty.SliderTickRate, taikoDuration / repeats);
if (tickSpacing > 0 && osuDuration < 2 * speedAdjustedBeatLength) if (tickSpacing > 0 && osuDuration < 2 * speedAdjustedBeatLength)
{ {
for (double j = obj.StartTime; j <= distanceData.EndTime + tickSpacing; j += tickSpacing) for (double j = obj.StartTime; j <= obj.StartTime + taikoDuration + tickSpacing / 8; j += tickSpacing)
{ {
// Todo: This should generate different type of hits (including strongs) // Todo: This should generate different type of hits (including strongs)
// depending on hitobject sound additions (not implemented fully yet) // depending on hitobject sound additions (not implemented fully yet)

View File

@ -27,11 +27,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
protected override void CheckJudgement(bool userTriggered) protected override void CheckJudgement(bool userTriggered)
{ {
if (!userTriggered) if (!userTriggered)
{
if (Judgement.TimeOffset > HitObject.HitWindow)
Judgement.Result = HitResult.Miss;
return; return;
}
if (Math.Abs(Judgement.TimeOffset) < HitObject.HitWindow) if (Math.Abs(Judgement.TimeOffset) < HitObject.HitWindow)
{ {

View File

@ -20,7 +20,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces
/// <summary> /// <summary>
/// The size of a tick. /// The size of a tick.
/// </summary> /// </summary>
private const float tick_size = TaikoHitObject.DEFAULT_CIRCLE_DIAMETER / 4; private const float tick_size = TaikoHitObject.DEFAULT_CIRCLE_DIAMETER / 6;
private bool filled; private bool filled;
public bool Filled public bool Filled

View File

@ -24,8 +24,8 @@ namespace osu.Game.Rulesets.Taiko.Replays
{ {
bool hitButton = true; bool hitButton = true;
Frames.Add(new ReplayFrame(-100000, 320, 240, ReplayButtonState.None)); Frames.Add(new ReplayFrame(-100000, null, null, ReplayButtonState.None));
Frames.Add(new ReplayFrame(beatmap.HitObjects[0].StartTime - 1000, 320, 240, ReplayButtonState.None)); Frames.Add(new ReplayFrame(beatmap.HitObjects[0].StartTime - 1000, null, null, ReplayButtonState.None));
for (int i = 0; i < beatmap.HitObjects.Count; i++) for (int i = 0; i < beatmap.HitObjects.Count; i++)
{ {
@ -64,7 +64,7 @@ namespace osu.Game.Rulesets.Taiko.Replays
break; break;
} }
Frames.Add(new ReplayFrame(j, 0, 0, button)); Frames.Add(new ReplayFrame(j, null, null, button));
d = (d + 1) % 4; d = (d + 1) % 4;
if (++count > req) if (++count > req)
break; break;
@ -74,7 +74,7 @@ namespace osu.Game.Rulesets.Taiko.Replays
{ {
foreach (var tick in drumRoll.Ticks) foreach (var tick in drumRoll.Ticks)
{ {
Frames.Add(new ReplayFrame(tick.StartTime, 0, 0, hitButton ? ReplayButtonState.Left1 : ReplayButtonState.Left2)); Frames.Add(new ReplayFrame(tick.StartTime, null, null, hitButton ? ReplayButtonState.Left1 : ReplayButtonState.Left2));
hitButton = !hitButton; hitButton = !hitButton;
} }
} }
@ -95,18 +95,18 @@ namespace osu.Game.Rulesets.Taiko.Replays
button = hitButton ? ReplayButtonState.Left1 : ReplayButtonState.Left2; button = hitButton ? ReplayButtonState.Left1 : ReplayButtonState.Left2;
} }
Frames.Add(new ReplayFrame(h.StartTime, 0, 0, button)); Frames.Add(new ReplayFrame(h.StartTime, null, null, button));
} }
else else
throw new Exception("Unknown hit object type."); throw new Exception("Unknown hit object type.");
Frames.Add(new ReplayFrame(endTime + KEY_UP_DELAY, 0, 0, ReplayButtonState.None)); Frames.Add(new ReplayFrame(endTime + KEY_UP_DELAY, null, null, ReplayButtonState.None));
if (i < beatmap.HitObjects.Count - 1) if (i < beatmap.HitObjects.Count - 1)
{ {
double waitTime = beatmap.HitObjects[i + 1].StartTime - 1000; double waitTime = beatmap.HitObjects[i + 1].StartTime - 1000;
if (waitTime > endTime) if (waitTime > endTime)
Frames.Add(new ReplayFrame(waitTime, 0, 0, ReplayButtonState.None)); Frames.Add(new ReplayFrame(waitTime, null, null, ReplayButtonState.None));
} }
hitButton = !hitButton; hitButton = !hitButton;

View File

@ -108,7 +108,7 @@ namespace osu.Game.Database
using (var lzma = new LzmaStream(properties, replayInStream, compressedSize, outSize)) using (var lzma = new LzmaStream(properties, replayInStream, compressedSize, outSize))
using (var reader = new StreamReader(lzma)) using (var reader = new StreamReader(lzma))
score.Replay = createReplay(reader); score.Replay = createLegacyReplay(reader);
} }
} }
@ -116,11 +116,11 @@ namespace osu.Game.Database
} }
/// <summary> /// <summary>
/// Creates a replay which is read from a stream. /// Creates a legacy replay which is read from a stream.
/// </summary> /// </summary>
/// <param name="reader">The stream reader.</param> /// <param name="reader">The stream reader.</param>
/// <returns>The replay.</returns> /// <returns>The legacy replay.</returns>
private Replay createReplay(StreamReader reader) private Replay createLegacyReplay(StreamReader reader)
{ {
var frames = new List<ReplayFrame>(); var frames = new List<ReplayFrame>();

View File

@ -80,6 +80,10 @@ namespace osu.Game.Graphics
public Color4 GrayE = FromHex(@"eee"); public Color4 GrayE = FromHex(@"eee");
public Color4 GrayF = FromHex(@"fff"); public Color4 GrayF = FromHex(@"fff");
public Color4 Red = FromHex(@"fc4549"); public Color4 RedLighter = FromHex(@"ffeded");
public Color4 RedLight = FromHex(@"ed7787");
public Color4 Red = FromHex(@"ed1121");
public Color4 RedDark = FromHex(@"ba0011");
public Color4 RedDarker = FromHex(@"870000");
} }
} }

View File

@ -7,12 +7,12 @@ namespace osu.Game.Rulesets.Replays
{ {
public class ReplayFrame public class ReplayFrame
{ {
public Vector2 Position => new Vector2(MouseX, MouseY); public Vector2 Position => new Vector2(MouseX ?? 0, MouseY ?? 0);
public bool IsImportant => MouseLeft || MouseRight; public bool IsImportant => MouseX.HasValue && MouseY.HasValue && (MouseLeft || MouseRight);
public float MouseX; public float? MouseX;
public float MouseY; public float? MouseY;
public bool MouseLeft => MouseLeft1 || MouseLeft2; public bool MouseLeft => MouseLeft1 || MouseLeft2;
public bool MouseRight => MouseRight1 || MouseRight2; public bool MouseRight => MouseRight1 || MouseRight2;
@ -55,10 +55,10 @@ namespace osu.Game.Rulesets.Replays
} }
public ReplayFrame(double time, float posX, float posY, ReplayButtonState buttonState) public ReplayFrame(double time, float? mouseX, float? mouseY, ReplayButtonState buttonState)
{ {
MouseX = posX; MouseX = mouseX;
MouseY = posY; MouseY = mouseY;
ButtonState = buttonState; ButtonState = buttonState;
Time = time; Time = time;
} }

View File

@ -19,6 +19,11 @@ namespace osu.Game.Rulesets.Scoring
/// </summary> /// </summary>
public event Action Failed; public event Action Failed;
/// <summary>
/// Invoked when a new judgement has occurred. This occurs after the judgement has been processed by the <see cref="ScoreProcessor"/>.
/// </summary>
public event Action<Judgement> NewJudgement;
/// <summary> /// <summary>
/// The current total score. /// The current total score.
/// </summary> /// </summary>
@ -105,6 +110,15 @@ namespace osu.Game.Rulesets.Scoring
Failed?.Invoke(); Failed?.Invoke();
} }
/// <summary>
/// Notifies subscribers of <see cref="NewJudgement"/> that a new judgement has occurred.
/// </summary>
/// <param name="judgement">The judgement to notify subscribers of.</param>
protected void NotifyNewJudgement(Judgement judgement)
{
NewJudgement?.Invoke(judgement);
}
/// <summary> /// <summary>
/// Retrieve a score populated with data for the current play this processor is responsible for. /// Retrieve a score populated with data for the current play this processor is responsible for.
/// </summary> /// </summary>
@ -177,6 +191,8 @@ namespace osu.Game.Rulesets.Scoring
Judgements.Add(judgement); Judgements.Add(judgement);
OnNewJudgement(judgement); OnNewJudgement(judgement);
NotifyNewJudgement(judgement);
} }
else else
OnJudgementChanged(judgement); OnJudgementChanged(judgement);

View File

@ -94,7 +94,7 @@ namespace osu.Game.Rulesets.UI
} }
} }
public void BindProcessor(ScoreProcessor processor) public virtual void BindProcessor(ScoreProcessor processor)
{ {
ScoreCounter?.Current.BindTo(processor.TotalScore); ScoreCounter?.Current.BindTo(processor.TotalScore);
AccuracyCounter?.Current.BindTo(processor.Accuracy); AccuracyCounter?.Current.BindTo(processor.Accuracy);
@ -102,7 +102,7 @@ namespace osu.Game.Rulesets.UI
HealthDisplay?.Current.BindTo(processor.Health); HealthDisplay?.Current.BindTo(processor.Health);
} }
public void BindHitRenderer(HitRenderer hitRenderer) public virtual void BindHitRenderer(HitRenderer hitRenderer)
{ {
hitRenderer.InputManager.Add(KeyCounter.GetReceptor()); hitRenderer.InputManager.Add(KeyCounter.GetReceptor());
} }

View File

@ -3,15 +3,42 @@
using OpenTK; using OpenTK;
using OpenTK.Graphics; using OpenTK.Graphics;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects.Drawables;
using System;
namespace osu.Game.Rulesets.UI namespace osu.Game.Rulesets.UI
{ {
public class StandardHealthDisplay : HealthDisplay, IHasAccentColour public class StandardHealthDisplay : HealthDisplay, IHasAccentColour
{ {
/// <summary>
/// The base opacity of the glow.
/// </summary>
private const float base_glow_opacity = 0.6f;
/// <summary>
/// The number of sequential hits required within <see cref="glow_fade_delay"/> to reach the maximum glow opacity.
/// </summary>
private const int glow_max_hits = 8;
/// <summary>
/// The amount of time to delay before fading the glow opacity back to <see cref="base_glow_opacity"/>.
/// <para>
/// This is calculated to require a stream snapped to 1/4 at 150bpm to reach the maximum glow opacity with <see cref="glow_max_hits"/> hits.
/// </para>
/// </summary>
private const float glow_fade_delay = 100;
/// <summary>
/// The amount of time to fade the glow to <see cref="base_glow_opacity"/> after <see cref="glow_fade_delay"/>.
/// </summary>
private const double glow_fade_time = 500;
private readonly Container fill; private readonly Container fill;
public Color4 AccentColour public Color4 AccentColour
@ -32,9 +59,10 @@ namespace osu.Game.Rulesets.UI
fill.EdgeEffect = new EdgeEffect fill.EdgeEffect = new EdgeEffect
{ {
Colour = glowColour, Colour = glowColour.Opacity(base_glow_opacity),
Radius = 8, Radius = 8,
Type = EdgeEffectType.Glow Roundness = 4,
Type = EdgeEffectType.Glow,
}; };
} }
} }
@ -51,7 +79,7 @@ namespace osu.Game.Rulesets.UI
fill = new Container fill = new Container
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Scale = new Vector2(0, 1), Size = new Vector2(0, 1),
Masking = true, Masking = true,
Children = new[] Children = new[]
{ {
@ -64,6 +92,16 @@ namespace osu.Game.Rulesets.UI
}; };
} }
protected override void SetHealth(float value) => fill.ScaleTo(new Vector2(value, 1), 200, EasingTypes.OutQuint); public void Flash(Judgement judgement)
{
if (judgement.Result == HitResult.Miss)
return;
fill.FadeEdgeEffectTo(Math.Min(1, fill.EdgeEffect.Colour.Linear.A + (1f - base_glow_opacity) / glow_max_hits), 50, EasingTypes.OutQuint);
fill.Delay(glow_fade_delay);
fill.FadeEdgeEffectTo(base_glow_opacity, glow_fade_time, EasingTypes.OutQuint);
}
protected override void SetHealth(float value) => fill.ResizeTo(new Vector2(value, 1), 200, EasingTypes.OutQuint);
} }
} }

View File

@ -3,11 +3,11 @@
using OpenTK; using OpenTK;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Primitives; using osu.Framework.Graphics.Primitives;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using osu.Game.Rulesets.Scoring;
using osu.Game.Screens.Play; using osu.Game.Screens.Play;
namespace osu.Game.Rulesets.UI namespace osu.Game.Rulesets.UI
@ -75,8 +75,17 @@ namespace osu.Game.Rulesets.UI
if (shd != null) if (shd != null)
{ {
shd.AccentColour = colours.BlueLighter; shd.AccentColour = colours.BlueLighter;
shd.GlowColour = colours.BlueDarker.Opacity(0.6f); shd.GlowColour = colours.BlueDarker;
} }
} }
public override void BindProcessor(ScoreProcessor processor)
{
base.BindProcessor(processor);
var shd = HealthDisplay as StandardHealthDisplay;
if (shd != null)
processor.NewJudgement += shd.Flash;
}
} }
} }