mirror of
https://github.com/ppy/osu.git
synced 2024-12-15 00:53:22 +08:00
Merge pull request #24208 from peppy/menu-star-fountains
Add kiai fountains to main menu
This commit is contained in:
commit
5214efca5a
@ -69,13 +69,13 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
spewer.Clock = new FramedClock(testClock);
|
||||
});
|
||||
AddStep("start spewer", () => spewer.Active.Value = true);
|
||||
AddAssert("spawned first particle", () => spewer.TotalCreatedParticles == 1);
|
||||
AddAssert("spawned first particle", () => spewer.TotalCreatedParticles, () => Is.EqualTo(1));
|
||||
|
||||
AddStep("move clock forward", () => testClock.CurrentTime = TestParticleSpewer.MAX_DURATION * 3);
|
||||
AddAssert("spawned second particle", () => spewer.TotalCreatedParticles == 2);
|
||||
AddAssert("spawned second particle", () => spewer.TotalCreatedParticles, () => Is.EqualTo(2));
|
||||
|
||||
AddStep("move clock backwards", () => testClock.CurrentTime = TestParticleSpewer.MAX_DURATION * -1);
|
||||
AddAssert("spawned third particle", () => spewer.TotalCreatedParticles == 3);
|
||||
AddAssert("spawned third particle", () => spewer.TotalCreatedParticles, () => Is.EqualTo(3));
|
||||
}
|
||||
|
||||
private TestParticleSpewer createSpewer() =>
|
||||
|
52
osu.Game.Tests/Visual/Menus/TestSceneStarFountain.cs
Normal file
52
osu.Game.Tests/Visual/Menus/TestSceneStarFountain.cs
Normal file
@ -0,0 +1,52 @@
|
||||
// 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.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Screens.Menu;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Menus
|
||||
{
|
||||
[TestFixture]
|
||||
public partial class TestSceneStarFountain : OsuTestScene
|
||||
{
|
||||
[SetUpSteps]
|
||||
public void SetUpSteps()
|
||||
{
|
||||
AddStep("make fountains", () =>
|
||||
{
|
||||
Children = new[]
|
||||
{
|
||||
new StarFountain
|
||||
{
|
||||
Anchor = Anchor.BottomCentre,
|
||||
Origin = Anchor.BottomCentre,
|
||||
X = 200,
|
||||
},
|
||||
new StarFountain
|
||||
{
|
||||
Anchor = Anchor.BottomCentre,
|
||||
Origin = Anchor.BottomCentre,
|
||||
X = -200,
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestPew()
|
||||
{
|
||||
AddRepeatStep("activate fountains sometimes", () =>
|
||||
{
|
||||
foreach (var fountain in Children.OfType<StarFountain>())
|
||||
{
|
||||
if (RNG.NextSingle() > 0.8f)
|
||||
fountain.Shoot();
|
||||
}
|
||||
}, 150);
|
||||
}
|
||||
}
|
||||
}
|
@ -5,7 +5,6 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Audio.Track;
|
||||
@ -283,8 +282,6 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
|
||||
if (ReferenceEquals(timingPoints[^1], current))
|
||||
{
|
||||
Debug.Assert(BeatSyncSource.Clock != null);
|
||||
|
||||
return (int)Math.Ceiling((BeatSyncSource.Clock.CurrentTime - current.Time) / current.BeatLength);
|
||||
}
|
||||
|
||||
@ -295,8 +292,6 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
{
|
||||
base.Update();
|
||||
|
||||
Debug.Assert(BeatSyncSource.Clock != null);
|
||||
|
||||
timeUntilNextBeat.Value = TimeUntilNextBeat;
|
||||
timeSinceLastBeat.Value = TimeSinceLastBeat;
|
||||
currentTime.Value = BeatSyncSource.Clock.CurrentTime;
|
||||
|
@ -5,14 +5,9 @@ namespace osu.Game.Beatmaps
|
||||
{
|
||||
public static class BeatSyncProviderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Check whether beat sync is currently available.
|
||||
/// </summary>
|
||||
public static bool CheckBeatSyncAvailable(this IBeatSyncProvider provider) => provider.Clock != null;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the beat sync provider is currently in a kiai section. Should make everything more epic.
|
||||
/// </summary>
|
||||
public static bool CheckIsKiaiTime(this IBeatSyncProvider provider) => provider.Clock != null && provider.ControlPoints?.EffectPointAt(provider.Clock.CurrentTime).KiaiMode == true;
|
||||
public static bool CheckIsKiaiTime(this IBeatSyncProvider provider) => provider.ControlPoints?.EffectPointAt(provider.Clock.CurrentTime).KiaiMode == true;
|
||||
}
|
||||
}
|
||||
|
@ -22,8 +22,8 @@ namespace osu.Game.Beatmaps
|
||||
ControlPointInfo? ControlPoints { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Access a clock currently responsible for providing beat sync. If <c>null</c>, no current provider is available.
|
||||
/// Access a clock currently responsible for providing beat sync.
|
||||
/// </summary>
|
||||
IClock? Clock { get; }
|
||||
IClock Clock { get; }
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,6 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio.Track;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
@ -86,14 +85,12 @@ namespace osu.Game.Graphics.Containers
|
||||
TimingControlPoint timingPoint;
|
||||
EffectControlPoint effectPoint;
|
||||
|
||||
IsBeatSyncedWithTrack = BeatSyncSource.CheckBeatSyncAvailable() && BeatSyncSource.Clock?.IsRunning == true;
|
||||
IsBeatSyncedWithTrack = BeatSyncSource.Clock.IsRunning;
|
||||
|
||||
double currentTrackTime;
|
||||
|
||||
if (IsBeatSyncedWithTrack)
|
||||
{
|
||||
Debug.Assert(BeatSyncSource.Clock != null);
|
||||
|
||||
currentTrackTime = BeatSyncSource.Clock.CurrentTime + EarlyActivationMilliseconds;
|
||||
|
||||
timingPoint = BeatSyncSource.ControlPoints?.TimingPointAt(currentTrackTime) ?? TimingControlPoint.DEFAULT;
|
||||
|
@ -4,6 +4,7 @@
|
||||
#nullable disable
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions.EnumExtensions;
|
||||
using osu.Framework.Graphics;
|
||||
@ -20,9 +21,9 @@ namespace osu.Game.Graphics
|
||||
{
|
||||
private readonly FallingParticle[] particles;
|
||||
private int currentIndex;
|
||||
private double lastParticleAdded;
|
||||
private double? lastParticleAdded;
|
||||
|
||||
private readonly double cooldown;
|
||||
private readonly double timeBetweenSpawns;
|
||||
private readonly double maxDuration;
|
||||
|
||||
/// <summary>
|
||||
@ -44,7 +45,7 @@ namespace osu.Game.Graphics
|
||||
|
||||
particles = new FallingParticle[perSecond * (int)Math.Ceiling(maxDuration / 1000)];
|
||||
|
||||
cooldown = 1000f / perSecond;
|
||||
timeBetweenSpawns = 1000f / perSecond;
|
||||
this.maxDuration = maxDuration;
|
||||
}
|
||||
|
||||
@ -52,18 +53,52 @@ namespace osu.Game.Graphics
|
||||
{
|
||||
base.Update();
|
||||
|
||||
if (Active.Value && CanSpawnParticles && Math.Abs(Time.Current - lastParticleAdded) > cooldown)
|
||||
Invalidate(Invalidation.DrawNode);
|
||||
|
||||
if (!Active.Value || !CanSpawnParticles)
|
||||
{
|
||||
var newParticle = CreateParticle();
|
||||
newParticle.StartTime = (float)Time.Current;
|
||||
|
||||
particles[currentIndex] = newParticle;
|
||||
|
||||
currentIndex = (currentIndex + 1) % particles.Length;
|
||||
lastParticleAdded = Time.Current;
|
||||
lastParticleAdded = null;
|
||||
return;
|
||||
}
|
||||
|
||||
Invalidate(Invalidation.DrawNode);
|
||||
// Always want to spawn the first particle in an activation immediately.
|
||||
if (lastParticleAdded == null)
|
||||
{
|
||||
lastParticleAdded = Time.Current;
|
||||
spawnParticle();
|
||||
return;
|
||||
}
|
||||
|
||||
double timeElapsed = Time.Current - lastParticleAdded.Value;
|
||||
|
||||
// Avoid spawning too many particles if a long amount of time has passed.
|
||||
if (Math.Abs(timeElapsed) > maxDuration)
|
||||
{
|
||||
lastParticleAdded = Time.Current;
|
||||
spawnParticle();
|
||||
return;
|
||||
}
|
||||
|
||||
Debug.Assert(lastParticleAdded != null);
|
||||
|
||||
for (int i = 0; i < timeElapsed / timeBetweenSpawns; i++)
|
||||
{
|
||||
lastParticleAdded += timeBetweenSpawns;
|
||||
spawnParticle();
|
||||
}
|
||||
}
|
||||
|
||||
private void spawnParticle()
|
||||
{
|
||||
Debug.Assert(lastParticleAdded != null);
|
||||
|
||||
var newParticle = CreateParticle();
|
||||
|
||||
newParticle.StartTime = (float)lastParticleAdded.Value;
|
||||
|
||||
particles[currentIndex] = newParticle;
|
||||
|
||||
currentIndex = (currentIndex + 1) % particles.Length;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -73,7 +108,7 @@ namespace osu.Game.Graphics
|
||||
|
||||
protected override DrawNode CreateDrawNode() => new ParticleSpewerDrawNode(this);
|
||||
|
||||
# region DrawNode
|
||||
#region DrawNode
|
||||
|
||||
private class ParticleSpewerDrawNode : SpriteDrawNode
|
||||
{
|
||||
|
@ -950,9 +950,9 @@ namespace osu.Game
|
||||
if (!args?.Any(a => a == @"--no-version-overlay") ?? true)
|
||||
loadComponentSingleFile(versionManager = new VersionManager { Depth = int.MinValue }, ScreenContainer.Add);
|
||||
|
||||
loadComponentSingleFile(osuLogo, logo =>
|
||||
loadComponentSingleFile(osuLogo, _ =>
|
||||
{
|
||||
logoContainer.Add(logo);
|
||||
osuLogo.SetupDefaultContainer(logoContainer);
|
||||
|
||||
// Loader has to be created after the logo has finished loading as Loader performs logo transformations on entering.
|
||||
ScreenStack.Push(CreateLoader().With(l => l.RelativeSizeAxes = Axes.Both));
|
||||
|
@ -36,7 +36,7 @@ namespace osu.Game.Rulesets.Mods
|
||||
int timeSignature = timingPoint.TimeSignature.Numerator;
|
||||
|
||||
// play metronome from one measure before the first object.
|
||||
if (BeatSyncSource.Clock?.CurrentTime < firstHitTime - timingPoint.BeatLength * timeSignature)
|
||||
if (BeatSyncSource.Clock.CurrentTime < firstHitTime - timingPoint.BeatLength * timeSignature)
|
||||
return;
|
||||
|
||||
sample.Frequency.Value = beatIndex % timeSignature == 0 ? 1 : 0.5f;
|
||||
|
@ -240,7 +240,7 @@ namespace osu.Game.Screens.Edit.Timing
|
||||
{
|
||||
base.Update();
|
||||
|
||||
if (BeatSyncSource.ControlPoints == null || BeatSyncSource.Clock == null)
|
||||
if (BeatSyncSource.ControlPoints == null)
|
||||
return;
|
||||
|
||||
metronomeClock.Rate = IsBeatSyncedWithTrack ? BeatSyncSource.Clock.Rate : 1;
|
||||
@ -259,7 +259,7 @@ namespace osu.Game.Screens.Edit.Timing
|
||||
this.TransformBindableTo(interpolatedBpm, (int)Math.Round(timingPoint.BPM), 600, Easing.OutQuint);
|
||||
}
|
||||
|
||||
if (BeatSyncSource.Clock?.IsRunning != true && isSwinging)
|
||||
if (!BeatSyncSource.Clock.IsRunning && isSwinging)
|
||||
{
|
||||
swing.ClearTransforms(true);
|
||||
|
||||
|
@ -310,7 +310,7 @@ namespace osu.Game.Screens.Edit.Timing
|
||||
}
|
||||
|
||||
double averageBeatLength = (tapTimings.Last() - tapTimings.Skip(initial_taps_to_ignore).First()) / (tapTimings.Count - initial_taps_to_ignore - 1);
|
||||
double clockRate = beatSyncSource?.Clock?.Rate ?? 1;
|
||||
double clockRate = beatSyncSource?.Clock.Rate ?? 1;
|
||||
|
||||
double bpm = Math.Round(60000 / averageBeatLength / clockRate);
|
||||
|
||||
|
67
osu.Game/Screens/Menu/KiaiMenuFountains.cs
Normal file
67
osu.Game/Screens/Menu/KiaiMenuFountains.cs
Normal file
@ -0,0 +1,67 @@
|
||||
// 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.Allocation;
|
||||
using osu.Framework.Audio.Track;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Graphics.Containers;
|
||||
|
||||
namespace osu.Game.Screens.Menu
|
||||
{
|
||||
public partial class KiaiMenuFountains : BeatSyncedContainer
|
||||
{
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
|
||||
Children = new[]
|
||||
{
|
||||
new StarFountain
|
||||
{
|
||||
Anchor = Anchor.BottomLeft,
|
||||
Origin = Anchor.BottomLeft,
|
||||
X = 250,
|
||||
},
|
||||
new StarFountain
|
||||
{
|
||||
Anchor = Anchor.BottomRight,
|
||||
Origin = Anchor.BottomRight,
|
||||
X = -250,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
private bool isTriggered;
|
||||
|
||||
private double? lastTrigger;
|
||||
|
||||
protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes)
|
||||
{
|
||||
base.OnNewBeat(beatIndex, timingPoint, effectPoint, amplitudes);
|
||||
|
||||
if (effectPoint.KiaiMode && !isTriggered)
|
||||
{
|
||||
bool isNearEffectPoint = Math.Abs(BeatSyncSource.Clock.CurrentTime - effectPoint.Time) < 500;
|
||||
if (isNearEffectPoint)
|
||||
Shoot();
|
||||
}
|
||||
|
||||
isTriggered = effectPoint.KiaiMode;
|
||||
}
|
||||
|
||||
public void Shoot()
|
||||
{
|
||||
if (lastTrigger != null && Clock.CurrentTime - lastTrigger < 500)
|
||||
return;
|
||||
|
||||
foreach (var fountain in Children.OfType<StarFountain>())
|
||||
fountain.Shoot();
|
||||
|
||||
lastTrigger = Clock.CurrentTime;
|
||||
}
|
||||
}
|
||||
}
|
@ -102,8 +102,7 @@ namespace osu.Game.Screens.Menu
|
||||
for (int i = 0; i < temporalAmplitudes.Length; i++)
|
||||
temporalAmplitudes[i] = 0;
|
||||
|
||||
if (beatSyncProvider.Clock != null)
|
||||
addAmplitudesFromSource(beatSyncProvider);
|
||||
addAmplitudesFromSource(beatSyncProvider);
|
||||
|
||||
foreach (var source in amplitudeSources)
|
||||
addAmplitudesFromSource(source);
|
||||
|
@ -8,6 +8,7 @@ using System.Diagnostics;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Input.Bindings;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Framework.Logging;
|
||||
@ -85,6 +86,7 @@ namespace osu.Game.Screens.Menu
|
||||
|
||||
private ParallaxContainer buttonsContainer;
|
||||
private SongTicker songTicker;
|
||||
private Container logoTarget;
|
||||
|
||||
[BackgroundDependencyLoader(true)]
|
||||
private void load(BeatmapListingOverlay beatmapListing, SettingsOverlay settings, OsuConfigManager config, SessionStatics statics)
|
||||
@ -129,6 +131,7 @@ namespace osu.Game.Screens.Menu
|
||||
}
|
||||
}
|
||||
},
|
||||
logoTarget = new Container { RelativeSizeAxes = Axes.Both, },
|
||||
sideFlashes = new MenuSideFlashes(),
|
||||
songTicker = new SongTicker
|
||||
{
|
||||
@ -136,6 +139,7 @@ namespace osu.Game.Screens.Menu
|
||||
Origin = Anchor.TopRight,
|
||||
Margin = new MarginPadding { Right = 15, Top = 5 }
|
||||
},
|
||||
new KiaiMenuFountains(),
|
||||
holdToExitGameOverlay?.CreateProxy() ?? Empty()
|
||||
});
|
||||
|
||||
@ -207,6 +211,8 @@ namespace osu.Game.Screens.Menu
|
||||
logo.FadeColour(Color4.White, 100, Easing.OutQuint);
|
||||
logo.FadeIn(100, Easing.OutQuint);
|
||||
|
||||
logo.ProxyToContainer(logoTarget);
|
||||
|
||||
if (resuming)
|
||||
{
|
||||
Buttons.State = ButtonSystemState.TopLevel;
|
||||
@ -244,6 +250,8 @@ namespace osu.Game.Screens.Menu
|
||||
var seq = logo.FadeOut(300, Easing.InSine)
|
||||
.ScaleTo(0.2f, 300, Easing.InSine);
|
||||
|
||||
logo.ReturnProxy();
|
||||
|
||||
seq.OnComplete(_ => Buttons.SetOsuLogo(null));
|
||||
seq.OnAbort(_ => Buttons.SetOsuLogo(null));
|
||||
}
|
||||
|
@ -435,5 +435,46 @@ namespace osu.Game.Screens.Menu
|
||||
logoBounceContainer.MoveTo(Vector2.Zero, 800, Easing.OutElastic);
|
||||
base.OnDragEnd(e);
|
||||
}
|
||||
|
||||
private Container defaultProxyTarget;
|
||||
private Container currentProxyTarget;
|
||||
private Drawable proxy;
|
||||
|
||||
public Drawable ProxyToContainer(Container c)
|
||||
{
|
||||
if (currentProxyTarget != null)
|
||||
throw new InvalidOperationException("Previous proxy usage was not returned");
|
||||
|
||||
if (defaultProxyTarget == null)
|
||||
throw new InvalidOperationException($"{nameof(SetupDefaultContainer)} must be called first");
|
||||
|
||||
currentProxyTarget = c;
|
||||
|
||||
defaultProxyTarget.Remove(proxy, false);
|
||||
currentProxyTarget.Add(proxy);
|
||||
return proxy;
|
||||
}
|
||||
|
||||
public void ReturnProxy()
|
||||
{
|
||||
if (currentProxyTarget == null)
|
||||
throw new InvalidOperationException("No usage to return");
|
||||
|
||||
if (defaultProxyTarget == null)
|
||||
throw new InvalidOperationException($"{nameof(SetupDefaultContainer)} must be called first");
|
||||
|
||||
currentProxyTarget.Remove(proxy, false);
|
||||
currentProxyTarget = null;
|
||||
|
||||
defaultProxyTarget.Add(proxy);
|
||||
}
|
||||
|
||||
public void SetupDefaultContainer(Container container)
|
||||
{
|
||||
defaultProxyTarget = container;
|
||||
|
||||
defaultProxyTarget.Add(this);
|
||||
defaultProxyTarget.Add(proxy = CreateProxy());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
93
osu.Game/Screens/Menu/StarFountain.cs
Normal file
93
osu.Game/Screens/Menu/StarFountain.cs
Normal file
@ -0,0 +1,93 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Screens.Menu
|
||||
{
|
||||
public partial class StarFountain : SkinReloadableDrawable
|
||||
{
|
||||
private StarFountainSpewer spewer = null!;
|
||||
|
||||
[Resolved]
|
||||
private TextureStore textures { get; set; } = null!;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
InternalChild = spewer = new StarFountainSpewer();
|
||||
}
|
||||
|
||||
public void Shoot() => spewer.Shoot();
|
||||
|
||||
protected override void SkinChanged(ISkinSource skin)
|
||||
{
|
||||
base.SkinChanged(skin);
|
||||
spewer.Texture = skin.GetTexture("Menu/fountain-star") ?? textures.Get("Menu/fountain-star");
|
||||
}
|
||||
|
||||
public partial class StarFountainSpewer : ParticleSpewer
|
||||
{
|
||||
private const int particle_duration_min = 300;
|
||||
private const int particle_duration_max = 1000;
|
||||
|
||||
private double? lastShootTime;
|
||||
private int lastShootDirection;
|
||||
|
||||
protected override float ParticleGravity => 800;
|
||||
|
||||
private const double shoot_duration = 800;
|
||||
|
||||
protected override bool CanSpawnParticles => lastShootTime != null && Time.Current - lastShootTime < shoot_duration;
|
||||
|
||||
[Resolved]
|
||||
private ISkinSource skin { get; set; } = null!;
|
||||
|
||||
public StarFountainSpewer()
|
||||
: base(null, 240, particle_duration_max)
|
||||
{
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(TextureStore textures)
|
||||
{
|
||||
Texture = skin.GetTexture("Menu/fountain-star") ?? textures.Get("Menu/fountain-star");
|
||||
Active.Value = true;
|
||||
}
|
||||
|
||||
protected override FallingParticle CreateParticle()
|
||||
{
|
||||
return new FallingParticle
|
||||
{
|
||||
StartPosition = new Vector2(0, 50),
|
||||
Duration = RNG.NextSingle(particle_duration_min, particle_duration_max),
|
||||
StartAngle = getRandomVariance(4),
|
||||
EndAngle = getRandomVariance(2),
|
||||
EndScale = 2.2f + getRandomVariance(0.4f),
|
||||
Velocity = new Vector2(getCurrentAngle(), -1400 + getRandomVariance(100)),
|
||||
};
|
||||
}
|
||||
|
||||
private float getCurrentAngle()
|
||||
{
|
||||
const float x_velocity_from_direction = 500;
|
||||
const float x_velocity_random_variance = 60;
|
||||
|
||||
return lastShootDirection * x_velocity_from_direction * (float)(1 - 2 * (Clock.CurrentTime - lastShootTime!.Value) / shoot_duration) + getRandomVariance(x_velocity_random_variance);
|
||||
}
|
||||
|
||||
public void Shoot()
|
||||
{
|
||||
lastShootTime = Clock.CurrentTime;
|
||||
lastShootDirection = RNG.Next(-1, 2);
|
||||
}
|
||||
|
||||
private static float getRandomVariance(float variance) => RNG.NextSingle(-variance, variance);
|
||||
}
|
||||
}
|
||||
}
|
@ -468,6 +468,13 @@ namespace osu.Game.Skinning
|
||||
|
||||
public override Texture? GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT)
|
||||
{
|
||||
switch (componentName)
|
||||
{
|
||||
case "Menu/fountain-star":
|
||||
componentName = "star2";
|
||||
break;
|
||||
}
|
||||
|
||||
foreach (string name in getFallbackNames(componentName))
|
||||
{
|
||||
// some component names (especially user-controlled ones, like `HitX` in mania)
|
||||
|
@ -128,7 +128,7 @@ namespace osu.Game.Storyboards.Drawables
|
||||
//
|
||||
// In the case of storyboard animations, we want to synchronise with game time perfectly
|
||||
// so let's get a correct time based on gameplay clock and earliest transform.
|
||||
PlaybackPosition = (beatSyncProvider.Clock?.CurrentTime ?? Clock.CurrentTime) - Animation.EarliestTransformTime;
|
||||
PlaybackPosition = beatSyncProvider.Clock.CurrentTime - Animation.EarliestTransformTime;
|
||||
}
|
||||
|
||||
private void skinSourceChanged()
|
||||
|
@ -37,7 +37,7 @@
|
||||
</PackageReference>
|
||||
<PackageReference Include="Realm" Version="11.1.2" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2023.724.0" />
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2023.707.0" />
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2023.719.0" />
|
||||
<PackageReference Include="Sentry" Version="3.28.1" />
|
||||
<PackageReference Include="SharpCompress" Version="0.32.2" />
|
||||
<PackageReference Include="NUnit" Version="3.13.3" />
|
||||
|
Loading…
Reference in New Issue
Block a user