1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-18 14:12:54 +08:00
osu-lazer/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

256 lines
8.5 KiB
C#
Raw Normal View History

2021-09-05 03:49:05 +08:00
// 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.
2022-06-17 15:37:17 +08:00
#nullable disable
2021-09-19 09:19:16 +08:00
using System;
2021-09-05 03:49:05 +08:00
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
2021-09-05 03:49:05 +08:00
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Textures;
using osu.Framework.Input;
2021-09-05 03:49:05 +08:00
using osu.Framework.Input.Bindings;
using osu.Framework.Input.Events;
2021-09-05 03:49:05 +08:00
using osu.Framework.Utils;
using osu.Game.Graphics;
using osu.Game.Rulesets.Objects.Drawables;
2021-09-05 03:49:05 +08:00
using osu.Game.Rulesets.Osu.Objects.Drawables;
using osu.Game.Rulesets.Osu.UI;
using osu.Game.Screens.Play;
using osu.Game.Skinning;
using osuTK;
2021-09-14 06:36:01 +08:00
using osuTK.Graphics;
2021-09-05 03:49:05 +08:00
namespace osu.Game.Rulesets.Osu.Skinning.Legacy
{
public class LegacyCursorParticles : CompositeDrawable, IKeyBindingHandler<OsuAction>
2021-09-05 03:49:05 +08:00
{
2021-09-13 05:53:41 +08:00
public bool Active => breakSpewer?.Active.Value == true || kiaiSpewer?.Active.Value == true;
private LegacyCursorParticleSpewer breakSpewer;
private LegacyCursorParticleSpewer kiaiSpewer;
2021-09-05 03:49:05 +08:00
[Resolved(canBeNull: true)]
private Player player { get; set; }
[Resolved(canBeNull: true)]
private OsuPlayfield playfield { get; set; }
[Resolved(canBeNull: true)]
2021-10-02 01:22:23 +08:00
private GameplayState gameplayState { get; set; }
2021-09-05 03:49:05 +08:00
[BackgroundDependencyLoader]
2022-01-15 08:06:39 +08:00
private void load(ISkinSource skin)
2021-09-05 03:49:05 +08:00
{
var texture = skin.GetTexture("star2");
2021-09-14 06:36:01 +08:00
var starBreakAdditive = skin.GetConfig<OsuSkinColour, Color4>(OsuSkinColour.StarBreakAdditive)?.Value ?? new Color4(255, 182, 193, 255);
2021-09-16 03:22:37 +08:00
if (texture != null)
{
// stable "magic ratio". see OsuPlayfieldAdjustmentContainer for full explanation.
texture.ScaleAdjust *= 1.6f;
}
2021-09-05 03:49:05 +08:00
InternalChildren = new[]
{
breakSpewer = new LegacyCursorParticleSpewer(texture, 20)
2021-09-05 03:49:05 +08:00
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
2021-09-14 06:36:01 +08:00
Colour = starBreakAdditive,
Direction = SpewDirection.None,
2021-09-05 03:49:05 +08:00
},
kiaiSpewer = new LegacyCursorParticleSpewer(texture, 60)
2021-09-05 03:49:05 +08:00
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
2021-09-14 06:36:01 +08:00
Colour = starBreakAdditive,
Direction = SpewDirection.None,
2021-09-05 03:49:05 +08:00
},
};
if (player != null)
((IBindable<bool>)breakSpewer.Active).BindTo(player.IsBreakTime);
2021-09-05 03:49:05 +08:00
}
protected override void Update()
{
2021-10-02 01:22:23 +08:00
if (playfield == null || gameplayState == null) return;
2021-09-05 03:49:05 +08:00
DrawableHitObject kiaiHitObject = null;
// Check whether currently in a kiai section first. This is only done as an optimisation to avoid enumerating AliveObjects when not necessary.
2021-10-02 01:22:23 +08:00
if (gameplayState.Beatmap.ControlPointInfo.EffectPointAt(Time.Current).KiaiMode)
kiaiHitObject = playfield.HitObjectContainer.AliveObjects.FirstOrDefault(isTracking);
2021-09-05 03:49:05 +08:00
kiaiSpewer.Active.Value = kiaiHitObject != null;
}
private bool isTracking(DrawableHitObject h)
{
if (!h.HitObject.Kiai)
return false;
switch (h)
{
case DrawableSlider slider:
return slider.Tracking.Value;
case DrawableSpinner spinner:
return spinner.RotationTracker.Tracking;
}
return false;
}
2021-09-19 10:39:35 +08:00
public bool OnPressed(KeyBindingPressEvent<OsuAction> e)
2021-09-05 03:49:05 +08:00
{
2021-09-19 10:39:35 +08:00
handleInput(e.Action, true);
2021-09-05 03:49:05 +08:00
return false;
}
2021-09-19 10:39:35 +08:00
public void OnReleased(KeyBindingReleaseEvent<OsuAction> e)
2021-09-05 03:49:05 +08:00
{
2021-09-19 10:39:35 +08:00
handleInput(e.Action, false);
2021-09-05 03:49:05 +08:00
}
private bool leftPressed;
private bool rightPressed;
private void handleInput(OsuAction action, bool pressed)
{
switch (action)
{
case OsuAction.LeftButton:
leftPressed = pressed;
break;
case OsuAction.RightButton:
rightPressed = pressed;
break;
}
if (leftPressed && rightPressed)
breakSpewer.Direction = SpewDirection.Omni;
else if (leftPressed)
breakSpewer.Direction = SpewDirection.Left;
else if (rightPressed)
breakSpewer.Direction = SpewDirection.Right;
else
breakSpewer.Direction = SpewDirection.None;
2021-09-05 03:49:05 +08:00
}
private class LegacyCursorParticleSpewer : ParticleSpewer, IRequireHighFrequencyMousePosition
2021-09-05 03:49:05 +08:00
{
private const int particle_duration_min = 300;
private const int particle_duration_max = 1000;
public SpewDirection Direction { get; set; }
protected override bool CanSpawnParticles => base.CanSpawnParticles && cursorScreenPosition.HasValue;
protected override float ParticleGravity => 240;
2021-09-05 03:49:05 +08:00
public LegacyCursorParticleSpewer(Texture texture, int perSecond)
: base(texture, perSecond, particle_duration_max)
2021-09-05 03:49:05 +08:00
{
Active.BindValueChanged(_ => resetVelocityCalculation());
}
2021-09-05 07:01:49 +08:00
private Vector2? cursorScreenPosition;
private Vector2 cursorVelocity;
2021-09-05 07:01:49 +08:00
private const double max_velocity_frame_length = 15;
private double velocityFrameLength;
private Vector2 totalPosDifference;
2021-09-14 06:16:42 +08:00
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true;
protected override bool OnMouseMove(MouseMoveEvent e)
2021-09-05 07:01:49 +08:00
{
if (cursorScreenPosition == null)
{
cursorScreenPosition = e.ScreenSpaceMousePosition;
return base.OnMouseMove(e);
}
// calculate cursor velocity.
totalPosDifference += e.ScreenSpaceMousePosition - cursorScreenPosition.Value;
cursorScreenPosition = e.ScreenSpaceMousePosition;
velocityFrameLength += Math.Abs(Clock.ElapsedFrameTime);
if (velocityFrameLength > max_velocity_frame_length)
{
cursorVelocity = totalPosDifference / (float)velocityFrameLength;
totalPosDifference = Vector2.Zero;
velocityFrameLength = 0;
}
return base.OnMouseMove(e);
2021-09-05 07:01:49 +08:00
}
private void resetVelocityCalculation()
2021-09-05 07:01:49 +08:00
{
cursorScreenPosition = null;
totalPosDifference = Vector2.Zero;
velocityFrameLength = 0;
2021-09-05 03:49:05 +08:00
}
protected override FallingParticle CreateParticle() =>
new FallingParticle
{
StartPosition = ToLocalSpace(cursorScreenPosition ?? Vector2.Zero),
Duration = RNG.NextSingle(particle_duration_min, particle_duration_max),
StartAngle = (float)(RNG.NextDouble() * 4 - 2),
EndAngle = RNG.NextSingle(-2f, 2f),
EndScale = RNG.NextSingle(2f),
Velocity = getVelocity(),
};
private Vector2 getVelocity()
2021-09-05 03:49:05 +08:00
{
Vector2 velocity = Vector2.Zero;
switch (Direction)
{
case SpewDirection.Left:
velocity = new Vector2(
RNG.NextSingle(-460f, 0),
RNG.NextSingle(-40f, 40f)
);
break;
case SpewDirection.Right:
velocity = new Vector2(
RNG.NextSingle(0, 460f),
RNG.NextSingle(-40f, 40f)
);
break;
case SpewDirection.Omni:
velocity = new Vector2(
RNG.NextSingle(-460f, 460f),
RNG.NextSingle(-160f, 160f)
);
break;
}
velocity += cursorVelocity * 40;
return velocity;
2021-09-05 03:49:05 +08:00
}
}
2021-09-05 03:49:05 +08:00
private enum SpewDirection
{
None,
Left,
Right,
Omni,
2021-09-05 03:49:05 +08:00
}
}
}