mirror of
https://github.com/ppy/osu.git
synced 2025-01-06 08:22:56 +08:00
Merge branch 'master' into separate-path-connection
This commit is contained in:
commit
d027c982e4
11
osu.Desktop/Properties/launchSettings.json
Normal file
11
osu.Desktop/Properties/launchSettings.json
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"profiles": {
|
||||||
|
"osu! Desktop": {
|
||||||
|
"commandName": "Project"
|
||||||
|
},
|
||||||
|
"osu! Tournament": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"commandLineArgs": "--tournament"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Humanizer;
|
using Humanizer;
|
||||||
@ -15,6 +16,7 @@ using osu.Framework.Input.Bindings;
|
|||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
using osu.Game.Screens.Edit.Compose;
|
using osu.Game.Screens.Edit.Compose;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
@ -27,7 +29,9 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
|||||||
internal readonly Container<PathControlPointPiece> Pieces;
|
internal readonly Container<PathControlPointPiece> Pieces;
|
||||||
|
|
||||||
private readonly Container<PathControlPointConnection> connections;
|
private readonly Container<PathControlPointConnection> connections;
|
||||||
|
|
||||||
private readonly Slider slider;
|
private readonly Slider slider;
|
||||||
|
|
||||||
private readonly bool allowSelection;
|
private readonly bool allowSelection;
|
||||||
|
|
||||||
private InputManager inputManager;
|
private InputManager inputManager;
|
||||||
@ -90,7 +94,10 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
|||||||
protected override bool OnClick(ClickEvent e)
|
protected override bool OnClick(ClickEvent e)
|
||||||
{
|
{
|
||||||
foreach (var piece in Pieces)
|
foreach (var piece in Pieces)
|
||||||
|
{
|
||||||
piece.IsSelected.Value = false;
|
piece.IsSelected.Value = false;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,16 +171,63 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
|||||||
if (!Pieces.Any(p => p.IsHovered))
|
if (!Pieces.Any(p => p.IsHovered))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
int selectedPoints = Pieces.Count(p => p.IsSelected.Value);
|
var selectedPieces = Pieces.Where(p => p.IsSelected.Value).ToList();
|
||||||
|
int count = selectedPieces.Count;
|
||||||
|
|
||||||
if (selectedPoints == 0)
|
if (count == 0)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
|
List<MenuItem> items = new List<MenuItem>();
|
||||||
|
|
||||||
|
if (!selectedPieces.Contains(Pieces[0]))
|
||||||
|
items.Add(createMenuItemForPathType(null));
|
||||||
|
|
||||||
|
// todo: hide/disable items which aren't valid for selected points
|
||||||
|
items.Add(createMenuItemForPathType(PathType.Linear));
|
||||||
|
items.Add(createMenuItemForPathType(PathType.PerfectCurve));
|
||||||
|
items.Add(createMenuItemForPathType(PathType.Bezier));
|
||||||
|
items.Add(createMenuItemForPathType(PathType.Catmull));
|
||||||
|
|
||||||
return new MenuItem[]
|
return new MenuItem[]
|
||||||
{
|
{
|
||||||
new OsuMenuItem($"Delete {"control point".ToQuantity(selectedPoints, selectedPoints > 1 ? ShowQuantityAs.Numeric : ShowQuantityAs.None)}", MenuItemType.Destructive, () => deleteSelected())
|
new OsuMenuItem($"Delete {"control point".ToQuantity(count, count > 1 ? ShowQuantityAs.Numeric : ShowQuantityAs.None)}", MenuItemType.Destructive, () => deleteSelected()),
|
||||||
|
new OsuMenuItem("Curve type")
|
||||||
|
{
|
||||||
|
Items = items
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private MenuItem createMenuItemForPathType(PathType? type)
|
||||||
|
{
|
||||||
|
int totalCount = Pieces.Count(p => p.IsSelected.Value);
|
||||||
|
int countOfState = Pieces.Where(p => p.IsSelected.Value).Count(p => p.ControlPoint.Type.Value == type);
|
||||||
|
|
||||||
|
var item = new PathTypeMenuItem(type, () =>
|
||||||
|
{
|
||||||
|
foreach (var p in Pieces.Where(p => p.IsSelected.Value))
|
||||||
|
p.ControlPoint.Type.Value = type;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (countOfState == totalCount)
|
||||||
|
item.State.Value = TernaryState.True;
|
||||||
|
else if (countOfState > 0)
|
||||||
|
item.State.Value = TernaryState.Indeterminate;
|
||||||
|
else
|
||||||
|
item.State.Value = TernaryState.False;
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class PathTypeMenuItem : TernaryStateMenuItem
|
||||||
|
{
|
||||||
|
public PathTypeMenuItem(PathType? type, Action action)
|
||||||
|
: base(type == null ? "Inherit" : type.ToString().Humanize(), changeState, MenuItemType.Standard, _ => action?.Invoke())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TernaryState changeState(TernaryState state) => TernaryState.True;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using JetBrains.Annotations;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
using osu.Game.Screens.Edit.Compose.Components;
|
using osu.Game.Screens.Edit.Compose.Components;
|
||||||
|
|
||||||
@ -8,8 +9,8 @@ namespace osu.Game.Rulesets.Osu.Edit
|
|||||||
{
|
{
|
||||||
public class OsuDistanceSnapGrid : CircularDistanceSnapGrid
|
public class OsuDistanceSnapGrid : CircularDistanceSnapGrid
|
||||||
{
|
{
|
||||||
public OsuDistanceSnapGrid(OsuHitObject hitObject, OsuHitObject nextHitObject)
|
public OsuDistanceSnapGrid(OsuHitObject hitObject, [CanBeNull] OsuHitObject nextHitObject = null)
|
||||||
: base(hitObject, nextHitObject, hitObject.StackedEndPosition)
|
: base(hitObject.StackedPosition, hitObject.StartTime, nextHitObject?.StartTime)
|
||||||
{
|
{
|
||||||
Masking = true;
|
Masking = true;
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,6 @@ using osu.Framework.Graphics;
|
|||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Rulesets.Edit;
|
using osu.Game.Rulesets.Edit;
|
||||||
using osu.Game.Rulesets.Objects;
|
|
||||||
using osu.Game.Rulesets.Osu.Beatmaps;
|
using osu.Game.Rulesets.Osu.Beatmaps;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
using osu.Game.Screens.Edit;
|
using osu.Game.Screens.Edit;
|
||||||
@ -44,7 +43,7 @@ namespace osu.Game.Tests.Visual.Editor
|
|||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Colour = Color4.SlateGray
|
Colour = Color4.SlateGray
|
||||||
},
|
},
|
||||||
new TestDistanceSnapGrid(new HitObject(), grid_position)
|
new TestDistanceSnapGrid()
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -73,7 +72,7 @@ namespace osu.Game.Tests.Visual.Editor
|
|||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Colour = Color4.SlateGray
|
Colour = Color4.SlateGray
|
||||||
},
|
},
|
||||||
new TestDistanceSnapGrid(new HitObject(), grid_position, new HitObject { StartTime = 100 })
|
new TestDistanceSnapGrid(100)
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -82,68 +81,68 @@ namespace osu.Game.Tests.Visual.Editor
|
|||||||
{
|
{
|
||||||
public new float DistanceSpacing => base.DistanceSpacing;
|
public new float DistanceSpacing => base.DistanceSpacing;
|
||||||
|
|
||||||
public TestDistanceSnapGrid(HitObject hitObject, Vector2 centrePosition, HitObject nextHitObject = null)
|
public TestDistanceSnapGrid(double? endTime = null)
|
||||||
: base(hitObject, nextHitObject, centrePosition)
|
: base(grid_position, 0, endTime)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void CreateContent(Vector2 centrePosition)
|
protected override void CreateContent(Vector2 startPosition)
|
||||||
{
|
{
|
||||||
AddInternal(new Circle
|
AddInternal(new Circle
|
||||||
{
|
{
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Size = new Vector2(5),
|
Size = new Vector2(5),
|
||||||
Position = centrePosition
|
Position = startPosition
|
||||||
});
|
});
|
||||||
|
|
||||||
int beatIndex = 0;
|
int beatIndex = 0;
|
||||||
|
|
||||||
for (float s = centrePosition.X + DistanceSpacing; s <= DrawWidth && beatIndex < MaxIntervals; s += DistanceSpacing, beatIndex++)
|
for (float s = startPosition.X + DistanceSpacing; s <= DrawWidth && beatIndex < MaxIntervals; s += DistanceSpacing, beatIndex++)
|
||||||
{
|
{
|
||||||
AddInternal(new Circle
|
AddInternal(new Circle
|
||||||
{
|
{
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Size = new Vector2(5, 10),
|
Size = new Vector2(5, 10),
|
||||||
Position = new Vector2(s, centrePosition.Y),
|
Position = new Vector2(s, startPosition.Y),
|
||||||
Colour = GetColourForBeatIndex(beatIndex)
|
Colour = GetColourForBeatIndex(beatIndex)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
beatIndex = 0;
|
beatIndex = 0;
|
||||||
|
|
||||||
for (float s = centrePosition.X - DistanceSpacing; s >= 0 && beatIndex < MaxIntervals; s -= DistanceSpacing, beatIndex++)
|
for (float s = startPosition.X - DistanceSpacing; s >= 0 && beatIndex < MaxIntervals; s -= DistanceSpacing, beatIndex++)
|
||||||
{
|
{
|
||||||
AddInternal(new Circle
|
AddInternal(new Circle
|
||||||
{
|
{
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Size = new Vector2(5, 10),
|
Size = new Vector2(5, 10),
|
||||||
Position = new Vector2(s, centrePosition.Y),
|
Position = new Vector2(s, startPosition.Y),
|
||||||
Colour = GetColourForBeatIndex(beatIndex)
|
Colour = GetColourForBeatIndex(beatIndex)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
beatIndex = 0;
|
beatIndex = 0;
|
||||||
|
|
||||||
for (float s = centrePosition.Y + DistanceSpacing; s <= DrawHeight && beatIndex < MaxIntervals; s += DistanceSpacing, beatIndex++)
|
for (float s = startPosition.Y + DistanceSpacing; s <= DrawHeight && beatIndex < MaxIntervals; s += DistanceSpacing, beatIndex++)
|
||||||
{
|
{
|
||||||
AddInternal(new Circle
|
AddInternal(new Circle
|
||||||
{
|
{
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Size = new Vector2(10, 5),
|
Size = new Vector2(10, 5),
|
||||||
Position = new Vector2(centrePosition.X, s),
|
Position = new Vector2(startPosition.X, s),
|
||||||
Colour = GetColourForBeatIndex(beatIndex)
|
Colour = GetColourForBeatIndex(beatIndex)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
beatIndex = 0;
|
beatIndex = 0;
|
||||||
|
|
||||||
for (float s = centrePosition.Y - DistanceSpacing; s >= 0 && beatIndex < MaxIntervals; s -= DistanceSpacing, beatIndex++)
|
for (float s = startPosition.Y - DistanceSpacing; s >= 0 && beatIndex < MaxIntervals; s -= DistanceSpacing, beatIndex++)
|
||||||
{
|
{
|
||||||
AddInternal(new Circle
|
AddInternal(new Circle
|
||||||
{
|
{
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Size = new Vector2(10, 5),
|
Size = new Vector2(10, 5),
|
||||||
Position = new Vector2(centrePosition.X, s),
|
Position = new Vector2(startPosition.X, s),
|
||||||
Colour = GetColourForBeatIndex(beatIndex)
|
Colour = GetColourForBeatIndex(beatIndex)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -285,8 +285,6 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
|
|
||||||
protected class PausePlayer : TestPlayer
|
protected class PausePlayer : TestPlayer
|
||||||
{
|
{
|
||||||
public new GameplayClockContainer GameplayClockContainer => base.GameplayClockContainer;
|
|
||||||
|
|
||||||
public new ScoreProcessor ScoreProcessor => base.ScoreProcessor;
|
public new ScoreProcessor ScoreProcessor => base.ScoreProcessor;
|
||||||
|
|
||||||
public new HUDOverlay HUDOverlay => base.HUDOverlay;
|
public new HUDOverlay HUDOverlay => base.HUDOverlay;
|
||||||
|
51
osu.Game.Tests/Visual/Gameplay/TestScenePauseWhenInactive.cs
Normal file
51
osu.Game.Tests/Visual/Gameplay/TestScenePauseWhenInactive.cs
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
// 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 NUnit.Framework;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Platform;
|
||||||
|
using osu.Framework.Testing;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets;
|
||||||
|
using osu.Game.Rulesets.Osu;
|
||||||
|
using osu.Game.Screens.Play;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Visual.Gameplay
|
||||||
|
{
|
||||||
|
[HeadlessTest] // we alter unsafe properties on the game host to test inactive window state.
|
||||||
|
public class TestScenePauseWhenInactive : PlayerTestScene
|
||||||
|
{
|
||||||
|
protected new TestPlayer Player => (TestPlayer)base.Player;
|
||||||
|
|
||||||
|
protected override IBeatmap CreateBeatmap(RulesetInfo ruleset)
|
||||||
|
{
|
||||||
|
var beatmap = (Beatmap)base.CreateBeatmap(ruleset);
|
||||||
|
|
||||||
|
beatmap.HitObjects.RemoveAll(h => h.StartTime < 30000);
|
||||||
|
|
||||||
|
return beatmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private GameHost host { get; set; }
|
||||||
|
|
||||||
|
public TestScenePauseWhenInactive()
|
||||||
|
: base(new OsuRuleset())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestDoesntPauseDuringIntro()
|
||||||
|
{
|
||||||
|
AddStep("set inactive", () => ((Bindable<bool>)host.IsActive).Value = false);
|
||||||
|
|
||||||
|
AddStep("resume player", () => Player.GameplayClockContainer.Start());
|
||||||
|
AddAssert("ensure not paused", () => !Player.GameplayClockContainer.IsPaused.Value);
|
||||||
|
AddUntilStep("wait for pause", () => Player.GameplayClockContainer.IsPaused.Value);
|
||||||
|
AddAssert("time of pause is after gameplay start time", () => Player.GameplayClockContainer.GameplayClock.CurrentTime >= Player.DrawableRuleset.GameplayStartTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Player CreatePlayer(Ruleset ruleset) => new TestPlayer(true, true, true);
|
||||||
|
}
|
||||||
|
}
|
@ -5,19 +5,18 @@ using System;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Graphics.UserInterface;
|
using osu.Framework.Graphics.UserInterface;
|
||||||
using osu.Game.Rulesets.Objects;
|
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Screens.Edit.Compose.Components
|
namespace osu.Game.Screens.Edit.Compose.Components
|
||||||
{
|
{
|
||||||
public abstract class CircularDistanceSnapGrid : DistanceSnapGrid
|
public abstract class CircularDistanceSnapGrid : DistanceSnapGrid
|
||||||
{
|
{
|
||||||
protected CircularDistanceSnapGrid(HitObject hitObject, HitObject nextHitObject, Vector2 centrePosition)
|
protected CircularDistanceSnapGrid(Vector2 startPosition, double startTime, double? endTime = null)
|
||||||
: base(hitObject, nextHitObject, centrePosition)
|
: base(startPosition, startTime, endTime)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void CreateContent(Vector2 centrePosition)
|
protected override void CreateContent(Vector2 startPosition)
|
||||||
{
|
{
|
||||||
const float crosshair_thickness = 1;
|
const float crosshair_thickness = 1;
|
||||||
const float crosshair_max_size = 10;
|
const float crosshair_max_size = 10;
|
||||||
@ -27,7 +26,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
new Box
|
new Box
|
||||||
{
|
{
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Position = centrePosition,
|
Position = startPosition,
|
||||||
Width = crosshair_thickness,
|
Width = crosshair_thickness,
|
||||||
EdgeSmoothness = new Vector2(1),
|
EdgeSmoothness = new Vector2(1),
|
||||||
Height = Math.Min(crosshair_max_size, DistanceSpacing * 2),
|
Height = Math.Min(crosshair_max_size, DistanceSpacing * 2),
|
||||||
@ -35,15 +34,15 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
new Box
|
new Box
|
||||||
{
|
{
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Position = centrePosition,
|
Position = startPosition,
|
||||||
EdgeSmoothness = new Vector2(1),
|
EdgeSmoothness = new Vector2(1),
|
||||||
Width = Math.Min(crosshair_max_size, DistanceSpacing * 2),
|
Width = Math.Min(crosshair_max_size, DistanceSpacing * 2),
|
||||||
Height = crosshair_thickness,
|
Height = crosshair_thickness,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
float dx = Math.Max(centrePosition.X, DrawWidth - centrePosition.X);
|
float dx = Math.Max(startPosition.X, DrawWidth - startPosition.X);
|
||||||
float dy = Math.Max(centrePosition.Y, DrawHeight - centrePosition.Y);
|
float dy = Math.Max(startPosition.Y, DrawHeight - startPosition.Y);
|
||||||
float maxDistance = new Vector2(dx, dy).Length;
|
float maxDistance = new Vector2(dx, dy).Length;
|
||||||
int requiredCircles = Math.Min(MaxIntervals, (int)(maxDistance / DistanceSpacing));
|
int requiredCircles = Math.Min(MaxIntervals, (int)(maxDistance / DistanceSpacing));
|
||||||
|
|
||||||
@ -54,7 +53,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
AddInternal(new CircularProgress
|
AddInternal(new CircularProgress
|
||||||
{
|
{
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Position = centrePosition,
|
Position = startPosition,
|
||||||
Current = { Value = 1 },
|
Current = { Value = 1 },
|
||||||
Size = new Vector2(radius),
|
Size = new Vector2(radius),
|
||||||
InnerRadius = 4 * 1f / radius,
|
InnerRadius = 4 * 1f / radius,
|
||||||
@ -66,9 +65,9 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
public override (Vector2 position, double time) GetSnappedPosition(Vector2 position)
|
public override (Vector2 position, double time) GetSnappedPosition(Vector2 position)
|
||||||
{
|
{
|
||||||
if (MaxIntervals == 0)
|
if (MaxIntervals == 0)
|
||||||
return (CentrePosition, StartTime);
|
return (StartPosition, StartTime);
|
||||||
|
|
||||||
Vector2 direction = position - CentrePosition;
|
Vector2 direction = position - StartPosition;
|
||||||
if (direction == Vector2.Zero)
|
if (direction == Vector2.Zero)
|
||||||
direction = new Vector2(0.001f, 0.001f);
|
direction = new Vector2(0.001f, 0.001f);
|
||||||
|
|
||||||
@ -78,9 +77,9 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
int radialCount = Math.Clamp((int)MathF.Round(distance / radius), 1, MaxIntervals);
|
int radialCount = Math.Clamp((int)MathF.Round(distance / radius), 1, MaxIntervals);
|
||||||
|
|
||||||
Vector2 normalisedDirection = direction * new Vector2(1f / distance);
|
Vector2 normalisedDirection = direction * new Vector2(1f / distance);
|
||||||
Vector2 snappedPosition = CentrePosition + normalisedDirection * radialCount * radius;
|
Vector2 snappedPosition = StartPosition + normalisedDirection * radialCount * radius;
|
||||||
|
|
||||||
return (snappedPosition, StartTime + SnapProvider.GetSnappedDurationFromDistance(StartTime, (snappedPosition - CentrePosition).Length));
|
return (snappedPosition, StartTime + SnapProvider.GetSnappedDurationFromDistance(StartTime, (snappedPosition - StartPosition).Length));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using JetBrains.Annotations;
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Caching;
|
using osu.Framework.Caching;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
@ -9,7 +8,6 @@ using osu.Framework.Graphics.Colour;
|
|||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Rulesets.Edit;
|
using osu.Game.Rulesets.Edit;
|
||||||
using osu.Game.Rulesets.Objects;
|
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Screens.Edit.Compose.Components
|
namespace osu.Game.Screens.Edit.Compose.Components
|
||||||
@ -24,21 +22,21 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
protected float DistanceSpacing { get; private set; }
|
protected float DistanceSpacing { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The snapping time at <see cref="CentrePosition"/>.
|
|
||||||
/// </summary>
|
|
||||||
protected double StartTime { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The maximum number of distance snapping intervals allowed.
|
/// The maximum number of distance snapping intervals allowed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected int MaxIntervals { get; private set; }
|
protected int MaxIntervals { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The position which the grid is centred on.
|
/// The position which the grid should start.
|
||||||
/// The first beat snapping tick is located at <see cref="CentrePosition"/> + <see cref="DistanceSpacing"/> in the desired direction.
|
/// The first beat snapping tick is located at <see cref="StartPosition"/> + <see cref="DistanceSpacing"/> away from this point.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected readonly Vector2 CentrePosition;
|
protected readonly Vector2 StartPosition;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The snapping time at <see cref="StartPosition"/>.
|
||||||
|
/// </summary>
|
||||||
|
protected readonly double StartTime;
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
protected OsuColour Colours { get; private set; }
|
protected OsuColour Colours { get; private set; }
|
||||||
@ -53,25 +51,23 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
private BindableBeatDivisor beatDivisor { get; set; }
|
private BindableBeatDivisor beatDivisor { get; set; }
|
||||||
|
|
||||||
private readonly Cached gridCache = new Cached();
|
private readonly Cached gridCache = new Cached();
|
||||||
private readonly HitObject hitObject;
|
private readonly double? endTime;
|
||||||
private readonly HitObject nextHitObject;
|
|
||||||
|
|
||||||
protected DistanceSnapGrid(HitObject hitObject, [CanBeNull] HitObject nextHitObject, Vector2 centrePosition)
|
/// <summary>
|
||||||
|
/// Creates a new <see cref="DistanceSnapGrid"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="startPosition">The position at which the grid should start. The first tick is located one distance spacing length away from this point.</param>
|
||||||
|
/// <param name="startTime">The snapping time at <see cref="StartPosition"/>.</param>
|
||||||
|
/// <param name="endTime">The time at which the snapping grid should end. If null, the grid will continue until the bounds of the screen are exceeded.</param>
|
||||||
|
protected DistanceSnapGrid(Vector2 startPosition, double startTime, double? endTime = null)
|
||||||
{
|
{
|
||||||
this.hitObject = hitObject;
|
this.endTime = endTime;
|
||||||
this.nextHitObject = nextHitObject;
|
StartPosition = startPosition;
|
||||||
|
StartTime = startTime;
|
||||||
CentrePosition = centrePosition;
|
|
||||||
|
|
||||||
RelativeSizeAxes = Axes.Both;
|
RelativeSizeAxes = Axes.Both;
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load()
|
|
||||||
{
|
|
||||||
StartTime = hitObject.GetEndTime();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
@ -83,12 +79,12 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
{
|
{
|
||||||
DistanceSpacing = SnapProvider.GetBeatSnapDistanceAt(StartTime);
|
DistanceSpacing = SnapProvider.GetBeatSnapDistanceAt(StartTime);
|
||||||
|
|
||||||
if (nextHitObject == null)
|
if (endTime == null)
|
||||||
MaxIntervals = int.MaxValue;
|
MaxIntervals = int.MaxValue;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// +1 is added since a snapped hitobject may have its start time slightly less than the snapped time due to floating point errors
|
// +1 is added since a snapped hitobject may have its start time slightly less than the snapped time due to floating point errors
|
||||||
double maxDuration = nextHitObject.StartTime - StartTime + 1;
|
double maxDuration = endTime.Value - StartTime + 1;
|
||||||
MaxIntervals = (int)(maxDuration / SnapProvider.DistanceToDuration(StartTime, DistanceSpacing));
|
MaxIntervals = (int)(maxDuration / SnapProvider.DistanceToDuration(StartTime, DistanceSpacing));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,7 +106,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
if (!gridCache.IsValid)
|
if (!gridCache.IsValid)
|
||||||
{
|
{
|
||||||
ClearInternal();
|
ClearInternal();
|
||||||
CreateContent(CentrePosition);
|
CreateContent(StartPosition);
|
||||||
gridCache.Validate();
|
gridCache.Validate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -118,7 +114,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates the content which visualises the grid ticks.
|
/// Creates the content which visualises the grid ticks.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected abstract void CreateContent(Vector2 centrePosition);
|
protected abstract void CreateContent(Vector2 startPosition);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Snaps a position to this grid.
|
/// Snaps a position to this grid.
|
||||||
|
@ -135,7 +135,7 @@ namespace osu.Game.Screens.Play
|
|||||||
addGameplayComponents(GameplayClockContainer, working);
|
addGameplayComponents(GameplayClockContainer, working);
|
||||||
addOverlayComponents(GameplayClockContainer, working);
|
addOverlayComponents(GameplayClockContainer, working);
|
||||||
|
|
||||||
DrawableRuleset.HasReplayLoaded.BindValueChanged(e => HUDOverlay.HoldToQuit.PauseOnFocusLost = !e.NewValue && PauseOnFocusLost, true);
|
DrawableRuleset.HasReplayLoaded.BindValueChanged(_ => updatePauseOnFocusLostState(), true);
|
||||||
|
|
||||||
// bind clock into components that require it
|
// bind clock into components that require it
|
||||||
DrawableRuleset.IsPaused.BindTo(GameplayClockContainer.IsPaused);
|
DrawableRuleset.IsPaused.BindTo(GameplayClockContainer.IsPaused);
|
||||||
@ -146,6 +146,7 @@ namespace osu.Game.Screens.Play
|
|||||||
|
|
||||||
foreach (var mod in Mods.Value.OfType<IApplicableToScoreProcessor>())
|
foreach (var mod in Mods.Value.OfType<IApplicableToScoreProcessor>())
|
||||||
mod.ApplyToScoreProcessor(ScoreProcessor);
|
mod.ApplyToScoreProcessor(ScoreProcessor);
|
||||||
|
breakOverlay.IsBreakTime.ValueChanged += _ => updatePauseOnFocusLostState();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addUnderlayComponents(Container target)
|
private void addUnderlayComponents(Container target)
|
||||||
@ -241,6 +242,11 @@ namespace osu.Game.Screens.Play
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updatePauseOnFocusLostState() =>
|
||||||
|
HUDOverlay.HoldToQuit.PauseOnFocusLost = PauseOnFocusLost
|
||||||
|
&& !DrawableRuleset.HasReplayLoaded.Value
|
||||||
|
&& !breakOverlay.IsBreakTime.Value;
|
||||||
|
|
||||||
private WorkingBeatmap loadBeatmap()
|
private WorkingBeatmap loadBeatmap()
|
||||||
{
|
{
|
||||||
WorkingBeatmap working = Beatmap.Value;
|
WorkingBeatmap working = Beatmap.Value;
|
||||||
|
@ -8,13 +8,16 @@ namespace osu.Game.Tests.Visual
|
|||||||
{
|
{
|
||||||
public class TestPlayer : Player
|
public class TestPlayer : Player
|
||||||
{
|
{
|
||||||
protected override bool PauseOnFocusLost => false;
|
protected override bool PauseOnFocusLost { get; }
|
||||||
|
|
||||||
public new DrawableRuleset DrawableRuleset => base.DrawableRuleset;
|
public new DrawableRuleset DrawableRuleset => base.DrawableRuleset;
|
||||||
|
|
||||||
public TestPlayer(bool allowPause = true, bool showResults = true)
|
public new GameplayClockContainer GameplayClockContainer => base.GameplayClockContainer;
|
||||||
|
|
||||||
|
public TestPlayer(bool allowPause = true, bool showResults = true, bool pauseOnFocusLost = false)
|
||||||
: base(allowPause, showResults)
|
: base(allowPause, showResults)
|
||||||
{
|
{
|
||||||
|
PauseOnFocusLost = pauseOnFocusLost;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user