Merge branch 'master' into fix-argon-health-bar-flash
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 62 KiB |
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 56 KiB |
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 56 KiB |
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 56 KiB |
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 56 KiB |
Before Width: | Height: | Size: 55 KiB After Width: | Height: | Size: 55 KiB |
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 56 KiB |
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
@ -15,7 +15,11 @@ namespace osu.Game.Rulesets.Catch.Skinning.Argon
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
Anchor = Anchor.TopCentre;
|
||||
Origin = Anchor.Centre;
|
||||
|
||||
RelativeSizeAxes = Axes.X;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
|
@ -9,6 +9,7 @@ using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Game.Rulesets.Catch.UI;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Skinning.Default
|
||||
{
|
||||
@ -22,6 +23,7 @@ namespace osu.Game.Rulesets.Catch.Skinning.Default
|
||||
|
||||
public DefaultCatcher()
|
||||
{
|
||||
Anchor = Anchor.TopCentre;
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
InternalChild = sprite = new Sprite
|
||||
{
|
||||
@ -32,6 +34,15 @@ namespace osu.Game.Rulesets.Catch.Skinning.Default
|
||||
};
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
// matches stable's origin position since we're using the same catcher sprite.
|
||||
// see LegacyCatcher for more information.
|
||||
OriginPosition = new Vector2(DrawWidth / 2, 16f);
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(TextureStore store, Bindable<CatcherAnimationState> currentState)
|
||||
{
|
||||
|
33
osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyCatcher.cs
Normal file
@ -0,0 +1,33 @@
|
||||
// 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 osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Skinning.Legacy
|
||||
{
|
||||
public abstract partial class LegacyCatcher : CompositeDrawable
|
||||
{
|
||||
protected LegacyCatcher()
|
||||
{
|
||||
Anchor = Anchor.TopCentre;
|
||||
Origin = Anchor.TopCentre;
|
||||
|
||||
// in stable, catcher sprites are displayed in their raw size. stable also has catcher sprites displayed with the following scale factors applied:
|
||||
// 1. 0.5x, affecting all sprites in the playfield, computed here based on lazer's catch playfield dimensions (see WIDTH/HEIGHT constants in CatchPlayfield),
|
||||
// source: https://github.com/peppy/osu-stable-reference/blob/1531237b63392e82c003c712faa028406073aa8f/osu!/GameplayElements/HitObjectManager.cs#L483-L494
|
||||
// 2. 0.7x, a constant scale applied to all catcher sprites on construction.
|
||||
AutoSizeAxes = Axes.Both;
|
||||
Scale = new Vector2(0.5f * 0.7f);
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
// stable sets the Y origin position of the catcher to 16px in order for the catching range and OD scaling to align with the top of the catcher's plate in the default skin.
|
||||
OriginPosition = new Vector2(DrawWidth / 2, 16f);
|
||||
}
|
||||
}
|
||||
}
|
@ -7,14 +7,12 @@ using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Animations;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Rulesets.Catch.UI;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Skinning.Legacy
|
||||
{
|
||||
public partial class LegacyCatcherNew : CompositeDrawable
|
||||
public partial class LegacyCatcherNew : LegacyCatcher
|
||||
{
|
||||
[Resolved]
|
||||
private Bindable<CatcherAnimationState> currentState { get; set; } = null!;
|
||||
@ -23,25 +21,12 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy
|
||||
|
||||
private Drawable currentDrawable = null!;
|
||||
|
||||
public LegacyCatcherNew()
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(ISkinSource skin)
|
||||
{
|
||||
foreach (var state in Enum.GetValues<CatcherAnimationState>())
|
||||
{
|
||||
AddInternal(drawables[state] = getDrawableFor(state).With(d =>
|
||||
{
|
||||
d.Anchor = Anchor.TopCentre;
|
||||
d.Origin = Anchor.TopCentre;
|
||||
d.RelativeSizeAxes = Axes.Both;
|
||||
d.Size = Vector2.One;
|
||||
d.FillMode = FillMode.Fit;
|
||||
d.Alpha = 0;
|
||||
}));
|
||||
AddInternal(drawables[state] = getDrawableFor(state).With(d => d.Alpha = 0));
|
||||
}
|
||||
|
||||
currentDrawable = drawables[CatcherAnimationState.Idle];
|
||||
|
@ -3,30 +3,21 @@
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Skinning.Legacy
|
||||
{
|
||||
public partial class LegacyCatcherOld : CompositeDrawable
|
||||
public partial class LegacyCatcherOld : LegacyCatcher
|
||||
{
|
||||
public LegacyCatcherOld()
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
AutoSizeAxes = Axes.Both;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(ISkinSource skin)
|
||||
{
|
||||
InternalChild = (skin.GetAnimation(@"fruit-ryuuta", true, true, true) ?? Empty()).With(d =>
|
||||
{
|
||||
d.Anchor = Anchor.TopCentre;
|
||||
d.Origin = Anchor.TopCentre;
|
||||
d.RelativeSizeAxes = Axes.Both;
|
||||
d.Size = Vector2.One;
|
||||
d.FillMode = FillMode.Fit;
|
||||
});
|
||||
InternalChild = skin.GetAnimation(@"fruit-ryuuta", true, true, true) ?? Empty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,12 +17,13 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
|
||||
public CatchPlayfieldAdjustmentContainer()
|
||||
{
|
||||
// because we are using centre anchor/origin, we will need to limit visibility in the future
|
||||
// to ensure tall windows do not get a readability advantage.
|
||||
// it may be possible to bake the catch-specific offsets (-100..340 mentioned below) into new values
|
||||
// which are compatible with TopCentre alignment.
|
||||
Anchor = Anchor.Centre;
|
||||
Origin = Anchor.Centre;
|
||||
Anchor = Anchor.TopCentre;
|
||||
Origin = Anchor.TopCentre;
|
||||
|
||||
// playfields in stable are positioned vertically at three fourths the difference between the playfield height and the window height in stable.
|
||||
// we can match that in lazer by using relative coordinates for Y and considering window height to be 1, and playfield height to be 0.8.
|
||||
RelativePositionAxes = Axes.Y;
|
||||
Y = (1 - playfield_size_adjust) / 4 * 3;
|
||||
|
||||
Size = new Vector2(playfield_size_adjust);
|
||||
|
||||
@ -42,18 +43,28 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
/// </summary>
|
||||
private partial class ScalingContainer : Container
|
||||
{
|
||||
public ScalingContainer()
|
||||
{
|
||||
Anchor = Anchor.BottomCentre;
|
||||
Origin = Anchor.BottomCentre;
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
// in stable, fruit fall vertically from -100 to 340.
|
||||
// to emulate this, we want to make our playfield 440 gameplay pixels high.
|
||||
// we then offset it -100 vertically in the position set below.
|
||||
const float stable_v_offset_ratio = 440 / 384f;
|
||||
// in stable, fruit fall vertically from 100 pixels above the playfield top down to the catcher's Y position (i.e. -100 to 340),
|
||||
// see: https://github.com/peppy/osu-stable-reference/blob/1531237b63392e82c003c712faa028406073aa8f/osu!/GameplayElements/HitObjects/Fruits/HitCircleFruits.cs#L65
|
||||
// we already have the playfield positioned similar to stable (see CatchPlayfieldAdjustmentContainer constructor),
|
||||
// so we only need to increase this container's height 100 pixels above the playfield, and offset it to have the bottom at 340 rather than 384.
|
||||
const float stable_fruit_start_position = -100;
|
||||
const float stable_catcher_y_position = 340;
|
||||
const float playfield_v_size_adjustment = (stable_catcher_y_position - stable_fruit_start_position) / CatchPlayfield.HEIGHT;
|
||||
const float playfield_v_catcher_offset = stable_catcher_y_position - CatchPlayfield.HEIGHT;
|
||||
|
||||
Scale = new Vector2(Parent.ChildSize.X / CatchPlayfield.WIDTH);
|
||||
Position = new Vector2(0, -100 * stable_v_offset_ratio + Scale.X);
|
||||
Size = Vector2.Divide(new Vector2(1, stable_v_offset_ratio), Scale);
|
||||
Scale = new Vector2(Parent!.ChildSize.X / CatchPlayfield.WIDTH);
|
||||
Position = new Vector2(0f, playfield_v_catcher_offset * Scale.Y);
|
||||
Size = Vector2.Divide(new Vector2(1, playfield_v_size_adjustment), Scale);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -29,6 +29,13 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
/// <summary>
|
||||
/// The size of the catcher at 1x scale.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is mainly used to compute catching range, the actual catcher size may differ based on skin implementation and sprite textures.
|
||||
/// This is also equivalent to the "catcherWidth" property in osu-stable when the game field and beatmap difficulty are set to default values.
|
||||
/// </remarks>
|
||||
/// <seealso cref="CatchPlayfield.WIDTH"/>
|
||||
/// <seealso cref="CatchPlayfield.HEIGHT"/>
|
||||
/// <seealso cref="IBeatmapDifficultyInfo.DEFAULT_DIFFICULTY"/>
|
||||
public const float BASE_SIZE = 106.75f;
|
||||
|
||||
/// <summary>
|
||||
|
@ -6,7 +6,6 @@ using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Rulesets.Catch.Skinning.Default;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.UI
|
||||
{
|
||||
@ -26,8 +25,8 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
: base(new CatchSkinComponentLookup(CatchSkinComponents.Catcher), _ => new DefaultCatcher())
|
||||
{
|
||||
Anchor = Anchor.TopCentre;
|
||||
// Sets the origin roughly to the centre of the catcher's plate to allow for correct scaling.
|
||||
OriginPosition = new Vector2(0.5f, 0.06f) * Catcher.BASE_SIZE;
|
||||
Origin = Anchor.TopCentre;
|
||||
CentreComponent = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,8 @@ using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Caching;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Pooling;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Rulesets.Edit;
|
||||
@ -23,7 +25,7 @@ namespace osu.Game.Rulesets.Mania.Edit
|
||||
/// <summary>
|
||||
/// A grid which displays coloured beat divisor lines in proximity to the selection or placement cursor.
|
||||
/// </summary>
|
||||
public partial class ManiaBeatSnapGrid : Component
|
||||
public partial class ManiaBeatSnapGrid : CompositeComponent
|
||||
{
|
||||
private const double visible_range = 750;
|
||||
|
||||
@ -53,6 +55,8 @@ namespace osu.Game.Rulesets.Mania.Edit
|
||||
|
||||
private readonly List<ScrollingHitObjectContainer> grids = new List<ScrollingHitObjectContainer>();
|
||||
|
||||
private readonly DrawablePool<DrawableGridLine> linesPool = new DrawablePool<DrawableGridLine>(50);
|
||||
|
||||
private readonly Cached lineCache = new Cached();
|
||||
|
||||
private (double start, double end)? selectionTimeRange;
|
||||
@ -60,6 +64,8 @@ namespace osu.Game.Rulesets.Mania.Edit
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(HitObjectComposer composer)
|
||||
{
|
||||
AddInternal(linesPool);
|
||||
|
||||
foreach (var stage in ((ManiaPlayfield)composer.Playfield).Stages)
|
||||
{
|
||||
foreach (var column in stage.Columns)
|
||||
@ -85,17 +91,10 @@ namespace osu.Game.Rulesets.Mania.Edit
|
||||
}
|
||||
}
|
||||
|
||||
private readonly Stack<DrawableGridLine> availableLines = new Stack<DrawableGridLine>();
|
||||
|
||||
private void createLines()
|
||||
{
|
||||
foreach (var grid in grids)
|
||||
{
|
||||
foreach (var line in grid.Objects.OfType<DrawableGridLine>())
|
||||
availableLines.Push(line);
|
||||
|
||||
grid.Clear();
|
||||
}
|
||||
|
||||
if (selectionTimeRange == null)
|
||||
return;
|
||||
@ -131,10 +130,13 @@ namespace osu.Game.Rulesets.Mania.Edit
|
||||
|
||||
foreach (var grid in grids)
|
||||
{
|
||||
if (!availableLines.TryPop(out var line))
|
||||
line = new DrawableGridLine();
|
||||
var line = linesPool.Get();
|
||||
|
||||
line.Apply(new HitObject
|
||||
{
|
||||
StartTime = time
|
||||
});
|
||||
|
||||
line.HitObject.StartTime = time;
|
||||
line.Colour = colour;
|
||||
|
||||
grid.Add(line);
|
||||
|
@ -21,7 +21,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
||||
private DrawableHitObject drawableObject { get; set; } = null!;
|
||||
|
||||
public LegacyApproachCircle()
|
||||
: base("Gameplay/osu/approachcircle", OsuHitObject.OBJECT_DIMENSIONS)
|
||||
: base("Gameplay/osu/approachcircle", OsuHitObject.OBJECT_DIMENSIONS * 2)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,9 @@ using osu.Framework.Screens;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Online.API.Requests;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
@ -26,6 +29,7 @@ using osu.Game.Screens;
|
||||
using osu.Game.Screens.Play;
|
||||
using osu.Game.Screens.Ranking;
|
||||
using osu.Game.Tests.Resources;
|
||||
using osu.Game.Users;
|
||||
using osuTK.Input;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Gameplay
|
||||
@ -98,6 +102,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
{
|
||||
DateTimeOffset? getLastPlayed() => Realm.Run(r => r.Find<BeatmapInfo>(Beatmap.Value.BeatmapInfo.ID)?.LastPlayed);
|
||||
|
||||
AddStep("reset last played", () => Realm.Write(r => r.Find<BeatmapInfo>(Beatmap.Value.BeatmapInfo.ID)!.LastPlayed = null));
|
||||
AddAssert("last played is null", () => getLastPlayed() == null);
|
||||
|
||||
CreateTest();
|
||||
@ -150,6 +155,40 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
AddUntilStep("score in database", () => Realm.Run(r => r.Find<ScoreInfo>(Player.Score.ScoreInfo.ID) != null));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestGuestScoreIsStoredAsGuest()
|
||||
{
|
||||
AddStep("set up API", () => ((DummyAPIAccess)API).HandleRequest = req =>
|
||||
{
|
||||
switch (req)
|
||||
{
|
||||
case GetUserRequest userRequest:
|
||||
userRequest.TriggerSuccess(new APIUser
|
||||
{
|
||||
Username = "Guest",
|
||||
CountryCode = CountryCode.JP,
|
||||
Id = 1234
|
||||
});
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
AddStep("log out", () => API.Logout());
|
||||
CreateTest();
|
||||
|
||||
AddUntilStep("wait for track to start running", () => Beatmap.Value.Track.IsRunning);
|
||||
AddStep("log back in", () => API.Login("username", "password"));
|
||||
|
||||
AddStep("seek to completion", () => Player.GameplayClockContainer.Seek(Player.DrawableRuleset.Objects.Last().GetEndTime()));
|
||||
|
||||
AddUntilStep("results displayed", () => Player.GetChildScreen() is ResultsScreen);
|
||||
AddUntilStep("score in database", () => Realm.Run(r => r.Find<ScoreInfo>(Player.Score.ScoreInfo.ID) != null));
|
||||
AddAssert("score is not associated with online user", () => Realm.Run(r => r.Find<ScoreInfo>(Player.Score.ScoreInfo.ID))!.UserID == APIUser.SYSTEM_USER_ID);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestReplayExport()
|
||||
{
|
||||
|
@ -11,6 +11,7 @@ using osu.Game.Online.Multiplayer;
|
||||
using osu.Game.Online.Rooms;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Screens.OnlinePlay.Multiplayer;
|
||||
using osu.Game.Screens.Play;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
@ -28,6 +29,11 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
Beatmap.Value = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo);
|
||||
});
|
||||
|
||||
AddStep("Start track playing", () =>
|
||||
{
|
||||
Beatmap.Value.Track.Start();
|
||||
});
|
||||
|
||||
AddStep("initialise gameplay", () =>
|
||||
{
|
||||
Stack.Push(player = new MultiplayerPlayer(MultiplayerClient.ServerAPIRoom, new PlaylistItem(Beatmap.Value.BeatmapInfo)
|
||||
@ -37,7 +43,14 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
});
|
||||
|
||||
AddUntilStep("wait for player to be current", () => player.IsCurrentScreen() && player.IsLoaded);
|
||||
|
||||
AddAssert("gameplay clock is paused", () => player.ChildrenOfType<GameplayClockContainer>().Single().IsPaused.Value);
|
||||
AddAssert("gameplay clock is not running", () => !player.ChildrenOfType<GameplayClockContainer>().Single().IsRunning);
|
||||
|
||||
AddStep("start gameplay", () => ((IMultiplayerClient)MultiplayerClient).GameplayStarted());
|
||||
|
||||
AddUntilStep("gameplay clock is not paused", () => !player.ChildrenOfType<GameplayClockContainer>().Single().IsPaused.Value);
|
||||
AddAssert("gameplay clock is running", () => player.ChildrenOfType<GameplayClockContainer>().Single().IsRunning);
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -190,6 +190,9 @@ namespace osu.Game.Scoring
|
||||
/// </summary>
|
||||
private void populateUserDetails(ScoreInfo model)
|
||||
{
|
||||
if (model.RealmUser.OnlineID == APIUser.SYSTEM_USER_ID)
|
||||
return;
|
||||
|
||||
string username = model.RealmUser.Username;
|
||||
|
||||
if (usernameLookupCache.TryGetValue(username, out var existing))
|
||||
|
@ -148,6 +148,9 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
|
||||
loadingDisplay.Show();
|
||||
client.ChangeState(MultiplayerUserState.ReadyForGameplay);
|
||||
}
|
||||
|
||||
// This will pause the clock, pending the gameplay started callback from the server.
|
||||
GameplayClockContainer.Reset();
|
||||
}
|
||||
|
||||
private void failAndBail(string message = null)
|
||||
|
@ -138,12 +138,16 @@ namespace osu.Game.Screens.Play
|
||||
/// Resets this <see cref="GameplayClockContainer"/> and the source to an initial state ready for gameplay.
|
||||
/// </summary>
|
||||
/// <param name="time">The time to seek to on resetting. If <c>null</c>, the existing <see cref="StartTime"/> will be used.</param>
|
||||
/// <param name="startClock">Whether to start the clock immediately, if not already started.</param>
|
||||
/// <param name="startClock">Whether to start the clock immediately. If <c>false</c> and the clock was already paused, the clock will remain paused after this call.
|
||||
/// </param>
|
||||
public void Reset(double? time = null, bool startClock = false)
|
||||
{
|
||||
bool wasPaused = isPaused.Value;
|
||||
|
||||
Stop();
|
||||
// The intention of the Reset method is to get things into a known sane state.
|
||||
// As such, we intentionally stop the underlying clock directly here, bypassing Stop/StopGameplayClock.
|
||||
// This is to avoid any kind of isPaused state checks and frequency ramping (as provided by MasterGameplayClockContainer).
|
||||
GameplayClock.Stop();
|
||||
|
||||
if (time != null)
|
||||
StartTime = time.Value;
|
||||
|
@ -15,7 +15,6 @@ using osu.Framework.Layout;
|
||||
using osu.Framework.Threading;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Skinning;
|
||||
@ -74,7 +73,7 @@ namespace osu.Game.Screens.Play.HUD
|
||||
return;
|
||||
|
||||
glowBarValue = value;
|
||||
updatePathVertices();
|
||||
Scheduler.AddOnce(updatePathVertices);
|
||||
}
|
||||
}
|
||||
|
||||
@ -89,7 +88,7 @@ namespace osu.Game.Screens.Play.HUD
|
||||
return;
|
||||
|
||||
healthBarValue = value;
|
||||
updatePathVertices();
|
||||
Scheduler.AddOnce(updatePathVertices);
|
||||
}
|
||||
}
|
||||
|
||||
@ -139,17 +138,7 @@ namespace osu.Game.Screens.Play.HUD
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
Current.BindValueChanged(v =>
|
||||
{
|
||||
if (v.NewValue >= GlowBarValue)
|
||||
finishMissDisplay();
|
||||
|
||||
double time = v.NewValue > GlowBarValue ? 500 : 250;
|
||||
|
||||
this.TransformTo(nameof(HealthBarValue), v.NewValue, time, Easing.OutQuint);
|
||||
if (resetMissBarDelegate == null)
|
||||
this.TransformTo(nameof(GlowBarValue), v.NewValue, time, Easing.OutQuint);
|
||||
}, true);
|
||||
Current.BindValueChanged(_ => Scheduler.AddOnce(updateCurrent), true);
|
||||
|
||||
BarLength.BindValueChanged(l => Width = l.NewValue, true);
|
||||
BarHeight.BindValueChanged(_ => updatePath());
|
||||
@ -164,6 +153,17 @@ namespace osu.Game.Screens.Play.HUD
|
||||
return base.OnInvalidate(invalidation, source);
|
||||
}
|
||||
|
||||
private void updateCurrent()
|
||||
{
|
||||
if (Current.Value >= GlowBarValue) finishMissDisplay();
|
||||
|
||||
double time = Current.Value > GlowBarValue ? 500 : 250;
|
||||
|
||||
// TODO: this should probably use interpolation in update.
|
||||
this.TransformTo(nameof(HealthBarValue), Current.Value, time, Easing.OutQuint);
|
||||
if (resetMissBarDelegate == null) this.TransformTo(nameof(GlowBarValue), Current.Value, time, Easing.OutQuint);
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
@ -172,9 +172,9 @@ namespace osu.Game.Screens.Play.HUD
|
||||
glowBar.Alpha = (float)Interpolation.DampContinuously(glowBar.Alpha, GlowBarValue > 0 ? 1 : 0, 40, Time.Elapsed);
|
||||
}
|
||||
|
||||
protected override void Flash(JudgementResult result)
|
||||
protected override void Flash()
|
||||
{
|
||||
base.Flash(result);
|
||||
base.Flash();
|
||||
|
||||
mainBar.TransformTo(nameof(BarPath.GlowColour), main_bar_glow_colour.Opacity(0.8f))
|
||||
.TransformTo(nameof(BarPath.GlowColour), main_bar_glow_colour, 300, Easing.OutQuint);
|
||||
@ -191,9 +191,9 @@ namespace osu.Game.Screens.Play.HUD
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Miss(JudgementResult result)
|
||||
protected override void Miss()
|
||||
{
|
||||
base.Miss(result);
|
||||
base.Miss();
|
||||
|
||||
if (resetMissBarDelegate != null)
|
||||
{
|
||||
|
@ -8,7 +8,6 @@ using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Effects;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
@ -112,6 +111,13 @@ namespace osu.Game.Screens.Play.HUD
|
||||
};
|
||||
}
|
||||
|
||||
protected override void Flash()
|
||||
{
|
||||
fill.FadeEdgeEffectTo(Math.Min(1, fill.EdgeEffect.Colour.Linear.A + (1f - base_glow_opacity) / glow_max_hits), 50, Easing.OutQuint)
|
||||
.Delay(glow_fade_delay)
|
||||
.FadeEdgeEffectTo(base_glow_opacity, glow_fade_time, Easing.OutQuint);
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
@ -119,15 +125,6 @@ namespace osu.Game.Screens.Play.HUD
|
||||
GlowColour = colours.BlueDarker;
|
||||
}
|
||||
|
||||
protected override void Flash(JudgementResult result) => Scheduler.AddOnce(flash);
|
||||
|
||||
private void flash()
|
||||
{
|
||||
fill.FadeEdgeEffectTo(Math.Min(1, fill.EdgeEffect.Colour.Linear.A + (1f - base_glow_opacity) / glow_max_hits), 50, Easing.OutQuint)
|
||||
.Delay(glow_fade_delay)
|
||||
.FadeEdgeEffectTo(base_glow_opacity, glow_fade_time, Easing.OutQuint);
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
@ -8,7 +8,6 @@ using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Threading;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Rulesets.UI;
|
||||
|
||||
@ -39,17 +38,17 @@ namespace osu.Game.Screens.Play.HUD
|
||||
|
||||
/// <summary>
|
||||
/// Triggered when a <see cref="Judgement"/> is a successful hit, signaling the health display to perform a flash animation (if designed to do so).
|
||||
/// Calls to this method are debounced.
|
||||
/// </summary>
|
||||
/// <param name="result">The judgement result.</param>
|
||||
protected virtual void Flash(JudgementResult result)
|
||||
protected virtual void Flash()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Triggered when a <see cref="Judgement"/> resulted in the player losing health.
|
||||
/// Calls to this method are debounced.
|
||||
/// </summary>
|
||||
/// <param name="result">The judgement result.</param>
|
||||
protected virtual void Miss(JudgementResult result)
|
||||
protected virtual void Miss()
|
||||
{
|
||||
}
|
||||
|
||||
@ -92,7 +91,7 @@ namespace osu.Game.Screens.Play.HUD
|
||||
{
|
||||
double newValue = Current.Value + 0.05f;
|
||||
this.TransformBindableTo(Current, newValue, increase_delay);
|
||||
Flash(new JudgementResult(new HitObject(), new Judgement()));
|
||||
Scheduler.AddOnce(Flash);
|
||||
|
||||
if (newValue >= 1)
|
||||
finishInitialAnimation();
|
||||
@ -101,6 +100,9 @@ namespace osu.Game.Screens.Play.HUD
|
||||
|
||||
private void finishInitialAnimation()
|
||||
{
|
||||
if (initialIncrease == null)
|
||||
return;
|
||||
|
||||
initialIncrease?.Cancel();
|
||||
initialIncrease = null;
|
||||
|
||||
@ -115,9 +117,9 @@ namespace osu.Game.Screens.Play.HUD
|
||||
private void onNewJudgement(JudgementResult judgement)
|
||||
{
|
||||
if (judgement.IsHit && judgement.Type != HitResult.IgnoreHit)
|
||||
Flash(judgement);
|
||||
Scheduler.AddOnce(Flash);
|
||||
else if (judgement.Judgement.HealthIncreaseFor(judgement) < 0)
|
||||
Miss(judgement);
|
||||
Scheduler.AddOnce(Miss);
|
||||
}
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
|
@ -1078,7 +1078,7 @@ namespace osu.Game.Screens.Play
|
||||
protected virtual void StartGameplay()
|
||||
{
|
||||
if (GameplayClockContainer.IsRunning)
|
||||
throw new InvalidOperationException($"{nameof(StartGameplay)} should not be called when the gameplay clock is already running");
|
||||
Logger.Error(new InvalidOperationException($"{nameof(StartGameplay)} should not be called when the gameplay clock is already running"), "Clock failure");
|
||||
|
||||
GameplayClockContainer.Reset(startClock: true);
|
||||
|
||||
|
@ -11,7 +11,6 @@ using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Screens.Play.HUD;
|
||||
using osu.Game.Utils;
|
||||
using osuTK;
|
||||
@ -80,7 +79,7 @@ namespace osu.Game.Skinning
|
||||
marker.Position = fill.Position + new Vector2(fill.DrawWidth, isNewStyle ? fill.DrawHeight / 2 : 0);
|
||||
}
|
||||
|
||||
protected override void Flash(JudgementResult result) => marker.Flash(result);
|
||||
protected override void Flash() => marker.Flash();
|
||||
|
||||
private static Texture getTexture(ISkin skin, string name) => skin?.GetTexture($"scorebar-{name}");
|
||||
|
||||
@ -238,7 +237,7 @@ namespace osu.Game.Skinning
|
||||
});
|
||||
}
|
||||
|
||||
public override void Flash(JudgementResult result)
|
||||
public override void Flash()
|
||||
{
|
||||
bulgeMain();
|
||||
|
||||
@ -257,7 +256,7 @@ namespace osu.Game.Skinning
|
||||
{
|
||||
public Bindable<double> Current { get; } = new Bindable<double>();
|
||||
|
||||
public virtual void Flash(JudgementResult result)
|
||||
public virtual void Flash()
|
||||
{
|
||||
}
|
||||
}
|
||||
|