mirror of
https://github.com/ppy/osu.git
synced 2025-01-28 02:02:53 +08:00
Merge branch 'master' into fix-storyboard-loop-end-time
This commit is contained in:
commit
07efa7d660
@ -418,10 +418,13 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
|
||||
private void clearPlate(DroppedObjectAnimation animation)
|
||||
{
|
||||
var droppedObjects = caughtObjectContainer.Children.Select(getDroppedObject).ToArray();
|
||||
var caughtObjects = caughtObjectContainer.Children.ToArray();
|
||||
|
||||
caughtObjectContainer.Clear(false);
|
||||
|
||||
// Use the already returned PoolableDrawables for new objects
|
||||
var droppedObjects = caughtObjects.Select(getDroppedObject).ToArray();
|
||||
|
||||
droppedObjectTarget.AddRange(droppedObjects);
|
||||
|
||||
foreach (var droppedObject in droppedObjects)
|
||||
@ -430,10 +433,10 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
|
||||
private void removeFromPlate(CaughtObject caughtObject, DroppedObjectAnimation animation)
|
||||
{
|
||||
var droppedObject = getDroppedObject(caughtObject);
|
||||
|
||||
caughtObjectContainer.Remove(caughtObject, false);
|
||||
|
||||
var droppedObject = getDroppedObject(caughtObject);
|
||||
|
||||
droppedObjectTarget.Add(droppedObject);
|
||||
|
||||
applyDropAnimation(droppedObject, animation);
|
||||
@ -456,6 +459,8 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
break;
|
||||
}
|
||||
|
||||
// Define lifetime start for dropped objects to be disposed correctly when rewinding replay
|
||||
d.LifetimeStart = Clock.CurrentTime;
|
||||
d.Expire();
|
||||
}
|
||||
|
||||
|
@ -160,6 +160,36 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDecodeVideoWithLowercaseExtension()
|
||||
{
|
||||
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
|
||||
|
||||
using (var resStream = TestResources.OpenResource("video-with-lowercase-extension.osb"))
|
||||
using (var stream = new LineBufferedReader(resStream))
|
||||
{
|
||||
var beatmap = decoder.Decode(stream);
|
||||
var metadata = beatmap.Metadata;
|
||||
|
||||
Assert.AreEqual("BG.jpg", metadata.BackgroundFile);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDecodeVideoWithUppercaseExtension()
|
||||
{
|
||||
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
|
||||
|
||||
using (var resStream = TestResources.OpenResource("video-with-uppercase-extension.osb"))
|
||||
using (var stream = new LineBufferedReader(resStream))
|
||||
{
|
||||
var beatmap = decoder.Decode(stream);
|
||||
var metadata = beatmap.Metadata;
|
||||
|
||||
Assert.AreEqual("BG.jpg", metadata.BackgroundFile);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDecodeImageSpecifiedAsVideo()
|
||||
{
|
||||
|
@ -190,6 +190,40 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDecodeVideoWithLowercaseExtension()
|
||||
{
|
||||
var decoder = new LegacyStoryboardDecoder();
|
||||
|
||||
using (var resStream = TestResources.OpenResource("video-with-lowercase-extension.osb"))
|
||||
using (var stream = new LineBufferedReader(resStream))
|
||||
{
|
||||
var storyboard = decoder.Decode(stream);
|
||||
|
||||
StoryboardLayer video = storyboard.Layers.Single(l => l.Name == "Video");
|
||||
Assert.That(video.Elements.Count, Is.EqualTo(1));
|
||||
|
||||
Assert.AreEqual("Video.avi", ((StoryboardVideo)video.Elements[0]).Path);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDecodeVideoWithUppercaseExtension()
|
||||
{
|
||||
var decoder = new LegacyStoryboardDecoder();
|
||||
|
||||
using (var resStream = TestResources.OpenResource("video-with-uppercase-extension.osb"))
|
||||
using (var stream = new LineBufferedReader(resStream))
|
||||
{
|
||||
var storyboard = decoder.Decode(stream);
|
||||
|
||||
StoryboardLayer video = storyboard.Layers.Single(l => l.Name == "Video");
|
||||
Assert.That(video.Elements.Count, Is.EqualTo(1));
|
||||
|
||||
Assert.AreEqual("Video.AVI", ((StoryboardVideo)video.Elements[0]).Path);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDecodeImageSpecifiedAsVideo()
|
||||
{
|
||||
@ -200,8 +234,8 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
{
|
||||
var storyboard = decoder.Decode(stream);
|
||||
|
||||
StoryboardLayer foreground = storyboard.Layers.Single(l => l.Name == "Video");
|
||||
Assert.That(foreground.Elements.Count, Is.Zero);
|
||||
StoryboardLayer video = storyboard.Layers.Single(l => l.Name == "Video");
|
||||
Assert.That(video.Elements.Count, Is.Zero);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,5 @@
|
||||
osu file format v14
|
||||
|
||||
[Events]
|
||||
0,0,"BG.jpg",0,0
|
||||
Video,0,"Video.avi",0,0
|
@ -0,0 +1,5 @@
|
||||
osu file format v14
|
||||
|
||||
[Events]
|
||||
0,0,"BG.jpg",0,0
|
||||
Video,0,"Video.AVI",0,0
|
@ -45,7 +45,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
|
||||
// best way to check without exposing.
|
||||
private Drawable hideTarget => hudOverlay.KeyCounter;
|
||||
private Drawable keyCounterFlow => hudOverlay.KeyCounter.ChildrenOfType<FillFlowContainer<DefaultKeyCounter>>().Single();
|
||||
private Drawable keyCounterFlow => hudOverlay.KeyCounter.ChildrenOfType<FillFlowContainer<KeyCounter>>().Single();
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
|
@ -7,7 +7,9 @@ using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Screens.Play;
|
||||
using osu.Game.Screens.Play.HUD;
|
||||
using osuTK;
|
||||
using osuTK.Input;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Gameplay
|
||||
@ -17,13 +19,21 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
{
|
||||
public TestSceneKeyCounter()
|
||||
{
|
||||
KeyCounterDisplay kc = new DefaultKeyCounterDisplay
|
||||
KeyCounterDisplay defaultDisplay = new DefaultKeyCounterDisplay
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Anchor = Anchor.Centre,
|
||||
Position = new Vector2(0, 72.7f)
|
||||
};
|
||||
|
||||
kc.AddRange(new InputTrigger[]
|
||||
KeyCounterDisplay argonDisplay = new ArgonKeyCounterDisplay
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Anchor = Anchor.Centre,
|
||||
Position = new Vector2(0, -72.7f)
|
||||
};
|
||||
|
||||
defaultDisplay.AddRange(new InputTrigger[]
|
||||
{
|
||||
new KeyCounterKeyboardTrigger(Key.X),
|
||||
new KeyCounterKeyboardTrigger(Key.X),
|
||||
@ -31,30 +41,41 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
new KeyCounterMouseTrigger(MouseButton.Right),
|
||||
});
|
||||
|
||||
var testCounter = (DefaultKeyCounter)kc.Counters.First();
|
||||
argonDisplay.AddRange(new InputTrigger[]
|
||||
{
|
||||
new KeyCounterKeyboardTrigger(Key.X),
|
||||
new KeyCounterKeyboardTrigger(Key.X),
|
||||
new KeyCounterMouseTrigger(MouseButton.Left),
|
||||
new KeyCounterMouseTrigger(MouseButton.Right),
|
||||
});
|
||||
|
||||
var testCounter = (DefaultKeyCounter)defaultDisplay.Counters.First();
|
||||
|
||||
AddStep("Add random", () =>
|
||||
{
|
||||
Key key = (Key)((int)Key.A + RNG.Next(26));
|
||||
kc.Add(new KeyCounterKeyboardTrigger(key));
|
||||
defaultDisplay.Add(new KeyCounterKeyboardTrigger(key));
|
||||
argonDisplay.Add(new KeyCounterKeyboardTrigger(key));
|
||||
});
|
||||
|
||||
Key testKey = ((KeyCounterKeyboardTrigger)kc.Counters.First().Trigger).Key;
|
||||
|
||||
void addPressKeyStep()
|
||||
{
|
||||
AddStep($"Press {testKey} key", () => InputManager.Key(testKey));
|
||||
}
|
||||
Key testKey = ((KeyCounterKeyboardTrigger)defaultDisplay.Counters.First().Trigger).Key;
|
||||
|
||||
addPressKeyStep();
|
||||
AddAssert($"Check {testKey} counter after keypress", () => testCounter.CountPresses.Value == 1);
|
||||
addPressKeyStep();
|
||||
AddAssert($"Check {testKey} counter after keypress", () => testCounter.CountPresses.Value == 2);
|
||||
AddStep("Disable counting", () => testCounter.IsCounting.Value = false);
|
||||
AddStep("Disable counting", () =>
|
||||
{
|
||||
argonDisplay.IsCounting.Value = false;
|
||||
defaultDisplay.IsCounting.Value = false;
|
||||
});
|
||||
addPressKeyStep();
|
||||
AddAssert($"Check {testKey} count has not changed", () => testCounter.CountPresses.Value == 2);
|
||||
|
||||
Add(kc);
|
||||
Add(defaultDisplay);
|
||||
Add(argonDisplay);
|
||||
|
||||
void addPressKeyStep() => AddStep($"Press {testKey} key", () => InputManager.Key(testKey));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
|
||||
// best way to check without exposing.
|
||||
private Drawable hideTarget => hudOverlay.KeyCounter;
|
||||
private Drawable keyCounterFlow => hudOverlay.KeyCounter.ChildrenOfType<FillFlowContainer<DefaultKeyCounter>>().Single();
|
||||
private Drawable keyCounterFlow => hudOverlay.KeyCounter.ChildrenOfType<FillFlowContainer<KeyCounter>>().Single();
|
||||
|
||||
[Test]
|
||||
public void TestComboCounterIncrementing()
|
||||
|
@ -368,7 +368,7 @@ namespace osu.Game.Beatmaps
|
||||
// user requested abort
|
||||
return;
|
||||
|
||||
var video = b.Files.FirstOrDefault(f => OsuGameBase.VIDEO_EXTENSIONS.Any(ex => f.Filename.EndsWith(ex, StringComparison.Ordinal)));
|
||||
var video = b.Files.FirstOrDefault(f => OsuGameBase.VIDEO_EXTENSIONS.Any(ex => f.Filename.EndsWith(ex, StringComparison.OrdinalIgnoreCase)));
|
||||
|
||||
if (video != null)
|
||||
{
|
||||
|
@ -369,7 +369,7 @@ namespace osu.Game.Beatmaps.Formats
|
||||
// Some very old beatmaps had incorrect type specifications for their backgrounds (ie. using 1 for VIDEO
|
||||
// instead of 0 for BACKGROUND). To handle this gracefully, check the file extension against known supported
|
||||
// video extensions and handle similar to a background if it doesn't match.
|
||||
if (!OsuGameBase.VIDEO_EXTENSIONS.Contains(Path.GetExtension(filename)))
|
||||
if (!OsuGameBase.VIDEO_EXTENSIONS.Contains(Path.GetExtension(filename).ToLowerInvariant()))
|
||||
{
|
||||
beatmap.BeatmapInfo.Metadata.BackgroundFile = filename;
|
||||
}
|
||||
|
@ -114,7 +114,7 @@ namespace osu.Game.Beatmaps.Formats
|
||||
//
|
||||
// This avoids potential weird crashes when ffmpeg attempts to parse an image file as a video
|
||||
// (see https://github.com/ppy/osu/issues/22829#issuecomment-1465552451).
|
||||
if (!OsuGameBase.VIDEO_EXTENSIONS.Contains(Path.GetExtension(path)))
|
||||
if (!OsuGameBase.VIDEO_EXTENSIONS.Contains(Path.GetExtension(path).ToLowerInvariant()))
|
||||
break;
|
||||
|
||||
storyboard.GetLayer("Video").Add(new StoryboardVideo(path, offset));
|
||||
|
@ -70,7 +70,7 @@ namespace osu.Game.Graphics.UserInterfaceV2
|
||||
{
|
||||
get
|
||||
{
|
||||
if (OsuGameBase.VIDEO_EXTENSIONS.Contains(File.Extension))
|
||||
if (OsuGameBase.VIDEO_EXTENSIONS.Contains(File.Extension.ToLowerInvariant()))
|
||||
return FontAwesome.Regular.FileVideo;
|
||||
|
||||
switch (File.Extension)
|
||||
|
@ -100,14 +100,14 @@ namespace osu.Game.Localisation
|
||||
public static LocalisableString TimelineTicks => new TranslatableString(getKey(@"timeline_ticks"), @"Ticks");
|
||||
|
||||
/// <summary>
|
||||
/// "{0:0.0}°"
|
||||
/// "{0:0}°"
|
||||
/// </summary>
|
||||
public static LocalisableString RotationUnsnapped(float newRotation) => new TranslatableString(getKey(@"rotation_unsnapped"), @"{0:0.0}°", newRotation);
|
||||
public static LocalisableString RotationUnsnapped(float newRotation) => new TranslatableString(getKey(@"rotation_unsnapped"), @"{0:0}°", newRotation);
|
||||
|
||||
/// <summary>
|
||||
/// "{0:0.0}° (snapped)"
|
||||
/// "{0:0}° (snapped)"
|
||||
/// </summary>
|
||||
public static LocalisableString RotationSnapped(float newRotation) => new TranslatableString(getKey(@"rotation_snapped"), @"{0:0.0}° (snapped)", newRotation);
|
||||
public static LocalisableString RotationSnapped(float newRotation) => new TranslatableString(getKey(@"rotation_snapped"), @"{0:0}° (snapped)", newRotation);
|
||||
|
||||
private static string getKey(string key) => $@"{prefix}:{key}";
|
||||
}
|
||||
|
@ -20,11 +20,31 @@ namespace osu.Game.Rulesets.Mods
|
||||
|
||||
public virtual bool RestartOnFail => Restart.Value;
|
||||
|
||||
private Action? triggerFailureDelegate;
|
||||
|
||||
public void ApplyToHealthProcessor(HealthProcessor healthProcessor)
|
||||
{
|
||||
triggerFailureDelegate = healthProcessor.TriggerFailure;
|
||||
healthProcessor.FailConditions += FailCondition;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Immediately triggers a failure on the loaded <see cref="HealthProcessor"/>.
|
||||
/// </summary>
|
||||
protected void TriggerFailure() => triggerFailureDelegate?.Invoke();
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether <paramref name="result"/> should trigger a failure. Called every time a
|
||||
/// judgement is applied to <paramref name="healthProcessor"/>.
|
||||
/// </summary>
|
||||
/// <param name="healthProcessor">The loaded <see cref="HealthProcessor"/>.</param>
|
||||
/// <param name="result">The latest <see cref="JudgementResult"/>.</param>
|
||||
/// <returns>Whether the fail condition has been met.</returns>
|
||||
/// <remarks>
|
||||
/// This method should only be used to trigger failures based on <paramref name="result"/>.
|
||||
/// Using outside values to evaluate failure may introduce event ordering discrepancies, use
|
||||
/// an <see cref="IApplicableMod"/> with <see cref="TriggerFailure"/> instead.
|
||||
/// </remarks>
|
||||
protected abstract bool FailCondition(HealthProcessor healthProcessor, JudgementResult result);
|
||||
}
|
||||
}
|
||||
|
@ -31,6 +31,15 @@ namespace osu.Game.Rulesets.Scoring
|
||||
/// </summary>
|
||||
public bool HasFailed { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Immediately triggers a failure for this HealthProcessor.
|
||||
/// </summary>
|
||||
public void TriggerFailure()
|
||||
{
|
||||
if (Failed?.Invoke() != false)
|
||||
HasFailed = true;
|
||||
}
|
||||
|
||||
protected override void ApplyResultInternal(JudgementResult result)
|
||||
{
|
||||
result.HealthAtJudgement = Health.Value;
|
||||
@ -42,10 +51,7 @@ namespace osu.Game.Rulesets.Scoring
|
||||
Health.Value += GetHealthIncreaseFor(result);
|
||||
|
||||
if (meetsAnyFailCondition(result))
|
||||
{
|
||||
if (Failed?.Invoke() != false)
|
||||
HasFailed = true;
|
||||
}
|
||||
TriggerFailure();
|
||||
}
|
||||
|
||||
protected override void RevertResultInternal(JudgementResult result)
|
||||
|
@ -118,7 +118,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
||||
{
|
||||
float oldRotation = cumulativeRotation.Value ?? 0;
|
||||
|
||||
float newRotation = shouldSnap ? snap(rawCumulativeRotation, snap_step) : rawCumulativeRotation;
|
||||
float newRotation = shouldSnap ? snap(rawCumulativeRotation, snap_step) : MathF.Round(rawCumulativeRotation);
|
||||
newRotation = (newRotation - 180) % 360 + 180;
|
||||
|
||||
cumulativeRotation.Value = newRotation;
|
||||
|
76
osu.Game/Screens/Play/ArgonKeyCounter.cs
Normal file
76
osu.Game/Screens/Play/ArgonKeyCounter.cs
Normal file
@ -0,0 +1,76 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Screens.Play.HUD;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Screens.Play
|
||||
{
|
||||
public partial class ArgonKeyCounter : KeyCounter
|
||||
{
|
||||
private Circle inputIndicator = null!;
|
||||
private OsuSpriteText countText = null!;
|
||||
|
||||
// These values were taken from Figma
|
||||
private const float line_height = 3;
|
||||
private const float name_font_size = 10;
|
||||
private const float count_font_size = 14;
|
||||
|
||||
// Make things look bigger without using Scale
|
||||
private const float scale_factor = 1.5f;
|
||||
|
||||
public ArgonKeyCounter(InputTrigger trigger)
|
||||
: base(trigger)
|
||||
{
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
Children = new Drawable[]
|
||||
{
|
||||
inputIndicator = new Circle
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = line_height * scale_factor,
|
||||
Alpha = 0.5f
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.BottomLeft,
|
||||
Origin = Anchor.BottomLeft,
|
||||
Position = new Vector2(0, -13) * scale_factor,
|
||||
Font = OsuFont.Torus.With(size: name_font_size * scale_factor, weight: FontWeight.Bold),
|
||||
Colour = colours.Blue0,
|
||||
Text = Trigger.Name
|
||||
},
|
||||
countText = new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.BottomLeft,
|
||||
Origin = Anchor.BottomLeft,
|
||||
Font = OsuFont.Torus.With(size: count_font_size * scale_factor, weight: FontWeight.Bold),
|
||||
},
|
||||
};
|
||||
|
||||
// Values from Figma didn't match visually
|
||||
// So these were just eyeballed
|
||||
Height = 30 * scale_factor;
|
||||
Width = 35 * scale_factor;
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
IsActive.BindValueChanged(e => inputIndicator.Alpha = e.NewValue ? 1 : 0.5f, true);
|
||||
CountPresses.BindValueChanged(e => countText.Text = e.NewValue.ToString(@"#,0"), true);
|
||||
}
|
||||
}
|
||||
}
|
40
osu.Game/Screens/Play/ArgonKeyCounterDisplay.cs
Normal file
40
osu.Game/Screens/Play/ArgonKeyCounterDisplay.cs
Normal file
@ -0,0 +1,40 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Screens.Play.HUD;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Screens.Play
|
||||
{
|
||||
public partial class ArgonKeyCounterDisplay : KeyCounterDisplay
|
||||
{
|
||||
private const int duration = 100;
|
||||
|
||||
protected override FillFlowContainer<KeyCounter> KeyFlow { get; }
|
||||
|
||||
public ArgonKeyCounterDisplay()
|
||||
{
|
||||
InternalChild = KeyFlow = new FillFlowContainer<KeyCounter>
|
||||
{
|
||||
Direction = FillDirection.Horizontal,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Alpha = 0,
|
||||
Spacing = new Vector2(2),
|
||||
};
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
Size = KeyFlow.Size;
|
||||
}
|
||||
|
||||
protected override KeyCounter CreateCounter(InputTrigger trigger) => new ArgonKeyCounter(trigger);
|
||||
|
||||
protected override void UpdateVisibility()
|
||||
=> KeyFlow.FadeTo(AlwaysVisible.Value || ConfigVisibility.Value ? 1 : 0, duration);
|
||||
}
|
||||
}
|
@ -57,7 +57,7 @@ namespace osu.Game.Screens.Play.HUD
|
||||
{
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = Name,
|
||||
Text = Trigger.Name,
|
||||
Font = OsuFont.Numeric.With(size: 12),
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osuTK.Graphics;
|
||||
@ -13,13 +13,11 @@ namespace osu.Game.Screens.Play.HUD
|
||||
private const int duration = 100;
|
||||
private const double key_fade_time = 80;
|
||||
|
||||
private readonly FillFlowContainer<DefaultKeyCounter> keyFlow;
|
||||
|
||||
public override IEnumerable<KeyCounter> Counters => keyFlow;
|
||||
protected override FillFlowContainer<KeyCounter> KeyFlow { get; }
|
||||
|
||||
public DefaultKeyCounterDisplay()
|
||||
{
|
||||
InternalChild = keyFlow = new FillFlowContainer<DefaultKeyCounter>
|
||||
InternalChild = KeyFlow = new FillFlowContainer<KeyCounter>
|
||||
{
|
||||
Direction = FillDirection.Horizontal,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
@ -33,20 +31,19 @@ namespace osu.Game.Screens.Play.HUD
|
||||
|
||||
// Don't use autosize as it will shrink to zero when KeyFlow is hidden.
|
||||
// In turn this can cause the display to be masked off screen and never become visible again.
|
||||
Size = keyFlow.Size;
|
||||
Size = KeyFlow.Size;
|
||||
}
|
||||
|
||||
public override void Add(InputTrigger trigger) =>
|
||||
keyFlow.Add(new DefaultKeyCounter(trigger)
|
||||
{
|
||||
FadeTime = key_fade_time,
|
||||
KeyDownTextColor = KeyDownTextColor,
|
||||
KeyUpTextColor = KeyUpTextColor,
|
||||
});
|
||||
protected override KeyCounter CreateCounter(InputTrigger trigger) => new DefaultKeyCounter(trigger)
|
||||
{
|
||||
FadeTime = key_fade_time,
|
||||
KeyDownTextColor = KeyDownTextColor,
|
||||
KeyUpTextColor = KeyUpTextColor,
|
||||
};
|
||||
|
||||
protected override void UpdateVisibility() =>
|
||||
// Isolate changing visibility of the key counters from fading this component.
|
||||
keyFlow.FadeTo(AlwaysVisible.Value || ConfigVisibility.Value ? 1 : 0, duration);
|
||||
KeyFlow.FadeTo(AlwaysVisible.Value || ConfigVisibility.Value ? 1 : 0, duration);
|
||||
|
||||
private Color4 keyDownTextColor = Color4.DarkGray;
|
||||
|
||||
@ -58,7 +55,7 @@ namespace osu.Game.Screens.Play.HUD
|
||||
if (value != keyDownTextColor)
|
||||
{
|
||||
keyDownTextColor = value;
|
||||
foreach (var child in keyFlow)
|
||||
foreach (var child in KeyFlow.Cast<DefaultKeyCounter>())
|
||||
child.KeyDownTextColor = value;
|
||||
}
|
||||
}
|
||||
@ -74,7 +71,7 @@ namespace osu.Game.Screens.Play.HUD
|
||||
if (value != keyUpTextColor)
|
||||
{
|
||||
keyUpTextColor = value;
|
||||
foreach (var child in keyFlow)
|
||||
foreach (var child in KeyFlow.Cast<DefaultKeyCounter>())
|
||||
child.KeyUpTextColor = value;
|
||||
}
|
||||
}
|
||||
|
@ -54,8 +54,6 @@ namespace osu.Game.Screens.Play.HUD
|
||||
|
||||
Trigger.OnActivate += Activate;
|
||||
Trigger.OnDeactivate += Deactivate;
|
||||
|
||||
Name = trigger.Name;
|
||||
}
|
||||
|
||||
private void increment()
|
||||
|
@ -29,7 +29,9 @@ namespace osu.Game.Screens.Play.HUD
|
||||
/// <summary>
|
||||
/// The <see cref="KeyCounter"/>s contained in this <see cref="KeyCounterDisplay"/>.
|
||||
/// </summary>
|
||||
public abstract IEnumerable<KeyCounter> Counters { get; }
|
||||
public IEnumerable<KeyCounter> Counters => KeyFlow;
|
||||
|
||||
protected abstract FillFlowContainer<KeyCounter> KeyFlow { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether the actions reported by all <see cref="InputTrigger"/>s within this <see cref="KeyCounterDisplay"/> should be counted.
|
||||
@ -53,13 +55,22 @@ namespace osu.Game.Screens.Play.HUD
|
||||
/// <summary>
|
||||
/// Add a <see cref="InputTrigger"/> to this display.
|
||||
/// </summary>
|
||||
public abstract void Add(InputTrigger trigger);
|
||||
public void Add(InputTrigger trigger)
|
||||
{
|
||||
var keyCounter = CreateCounter(trigger);
|
||||
|
||||
KeyFlow.Add(keyCounter);
|
||||
|
||||
IsCounting.BindTo(keyCounter.IsCounting);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a range of <see cref="InputTrigger"/> to this display.
|
||||
/// </summary>
|
||||
public void AddRange(IEnumerable<InputTrigger> triggers) => triggers.ForEach(Add);
|
||||
|
||||
protected abstract KeyCounter CreateCounter(InputTrigger trigger);
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuConfigManager config)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user