mirror of
https://github.com/ppy/osu.git
synced 2025-02-13 15:03:13 +08:00
Merge branch 'master' into mod-muted
This commit is contained in:
commit
7251c28c4a
@ -52,7 +52,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.722.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2021.723.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2021.728.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Transitive Dependencies">
|
||||
<!-- Realm needs to be directly referenced in all Xamarin projects, as it will not pull in its transitive dependencies otherwise. -->
|
||||
|
@ -41,7 +41,7 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
var skin = new TestSkin { FlipCatcherPlate = flip };
|
||||
container.Child = new SkinProvidingContainer(skin)
|
||||
{
|
||||
Child = catcher = new Catcher(new Container(), new DroppedObjectContainer())
|
||||
Child = catcher = new Catcher(new DroppedObjectContainer())
|
||||
{
|
||||
Anchor = Anchor.Centre
|
||||
}
|
||||
|
@ -31,8 +31,6 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
[Resolved]
|
||||
private OsuConfigManager config { get; set; }
|
||||
|
||||
private Container trailContainer;
|
||||
|
||||
private DroppedObjectContainer droppedObjectContainer;
|
||||
|
||||
private TestCatcher catcher;
|
||||
@ -45,7 +43,6 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
CircleSize = 0,
|
||||
};
|
||||
|
||||
trailContainer = new Container();
|
||||
droppedObjectContainer = new DroppedObjectContainer();
|
||||
|
||||
Child = new Container
|
||||
@ -54,8 +51,7 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
Children = new Drawable[]
|
||||
{
|
||||
droppedObjectContainer,
|
||||
catcher = new TestCatcher(trailContainer, droppedObjectContainer, difficulty),
|
||||
trailContainer,
|
||||
catcher = new TestCatcher(droppedObjectContainer, difficulty),
|
||||
}
|
||||
};
|
||||
});
|
||||
@ -294,8 +290,8 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
{
|
||||
public IEnumerable<CaughtObject> CaughtObjects => this.ChildrenOfType<CaughtObject>();
|
||||
|
||||
public TestCatcher(Container trailsTarget, DroppedObjectContainer droppedObjectTarget, BeatmapDifficulty difficulty)
|
||||
: base(trailsTarget, droppedObjectTarget, difficulty)
|
||||
public TestCatcher(DroppedObjectContainer droppedObjectTarget, BeatmapDifficulty difficulty)
|
||||
: base(droppedObjectTarget, difficulty)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
@ -122,10 +122,9 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
public TestCatcherArea(BeatmapDifficulty beatmapDifficulty)
|
||||
{
|
||||
var droppedObjectContainer = new DroppedObjectContainer();
|
||||
|
||||
Add(droppedObjectContainer);
|
||||
|
||||
Catcher = new Catcher(this, droppedObjectContainer, beatmapDifficulty)
|
||||
Catcher = new Catcher(droppedObjectContainer, beatmapDifficulty)
|
||||
{
|
||||
X = CatchPlayfield.CENTER_X
|
||||
};
|
||||
|
@ -47,7 +47,7 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCustomEndGlowColour()
|
||||
public void TestCustomAfterImageColour()
|
||||
{
|
||||
var skin = new TestSkin
|
||||
{
|
||||
@ -58,7 +58,7 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCustomEndGlowColourPriority()
|
||||
public void TestCustomAfterImageColourPriority()
|
||||
{
|
||||
var skin = new TestSkin
|
||||
{
|
||||
@ -111,39 +111,37 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
checkHyperDashFruitColour(skin, skin.HyperDashColour);
|
||||
}
|
||||
|
||||
private void checkHyperDashCatcherColour(ISkin skin, Color4 expectedCatcherColour, Color4? expectedEndGlowColour = null)
|
||||
private void checkHyperDashCatcherColour(ISkin skin, Color4 expectedCatcherColour, Color4? expectedAfterImageColour = null)
|
||||
{
|
||||
Container trailsContainer = null;
|
||||
Catcher catcher = null;
|
||||
CatcherTrailDisplay trails = null;
|
||||
Catcher catcher = null;
|
||||
|
||||
AddStep("create hyper-dashing catcher", () =>
|
||||
{
|
||||
trailsContainer = new Container();
|
||||
CatcherArea catcherArea;
|
||||
Child = setupSkinHierarchy(new Container
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Children = new Drawable[]
|
||||
Child = catcherArea = new CatcherArea
|
||||
{
|
||||
catcher = new Catcher(trailsContainer, new DroppedObjectContainer())
|
||||
Catcher = catcher = new Catcher(new DroppedObjectContainer())
|
||||
{
|
||||
Scale = new Vector2(4)
|
||||
},
|
||||
trailsContainer
|
||||
}
|
||||
}
|
||||
}, skin);
|
||||
trails = catcherArea.ChildrenOfType<CatcherTrailDisplay>().Single();
|
||||
});
|
||||
|
||||
AddStep("get trails container", () =>
|
||||
AddStep("start hyper-dash", () =>
|
||||
{
|
||||
trails = trailsContainer.OfType<CatcherTrailDisplay>().Single();
|
||||
catcher.SetHyperDashState(2);
|
||||
});
|
||||
|
||||
AddUntilStep("catcher colour is correct", () => catcher.Colour == expectedCatcherColour);
|
||||
|
||||
AddAssert("catcher trails colours are correct", () => trails.HyperDashTrailsColour == expectedCatcherColour);
|
||||
AddAssert("catcher end-glow colours are correct", () => trails.EndGlowSpritesColour == (expectedEndGlowColour ?? expectedCatcherColour));
|
||||
AddAssert("catcher after-image colours are correct", () => trails.HyperDashAfterImageColour == (expectedAfterImageColour ?? expectedCatcherColour));
|
||||
|
||||
AddStep("finish hyper-dashing", () =>
|
||||
{
|
||||
|
@ -3,7 +3,6 @@
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Catch.Objects;
|
||||
using osu.Game.Rulesets.Catch.Objects.Drawables;
|
||||
@ -45,14 +44,9 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
var trailContainer = new Container
|
||||
{
|
||||
Anchor = Anchor.BottomLeft,
|
||||
Origin = Anchor.TopLeft
|
||||
};
|
||||
var droppedObjectContainer = new DroppedObjectContainer();
|
||||
|
||||
Catcher = new Catcher(trailContainer, droppedObjectContainer, difficulty)
|
||||
Catcher = new Catcher(droppedObjectContainer, difficulty)
|
||||
{
|
||||
X = CENTER_X
|
||||
};
|
||||
@ -70,7 +64,6 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
Origin = Anchor.TopLeft,
|
||||
Catcher = Catcher,
|
||||
},
|
||||
trailContainer,
|
||||
HitObjectContainer,
|
||||
});
|
||||
|
||||
|
@ -36,8 +36,7 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
public const float ALLOWED_CATCH_RANGE = 0.8f;
|
||||
|
||||
/// <summary>
|
||||
/// The default colour used to tint hyper-dash fruit, along with the moving catcher, its trail
|
||||
/// and end glow/after-image during a hyper-dash.
|
||||
/// The default colour used to tint hyper-dash fruit, along with the moving catcher, its trail and after-image during a hyper-dash.
|
||||
/// </summary>
|
||||
public static readonly Color4 DEFAULT_HYPER_DASH_COLOUR = Color4.Red;
|
||||
|
||||
@ -71,11 +70,6 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
/// </summary>
|
||||
private const float caught_fruit_scale_adjust = 0.5f;
|
||||
|
||||
[NotNull]
|
||||
private readonly Container trailsTarget;
|
||||
|
||||
private CatcherTrailDisplay trails;
|
||||
|
||||
/// <summary>
|
||||
/// Contains caught objects on the plate.
|
||||
/// </summary>
|
||||
@ -88,30 +82,22 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
|
||||
public CatcherAnimationState CurrentState
|
||||
{
|
||||
get => Body.AnimationState.Value;
|
||||
private set => Body.AnimationState.Value = value;
|
||||
get => body.AnimationState.Value;
|
||||
private set => body.AnimationState.Value = value;
|
||||
}
|
||||
|
||||
private bool dashing;
|
||||
|
||||
public bool Dashing
|
||||
{
|
||||
get => dashing;
|
||||
set
|
||||
{
|
||||
if (value == dashing) return;
|
||||
|
||||
dashing = value;
|
||||
|
||||
updateTrailVisibility();
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Whether the catcher is currently dashing.
|
||||
/// </summary>
|
||||
public bool Dashing { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The currently facing direction.
|
||||
/// </summary>
|
||||
public Direction VisualDirection { get; set; } = Direction.Right;
|
||||
|
||||
public Vector2 BodyScale => Scale * body.Scale;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the contents of the catcher plate should be visually flipped when the catcher direction is changed.
|
||||
/// </summary>
|
||||
@ -122,10 +108,9 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
/// </summary>
|
||||
private readonly float catchWidth;
|
||||
|
||||
internal readonly SkinnableCatcher Body;
|
||||
private readonly SkinnableCatcher body;
|
||||
|
||||
private Color4 hyperDashColour = DEFAULT_HYPER_DASH_COLOUR;
|
||||
private Color4 hyperDashEndGlowColour = DEFAULT_HYPER_DASH_COLOUR;
|
||||
|
||||
private double hyperDashModifier = 1;
|
||||
private int hyperDashDirection;
|
||||
@ -138,9 +123,8 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
private readonly DrawablePool<CaughtBanana> caughtBananaPool;
|
||||
private readonly DrawablePool<CaughtDroplet> caughtDropletPool;
|
||||
|
||||
public Catcher([NotNull] Container trailsTarget, [NotNull] DroppedObjectContainer droppedObjectTarget, BeatmapDifficulty difficulty = null)
|
||||
public Catcher([NotNull] DroppedObjectContainer droppedObjectTarget, BeatmapDifficulty difficulty = null)
|
||||
{
|
||||
this.trailsTarget = trailsTarget;
|
||||
this.droppedObjectTarget = droppedObjectTarget;
|
||||
|
||||
Origin = Anchor.TopCentre;
|
||||
@ -164,7 +148,7 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
// offset fruit vertically to better place "above" the plate.
|
||||
Y = -5
|
||||
},
|
||||
Body = new SkinnableCatcher(),
|
||||
body = new SkinnableCatcher(),
|
||||
hitExplosionContainer = new HitExplosionContainer
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
@ -177,15 +161,6 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
private void load(OsuConfigManager config)
|
||||
{
|
||||
hitLighting = config.GetBindable<bool>(OsuSetting.HitLighting);
|
||||
trails = new CatcherTrailDisplay(this);
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
// don't add in above load as we may potentially modify a parent in an unsafe manner.
|
||||
trailsTarget.Add(trails);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -307,12 +282,9 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
hyperDashTargetPosition = targetPosition;
|
||||
|
||||
if (!wasHyperDashing)
|
||||
{
|
||||
trails.DisplayEndGlow();
|
||||
runHyperDashStateTransition(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Drop any fruit off the plate.
|
||||
@ -326,13 +298,9 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
|
||||
private void runHyperDashStateTransition(bool hyperDashing)
|
||||
{
|
||||
updateTrailVisibility();
|
||||
|
||||
this.FadeColour(hyperDashing ? hyperDashColour : Color4.White, HYPER_DASH_TRANSITION_DURATION, Easing.OutQuint);
|
||||
}
|
||||
|
||||
private void updateTrailVisibility() => trails.DisplayTrail = Dashing || HyperDashing;
|
||||
|
||||
protected override void SkinChanged(ISkinSource skin)
|
||||
{
|
||||
base.SkinChanged(skin);
|
||||
@ -341,13 +309,6 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
skin.GetConfig<CatchSkinColour, Color4>(CatchSkinColour.HyperDash)?.Value ??
|
||||
DEFAULT_HYPER_DASH_COLOUR;
|
||||
|
||||
hyperDashEndGlowColour =
|
||||
skin.GetConfig<CatchSkinColour, Color4>(CatchSkinColour.HyperDashAfterImage)?.Value ??
|
||||
hyperDashColour;
|
||||
|
||||
trails.HyperDashTrailsColour = hyperDashColour;
|
||||
trails.EndGlowSpritesColour = hyperDashEndGlowColour;
|
||||
|
||||
flipCatcherPlate = skin.GetConfig<CatchSkinConfiguration, bool>(CatchSkinConfiguration.FlipCatcherPlate)?.Value ?? true;
|
||||
|
||||
runHyperDashStateTransition(HyperDashing);
|
||||
@ -358,7 +319,7 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
base.Update();
|
||||
|
||||
var scaleFromDirection = new Vector2((int)VisualDirection, 1);
|
||||
Body.Scale = scaleFromDirection;
|
||||
body.Scale = scaleFromDirection;
|
||||
caughtObjectContainer.Scale = hitExplosionContainer.Scale = flipCatcherPlate ? scaleFromDirection : Vector2.One;
|
||||
|
||||
// Correct overshooting.
|
||||
|
@ -25,17 +25,15 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
public Catcher Catcher
|
||||
{
|
||||
get => catcher;
|
||||
set
|
||||
{
|
||||
if (catcher != null)
|
||||
Remove(catcher);
|
||||
set => catcherContainer.Child = catcher = value;
|
||||
}
|
||||
|
||||
Add(catcher = value);
|
||||
}
|
||||
}
|
||||
private readonly Container<Catcher> catcherContainer;
|
||||
|
||||
private readonly CatchComboDisplay comboDisplay;
|
||||
|
||||
private readonly CatcherTrailDisplay catcherTrails;
|
||||
|
||||
private Catcher catcher;
|
||||
|
||||
/// <summary>
|
||||
@ -45,13 +43,20 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
/// </summary>
|
||||
private int currentDirection;
|
||||
|
||||
// TODO: support replay rewind
|
||||
private bool lastHyperDashState;
|
||||
|
||||
/// <remarks>
|
||||
/// <see cref="Catcher"/> must be set before loading.
|
||||
/// </remarks>
|
||||
public CatcherArea()
|
||||
{
|
||||
Size = new Vector2(CatchPlayfield.WIDTH, Catcher.BASE_SIZE);
|
||||
Child = comboDisplay = new CatchComboDisplay
|
||||
Children = new Drawable[]
|
||||
{
|
||||
catcherContainer = new Container<Catcher> { RelativeSizeAxes = Axes.Both },
|
||||
catcherTrails = new CatcherTrailDisplay(),
|
||||
comboDisplay = new CatchComboDisplay
|
||||
{
|
||||
RelativeSizeAxes = Axes.None,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
@ -59,6 +64,7 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
Origin = Anchor.Centre,
|
||||
Margin = new MarginPadding { Bottom = 350f },
|
||||
X = CatchPlayfield.CENTER_X
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ -102,6 +108,19 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
base.UpdateAfterChildren();
|
||||
|
||||
comboDisplay.X = Catcher.X;
|
||||
|
||||
if (!lastHyperDashState && Catcher.HyperDashing && Time.Elapsed > 0)
|
||||
catcherTrails.DisplayHyperDashAfterImage(Catcher.CurrentState, Catcher.X, Catcher.BodyScale);
|
||||
|
||||
if (Catcher.Dashing || Catcher.HyperDashing)
|
||||
{
|
||||
double generationInterval = Catcher.HyperDashing ? 25 : 50;
|
||||
|
||||
if (Time.Current - catcherTrails.LastDashTrailTime >= generationInterval)
|
||||
catcherTrails.DisplayDashTrail(Catcher.CurrentState, Catcher.X, Catcher.BodyScale, Catcher.HyperDashing);
|
||||
}
|
||||
|
||||
lastHyperDashState = Catcher.HyperDashing;
|
||||
}
|
||||
|
||||
public void SetCatcherPosition(float X)
|
||||
|
@ -2,10 +2,11 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using JetBrains.Annotations;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Pooling;
|
||||
using osu.Game.Rulesets.Catch.Skinning;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
@ -15,70 +16,27 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
/// Represents a component responsible for displaying
|
||||
/// the appropriate catcher trails when requested to.
|
||||
/// </summary>
|
||||
public class CatcherTrailDisplay : CompositeDrawable
|
||||
public class CatcherTrailDisplay : SkinReloadableDrawable
|
||||
{
|
||||
private readonly Catcher catcher;
|
||||
/// <summary>
|
||||
/// The most recent time a dash trail was added to this container.
|
||||
/// Only alive (not faded out) trails are considered.
|
||||
/// Returns <see cref="double.NegativeInfinity"/> if no dash trail is alive.
|
||||
/// </summary>
|
||||
public double LastDashTrailTime => getLastDashTrailTime();
|
||||
|
||||
public Color4 HyperDashTrailsColour => hyperDashTrails.Colour;
|
||||
|
||||
public Color4 HyperDashAfterImageColour => hyperDashAfterImages.Colour;
|
||||
|
||||
private readonly DrawablePool<CatcherTrail> trailPool;
|
||||
|
||||
private readonly Container<CatcherTrail> dashTrails;
|
||||
private readonly Container<CatcherTrail> hyperDashTrails;
|
||||
private readonly Container<CatcherTrail> endGlowSprites;
|
||||
private readonly Container<CatcherTrail> hyperDashAfterImages;
|
||||
|
||||
private Color4 hyperDashTrailsColour = Catcher.DEFAULT_HYPER_DASH_COLOUR;
|
||||
|
||||
public Color4 HyperDashTrailsColour
|
||||
public CatcherTrailDisplay()
|
||||
{
|
||||
get => hyperDashTrailsColour;
|
||||
set
|
||||
{
|
||||
if (hyperDashTrailsColour == value)
|
||||
return;
|
||||
|
||||
hyperDashTrailsColour = value;
|
||||
hyperDashTrails.Colour = hyperDashTrailsColour;
|
||||
}
|
||||
}
|
||||
|
||||
private Color4 endGlowSpritesColour = Catcher.DEFAULT_HYPER_DASH_COLOUR;
|
||||
|
||||
public Color4 EndGlowSpritesColour
|
||||
{
|
||||
get => endGlowSpritesColour;
|
||||
set
|
||||
{
|
||||
if (endGlowSpritesColour == value)
|
||||
return;
|
||||
|
||||
endGlowSpritesColour = value;
|
||||
endGlowSprites.Colour = endGlowSpritesColour;
|
||||
}
|
||||
}
|
||||
|
||||
private bool trail;
|
||||
|
||||
/// <summary>
|
||||
/// Whether to start displaying trails following the catcher.
|
||||
/// </summary>
|
||||
public bool DisplayTrail
|
||||
{
|
||||
get => trail;
|
||||
set
|
||||
{
|
||||
if (trail == value)
|
||||
return;
|
||||
|
||||
trail = value;
|
||||
|
||||
if (trail)
|
||||
displayTrail();
|
||||
}
|
||||
}
|
||||
|
||||
public CatcherTrailDisplay([NotNull] Catcher catcher)
|
||||
{
|
||||
this.catcher = catcher ?? throw new ArgumentNullException(nameof(catcher));
|
||||
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
|
||||
InternalChildren = new Drawable[]
|
||||
@ -86,47 +44,68 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
trailPool = new DrawablePool<CatcherTrail>(30),
|
||||
dashTrails = new Container<CatcherTrail> { RelativeSizeAxes = Axes.Both },
|
||||
hyperDashTrails = new Container<CatcherTrail> { RelativeSizeAxes = Axes.Both, Colour = Catcher.DEFAULT_HYPER_DASH_COLOUR },
|
||||
endGlowSprites = new Container<CatcherTrail> { RelativeSizeAxes = Axes.Both, Colour = Catcher.DEFAULT_HYPER_DASH_COLOUR },
|
||||
hyperDashAfterImages = new Container<CatcherTrail> { RelativeSizeAxes = Axes.Both, Colour = Catcher.DEFAULT_HYPER_DASH_COLOUR },
|
||||
};
|
||||
}
|
||||
|
||||
protected override void SkinChanged(ISkinSource skin)
|
||||
{
|
||||
base.SkinChanged(skin);
|
||||
|
||||
hyperDashTrails.Colour = skin.GetConfig<CatchSkinColour, Color4>(CatchSkinColour.HyperDash)?.Value ?? Catcher.DEFAULT_HYPER_DASH_COLOUR;
|
||||
hyperDashAfterImages.Colour = skin.GetConfig<CatchSkinColour, Color4>(CatchSkinColour.HyperDashAfterImage)?.Value ?? hyperDashTrails.Colour;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Displays a single end-glow catcher sprite.
|
||||
/// Displays a hyper-dash after-image of the catcher.
|
||||
/// </summary>
|
||||
public void DisplayEndGlow()
|
||||
public void DisplayHyperDashAfterImage(CatcherAnimationState animationState, float x, Vector2 scale)
|
||||
{
|
||||
var endGlow = createTrailSprite(endGlowSprites);
|
||||
var trail = createTrail(animationState, x, scale);
|
||||
|
||||
endGlow.MoveToOffset(new Vector2(0, -10), 1200, Easing.In);
|
||||
endGlow.ScaleTo(endGlow.Scale * 0.95f).ScaleTo(endGlow.Scale * 1.2f, 1200, Easing.In);
|
||||
endGlow.FadeOut(1200);
|
||||
endGlow.Expire(true);
|
||||
hyperDashAfterImages.Add(trail);
|
||||
|
||||
trail.MoveToOffset(new Vector2(0, -10), 1200, Easing.In);
|
||||
trail.ScaleTo(trail.Scale * 0.95f).ScaleTo(trail.Scale * 1.2f, 1200, Easing.In);
|
||||
trail.FadeOut(1200);
|
||||
trail.Expire(true);
|
||||
}
|
||||
|
||||
private void displayTrail()
|
||||
public void DisplayDashTrail(CatcherAnimationState animationState, float x, Vector2 scale, bool hyperDashing)
|
||||
{
|
||||
if (!DisplayTrail)
|
||||
return;
|
||||
var trail = createTrail(animationState, x, scale);
|
||||
|
||||
var sprite = createTrailSprite(catcher.HyperDashing ? hyperDashTrails : dashTrails);
|
||||
if (hyperDashing)
|
||||
hyperDashTrails.Add(trail);
|
||||
else
|
||||
dashTrails.Add(trail);
|
||||
|
||||
sprite.FadeTo(0.4f).FadeOut(800, Easing.OutQuint);
|
||||
sprite.Expire(true);
|
||||
|
||||
Scheduler.AddDelayed(displayTrail, catcher.HyperDashing ? 25 : 50);
|
||||
trail.FadeTo(0.4f).FadeOut(800, Easing.OutQuint);
|
||||
trail.Expire(true);
|
||||
}
|
||||
|
||||
private CatcherTrail createTrailSprite(Container<CatcherTrail> target)
|
||||
private CatcherTrail createTrail(CatcherAnimationState animationState, float x, Vector2 scale)
|
||||
{
|
||||
CatcherTrail sprite = trailPool.Get();
|
||||
CatcherTrail trail = trailPool.Get();
|
||||
|
||||
sprite.AnimationState = catcher.CurrentState;
|
||||
sprite.Scale = catcher.Scale * catcher.Body.Scale;
|
||||
sprite.Position = catcher.Position;
|
||||
trail.AnimationState = animationState;
|
||||
trail.Scale = scale;
|
||||
trail.Position = new Vector2(x, 0);
|
||||
|
||||
target.Add(sprite);
|
||||
return trail;
|
||||
}
|
||||
|
||||
return sprite;
|
||||
private double getLastDashTrailTime()
|
||||
{
|
||||
double maxTime = double.NegativeInfinity;
|
||||
|
||||
foreach (var trail in dashTrails)
|
||||
maxTime = Math.Max(maxTime, trail.LifetimeStart);
|
||||
|
||||
foreach (var trail in hyperDashTrails)
|
||||
maxTime = Math.Max(maxTime, trail.LifetimeStart);
|
||||
|
||||
return maxTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,13 +10,9 @@ using osu.Game.Rulesets.Mania.Beatmaps;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Mods
|
||||
{
|
||||
public class ManiaModMirror : Mod, IApplicableToBeatmap
|
||||
public class ManiaModMirror : ModMirror, IApplicableToBeatmap
|
||||
{
|
||||
public override string Name => "Mirror";
|
||||
public override string Acronym => "MR";
|
||||
public override ModType Type => ModType.Conversion;
|
||||
public override string Description => "Notes are flipped horizontally.";
|
||||
public override double ScoreMultiplier => 1;
|
||||
|
||||
public void ApplyToBeatmap(IBeatmap beatmap)
|
||||
{
|
||||
|
@ -1,13 +1,12 @@
|
||||
// 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;
|
||||
using System.Linq;
|
||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Rulesets.Osu.UI;
|
||||
using osuTK;
|
||||
using osu.Game.Rulesets.Osu.Utils;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Mods
|
||||
{
|
||||
@ -15,23 +14,13 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
{
|
||||
public override double ScoreMultiplier => 1.06;
|
||||
|
||||
public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(ModMirror)).ToArray();
|
||||
|
||||
public void ApplyToHitObject(HitObject hitObject)
|
||||
{
|
||||
var osuObject = (OsuHitObject)hitObject;
|
||||
|
||||
osuObject.Position = new Vector2(osuObject.Position.X, OsuPlayfield.BASE_SIZE.Y - osuObject.Y);
|
||||
|
||||
if (!(hitObject is Slider slider))
|
||||
return;
|
||||
|
||||
slider.NestedHitObjects.OfType<SliderTick>().ForEach(h => h.Position = new Vector2(h.Position.X, OsuPlayfield.BASE_SIZE.Y - h.Position.Y));
|
||||
slider.NestedHitObjects.OfType<SliderRepeat>().ForEach(h => h.Position = new Vector2(h.Position.X, OsuPlayfield.BASE_SIZE.Y - h.Position.Y));
|
||||
|
||||
var controlPoints = slider.Path.ControlPoints.Select(p => new PathControlPoint(p.Position.Value, p.Type.Value)).ToArray();
|
||||
foreach (var point in controlPoints)
|
||||
point.Position.Value = new Vector2(point.Position.Value.X, -point.Position.Value.Y);
|
||||
|
||||
slider.Path = new SliderPath(controlPoints, slider.Path.ExpectedDistance.Value);
|
||||
OsuHitObjectGenerationUtils.ReflectVertically(osuObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
50
osu.Game.Rulesets.Osu/Mods/OsuModMirror.cs
Normal file
50
osu.Game.Rulesets.Osu/Mods/OsuModMirror.cs
Normal file
@ -0,0 +1,50 @@
|
||||
// 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;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Rulesets.Osu.Utils;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Mods
|
||||
{
|
||||
public class OsuModMirror : ModMirror, IApplicableToHitObject
|
||||
{
|
||||
public override string Description => "Flip objects on the chosen axes.";
|
||||
public override Type[] IncompatibleMods => new[] { typeof(ModHardRock) };
|
||||
|
||||
[SettingSource("Mirrored axes", "Choose which axes objects are mirrored over.")]
|
||||
public Bindable<MirrorType> Reflection { get; } = new Bindable<MirrorType>();
|
||||
|
||||
public void ApplyToHitObject(HitObject hitObject)
|
||||
{
|
||||
var osuObject = (OsuHitObject)hitObject;
|
||||
|
||||
switch (Reflection.Value)
|
||||
{
|
||||
case MirrorType.Horizontal:
|
||||
OsuHitObjectGenerationUtils.ReflectHorizontally(osuObject);
|
||||
break;
|
||||
|
||||
case MirrorType.Vertical:
|
||||
OsuHitObjectGenerationUtils.ReflectVertically(osuObject);
|
||||
break;
|
||||
|
||||
case MirrorType.Both:
|
||||
OsuHitObjectGenerationUtils.ReflectHorizontally(osuObject);
|
||||
OsuHitObjectGenerationUtils.ReflectVertically(osuObject);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public enum MirrorType
|
||||
{
|
||||
Horizontal,
|
||||
Vertical,
|
||||
Both
|
||||
}
|
||||
}
|
||||
}
|
@ -4,8 +4,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio.Track;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
@ -16,7 +14,6 @@ using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Beatmaps.Timing;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Overlays.Settings;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
@ -29,7 +26,6 @@ using osu.Game.Rulesets.Osu.UI;
|
||||
using osu.Game.Rulesets.Osu.Utils;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
@ -67,11 +63,6 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
/// </summary>
|
||||
private const float distance_cap = 380f;
|
||||
|
||||
// The distances from the hit objects to the borders of the playfield they start to "turn around" and curve towards the middle.
|
||||
// The closer the hit objects draw to the border, the sharper the turn
|
||||
private const byte border_distance_x = 192;
|
||||
private const byte border_distance_y = 144;
|
||||
|
||||
/// <summary>
|
||||
/// The extent of rotation towards playfield centre when a circle is near the edge
|
||||
/// </summary>
|
||||
@ -341,46 +332,7 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
|
||||
public void ApplyToDrawableRuleset(DrawableRuleset<OsuHitObject> drawableRuleset)
|
||||
{
|
||||
drawableRuleset.Overlays.Add(new TargetBeatContainer(drawableRuleset.Beatmap.HitObjects.First().StartTime));
|
||||
}
|
||||
|
||||
public class TargetBeatContainer : BeatSyncedContainer
|
||||
{
|
||||
private readonly double firstHitTime;
|
||||
|
||||
private PausableSkinnableSound sample;
|
||||
|
||||
public TargetBeatContainer(double firstHitTime)
|
||||
{
|
||||
this.firstHitTime = firstHitTime;
|
||||
AllowMistimedEventFiring = false;
|
||||
Divisor = 1;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
sample = new PausableSkinnableSound(new SampleInfo("Gameplay/catch-banana"))
|
||||
};
|
||||
}
|
||||
|
||||
protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes)
|
||||
{
|
||||
base.OnNewBeat(beatIndex, timingPoint, effectPoint, amplitudes);
|
||||
|
||||
if (!IsBeatSyncedWithTrack) return;
|
||||
|
||||
int timeSignature = (int)timingPoint.TimeSignature;
|
||||
|
||||
// play metronome from one measure before the first object.
|
||||
if (BeatSyncClock.CurrentTime < firstHitTime - timingPoint.BeatLength * timeSignature)
|
||||
return;
|
||||
|
||||
sample.Frequency.Value = beatIndex % timeSignature == 0 ? 1 : 0.5f;
|
||||
sample.Play();
|
||||
}
|
||||
drawableRuleset.Overlays.Add(new Metronome(drawableRuleset.Beatmap.HitObjects.First().StartTime));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
@ -166,6 +166,7 @@ namespace osu.Game.Rulesets.Osu
|
||||
new OsuModDifficultyAdjust(),
|
||||
new OsuModClassic(),
|
||||
new OsuModRandom(),
|
||||
new OsuModMirror(),
|
||||
};
|
||||
|
||||
case ModType.Automation:
|
||||
|
@ -2,7 +2,11 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||
using osu.Game.Rulesets.Osu.UI;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Utils
|
||||
@ -100,5 +104,47 @@ namespace osu.Game.Rulesets.Osu.Utils
|
||||
initial.Length * MathF.Sin(finalAngleRad)
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reflects the position of the <see cref="OsuHitObject"/> in the playfield horizontally.
|
||||
/// </summary>
|
||||
/// <param name="osuObject">The object to reflect.</param>
|
||||
public static void ReflectHorizontally(OsuHitObject osuObject)
|
||||
{
|
||||
osuObject.Position = new Vector2(OsuPlayfield.BASE_SIZE.X - osuObject.X, osuObject.Position.Y);
|
||||
|
||||
if (!(osuObject is Slider slider))
|
||||
return;
|
||||
|
||||
slider.NestedHitObjects.OfType<SliderTick>().ForEach(h => h.Position = new Vector2(OsuPlayfield.BASE_SIZE.X - h.Position.X, h.Position.Y));
|
||||
slider.NestedHitObjects.OfType<SliderRepeat>().ForEach(h => h.Position = new Vector2(OsuPlayfield.BASE_SIZE.X - h.Position.X, h.Position.Y));
|
||||
|
||||
var controlPoints = slider.Path.ControlPoints.Select(p => new PathControlPoint(p.Position.Value, p.Type.Value)).ToArray();
|
||||
foreach (var point in controlPoints)
|
||||
point.Position.Value = new Vector2(-point.Position.Value.X, point.Position.Value.Y);
|
||||
|
||||
slider.Path = new SliderPath(controlPoints, slider.Path.ExpectedDistance.Value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reflects the position of the <see cref="OsuHitObject"/> in the playfield vertically.
|
||||
/// </summary>
|
||||
/// <param name="osuObject">The object to reflect.</param>
|
||||
public static void ReflectVertically(OsuHitObject osuObject)
|
||||
{
|
||||
osuObject.Position = new Vector2(osuObject.Position.X, OsuPlayfield.BASE_SIZE.Y - osuObject.Y);
|
||||
|
||||
if (!(osuObject is Slider slider))
|
||||
return;
|
||||
|
||||
slider.NestedHitObjects.OfType<SliderTick>().ForEach(h => h.Position = new Vector2(h.Position.X, OsuPlayfield.BASE_SIZE.Y - h.Position.Y));
|
||||
slider.NestedHitObjects.OfType<SliderRepeat>().ForEach(h => h.Position = new Vector2(h.Position.X, OsuPlayfield.BASE_SIZE.Y - h.Position.Y));
|
||||
|
||||
var controlPoints = slider.Path.ControlPoints.Select(p => new PathControlPoint(p.Position.Value, p.Type.Value)).ToArray();
|
||||
foreach (var point in controlPoints)
|
||||
point.Position.Value = new Vector2(point.Position.Value.X, -point.Position.Value.Y);
|
||||
|
||||
slider.Path = new SliderPath(controlPoints, slider.Path.ExpectedDistance.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -171,9 +171,13 @@ namespace osu.Game.Online.API
|
||||
|
||||
WebRequest?.Abort();
|
||||
|
||||
// in the case of a cancellation we don't care about whether there's an error in the response.
|
||||
if (!(e is OperationCanceledException))
|
||||
{
|
||||
string responseString = WebRequest?.GetResponseString();
|
||||
|
||||
if (!string.IsNullOrEmpty(responseString))
|
||||
// naive check whether there's an error in the response to avoid unnecessary JSON deserialisation.
|
||||
if (!string.IsNullOrEmpty(responseString) && responseString.Contains(@"""error"""))
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -186,6 +190,7 @@ namespace osu.Game.Online.API
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Logger.Log($@"Failing request {this} ({e})", LoggingTarget.Network);
|
||||
pendingFailure = () => TriggerFailure(e);
|
||||
|
@ -116,10 +116,7 @@ namespace osu.Game.Online
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Log($"{clientName} connection error: {e}", LoggingTarget.Network);
|
||||
|
||||
// retry on any failure.
|
||||
await Task.Delay(5000, cancellationToken).ConfigureAwait(false);
|
||||
await handleErrorAndDelay(e, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -129,6 +126,15 @@ namespace osu.Game.Online
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles an exception and delays an async flow.
|
||||
/// </summary>
|
||||
private async Task handleErrorAndDelay(Exception exception, CancellationToken cancellationToken)
|
||||
{
|
||||
Logger.Log($"{clientName} connection error: {exception}", LoggingTarget.Network);
|
||||
await Task.Delay(5000, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private HubConnection buildConnection(CancellationToken cancellationToken)
|
||||
{
|
||||
var builder = new HubConnectionBuilder()
|
||||
@ -155,17 +161,18 @@ namespace osu.Game.Online
|
||||
return newConnection;
|
||||
}
|
||||
|
||||
private Task onConnectionClosed(Exception? ex, CancellationToken cancellationToken)
|
||||
private async Task onConnectionClosed(Exception? ex, CancellationToken cancellationToken)
|
||||
{
|
||||
isConnected.Value = false;
|
||||
|
||||
Logger.Log(ex != null ? $"{clientName} lost connection: {ex}" : $"{clientName} disconnected", LoggingTarget.Network);
|
||||
if (ex != null)
|
||||
await handleErrorAndDelay(ex, cancellationToken).ConfigureAwait(false);
|
||||
else
|
||||
Logger.Log($"{clientName} disconnected", LoggingTarget.Network);
|
||||
|
||||
// make sure a disconnect wasn't triggered (and this is still the active connection).
|
||||
if (!cancellationToken.IsCancellationRequested)
|
||||
Task.Run(connect, default);
|
||||
|
||||
return Task.CompletedTask;
|
||||
await Task.Run(connect, default).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async Task disconnect(bool takeLock)
|
||||
|
@ -18,6 +18,8 @@ using osu.Game.Scoring;
|
||||
using osu.Game.Users.Drawables;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Framework.Extensions.LocalisationExtensions;
|
||||
|
||||
namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
{
|
||||
@ -211,11 +213,11 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
return content.ToArray();
|
||||
}
|
||||
|
||||
protected override Drawable CreateHeader(int index, TableColumn column) => new HeaderText(column?.Header ?? string.Empty);
|
||||
protected override Drawable CreateHeader(int index, TableColumn column) => new HeaderText(column?.Header ?? default);
|
||||
|
||||
private class HeaderText : OsuSpriteText
|
||||
{
|
||||
public HeaderText(string text)
|
||||
public HeaderText(LocalisableString text)
|
||||
{
|
||||
Text = text.ToUpper();
|
||||
Font = OsuFont.GetFont(size: 10, weight: FontWeight.Bold);
|
||||
|
@ -13,6 +13,7 @@ using osu.Framework.Extensions.IEnumerableExtensions;
|
||||
using osu.Game.Users;
|
||||
using osu.Game.Users.Drawables;
|
||||
using osuTK;
|
||||
using osu.Framework.Localisation;
|
||||
|
||||
namespace osu.Game.Overlays.Rankings.Tables
|
||||
{
|
||||
@ -74,7 +75,7 @@ namespace osu.Game.Overlays.Rankings.Tables
|
||||
|
||||
protected override Drawable CreateHeader(int index, TableColumn column)
|
||||
{
|
||||
var title = column?.Header ?? string.Empty;
|
||||
var title = column?.Header ?? default;
|
||||
return new HeaderText(title, title == HighlightedColumn);
|
||||
}
|
||||
|
||||
@ -109,7 +110,7 @@ namespace osu.Game.Overlays.Rankings.Tables
|
||||
{
|
||||
private readonly bool isHighlighted;
|
||||
|
||||
public HeaderText(string text, bool isHighlighted)
|
||||
public HeaderText(LocalisableString text, bool isHighlighted)
|
||||
{
|
||||
this.isHighlighted = isHighlighted;
|
||||
|
||||
|
@ -9,6 +9,7 @@ using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Users;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Framework.Localisation;
|
||||
|
||||
namespace osu.Game.Overlays.Rankings.Tables
|
||||
{
|
||||
@ -31,8 +32,8 @@ namespace osu.Game.Overlays.Rankings.Tables
|
||||
|
||||
protected override Drawable CreateHeader(int index, TableColumn column)
|
||||
{
|
||||
var title = column?.Header ?? string.Empty;
|
||||
return new UserTableHeaderText(title, HighlightedColumn == title, GradeColumns.Contains(title));
|
||||
var title = column?.Header ?? default;
|
||||
return new UserTableHeaderText(title, HighlightedColumn == title, GradeColumns.Contains(title.ToString()));
|
||||
}
|
||||
|
||||
protected sealed override Country GetCountry(UserStatistics item) => item.User.Country;
|
||||
@ -66,7 +67,7 @@ namespace osu.Game.Overlays.Rankings.Tables
|
||||
|
||||
private class UserTableHeaderText : HeaderText
|
||||
{
|
||||
public UserTableHeaderText(string text, bool isHighlighted, bool isGrade)
|
||||
public UserTableHeaderText(LocalisableString text, bool isHighlighted, bool isGrade)
|
||||
: base(text, isHighlighted)
|
||||
{
|
||||
Margin = new MarginPadding
|
||||
|
53
osu.Game/Rulesets/Mods/Metronome.cs
Normal file
53
osu.Game/Rulesets/Mods/Metronome.cs
Normal file
@ -0,0 +1,53 @@
|
||||
// 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.Audio.Track;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Skinning;
|
||||
|
||||
namespace osu.Game.Rulesets.Mods
|
||||
{
|
||||
public class Metronome : BeatSyncedContainer
|
||||
{
|
||||
private readonly double firstHitTime;
|
||||
|
||||
private PausableSkinnableSound sample;
|
||||
|
||||
/// <param name="firstHitTime">Start time of the first hit object, used for providing a count down.</param>
|
||||
public Metronome(double firstHitTime)
|
||||
{
|
||||
this.firstHitTime = firstHitTime;
|
||||
AllowMistimedEventFiring = false;
|
||||
Divisor = 1;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
sample = new PausableSkinnableSound(new SampleInfo("Gameplay/catch-banana"))
|
||||
};
|
||||
}
|
||||
|
||||
protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes)
|
||||
{
|
||||
base.OnNewBeat(beatIndex, timingPoint, effectPoint, amplitudes);
|
||||
|
||||
if (!IsBeatSyncedWithTrack) return;
|
||||
|
||||
int timeSignature = (int)timingPoint.TimeSignature;
|
||||
|
||||
// play metronome from one measure before the first object.
|
||||
if (BeatSyncClock.CurrentTime < firstHitTime - timingPoint.BeatLength * timeSignature)
|
||||
return;
|
||||
|
||||
sample.Frequency.Value = beatIndex % timeSignature == 0 ? 1 : 0.5f;
|
||||
sample.Play();
|
||||
}
|
||||
}
|
||||
}
|
13
osu.Game/Rulesets/Mods/ModMirror.cs
Normal file
13
osu.Game/Rulesets/Mods/ModMirror.cs
Normal file
@ -0,0 +1,13 @@
|
||||
// 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.
|
||||
|
||||
namespace osu.Game.Rulesets.Mods
|
||||
{
|
||||
public abstract class ModMirror : Mod
|
||||
{
|
||||
public override string Name => "Mirror";
|
||||
public override string Acronym => "MR";
|
||||
public override ModType Type => ModType.Conversion;
|
||||
public override double ScoreMultiplier => 1;
|
||||
}
|
||||
}
|
@ -2,10 +2,12 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions.LocalisationExtensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
@ -42,11 +44,11 @@ namespace osu.Game.Screens.Edit
|
||||
});
|
||||
}
|
||||
|
||||
protected override Drawable CreateHeader(int index, TableColumn column) => new HeaderText(column?.Header ?? string.Empty);
|
||||
protected override Drawable CreateHeader(int index, TableColumn column) => new HeaderText(column?.Header ?? default);
|
||||
|
||||
private class HeaderText : OsuSpriteText
|
||||
{
|
||||
public HeaderText(string text)
|
||||
public HeaderText(LocalisableString text)
|
||||
{
|
||||
Text = text.ToUpper();
|
||||
Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold);
|
||||
|
@ -36,7 +36,7 @@
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Realm" Version="10.3.0" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2021.723.0" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2021.728.0" />
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.722.0" />
|
||||
<PackageReference Include="Sentry" Version="3.8.2" />
|
||||
<PackageReference Include="SharpCompress" Version="0.28.3" />
|
||||
|
@ -70,7 +70,7 @@
|
||||
<Reference Include="System.Net.Http" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="ppy.osu.Framework.iOS" Version="2021.723.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.iOS" Version="2021.728.0" />
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.722.0" />
|
||||
</ItemGroup>
|
||||
<!-- See https://github.com/dotnet/runtime/issues/35988 (can be removed after Xamarin uses net5.0 / net6.0) -->
|
||||
@ -93,7 +93,7 @@
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2021.723.0" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2021.728.0" />
|
||||
<PackageReference Include="SharpCompress" Version="0.28.3" />
|
||||
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||
<PackageReference Include="SharpRaven" Version="2.4.0" />
|
||||
|
Loading…
Reference in New Issue
Block a user