mirror of
https://github.com/ppy/osu.git
synced 2024-12-15 00:33:21 +08:00
Merge branch 'master' into breadcrumbs
This commit is contained in:
commit
4a0c8fb5dd
@ -1 +1 @@
|
|||||||
Subproject commit 8baad1b9484b9f35724e2f965c18cfe710907d80
|
Subproject commit 0f3db5da09d0e7c4d2ef3057030e018f34ba536e
|
@ -11,6 +11,9 @@ using OpenTK;
|
|||||||
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Mania.Objects;
|
using osu.Game.Rulesets.Mania.Objects;
|
||||||
using osu.Game.Rulesets.Mania.Timing;
|
using osu.Game.Rulesets.Mania.Timing;
|
||||||
|
using osu.Framework.Configuration;
|
||||||
|
using OpenTK.Input;
|
||||||
|
using osu.Framework.Timing;
|
||||||
|
|
||||||
namespace osu.Desktop.VisualTests.Tests
|
namespace osu.Desktop.VisualTests.Tests
|
||||||
{
|
{
|
||||||
@ -59,6 +62,51 @@ namespace osu.Desktop.VisualTests.Tests
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Action createPlayfieldWithNotesAcceptingInput = () =>
|
||||||
|
{
|
||||||
|
Clear();
|
||||||
|
|
||||||
|
var rateAdjustClock = new StopwatchClock(true) { Rate = 0.5 };
|
||||||
|
|
||||||
|
ManiaPlayfield playField;
|
||||||
|
Add(playField = new ManiaPlayfield(4, new List<TimingChange> { new TimingChange { BeatLength = 200 } })
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Scale = new Vector2(1, -1),
|
||||||
|
Clock = new FramedClock(rateAdjustClock)
|
||||||
|
});
|
||||||
|
|
||||||
|
for (int t = 1000; t <= 2000; t += 100)
|
||||||
|
{
|
||||||
|
playField.Add(new DrawableNote(new Note
|
||||||
|
{
|
||||||
|
StartTime = t,
|
||||||
|
Column = 0
|
||||||
|
}, new Bindable<Key>(Key.D)));
|
||||||
|
|
||||||
|
playField.Add(new DrawableNote(new Note
|
||||||
|
{
|
||||||
|
StartTime = t,
|
||||||
|
Column = 3
|
||||||
|
}, new Bindable<Key>(Key.K)));
|
||||||
|
}
|
||||||
|
|
||||||
|
playField.Add(new DrawableHoldNote(new HoldNote
|
||||||
|
{
|
||||||
|
StartTime = 1000,
|
||||||
|
Duration = 1000,
|
||||||
|
Column = 1
|
||||||
|
}, new Bindable<Key>(Key.F)));
|
||||||
|
|
||||||
|
playField.Add(new DrawableHoldNote(new HoldNote
|
||||||
|
{
|
||||||
|
StartTime = 1000,
|
||||||
|
Duration = 1000,
|
||||||
|
Column = 2
|
||||||
|
}, new Bindable<Key>(Key.J)));
|
||||||
|
};
|
||||||
|
|
||||||
AddStep("1 column", () => createPlayfield(1, SpecialColumnPosition.Normal));
|
AddStep("1 column", () => createPlayfield(1, SpecialColumnPosition.Normal));
|
||||||
AddStep("4 columns", () => createPlayfield(4, SpecialColumnPosition.Normal));
|
AddStep("4 columns", () => createPlayfield(4, SpecialColumnPosition.Normal));
|
||||||
AddStep("Left special style", () => createPlayfield(4, SpecialColumnPosition.Left));
|
AddStep("Left special style", () => createPlayfield(4, SpecialColumnPosition.Left));
|
||||||
@ -76,11 +124,13 @@ namespace osu.Desktop.VisualTests.Tests
|
|||||||
AddWaitStep(10);
|
AddWaitStep(10);
|
||||||
AddStep("Right special style", () => createPlayfieldWithNotes(4, SpecialColumnPosition.Right));
|
AddStep("Right special style", () => createPlayfieldWithNotes(4, SpecialColumnPosition.Right));
|
||||||
AddWaitStep(10);
|
AddWaitStep(10);
|
||||||
|
|
||||||
|
AddStep("Notes with input", () => createPlayfieldWithNotesAcceptingInput());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void triggerKeyDown(Column column)
|
private void triggerKeyDown(Column column)
|
||||||
{
|
{
|
||||||
column.TriggerKeyDown(new InputState(), new KeyDownEventArgs
|
column.TriggerOnKeyDown(new InputState(), new KeyDownEventArgs
|
||||||
{
|
{
|
||||||
Key = column.Key,
|
Key = column.Key,
|
||||||
Repeat = false
|
Repeat = false
|
||||||
@ -89,7 +139,7 @@ namespace osu.Desktop.VisualTests.Tests
|
|||||||
|
|
||||||
private void triggerKeyUp(Column column)
|
private void triggerKeyUp(Column column)
|
||||||
{
|
{
|
||||||
column.TriggerKeyUp(new InputState(), new KeyUpEventArgs
|
column.TriggerOnKeyUp(new InputState(), new KeyUpEventArgs
|
||||||
{
|
{
|
||||||
Key = column.Key
|
Key = column.Key
|
||||||
});
|
});
|
||||||
|
@ -32,14 +32,14 @@ namespace osu.Desktop.VisualTests.Tests
|
|||||||
Username = @"flyte",
|
Username = @"flyte",
|
||||||
Id = 3103765,
|
Id = 3103765,
|
||||||
Country = new Country { FlagName = @"JP" },
|
Country = new Country { FlagName = @"JP" },
|
||||||
CoverUrl = @"https://assets.ppy.sh/user-profile-covers/3103765/5b012e13611d5761caa7e24fecb3d3a16e1cf48fc2a3032cfd43dd444af83d82.jpeg"
|
CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c6.jpg"
|
||||||
}) { Width = 300 },
|
}) { Width = 300 },
|
||||||
peppy = new UserPanel(new User
|
peppy = new UserPanel(new User
|
||||||
{
|
{
|
||||||
Username = @"peppy",
|
Username = @"peppy",
|
||||||
Id = 2,
|
Id = 2,
|
||||||
Country = new Country { FlagName = @"AU" },
|
Country = new Country { FlagName = @"AU" },
|
||||||
CoverUrl = @"https://assets.ppy.sh/user-profile-covers/2/08cad88747c235a64fca5f1b770e100f120827ded1ffe3b66bfcd19c940afa65.jpeg"
|
CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c3.jpg"
|
||||||
}) { Width = 300 },
|
}) { Width = 300 },
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -471,14 +471,17 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
newObject = new HoldNote
|
var holdNote = new HoldNote
|
||||||
{
|
{
|
||||||
StartTime = startTime,
|
StartTime = startTime,
|
||||||
Samples = sampleInfoListAt(startTime),
|
|
||||||
EndSamples = sampleInfoListAt(endTime),
|
|
||||||
Column = column,
|
Column = column,
|
||||||
Duration = endTime - startTime
|
Duration = endTime - startTime,
|
||||||
|
Head = { Samples = sampleInfoListAt(startTime) },
|
||||||
|
Tail = { Samples = sampleInfoListAt(endTime) }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
newObject = holdNote;
|
||||||
}
|
}
|
||||||
|
|
||||||
pattern.Add(newObject);
|
pattern.Add(newObject);
|
||||||
|
@ -69,18 +69,21 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
|
|
||||||
if (holdNote)
|
if (holdNote)
|
||||||
{
|
{
|
||||||
newObject = new HoldNote
|
var hold = new HoldNote
|
||||||
{
|
{
|
||||||
StartTime = HitObject.StartTime,
|
StartTime = HitObject.StartTime,
|
||||||
EndSamples = HitObject.Samples,
|
|
||||||
Column = column,
|
Column = column,
|
||||||
Duration = endTime - HitObject.StartTime
|
Duration = endTime - HitObject.StartTime
|
||||||
};
|
};
|
||||||
|
|
||||||
newObject.Samples.Add(new SampleInfo
|
hold.Head.Samples.Add(new SampleInfo
|
||||||
{
|
{
|
||||||
Name = SampleInfo.HIT_NORMAL
|
Name = SampleInfo.HIT_NORMAL
|
||||||
});
|
});
|
||||||
|
|
||||||
|
hold.Tail.Samples = HitObject.Samples;
|
||||||
|
|
||||||
|
newObject = hold;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
13
osu.Game.Rulesets.Mania/Judgements/HoldNoteTailJudgement.cs
Normal file
13
osu.Game.Rulesets.Mania/Judgements/HoldNoteTailJudgement.cs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Judgements
|
||||||
|
{
|
||||||
|
public class HoldNoteTailJudgement : ManiaJudgement
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the hold note has been released too early and shouldn't give full score for the release.
|
||||||
|
/// </summary>
|
||||||
|
public bool HasBroken;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Judgements
|
||||||
|
{
|
||||||
|
public class HoldNoteTickJudgement : ManiaJudgement
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
@ -7,14 +7,34 @@ using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
|
|||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
using osu.Framework.Configuration;
|
using osu.Framework.Configuration;
|
||||||
using OpenTK.Input;
|
using OpenTK.Input;
|
||||||
|
using osu.Framework.Input;
|
||||||
|
using OpenTK;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Game.Rulesets.Mania.Judgements;
|
||||||
|
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Visualises a <see cref="HoldNote"/> hit object.
|
||||||
|
/// </summary>
|
||||||
public class DrawableHoldNote : DrawableManiaHitObject<HoldNote>
|
public class DrawableHoldNote : DrawableManiaHitObject<HoldNote>
|
||||||
{
|
{
|
||||||
private readonly NotePiece headPiece;
|
private readonly DrawableNote head;
|
||||||
|
private readonly DrawableNote tail;
|
||||||
|
|
||||||
private readonly BodyPiece bodyPiece;
|
private readonly BodyPiece bodyPiece;
|
||||||
private readonly NotePiece tailPiece;
|
private readonly Container<DrawableHoldNoteTick> tickContainer;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Time at which the user started holding this hold note. Null if the user is not holding this hold note.
|
||||||
|
/// </summary>
|
||||||
|
private double? holdStartTime;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the hold note has been released too early and shouldn't give full score for the release.
|
||||||
|
/// </summary>
|
||||||
|
private bool hasBroken;
|
||||||
|
|
||||||
public DrawableHoldNote(HoldNote hitObject, Bindable<Key> key = null)
|
public DrawableHoldNote(HoldNote hitObject, Bindable<Key> key = null)
|
||||||
: base(hitObject, key)
|
: base(hitObject, key)
|
||||||
@ -32,17 +52,39 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
Anchor = Anchor.TopCentre,
|
Anchor = Anchor.TopCentre,
|
||||||
Origin = Anchor.TopCentre,
|
Origin = Anchor.TopCentre,
|
||||||
},
|
},
|
||||||
headPiece = new NotePiece
|
tickContainer = new Container<DrawableHoldNoteTick>
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
RelativeCoordinateSpace = new Vector2(1, (float)HitObject.Duration)
|
||||||
|
},
|
||||||
|
head = new DrawableHeadNote(this, key)
|
||||||
{
|
{
|
||||||
Anchor = Anchor.TopCentre,
|
Anchor = Anchor.TopCentre,
|
||||||
Origin = Anchor.TopCentre
|
Origin = Anchor.TopCentre
|
||||||
},
|
},
|
||||||
tailPiece = new NotePiece
|
tail = new DrawableTailNote(this, key)
|
||||||
{
|
{
|
||||||
Anchor = Anchor.BottomCentre,
|
Anchor = Anchor.BottomCentre,
|
||||||
Origin = Anchor.TopCentre
|
Origin = Anchor.TopCentre
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
foreach (var tick in HitObject.Ticks)
|
||||||
|
{
|
||||||
|
var drawableTick = new DrawableHoldNoteTick(tick)
|
||||||
|
{
|
||||||
|
HoldStartTime = () => holdStartTime
|
||||||
|
};
|
||||||
|
|
||||||
|
// To make the ticks relative to ourselves we need to offset them backwards
|
||||||
|
drawableTick.Y -= (float)HitObject.StartTime;
|
||||||
|
|
||||||
|
tickContainer.Add(drawableTick);
|
||||||
|
AddNested(drawableTick);
|
||||||
|
}
|
||||||
|
|
||||||
|
AddNested(head);
|
||||||
|
AddNested(tail);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Color4 AccentColour
|
public override Color4 AccentColour
|
||||||
@ -54,9 +96,11 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
return;
|
return;
|
||||||
base.AccentColour = value;
|
base.AccentColour = value;
|
||||||
|
|
||||||
headPiece.AccentColour = value;
|
tickContainer.Children.ForEach(t => t.AccentColour = value);
|
||||||
|
|
||||||
bodyPiece.AccentColour = value;
|
bodyPiece.AccentColour = value;
|
||||||
tailPiece.AccentColour = value;
|
head.AccentColour = value;
|
||||||
|
tail.AccentColour = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,14 +108,132 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Update()
|
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
|
||||||
{
|
{
|
||||||
if (Time.Current > HitObject.StartTime)
|
// Make sure the keypress happened within the body of the hold note
|
||||||
headPiece.Colour = Color4.Green;
|
if (Time.Current < HitObject.StartTime || Time.Current > HitObject.EndTime)
|
||||||
if (Time.Current > HitObject.EndTime)
|
return false;
|
||||||
|
|
||||||
|
if (args.Key != Key)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (args.Repeat)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// The user has pressed during the body of the hold note, after the head note and its hit windows have passed
|
||||||
|
// and within the limited range of the above if-statement. This state will be managed by the head note if the
|
||||||
|
// user has pressed during the hit windows of the head note.
|
||||||
|
holdStartTime = Time.Current;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool OnKeyUp(InputState state, KeyUpEventArgs args)
|
||||||
|
{
|
||||||
|
// Make sure that the user started holding the key during the hold note
|
||||||
|
if (!holdStartTime.HasValue)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (args.Key != Key)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
holdStartTime = null;
|
||||||
|
|
||||||
|
// If the key has been released too early, the user should not receive full score for the release
|
||||||
|
if (!tail.Judged)
|
||||||
|
hasBroken = true;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The head note of a hold.
|
||||||
|
/// </summary>
|
||||||
|
private class DrawableHeadNote : DrawableNote
|
||||||
|
{
|
||||||
|
private readonly DrawableHoldNote holdNote;
|
||||||
|
|
||||||
|
public DrawableHeadNote(DrawableHoldNote holdNote, Bindable<Key> key = null)
|
||||||
|
: base(holdNote.HitObject.Head, key)
|
||||||
{
|
{
|
||||||
bodyPiece.Colour = Color4.Green;
|
this.holdNote = holdNote;
|
||||||
tailPiece.Colour = Color4.Green;
|
|
||||||
|
RelativePositionAxes = Axes.None;
|
||||||
|
Y = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
|
||||||
|
{
|
||||||
|
if (!base.OnKeyDown(state, args))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// We only want to trigger a holding state from the head if the head has received a judgement
|
||||||
|
if (!Judged)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// If the key has been released too early, the user should not receive full score for the release
|
||||||
|
if (Judgement.Result == HitResult.Miss)
|
||||||
|
holdNote.hasBroken = true;
|
||||||
|
|
||||||
|
// The head note also handles early hits before the body, but we want accurate early hits to count as the body being held
|
||||||
|
// The body doesn't handle these early early hits, so we have to explicitly set the holding state here
|
||||||
|
holdNote.holdStartTime = Time.Current;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The tail note of a hold.
|
||||||
|
/// </summary>
|
||||||
|
private class DrawableTailNote : DrawableNote
|
||||||
|
{
|
||||||
|
private readonly DrawableHoldNote holdNote;
|
||||||
|
|
||||||
|
public DrawableTailNote(DrawableHoldNote holdNote, Bindable<Key> key = null)
|
||||||
|
: base(holdNote.HitObject.Tail, key)
|
||||||
|
{
|
||||||
|
this.holdNote = holdNote;
|
||||||
|
|
||||||
|
RelativePositionAxes = Axes.None;
|
||||||
|
Y = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override ManiaJudgement CreateJudgement() => new HoldNoteTailJudgement();
|
||||||
|
|
||||||
|
protected override void CheckJudgement(bool userTriggered)
|
||||||
|
{
|
||||||
|
base.CheckJudgement(userTriggered);
|
||||||
|
|
||||||
|
var tailJudgement = Judgement as HoldNoteTailJudgement;
|
||||||
|
if (tailJudgement == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
tailJudgement.HasBroken = holdNote.hasBroken;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool OnKeyUp(InputState state, KeyUpEventArgs args)
|
||||||
|
{
|
||||||
|
// Make sure that the user started holding the key during the hold note
|
||||||
|
if (!holdNote.holdStartTime.HasValue)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (Judgement.Result != HitResult.None)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (args.Key != Key)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
UpdateJudgement(true);
|
||||||
|
|
||||||
|
// Handled by the hold note, which will set holding = false
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
|
||||||
|
{
|
||||||
|
// Tail doesn't handle key down
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,121 @@
|
|||||||
|
// 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 OpenTK;
|
||||||
|
using OpenTK.Graphics;
|
||||||
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Game.Rulesets.Mania.Judgements;
|
||||||
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Visualises a <see cref="HoldNoteTick"/> hit object.
|
||||||
|
/// </summary>
|
||||||
|
public class DrawableHoldNoteTick : DrawableManiaHitObject<HoldNoteTick>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// References the time at which the user started holding the hold note.
|
||||||
|
/// </summary>
|
||||||
|
public Func<double?> HoldStartTime;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// References whether the user is currently holding the hold note.
|
||||||
|
/// </summary>
|
||||||
|
public Func<bool> IsHolding;
|
||||||
|
|
||||||
|
private readonly Container glowContainer;
|
||||||
|
|
||||||
|
public DrawableHoldNoteTick(HoldNoteTick hitObject)
|
||||||
|
: base(hitObject)
|
||||||
|
{
|
||||||
|
Anchor = Anchor.TopCentre;
|
||||||
|
Origin = Anchor.TopCentre;
|
||||||
|
|
||||||
|
RelativeSizeAxes = Axes.X;
|
||||||
|
Size = new Vector2(1);
|
||||||
|
|
||||||
|
Children = new[]
|
||||||
|
{
|
||||||
|
glowContainer = new CircularContainer
|
||||||
|
{
|
||||||
|
Anchor = Anchor.TopCentre,
|
||||||
|
Origin = Anchor.TopCentre,
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Masking = true,
|
||||||
|
Children = new[]
|
||||||
|
{
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Alpha = 0,
|
||||||
|
AlwaysPresent = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Set the default glow
|
||||||
|
AccentColour = Color4.White;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Color4 AccentColour
|
||||||
|
{
|
||||||
|
get { return base.AccentColour; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
base.AccentColour = value;
|
||||||
|
|
||||||
|
glowContainer.EdgeEffect = new EdgeEffect
|
||||||
|
{
|
||||||
|
Type = EdgeEffectType.Glow,
|
||||||
|
Radius = 2f,
|
||||||
|
Roundness = 15f,
|
||||||
|
Colour = value.Opacity(0.3f)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override ManiaJudgement CreateJudgement() => new HoldNoteTickJudgement();
|
||||||
|
|
||||||
|
protected override void CheckJudgement(bool userTriggered)
|
||||||
|
{
|
||||||
|
if (!userTriggered)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (Time.Current < HitObject.StartTime)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (HoldStartTime?.Invoke() > HitObject.StartTime)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Judgement.ManiaResult = ManiaHitResult.Perfect;
|
||||||
|
Judgement.Result = HitResult.Hit;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void UpdateState(ArmedState state)
|
||||||
|
{
|
||||||
|
switch (State)
|
||||||
|
{
|
||||||
|
case ArmedState.Hit:
|
||||||
|
AccentColour = Color4.Green;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Update()
|
||||||
|
{
|
||||||
|
if (Judgement.Result != HitResult.None)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (IsHolding?.Invoke() != true)
|
||||||
|
return;
|
||||||
|
|
||||||
|
UpdateJudgement(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -13,6 +13,9 @@ using osu.Game.Rulesets.Objects.Drawables;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Visualises a <see cref="Note"/> hit object.
|
||||||
|
/// </summary>
|
||||||
public class DrawableNote : DrawableManiaHitObject<Note>
|
public class DrawableNote : DrawableManiaHitObject<Note>
|
||||||
{
|
{
|
||||||
private readonly NotePiece headPiece;
|
private readonly NotePiece headPiece;
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
using osu.Game.Audio;
|
using System.Collections.Generic;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Database;
|
using osu.Game.Database;
|
||||||
using osu.Game.Rulesets.Mania.Judgements;
|
|
||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Objects
|
namespace osu.Game.Rulesets.Mania.Objects
|
||||||
@ -12,32 +11,96 @@ namespace osu.Game.Rulesets.Mania.Objects
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a hit object which requires pressing, holding, and releasing a key.
|
/// Represents a hit object which requires pressing, holding, and releasing a key.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class HoldNote : Note, IHasEndTime
|
public class HoldNote : ManiaHitObject, IHasEndTime
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Lenience of release hit windows. This is to make cases where the hold note release
|
|
||||||
/// is timed alongside presses of other hit objects less awkward.
|
|
||||||
/// </summary>
|
|
||||||
private const double release_window_lenience = 1.5;
|
|
||||||
|
|
||||||
public double Duration { get; set; }
|
|
||||||
public double EndTime => StartTime + Duration;
|
public double EndTime => StartTime + Duration;
|
||||||
|
|
||||||
/// <summary>
|
private double duration;
|
||||||
/// The samples to be played when this hold note is released.
|
public double Duration
|
||||||
/// </summary>
|
{
|
||||||
public SampleInfoList EndSamples = new SampleInfoList();
|
get { return duration; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
duration = value;
|
||||||
|
Tail.StartTime = EndTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override double StartTime
|
||||||
|
{
|
||||||
|
get { return base.StartTime; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
base.StartTime = value;
|
||||||
|
Head.StartTime = value;
|
||||||
|
Tail.StartTime = EndTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The key-release hit windows for this hold note.
|
/// The head note of the hold.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public HitWindows ReleaseHitWindows { get; protected set; } = new HitWindows();
|
public readonly Note Head = new Note();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The tail note of the hold.
|
||||||
|
/// </summary>
|
||||||
|
public readonly Note Tail = new TailNote();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The time between ticks of this hold.
|
||||||
|
/// </summary>
|
||||||
|
private double tickSpacing = 50;
|
||||||
|
|
||||||
public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
|
public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
|
||||||
{
|
{
|
||||||
base.ApplyDefaults(controlPointInfo, difficulty);
|
base.ApplyDefaults(controlPointInfo, difficulty);
|
||||||
|
|
||||||
ReleaseHitWindows = HitWindows * release_window_lenience;
|
TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(StartTime);
|
||||||
|
tickSpacing = timingPoint.BeatLength / difficulty.SliderTickRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The scoring scoring ticks of the hold note.
|
||||||
|
/// </summary>
|
||||||
|
public IEnumerable<HoldNoteTick> Ticks => ticks ?? (ticks = createTicks());
|
||||||
|
private List<HoldNoteTick> ticks;
|
||||||
|
|
||||||
|
private List<HoldNoteTick> createTicks()
|
||||||
|
{
|
||||||
|
var ret = new List<HoldNoteTick>();
|
||||||
|
|
||||||
|
if (tickSpacing == 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
for (double t = StartTime + tickSpacing; t <= EndTime - tickSpacing; t += tickSpacing)
|
||||||
|
{
|
||||||
|
ret.Add(new HoldNoteTick
|
||||||
|
{
|
||||||
|
StartTime = t
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The tail of the hold note.
|
||||||
|
/// </summary>
|
||||||
|
private class TailNote : Note
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Lenience of release hit windows. This is to make cases where the hold note release
|
||||||
|
/// is timed alongside presses of other hit objects less awkward.
|
||||||
|
/// </summary>
|
||||||
|
private const double release_window_lenience = 1.5;
|
||||||
|
|
||||||
|
public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
|
||||||
|
{
|
||||||
|
base.ApplyDefaults(controlPointInfo, difficulty);
|
||||||
|
|
||||||
|
HitWindows *= release_window_lenience;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
12
osu.Game.Rulesets.Mania/Objects/HoldNoteTick.cs
Normal file
12
osu.Game.Rulesets.Mania/Objects/HoldNoteTick.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Objects
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A scoring tick of a hold note.
|
||||||
|
/// </summary>
|
||||||
|
public class HoldNoteTick : ManiaHitObject
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
@ -8,6 +8,7 @@ using osu.Framework.Graphics;
|
|||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
|
using osu.Game.Rulesets.Objects;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Timing
|
namespace osu.Game.Rulesets.Mania.Timing
|
||||||
{
|
{
|
||||||
@ -128,6 +129,8 @@ namespace osu.Game.Rulesets.Mania.Timing
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private class AutoTimeRelativeContainer : Container
|
private class AutoTimeRelativeContainer : Container
|
||||||
{
|
{
|
||||||
|
protected override IComparer<Drawable> DepthComparer => new HitObjectReverseStartTimeComparer();
|
||||||
|
|
||||||
public override void InvalidateFromChild(Invalidation invalidation)
|
public override void InvalidateFromChild(Invalidation invalidation)
|
||||||
{
|
{
|
||||||
// We only want to re-compute our size when a child's size or position has changed
|
// We only want to re-compute our size when a child's size or position has changed
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
using OpenTK.Input;
|
using OpenTK.Input;
|
||||||
@ -188,7 +187,11 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Add(DrawableHitObject<ManiaHitObject, ManiaJudgement> hitObject) => ControlPointContainer.Add(hitObject);
|
public void Add(DrawableHitObject<ManiaHitObject, ManiaJudgement> hitObject)
|
||||||
|
{
|
||||||
|
hitObject.AccentColour = AccentColour;
|
||||||
|
ControlPointContainer.Add(hitObject);
|
||||||
|
}
|
||||||
|
|
||||||
private bool onKeyDown(InputState state, KeyDownEventArgs args)
|
private bool onKeyDown(InputState state, KeyDownEventArgs args)
|
||||||
{
|
{
|
||||||
|
@ -57,10 +57,13 @@
|
|||||||
<Compile Include="Beatmaps\Patterns\Pattern.cs" />
|
<Compile Include="Beatmaps\Patterns\Pattern.cs" />
|
||||||
<Compile Include="MathUtils\FastRandom.cs" />
|
<Compile Include="MathUtils\FastRandom.cs" />
|
||||||
<Compile Include="Judgements\HitWindows.cs" />
|
<Compile Include="Judgements\HitWindows.cs" />
|
||||||
|
<Compile Include="Judgements\HoldNoteTailJudgement.cs" />
|
||||||
|
<Compile Include="Judgements\HoldNoteTickJudgement.cs" />
|
||||||
<Compile Include="Judgements\ManiaHitResult.cs" />
|
<Compile Include="Judgements\ManiaHitResult.cs" />
|
||||||
<Compile Include="Judgements\ManiaJudgement.cs" />
|
<Compile Include="Judgements\ManiaJudgement.cs" />
|
||||||
<Compile Include="ManiaDifficultyCalculator.cs" />
|
<Compile Include="ManiaDifficultyCalculator.cs" />
|
||||||
<Compile Include="Objects\Drawables\DrawableHoldNote.cs" />
|
<Compile Include="Objects\Drawables\DrawableHoldNote.cs" />
|
||||||
|
<Compile Include="Objects\Drawables\DrawableHoldNoteTick.cs" />
|
||||||
<Compile Include="Objects\Drawables\DrawableManiaHitObject.cs" />
|
<Compile Include="Objects\Drawables\DrawableManiaHitObject.cs" />
|
||||||
<Compile Include="Objects\Drawables\DrawableNote.cs" />
|
<Compile Include="Objects\Drawables\DrawableNote.cs" />
|
||||||
<Compile Include="Objects\Drawables\Pieces\BodyPiece.cs" />
|
<Compile Include="Objects\Drawables\Pieces\BodyPiece.cs" />
|
||||||
@ -68,6 +71,7 @@
|
|||||||
<Compile Include="Objects\Types\IHasColumn.cs" />
|
<Compile Include="Objects\Types\IHasColumn.cs" />
|
||||||
<Compile Include="Scoring\ManiaScoreProcessor.cs" />
|
<Compile Include="Scoring\ManiaScoreProcessor.cs" />
|
||||||
<Compile Include="Objects\HoldNote.cs" />
|
<Compile Include="Objects\HoldNote.cs" />
|
||||||
|
<Compile Include="Objects\HoldNoteTick.cs" />
|
||||||
<Compile Include="Objects\ManiaHitObject.cs" />
|
<Compile Include="Objects\ManiaHitObject.cs" />
|
||||||
<Compile Include="Objects\Note.cs" />
|
<Compile Include="Objects\Note.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
@ -428,6 +428,9 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (var hitObject in beatmap.HitObjects)
|
||||||
|
hitObject.ApplyDefaults(beatmap.ControlPointInfo, beatmap.BeatmapInfo.Difficulty);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal enum LegacySampleBank
|
internal enum LegacySampleBank
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
using OpenTK.Input;
|
using OpenTK.Input;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -23,11 +24,19 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
set
|
set
|
||||||
{
|
{
|
||||||
focus = value;
|
focus = value;
|
||||||
if (!focus)
|
if (!focus && HasFocus)
|
||||||
TriggerFocusLost();
|
inputManager.ChangeFocus(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private InputManager inputManager;
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(UserInputManager inputManager)
|
||||||
|
{
|
||||||
|
this.inputManager = inputManager;
|
||||||
|
}
|
||||||
|
|
||||||
protected override bool OnFocus(InputState state)
|
protected override bool OnFocus(InputState state)
|
||||||
{
|
{
|
||||||
var result = base.OnFocus(state);
|
var result = base.OnFocus(state);
|
||||||
|
@ -5,18 +5,21 @@ using osu.Framework.Audio.Sample;
|
|||||||
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.Framework.Graphics.Transforms;
|
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
|
using osu.Game.Graphics.Containers;
|
||||||
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
|
using osu.Framework.Audio.Track;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace osu.Game.Graphics.UserInterface
|
namespace osu.Game.Graphics.UserInterface
|
||||||
{
|
{
|
||||||
public class TwoLayerButton : ClickableContainer
|
public class TwoLayerButton : ClickableContainer
|
||||||
{
|
{
|
||||||
private readonly TextAwesome icon;
|
private readonly BouncingIcon bouncingIcon;
|
||||||
|
|
||||||
public Box IconLayer;
|
public Box IconLayer;
|
||||||
public Box TextLayer;
|
public Box TextLayer;
|
||||||
@ -95,11 +98,10 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
icon = new TextAwesome
|
bouncingIcon = new BouncingIcon
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
TextSize = 25,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -146,7 +148,7 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
{
|
{
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
icon.Icon = value;
|
bouncingIcon.Icon = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -162,58 +164,20 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
|
|
||||||
protected override bool OnHover(InputState state)
|
protected override bool OnHover(InputState state)
|
||||||
{
|
{
|
||||||
icon.ClearTransforms();
|
|
||||||
|
|
||||||
ResizeTo(SIZE_EXTENDED, transform_time, EasingTypes.OutElastic);
|
ResizeTo(SIZE_EXTENDED, transform_time, EasingTypes.OutElastic);
|
||||||
|
|
||||||
int duration = 0; //(int)(Game.Audio.BeatLength / 2);
|
|
||||||
if (duration == 0) duration = pulse_length;
|
|
||||||
|
|
||||||
IconLayer.FadeColour(HoverColour, transform_time, EasingTypes.OutElastic);
|
IconLayer.FadeColour(HoverColour, transform_time, EasingTypes.OutElastic);
|
||||||
|
|
||||||
const double offset = 0; //(1 - Game.Audio.SyncBeatProgress) * duration;
|
bouncingIcon.ScaleTo(1.1f, transform_time, EasingTypes.OutElastic);
|
||||||
double startTime = Time.Current + offset;
|
|
||||||
|
|
||||||
// basic pulse
|
|
||||||
icon.Transforms.Add(new TransformScale
|
|
||||||
{
|
|
||||||
StartValue = new Vector2(1.1f),
|
|
||||||
EndValue = Vector2.One,
|
|
||||||
StartTime = startTime,
|
|
||||||
EndTime = startTime + duration,
|
|
||||||
Easing = EasingTypes.Out,
|
|
||||||
LoopCount = -1,
|
|
||||||
LoopDelay = duration
|
|
||||||
});
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnHoverLost(InputState state)
|
protected override void OnHoverLost(InputState state)
|
||||||
{
|
{
|
||||||
icon.ClearTransforms();
|
|
||||||
|
|
||||||
ResizeTo(SIZE_RETRACTED, transform_time, EasingTypes.OutElastic);
|
ResizeTo(SIZE_RETRACTED, transform_time, EasingTypes.OutElastic);
|
||||||
|
|
||||||
IconLayer.FadeColour(TextLayer.Colour, transform_time, EasingTypes.OutElastic);
|
IconLayer.FadeColour(TextLayer.Colour, transform_time, EasingTypes.OutElastic);
|
||||||
|
|
||||||
int duration = 0; //(int)(Game.Audio.BeatLength);
|
bouncingIcon.ScaleTo(1, transform_time, EasingTypes.OutElastic);
|
||||||
if (duration == 0) duration = pulse_length * 2;
|
|
||||||
|
|
||||||
const double offset = 0; //(1 - Game.Audio.SyncBeatProgress) * duration;
|
|
||||||
double startTime = Time.Current + offset;
|
|
||||||
|
|
||||||
// slow pulse
|
|
||||||
icon.Transforms.Add(new TransformScale
|
|
||||||
{
|
|
||||||
StartValue = new Vector2(1.1f),
|
|
||||||
EndValue = Vector2.One,
|
|
||||||
StartTime = startTime,
|
|
||||||
EndTime = startTime + duration,
|
|
||||||
Easing = EasingTypes.Out,
|
|
||||||
LoopCount = -1,
|
|
||||||
LoopDelay = duration
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
|
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
|
||||||
@ -239,5 +203,45 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
|
|
||||||
return base.OnClick(state);
|
return base.OnClick(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class BouncingIcon : BeatSyncedContainer
|
||||||
|
{
|
||||||
|
private const double beat_in_time = 60;
|
||||||
|
|
||||||
|
private readonly TextAwesome icon;
|
||||||
|
|
||||||
|
public FontAwesome Icon { set { icon.Icon = value; } }
|
||||||
|
|
||||||
|
public BouncingIcon()
|
||||||
|
{
|
||||||
|
EarlyActivationMilliseconds = beat_in_time;
|
||||||
|
AutoSizeAxes = Axes.Both;
|
||||||
|
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
icon = new TextAwesome
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
TextSize = 25
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, TrackAmplitudes amplitudes)
|
||||||
|
{
|
||||||
|
base.OnNewBeat(beatIndex, timingPoint, effectPoint, amplitudes);
|
||||||
|
|
||||||
|
var beatLength = timingPoint.BeatLength;
|
||||||
|
|
||||||
|
float amplitudeAdjust = Math.Min(1, 0.4f + amplitudes.Maximum);
|
||||||
|
|
||||||
|
if (beatIndex < 0) return;
|
||||||
|
|
||||||
|
icon.ScaleTo(1 - 0.1f * amplitudeAdjust, beat_in_time, EasingTypes.Out);
|
||||||
|
using (icon.BeginDelayedSequence(beat_in_time))
|
||||||
|
icon.ScaleTo(1, beatLength * 2, EasingTypes.OutQuint);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -74,7 +74,7 @@ namespace osu.Game.Graphics.UserInterface.Volume
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
volumeMeterMaster.TriggerWheel(state);
|
volumeMeterMaster.TriggerOnWheel(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
|
@ -255,6 +255,9 @@ namespace osu.Game
|
|||||||
settings.ToggleVisibility();
|
settings.ToggleVisibility();
|
||||||
return true;
|
return true;
|
||||||
case Key.D:
|
case Key.D:
|
||||||
|
if (state.Keyboard.ShiftPressed || state.Keyboard.AltPressed)
|
||||||
|
return false;
|
||||||
|
|
||||||
direct.ToggleVisibility();
|
direct.ToggleVisibility();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -135,17 +135,22 @@ namespace osu.Game.Overlays
|
|||||||
channelTabs.Current.ValueChanged += newChannel => CurrentChannel = newChannel;
|
channelTabs.Current.ValueChanged += newChannel => CurrentChannel = newChannel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private double startDragChatHeight;
|
||||||
|
|
||||||
protected override bool OnDragStart(InputState state)
|
protected override bool OnDragStart(InputState state)
|
||||||
{
|
{
|
||||||
if (channelTabs.Hovering)
|
if (!channelTabs.Hovering)
|
||||||
return true;
|
return base.OnDragStart(state);
|
||||||
|
|
||||||
return base.OnDragStart(state);
|
startDragChatHeight = chatHeight.Value;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnDrag(InputState state)
|
protected override bool OnDrag(InputState state)
|
||||||
{
|
{
|
||||||
chatHeight.Value = Height - state.Mouse.Delta.Y / Parent.DrawSize.Y;
|
Trace.Assert(state.Mouse.PositionMouseDown != null);
|
||||||
|
|
||||||
|
chatHeight.Value = startDragChatHeight - (state.Mouse.Position.Y - state.Mouse.PositionMouseDown.Value.Y) / Parent.DrawSize.Y;
|
||||||
return base.OnDrag(state);
|
return base.OnDrag(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -165,7 +170,7 @@ namespace osu.Game.Overlays
|
|||||||
protected override bool OnFocus(InputState state)
|
protected override bool OnFocus(InputState state)
|
||||||
{
|
{
|
||||||
//this is necessary as inputTextBox is masked away and therefore can't get focus :(
|
//this is necessary as inputTextBox is masked away and therefore can't get focus :(
|
||||||
inputTextBox.TriggerFocus();
|
InputManager.ChangeFocus(inputTextBox);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@ namespace osu.Game.Overlays.Dialog
|
|||||||
private void pressButtonAtIndex(int index)
|
private void pressButtonAtIndex(int index)
|
||||||
{
|
{
|
||||||
if (index < Buttons.Count())
|
if (index < Buttons.Count())
|
||||||
Buttons.Skip(index).First().TriggerClick();
|
Buttons.Skip(index).First().TriggerOnClick();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
|
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
|
||||||
@ -80,7 +80,7 @@ namespace osu.Game.Overlays.Dialog
|
|||||||
|
|
||||||
if (args.Key == Key.Enter)
|
if (args.Key == Key.Enter)
|
||||||
{
|
{
|
||||||
Buttons.OfType<PopupDialogOkButton>().FirstOrDefault()?.TriggerClick();
|
Buttons.OfType<PopupDialogOkButton>().FirstOrDefault()?.TriggerOnClick();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,7 +189,7 @@ namespace osu.Game.Overlays
|
|||||||
|
|
||||||
protected override bool OnFocus(InputState state)
|
protected override bool OnFocus(InputState state)
|
||||||
{
|
{
|
||||||
filter.Search.TriggerFocus();
|
InputManager.ChangeFocus(filter.Search);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,7 +66,7 @@ namespace osu.Game.Overlays
|
|||||||
settingsSection.Bounding = true;
|
settingsSection.Bounding = true;
|
||||||
FadeIn(transition_time, EasingTypes.OutQuint);
|
FadeIn(transition_time, EasingTypes.OutQuint);
|
||||||
|
|
||||||
settingsSection.TriggerFocus();
|
InputManager.ChangeFocus(settingsSection);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void PopOut()
|
protected override void PopOut()
|
||||||
|
@ -17,6 +17,7 @@ using osu.Game.Graphics;
|
|||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
using osu.Framework.Extensions;
|
using osu.Framework.Extensions;
|
||||||
|
using osu.Framework.Input;
|
||||||
|
|
||||||
namespace osu.Game.Overlays.Music
|
namespace osu.Game.Overlays.Music
|
||||||
{
|
{
|
||||||
@ -35,10 +36,12 @@ namespace osu.Game.Overlays.Music
|
|||||||
private readonly Bindable<WorkingBeatmap> beatmapBacking = new Bindable<WorkingBeatmap>();
|
private readonly Bindable<WorkingBeatmap> beatmapBacking = new Bindable<WorkingBeatmap>();
|
||||||
|
|
||||||
public IEnumerable<BeatmapSetInfo> BeatmapSets;
|
public IEnumerable<BeatmapSetInfo> BeatmapSets;
|
||||||
|
private InputManager inputManager;
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuGameBase game, BeatmapDatabase beatmaps, OsuColour colours)
|
private void load(OsuGameBase game, BeatmapDatabase beatmaps, OsuColour colours, UserInputManager inputManager)
|
||||||
{
|
{
|
||||||
|
this.inputManager = inputManager;
|
||||||
this.beatmaps = beatmaps;
|
this.beatmaps = beatmaps;
|
||||||
trackManager = game.Audio.Track;
|
trackManager = game.Audio.Track;
|
||||||
|
|
||||||
@ -100,7 +103,7 @@ namespace osu.Game.Overlays.Music
|
|||||||
protected override void PopIn()
|
protected override void PopIn()
|
||||||
{
|
{
|
||||||
filter.Search.HoldFocus = true;
|
filter.Search.HoldFocus = true;
|
||||||
Schedule(() => filter.Search.TriggerFocus());
|
Schedule(() => inputManager.ChangeFocus(filter.Search));
|
||||||
|
|
||||||
ResizeTo(new Vector2(1, playlist_height), transition_duration, EasingTypes.OutQuint);
|
ResizeTo(new Vector2(1, playlist_height), transition_duration, EasingTypes.OutQuint);
|
||||||
FadeIn(transition_duration, EasingTypes.OutQuint);
|
FadeIn(transition_duration, EasingTypes.OutQuint);
|
||||||
|
@ -266,24 +266,27 @@ namespace osu.Game.Overlays
|
|||||||
{
|
{
|
||||||
progressBar.IsEnabled = beatmap != null;
|
progressBar.IsEnabled = beatmap != null;
|
||||||
|
|
||||||
bool audioEquals = beatmapBacking.Value?.BeatmapInfo?.AudioEquals(current?.BeatmapInfo) ?? false;
|
TransformDirection direction = TransformDirection.None;
|
||||||
|
|
||||||
TransformDirection direction;
|
if (current != null)
|
||||||
|
|
||||||
if (audioEquals)
|
|
||||||
direction = TransformDirection.None;
|
|
||||||
else if (queuedDirection.HasValue)
|
|
||||||
{
|
{
|
||||||
direction = queuedDirection.Value;
|
bool audioEquals = beatmapBacking.Value?.BeatmapInfo?.AudioEquals(current.BeatmapInfo) ?? false;
|
||||||
queuedDirection = null;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//figure out the best direction based on order in playlist.
|
|
||||||
var last = current == null ? -1 : playlist.BeatmapSets.TakeWhile(b => b.ID != current.BeatmapSetInfo.ID).Count();
|
|
||||||
var next = beatmapBacking.Value == null ? -1 : playlist.BeatmapSets.TakeWhile(b => b.ID != beatmapBacking.Value.BeatmapSetInfo.ID).Count();
|
|
||||||
|
|
||||||
direction = last > next ? TransformDirection.Prev : TransformDirection.Next;
|
if (audioEquals)
|
||||||
|
direction = TransformDirection.None;
|
||||||
|
else if (queuedDirection.HasValue)
|
||||||
|
{
|
||||||
|
direction = queuedDirection.Value;
|
||||||
|
queuedDirection = null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//figure out the best direction based on order in playlist.
|
||||||
|
var last = playlist.BeatmapSets.TakeWhile(b => b.ID != current.BeatmapSetInfo.ID).Count();
|
||||||
|
var next = beatmapBacking.Value == null ? -1 : playlist.BeatmapSets.TakeWhile(b => b.ID != beatmapBacking.Value.BeatmapSetInfo.ID).Count();
|
||||||
|
|
||||||
|
direction = last > next ? TransformDirection.Prev : TransformDirection.Next;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
current = beatmapBacking.Value;
|
current = beatmapBacking.Value;
|
||||||
|
@ -51,9 +51,12 @@ namespace osu.Game.Overlays.Settings.Sections.General
|
|||||||
Spacing = new Vector2(0f, 5f);
|
Spacing = new Vector2(0f, 5f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private InputManager inputManager;
|
||||||
|
|
||||||
[BackgroundDependencyLoader(permitNulls: true)]
|
[BackgroundDependencyLoader(permitNulls: true)]
|
||||||
private void load(OsuColour colours, APIAccess api)
|
private void load(OsuColour colours, APIAccess api, UserInputManager inputManager)
|
||||||
{
|
{
|
||||||
|
this.inputManager = inputManager;
|
||||||
this.colours = colours;
|
this.colours = colours;
|
||||||
api?.Register(this);
|
api?.Register(this);
|
||||||
}
|
}
|
||||||
@ -160,12 +163,12 @@ namespace osu.Game.Overlays.Settings.Sections.General
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
form?.TriggerFocus();
|
if (form != null) inputManager.ChangeFocus(form);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnFocus(InputState state)
|
protected override bool OnFocus(InputState state)
|
||||||
{
|
{
|
||||||
form?.TriggerFocus();
|
if (form != null) inputManager.ChangeFocus(form);
|
||||||
return base.OnFocus(state);
|
return base.OnFocus(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,6 +177,7 @@ namespace osu.Game.Overlays.Settings.Sections.General
|
|||||||
private TextBox username;
|
private TextBox username;
|
||||||
private TextBox password;
|
private TextBox password;
|
||||||
private APIAccess api;
|
private APIAccess api;
|
||||||
|
private InputManager inputManager;
|
||||||
|
|
||||||
private void performLogin()
|
private void performLogin()
|
||||||
{
|
{
|
||||||
@ -182,8 +186,9 @@ namespace osu.Game.Overlays.Settings.Sections.General
|
|||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader(permitNulls: true)]
|
[BackgroundDependencyLoader(permitNulls: true)]
|
||||||
private void load(APIAccess api, OsuConfigManager config)
|
private void load(APIAccess api, OsuConfigManager config, UserInputManager inputManager)
|
||||||
{
|
{
|
||||||
|
this.inputManager = inputManager;
|
||||||
this.api = api;
|
this.api = api;
|
||||||
Direction = FillDirection.Vertical;
|
Direction = FillDirection.Vertical;
|
||||||
Spacing = new Vector2(0, 5);
|
Spacing = new Vector2(0, 5);
|
||||||
@ -232,14 +237,7 @@ namespace osu.Game.Overlays.Settings.Sections.General
|
|||||||
|
|
||||||
protected override bool OnFocus(InputState state)
|
protected override bool OnFocus(InputState state)
|
||||||
{
|
{
|
||||||
Schedule(() =>
|
Schedule(() => { inputManager.ChangeFocus(string.IsNullOrEmpty(username.Text) ? username : password); });
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(username.Text))
|
|
||||||
username.TriggerFocus();
|
|
||||||
else
|
|
||||||
password.TriggerFocus();
|
|
||||||
});
|
|
||||||
|
|
||||||
return base.OnFocus(state);
|
return base.OnFocus(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -134,12 +134,13 @@ namespace osu.Game.Overlays
|
|||||||
FadeTo(0, TRANSITION_LENGTH / 2);
|
FadeTo(0, TRANSITION_LENGTH / 2);
|
||||||
|
|
||||||
searchTextBox.HoldFocus = false;
|
searchTextBox.HoldFocus = false;
|
||||||
searchTextBox.TriggerFocusLost();
|
if (searchTextBox.HasFocus)
|
||||||
|
InputManager.ChangeFocus(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnFocus(InputState state)
|
protected override bool OnFocus(InputState state)
|
||||||
{
|
{
|
||||||
searchTextBox.TriggerFocus(state);
|
InputManager.ChangeFocus(searchTextBox);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,28 +15,51 @@ using System.Linq;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Objects.Drawables
|
namespace osu.Game.Rulesets.Objects.Drawables
|
||||||
{
|
{
|
||||||
public abstract class DrawableHitObject<TObject, TJudgement> : Container
|
public abstract class DrawableHitObject : Container
|
||||||
where TObject : HitObject
|
|
||||||
where TJudgement : Judgement
|
|
||||||
{
|
{
|
||||||
public event Action<DrawableHitObject<TObject, TJudgement>> OnJudgement;
|
public readonly HitObject HitObject;
|
||||||
|
|
||||||
public TObject HitObject;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The colour used for various elements of this DrawableHitObject.
|
/// The colour used for various elements of this DrawableHitObject.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual Color4 AccentColour { get; set; }
|
public virtual Color4 AccentColour { get; set; }
|
||||||
|
|
||||||
|
protected DrawableHitObject(HitObject hitObject)
|
||||||
|
{
|
||||||
|
HitObject = hitObject;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract class DrawableHitObject<TObject> : DrawableHitObject
|
||||||
|
where TObject : HitObject
|
||||||
|
{
|
||||||
|
public new readonly TObject HitObject;
|
||||||
|
|
||||||
|
protected DrawableHitObject(TObject hitObject)
|
||||||
|
: base(hitObject)
|
||||||
|
{
|
||||||
|
HitObject = hitObject;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract class DrawableHitObject<TObject, TJudgement> : DrawableHitObject<TObject>
|
||||||
|
where TObject : HitObject
|
||||||
|
where TJudgement : Judgement
|
||||||
|
{
|
||||||
|
public event Action<DrawableHitObject<TObject, TJudgement>> OnJudgement;
|
||||||
|
|
||||||
public override bool HandleInput => Interactive;
|
public override bool HandleInput => Interactive;
|
||||||
|
|
||||||
public bool Interactive = true;
|
public bool Interactive = true;
|
||||||
|
|
||||||
public TJudgement Judgement;
|
public TJudgement Judgement;
|
||||||
|
|
||||||
protected abstract TJudgement CreateJudgement();
|
protected List<SampleChannel> Samples = new List<SampleChannel>();
|
||||||
|
|
||||||
protected abstract void UpdateState(ArmedState state);
|
protected DrawableHitObject(TObject hitObject)
|
||||||
|
: base(hitObject)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
private ArmedState state;
|
private ArmedState state;
|
||||||
public ArmedState State
|
public ArmedState State
|
||||||
@ -59,8 +82,6 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected List<SampleChannel> Samples = new List<SampleChannel>();
|
|
||||||
|
|
||||||
protected void PlaySamples()
|
protected void PlaySamples()
|
||||||
{
|
{
|
||||||
Samples.ForEach(s => s?.Play());
|
Samples.ForEach(s => s?.Play());
|
||||||
@ -79,11 +100,6 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool Judged => (Judgement?.Result ?? HitResult.None) != HitResult.None && (NestedHitObjects?.All(h => h.Judged) ?? true);
|
public bool Judged => (Judgement?.Result ?? HitResult.None) != HitResult.None && (NestedHitObjects?.All(h => h.Judged) ?? true);
|
||||||
|
|
||||||
protected DrawableHitObject(TObject hitObject)
|
|
||||||
{
|
|
||||||
HitObject = hitObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Process a hit of this hitobject. Carries out judgement.
|
/// Process a hit of this hitobject. Carries out judgement.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -176,5 +192,8 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
|||||||
h.OnJudgement += d => OnJudgement?.Invoke(d);
|
h.OnJudgement += d => OnJudgement?.Invoke(d);
|
||||||
nestedHitObjects.Add(h);
|
nestedHitObjects.Add(h);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected abstract TJudgement CreateJudgement();
|
||||||
|
protected abstract void UpdateState(ArmedState state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Objects
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The time at which the HitObject starts.
|
/// The time at which the HitObject starts.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public double StartTime;
|
public virtual double StartTime { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The samples to be played when this hit object is hit.
|
/// The samples to be played when this hit object is hit.
|
||||||
|
55
osu.Game/Rulesets/Objects/HitObjectStartTimeComparer.cs
Normal file
55
osu.Game/Rulesets/Objects/HitObjectStartTimeComparer.cs
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
// 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.Game.Rulesets.Objects.Drawables;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Objects
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Compares two hit objects by their start time, falling back to creation order if their start time is equal.
|
||||||
|
/// </summary>
|
||||||
|
public class HitObjectStartTimeComparer : Drawable.CreationOrderDepthComparer
|
||||||
|
{
|
||||||
|
public override int Compare(Drawable x, Drawable y)
|
||||||
|
{
|
||||||
|
var hitObjectX = x as DrawableHitObject;
|
||||||
|
var hitObjectY = y as DrawableHitObject;
|
||||||
|
|
||||||
|
// If either of the two drawables are not hit objects, fall back to the base comparer
|
||||||
|
if (hitObjectX?.HitObject == null || hitObjectY?.HitObject == null)
|
||||||
|
return base.Compare(x, y);
|
||||||
|
|
||||||
|
// Compare by start time
|
||||||
|
int i = hitObjectX.HitObject.StartTime.CompareTo(hitObjectY.HitObject.StartTime);
|
||||||
|
if (i != 0)
|
||||||
|
return i;
|
||||||
|
|
||||||
|
return base.Compare(x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Compares two hit objects by their start time, falling back to creation order if their start time is equal.
|
||||||
|
/// This will compare the two hit objects in reverse order.
|
||||||
|
/// </summary>
|
||||||
|
public class HitObjectReverseStartTimeComparer : Drawable.ReverseCreationOrderDepthComparer
|
||||||
|
{
|
||||||
|
public override int Compare(Drawable x, Drawable y)
|
||||||
|
{
|
||||||
|
var hitObjectX = x as DrawableHitObject;
|
||||||
|
var hitObjectY = y as DrawableHitObject;
|
||||||
|
|
||||||
|
// If either of the two drawables are not hit objects, fall back to the base comparer
|
||||||
|
if (hitObjectX?.HitObject == null || hitObjectY?.HitObject == null)
|
||||||
|
return base.Compare(x, y);
|
||||||
|
|
||||||
|
// Compare by start time
|
||||||
|
int i = hitObjectY.HitObject.StartTime.CompareTo(hitObjectX.HitObject.StartTime);
|
||||||
|
if (i != 0)
|
||||||
|
return i;
|
||||||
|
|
||||||
|
return base.Compare(x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -6,20 +6,30 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
|
using osu.Game.Database;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Objects.Legacy
|
namespace osu.Game.Rulesets.Objects.Legacy
|
||||||
{
|
{
|
||||||
internal abstract class ConvertSlider : HitObject, IHasCurve
|
internal abstract class ConvertSlider : HitObject, IHasCurve
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Scoring distance with a speed-adjusted beat length of 1 second.
|
||||||
|
/// </summary>
|
||||||
|
private const float base_scoring_distance = 100;
|
||||||
|
|
||||||
public List<Vector2> ControlPoints { get; set; }
|
public List<Vector2> ControlPoints { get; set; }
|
||||||
public CurveType CurveType { get; set; }
|
public CurveType CurveType { get; set; }
|
||||||
|
|
||||||
public double Distance { get; set; }
|
public double Distance { get; set; }
|
||||||
|
|
||||||
public List<SampleInfoList> RepeatSamples { get; set; }
|
public List<SampleInfoList> RepeatSamples { get; set; }
|
||||||
public int RepeatCount { get; set; } = 1;
|
public int RepeatCount { get; set; } = 1;
|
||||||
|
|
||||||
public double EndTime { get; set; }
|
public double EndTime => StartTime + RepeatCount * Distance / Velocity;
|
||||||
public double Duration { get; set; }
|
public double Duration => EndTime - StartTime;
|
||||||
|
|
||||||
|
public double Velocity = 1;
|
||||||
|
|
||||||
public Vector2 PositionAt(double progress)
|
public Vector2 PositionAt(double progress)
|
||||||
{
|
{
|
||||||
@ -35,5 +45,17 @@ namespace osu.Game.Rulesets.Objects.Legacy
|
|||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
|
||||||
|
{
|
||||||
|
base.ApplyDefaults(controlPointInfo, difficulty);
|
||||||
|
|
||||||
|
TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(StartTime);
|
||||||
|
DifficultyControlPoint difficultyPoint = controlPointInfo.DifficultyPointAt(StartTime);
|
||||||
|
|
||||||
|
double scoringDistance = base_scoring_distance * difficulty.SliderMultiplier / difficultyPoint.SpeedMultiplier;
|
||||||
|
|
||||||
|
Velocity = scoringDistance / timingPoint.BeatLength;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -135,7 +135,7 @@ namespace osu.Game.Screens.Menu
|
|||||||
switch (args.Key)
|
switch (args.Key)
|
||||||
{
|
{
|
||||||
case Key.Space:
|
case Key.Space:
|
||||||
osuLogo.TriggerClick(state);
|
osuLogo.TriggerOnClick(state);
|
||||||
return true;
|
return true;
|
||||||
case Key.Escape:
|
case Key.Escape:
|
||||||
switch (State)
|
switch (State)
|
||||||
@ -144,7 +144,7 @@ namespace osu.Game.Screens.Menu
|
|||||||
State = MenuState.Initial;
|
State = MenuState.Initial;
|
||||||
return true;
|
return true;
|
||||||
case MenuState.Play:
|
case MenuState.Play:
|
||||||
backButton.TriggerClick();
|
backButton.TriggerOnClick();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,10 +178,10 @@ namespace osu.Game.Screens.Menu
|
|||||||
State = MenuState.TopLevel;
|
State = MenuState.TopLevel;
|
||||||
return;
|
return;
|
||||||
case MenuState.TopLevel:
|
case MenuState.TopLevel:
|
||||||
buttonsTopLevel.First().TriggerClick();
|
buttonsTopLevel.First().TriggerOnClick();
|
||||||
return;
|
return;
|
||||||
case MenuState.Play:
|
case MenuState.Play:
|
||||||
buttonsPlay.First().TriggerClick();
|
buttonsPlay.First().TriggerOnClick();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ namespace osu.Game.Screens.Play
|
|||||||
{
|
{
|
||||||
if (!args.Repeat && args.Key == Key.Escape)
|
if (!args.Repeat && args.Key == Key.Escape)
|
||||||
{
|
{
|
||||||
Buttons.Children.Last().TriggerClick();
|
Buttons.Children.Last().TriggerOnClick();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,13 +131,13 @@ namespace osu.Game.Screens.Play
|
|||||||
|
|
||||||
public override bool HandleInput => true;
|
public override bool HandleInput => true;
|
||||||
|
|
||||||
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) => target.Children.Any(c => c.TriggerKeyDown(state, args));
|
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) => target.Children.Any(c => c.TriggerOnKeyDown(state, args));
|
||||||
|
|
||||||
protected override bool OnKeyUp(InputState state, KeyUpEventArgs args) => target.Children.Any(c => c.TriggerKeyUp(state, args));
|
protected override bool OnKeyUp(InputState state, KeyUpEventArgs args) => target.Children.Any(c => c.TriggerOnKeyUp(state, args));
|
||||||
|
|
||||||
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) => target.Children.Any(c => c.TriggerMouseDown(state, args));
|
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) => target.Children.Any(c => c.TriggerOnMouseDown(state, args));
|
||||||
|
|
||||||
protected override bool OnMouseUp(InputState state, MouseUpEventArgs args) => target.Children.Any(c => c.TriggerMouseUp(state, args));
|
protected override bool OnMouseUp(InputState state, MouseUpEventArgs args) => target.Children.Any(c => c.TriggerOnMouseUp(state, args));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -136,7 +136,7 @@ namespace osu.Game.Screens.Play
|
|||||||
{
|
{
|
||||||
if (!args.Repeat && args.Key == Key.Escape)
|
if (!args.Repeat && args.Key == Key.Escape)
|
||||||
{
|
{
|
||||||
Buttons.Children.First().TriggerClick();
|
Buttons.Children.First().TriggerOnClick();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -293,7 +293,7 @@ namespace osu.Game.Screens.Play
|
|||||||
|
|
||||||
protected override bool OnExiting(Screen next)
|
protected override bool OnExiting(Screen next)
|
||||||
{
|
{
|
||||||
if (HasFailed || !ValidForResume || pauseContainer.AllowExit || HitRenderer.HasReplayLoaded)
|
if (HasFailed || !ValidForResume || pauseContainer?.AllowExit != false || HitRenderer?.HasReplayLoaded != false)
|
||||||
{
|
{
|
||||||
fadeOut();
|
fadeOut();
|
||||||
return base.OnExiting(next);
|
return base.OnExiting(next);
|
||||||
@ -310,7 +310,7 @@ namespace osu.Game.Screens.Play
|
|||||||
HitRenderer?.FadeOut(fade_out_duration);
|
HitRenderer?.FadeOut(fade_out_duration);
|
||||||
Content.FadeOut(fade_out_duration);
|
Content.FadeOut(fade_out_duration);
|
||||||
|
|
||||||
hudOverlay.ScaleTo(0.7f, fade_out_duration * 3, EasingTypes.In);
|
hudOverlay?.ScaleTo(0.7f, fade_out_duration * 3, EasingTypes.In);
|
||||||
|
|
||||||
Background?.FadeTo(1f, fade_out_duration);
|
Background?.FadeTo(1f, fade_out_duration);
|
||||||
}
|
}
|
||||||
|
@ -127,7 +127,7 @@ namespace osu.Game.Screens.Play
|
|||||||
switch (args.Key)
|
switch (args.Key)
|
||||||
{
|
{
|
||||||
case Key.Space:
|
case Key.Space:
|
||||||
button.TriggerClick();
|
button.TriggerOnClick();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,7 +154,8 @@ namespace osu.Game.Screens.Select
|
|||||||
public void Deactivate()
|
public void Deactivate()
|
||||||
{
|
{
|
||||||
searchTextBox.HoldFocus = false;
|
searchTextBox.HoldFocus = false;
|
||||||
searchTextBox.TriggerFocusLost();
|
if (searchTextBox.HasFocus)
|
||||||
|
inputManager.ChangeFocus(searchTextBox);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Activate()
|
public void Activate()
|
||||||
@ -164,9 +165,13 @@ namespace osu.Game.Screens.Select
|
|||||||
|
|
||||||
private readonly Bindable<RulesetInfo> ruleset = new Bindable<RulesetInfo>();
|
private readonly Bindable<RulesetInfo> ruleset = new Bindable<RulesetInfo>();
|
||||||
|
|
||||||
[BackgroundDependencyLoader(permitNulls:true)]
|
private InputManager inputManager;
|
||||||
private void load(OsuColour colours, OsuGame osu)
|
|
||||||
|
[BackgroundDependencyLoader(permitNulls: true)]
|
||||||
|
private void load(OsuColour colours, OsuGame osu, UserInputManager inputManager)
|
||||||
{
|
{
|
||||||
|
this.inputManager = inputManager;
|
||||||
|
|
||||||
sortTabs.AccentColour = colours.GreenLight;
|
sortTabs.AccentColour = colours.GreenLight;
|
||||||
|
|
||||||
if (osu != null)
|
if (osu != null)
|
||||||
|
@ -176,6 +176,7 @@
|
|||||||
<Compile Include="Rulesets\Objects\Drawables\IDrawableHitObjectWithProxiedApproach.cs" />
|
<Compile Include="Rulesets\Objects\Drawables\IDrawableHitObjectWithProxiedApproach.cs" />
|
||||||
<Compile Include="Rulesets\Judgements\Judgement.cs" />
|
<Compile Include="Rulesets\Judgements\Judgement.cs" />
|
||||||
<Compile Include="Rulesets\Objects\HitObjectParser.cs" />
|
<Compile Include="Rulesets\Objects\HitObjectParser.cs" />
|
||||||
|
<Compile Include="Rulesets\Objects\HitObjectStartTimeComparer.cs" />
|
||||||
<Compile Include="Rulesets\Objects\Types\IHasCombo.cs" />
|
<Compile Include="Rulesets\Objects\Types\IHasCombo.cs" />
|
||||||
<Compile Include="Rulesets\Objects\Types\IHasEndTime.cs" />
|
<Compile Include="Rulesets\Objects\Types\IHasEndTime.cs" />
|
||||||
<Compile Include="Rulesets\Objects\Types\IHasDistance.cs" />
|
<Compile Include="Rulesets\Objects\Types\IHasDistance.cs" />
|
||||||
|
Loading…
Reference in New Issue
Block a user