From 99eff4f41f5e5d126fc165fed86309e98ed05cfd Mon Sep 17 00:00:00 2001 From: Opelkuh <25430283+Opelkuh@users.noreply.github.com> Date: Thu, 9 Sep 2021 23:18:19 +0200 Subject: [PATCH] Move cursor particles under `OsuCursorContainer` --- .../Skinning/Legacy/LegacyCursor.cs | 5 -- .../Legacy/LegacyCursorStarParticles.cs | 71 ++++++++++--------- .../UI/Cursor/OsuCursorContainer.cs | 11 ++- osu.Game/Graphics/Particles/ParticleSpewer.cs | 27 ++----- 4 files changed, 53 insertions(+), 61 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursor.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursor.cs index cd7954a8d6..b2ffc171be 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursor.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursor.cs @@ -31,11 +31,6 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy InternalChildren = new[] { - new LegacyCursorStarParticles - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - }, ExpandTarget = new NonPlayfieldSprite { Texture = skin.GetTexture("cursor"), diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorStarParticles.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorStarParticles.cs index 9c901a7de5..89ffa4ca15 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorStarParticles.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorStarParticles.cs @@ -4,11 +4,13 @@ using System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Textures; +using osu.Framework.Input; using osu.Framework.Input.Bindings; +using osu.Framework.Input.Events; using osu.Framework.Utils; using osu.Game.Graphics; -using osu.Game.Graphics.Containers; using osu.Game.Graphics.Particles; using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Rulesets.Osu.UI; @@ -18,7 +20,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Skinning.Legacy { - public class LegacyCursorStarParticles : BeatSyncedContainer, IKeyBindingHandler + public class LegacyCursorStarParticles : CompositeDrawable, IKeyBindingHandler { private StarParticleSpewer breakSpewer; private StarParticleSpewer kiaiSpewer; @@ -64,12 +66,6 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy { breakSpewer.Active.BindTarget = player.IsBreakTime; } - - if (osuPlayfield != null) - { - breakSpewer.ParticleParent = osuPlayfield; - kiaiSpewer.ParticleParent = osuPlayfield; - } } protected override void Update() @@ -116,7 +112,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy } if (leftPressed && rightPressed) - breakSpewer.Direction = SpewDirection.Both; + breakSpewer.Direction = SpewDirection.Omni; else if (leftPressed) breakSpewer.Direction = SpewDirection.Left; else if (rightPressed) @@ -125,13 +121,14 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy breakSpewer.Direction = SpewDirection.None; } - private class StarParticleSpewer : ParticleSpewer + private class StarParticleSpewer : ParticleSpewer, IRequireHighFrequencyMousePosition { private const int particle_lifetime_min = 300; private const int particle_lifetime_max = 1000; public SpewDirection Direction { get; set; } + protected override bool CanSpawnParticles => base.CanSpawnParticles && cursorScreenPosition.HasValue; protected override float ParticleGravity => 240; public StarParticleSpewer(Texture texture, int perSecond) @@ -140,48 +137,52 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy Active.BindValueChanged(_ => resetVelocityCalculation()); } - private Vector2 positionInParent => ToSpaceOfOtherDrawable(OriginPosition, ParticleParent); + private Vector2? cursorScreenPosition; + private Vector2 cursorVelocity; - private Vector2 screenVelocity; + private const double max_velocity_frame_length = 15; + private double velocityFrameLength; + private Vector2 totalPosDifference; - private const double velocity_calculation_delay = 15; - private double lastVelocityCalculation; - private Vector2 positionDifference; - private Vector2? lastPosition; - - protected override void Update() + protected override bool OnMouseMove(MouseMoveEvent e) { - base.Update(); - - if (lastPosition != null) + if (cursorScreenPosition == null) { - positionDifference += (positionInParent - lastPosition.Value); - lastVelocityCalculation += Clock.ElapsedFrameTime; + cursorScreenPosition = e.ScreenSpaceMousePosition; + return base.OnMouseMove(e); } - lastPosition = positionInParent; + // calculate cursor velocity. + totalPosDifference += e.ScreenSpaceMousePosition - cursorScreenPosition.Value; + cursorScreenPosition = e.ScreenSpaceMousePosition; - if (lastVelocityCalculation > velocity_calculation_delay) + velocityFrameLength += Clock.ElapsedFrameTime; + + if (velocityFrameLength > max_velocity_frame_length) { - screenVelocity = positionDifference / (float)lastVelocityCalculation; + cursorVelocity = totalPosDifference / (float)velocityFrameLength; - positionDifference = Vector2.Zero; - lastVelocityCalculation = 0; + totalPosDifference = Vector2.Zero; + velocityFrameLength = 0; } + + return base.OnMouseMove(e); } + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true; + private void resetVelocityCalculation() { - positionDifference = Vector2.Zero; - lastVelocityCalculation = 0; - lastPosition = null; + cursorScreenPosition = null; + totalPosDifference = Vector2.Zero; + velocityFrameLength = 0; } protected override FallingParticle SpawnParticle() { var p = base.SpawnParticle(); - p.StartPosition = positionInParent; + p.StartPosition = ToLocalSpace(cursorScreenPosition ?? Vector2.Zero); p.Duration = RNG.NextSingle(particle_lifetime_min, particle_lifetime_max); p.StartAngle = (float)(RNG.NextDouble() * 4 - 2); p.EndAngle = RNG.NextSingle(-2f, 2f); @@ -207,7 +208,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy ); break; - case SpewDirection.Both: + case SpewDirection.Omni: p.Velocity = new Vector2( RNG.NextSingle(-460f, 460f), RNG.NextSingle(-160f, 160f) @@ -215,7 +216,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy break; } - p.Velocity += screenVelocity * 40; + p.Velocity += cursorVelocity * 40; return p; } @@ -226,7 +227,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy None, Left, Right, - Both, + Omni, } } } diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs index 5812e8cf75..fbb7bfd7b1 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs @@ -11,6 +11,7 @@ using osu.Framework.Input.Bindings; using osu.Game.Beatmaps; using osu.Game.Configuration; using osu.Game.Rulesets.Osu.Configuration; +using osu.Game.Rulesets.Osu.Skinning.Legacy; using osu.Game.Rulesets.UI; using osu.Game.Screens.Play; using osu.Game.Skinning; @@ -42,7 +43,15 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor InternalChild = fadeContainer = new Container { RelativeSizeAxes = Axes.Both, - Child = cursorTrail = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.CursorTrail), _ => new DefaultCursorTrail(), confineMode: ConfineMode.NoScaling) + Children = new[] + { + cursorTrail = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.CursorTrail), _ => new DefaultCursorTrail(), confineMode: ConfineMode.NoScaling), + new LegacyCursorStarParticles() + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }, + } }; } diff --git a/osu.Game/Graphics/Particles/ParticleSpewer.cs b/osu.Game/Graphics/Particles/ParticleSpewer.cs index 3d2225d382..f0c9dff239 100644 --- a/osu.Game/Graphics/Particles/ParticleSpewer.cs +++ b/osu.Game/Graphics/Particles/ParticleSpewer.cs @@ -26,22 +26,16 @@ namespace osu.Game.Graphics.Particles /// public readonly BindableBool Active = new BindableBool(); - /// - /// whose DrawInfo will be used to draw each particle. - /// Defaults to the itself. - /// - public IDrawable ParticleParent; - public bool HasActiveParticles => Active.Value || (lastParticleAdded + maxLifetime) > Time.Current; public override bool IsPresent => base.IsPresent && HasActiveParticles; + protected virtual bool CanSpawnParticles => true; protected virtual float ParticleGravity => 0; protected ParticleSpewer(Texture texture, int perSecond, double maxLifetime) { Texture = texture; Blending = BlendingParameters.Additive; - ParticleParent = this; particles = new FallingParticle[perSecond * (int)Math.Ceiling(maxLifetime / 1000)]; @@ -57,9 +51,12 @@ namespace osu.Game.Graphics.Particles // this can happen when seeking in replays. if (lastParticleAdded > Time.Current) lastParticleAdded = 0; - if (Active.Value && Time.Current > lastParticleAdded + cooldown) + if (Active.Value && CanSpawnParticles && Time.Current > lastParticleAdded + cooldown) { - addParticle(SpawnParticle()); + particles[currentIndex] = SpawnParticle(); + + currentIndex = (currentIndex + 1) % particles.Length; + lastParticleAdded = Time.Current; } Invalidate(Invalidation.DrawNode); @@ -76,14 +73,6 @@ namespace osu.Game.Graphics.Particles }; } - private void addParticle(FallingParticle fallingParticle) - { - particles[currentIndex] = fallingParticle; - - currentIndex = (currentIndex + 1) % particles.Length; - lastParticleAdded = Time.Current; - } - protected override DrawNode CreateDrawNode() => new ParticleSpewerDrawNode(this); # region DrawNode @@ -96,7 +85,6 @@ namespace osu.Game.Graphics.Particles private float currentTime; private float gravity; - private Matrix3 particleDrawMatrix; public ParticleSpewerDrawNode(Sprite source) : base(source) @@ -112,7 +100,6 @@ namespace osu.Game.Graphics.Particles currentTime = (float)Source.Time.Current; gravity = Source.ParticleGravity; - particleDrawMatrix = Source.ParticleParent.DrawInfo.Matrix; } protected override void Blit(Action vertexAction) @@ -165,7 +152,7 @@ namespace osu.Game.Graphics.Particles float x = centre.X + (pos.X - centre.X) * cos + (pos.Y - centre.Y) * sin; float y = centre.Y + (pos.Y - centre.Y) * cos - (pos.X - centre.X) * sin; - return Vector2Extensions.Transform(new Vector2(x, y), particleDrawMatrix); + return Vector2Extensions.Transform(new Vector2(x, y), DrawInfo.Matrix); } }