1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-11 12:57:36 +08:00

Move cursor particles under OsuCursorContainer

This commit is contained in:
Opelkuh 2021-09-09 23:18:19 +02:00
parent c2f7b01ca4
commit 99eff4f41f
4 changed files with 53 additions and 61 deletions

View File

@ -31,11 +31,6 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
InternalChildren = new[] InternalChildren = new[]
{ {
new LegacyCursorStarParticles
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
},
ExpandTarget = new NonPlayfieldSprite ExpandTarget = new NonPlayfieldSprite
{ {
Texture = skin.GetTexture("cursor"), Texture = skin.GetTexture("cursor"),

View File

@ -4,11 +4,13 @@
using System.Linq; using System.Linq;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Textures; using osu.Framework.Graphics.Textures;
using osu.Framework.Input;
using osu.Framework.Input.Bindings; using osu.Framework.Input.Bindings;
using osu.Framework.Input.Events;
using osu.Framework.Utils; using osu.Framework.Utils;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Particles; using osu.Game.Graphics.Particles;
using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects.Drawables;
using osu.Game.Rulesets.Osu.UI; using osu.Game.Rulesets.Osu.UI;
@ -18,7 +20,7 @@ using osuTK;
namespace osu.Game.Rulesets.Osu.Skinning.Legacy namespace osu.Game.Rulesets.Osu.Skinning.Legacy
{ {
public class LegacyCursorStarParticles : BeatSyncedContainer, IKeyBindingHandler<OsuAction> public class LegacyCursorStarParticles : CompositeDrawable, IKeyBindingHandler<OsuAction>
{ {
private StarParticleSpewer breakSpewer; private StarParticleSpewer breakSpewer;
private StarParticleSpewer kiaiSpewer; private StarParticleSpewer kiaiSpewer;
@ -64,12 +66,6 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
{ {
breakSpewer.Active.BindTarget = player.IsBreakTime; breakSpewer.Active.BindTarget = player.IsBreakTime;
} }
if (osuPlayfield != null)
{
breakSpewer.ParticleParent = osuPlayfield;
kiaiSpewer.ParticleParent = osuPlayfield;
}
} }
protected override void Update() protected override void Update()
@ -116,7 +112,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
} }
if (leftPressed && rightPressed) if (leftPressed && rightPressed)
breakSpewer.Direction = SpewDirection.Both; breakSpewer.Direction = SpewDirection.Omni;
else if (leftPressed) else if (leftPressed)
breakSpewer.Direction = SpewDirection.Left; breakSpewer.Direction = SpewDirection.Left;
else if (rightPressed) else if (rightPressed)
@ -125,13 +121,14 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
breakSpewer.Direction = SpewDirection.None; 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_min = 300;
private const int particle_lifetime_max = 1000; private const int particle_lifetime_max = 1000;
public SpewDirection Direction { get; set; } public SpewDirection Direction { get; set; }
protected override bool CanSpawnParticles => base.CanSpawnParticles && cursorScreenPosition.HasValue;
protected override float ParticleGravity => 240; protected override float ParticleGravity => 240;
public StarParticleSpewer(Texture texture, int perSecond) public StarParticleSpewer(Texture texture, int perSecond)
@ -140,48 +137,52 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
Active.BindValueChanged(_ => resetVelocityCalculation()); 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; protected override bool OnMouseMove(MouseMoveEvent e)
private double lastVelocityCalculation;
private Vector2 positionDifference;
private Vector2? lastPosition;
protected override void Update()
{ {
base.Update(); if (cursorScreenPosition == null)
if (lastPosition != null)
{ {
positionDifference += (positionInParent - lastPosition.Value); cursorScreenPosition = e.ScreenSpaceMousePosition;
lastVelocityCalculation += Clock.ElapsedFrameTime; 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; totalPosDifference = Vector2.Zero;
lastVelocityCalculation = 0; velocityFrameLength = 0;
} }
return base.OnMouseMove(e);
} }
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true;
private void resetVelocityCalculation() private void resetVelocityCalculation()
{ {
positionDifference = Vector2.Zero; cursorScreenPosition = null;
lastVelocityCalculation = 0; totalPosDifference = Vector2.Zero;
lastPosition = null; velocityFrameLength = 0;
} }
protected override FallingParticle SpawnParticle() protected override FallingParticle SpawnParticle()
{ {
var p = base.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.Duration = RNG.NextSingle(particle_lifetime_min, particle_lifetime_max);
p.StartAngle = (float)(RNG.NextDouble() * 4 - 2); p.StartAngle = (float)(RNG.NextDouble() * 4 - 2);
p.EndAngle = RNG.NextSingle(-2f, 2f); p.EndAngle = RNG.NextSingle(-2f, 2f);
@ -207,7 +208,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
); );
break; break;
case SpewDirection.Both: case SpewDirection.Omni:
p.Velocity = new Vector2( p.Velocity = new Vector2(
RNG.NextSingle(-460f, 460f), RNG.NextSingle(-460f, 460f),
RNG.NextSingle(-160f, 160f) RNG.NextSingle(-160f, 160f)
@ -215,7 +216,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
break; break;
} }
p.Velocity += screenVelocity * 40; p.Velocity += cursorVelocity * 40;
return p; return p;
} }
@ -226,7 +227,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
None, None,
Left, Left,
Right, Right,
Both, Omni,
} }
} }
} }

View File

@ -11,6 +11,7 @@ using osu.Framework.Input.Bindings;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Configuration; using osu.Game.Configuration;
using osu.Game.Rulesets.Osu.Configuration; using osu.Game.Rulesets.Osu.Configuration;
using osu.Game.Rulesets.Osu.Skinning.Legacy;
using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI;
using osu.Game.Screens.Play; using osu.Game.Screens.Play;
using osu.Game.Skinning; using osu.Game.Skinning;
@ -42,7 +43,15 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
InternalChild = fadeContainer = new Container InternalChild = fadeContainer = new Container
{ {
RelativeSizeAxes = Axes.Both, 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,
},
}
}; };
} }

View File

@ -26,22 +26,16 @@ namespace osu.Game.Graphics.Particles
/// </summary> /// </summary>
public readonly BindableBool Active = new BindableBool(); public readonly BindableBool Active = new BindableBool();
/// <summary>
/// <see cref="Drawable"/> whose DrawInfo will be used to draw each particle.
/// Defaults to the <see cref="ParticleSpewer"/> itself.
/// </summary>
public IDrawable ParticleParent;
public bool HasActiveParticles => Active.Value || (lastParticleAdded + maxLifetime) > Time.Current; public bool HasActiveParticles => Active.Value || (lastParticleAdded + maxLifetime) > Time.Current;
public override bool IsPresent => base.IsPresent && HasActiveParticles; public override bool IsPresent => base.IsPresent && HasActiveParticles;
protected virtual bool CanSpawnParticles => true;
protected virtual float ParticleGravity => 0; protected virtual float ParticleGravity => 0;
protected ParticleSpewer(Texture texture, int perSecond, double maxLifetime) protected ParticleSpewer(Texture texture, int perSecond, double maxLifetime)
{ {
Texture = texture; Texture = texture;
Blending = BlendingParameters.Additive; Blending = BlendingParameters.Additive;
ParticleParent = this;
particles = new FallingParticle[perSecond * (int)Math.Ceiling(maxLifetime / 1000)]; 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. // this can happen when seeking in replays.
if (lastParticleAdded > Time.Current) lastParticleAdded = 0; 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); 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); protected override DrawNode CreateDrawNode() => new ParticleSpewerDrawNode(this);
# region DrawNode # region DrawNode
@ -96,7 +85,6 @@ namespace osu.Game.Graphics.Particles
private float currentTime; private float currentTime;
private float gravity; private float gravity;
private Matrix3 particleDrawMatrix;
public ParticleSpewerDrawNode(Sprite source) public ParticleSpewerDrawNode(Sprite source)
: base(source) : base(source)
@ -112,7 +100,6 @@ namespace osu.Game.Graphics.Particles
currentTime = (float)Source.Time.Current; currentTime = (float)Source.Time.Current;
gravity = Source.ParticleGravity; gravity = Source.ParticleGravity;
particleDrawMatrix = Source.ParticleParent.DrawInfo.Matrix;
} }
protected override void Blit(Action<TexturedVertex2D> vertexAction) protected override void Blit(Action<TexturedVertex2D> 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 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; 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);
} }
} }