mirror of
https://github.com/osukey/osukey.git
synced 2025-08-03 22:56:36 +09:00
Merge branch 'master' into slider_ticks
Conflicts: osu.Game.Modes.Osu/Objects/Drawables/DrawableSlider.cs osu.Game.Modes.Osu/Objects/Slider.cs
This commit is contained in:
@ -2,7 +2,6 @@
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Transformations;
|
||||
using osu.Game.Modes.Objects.Drawables;
|
||||
@ -11,9 +10,9 @@ using OpenTK;
|
||||
|
||||
namespace osu.Game.Modes.Osu.Objects.Drawables
|
||||
{
|
||||
public class DrawableHitCircle : DrawableOsuHitObject
|
||||
public class DrawableHitCircle : DrawableOsuHitObject, IDrawableHitObjectWithProxiedApproach
|
||||
{
|
||||
private HitCircle osuObject;
|
||||
private OsuHitObject osuObject;
|
||||
|
||||
public ApproachCircle ApproachCircle;
|
||||
private CirclePiece circle;
|
||||
@ -23,11 +22,12 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
|
||||
private NumberPiece number;
|
||||
private GlowPiece glow;
|
||||
|
||||
public DrawableHitCircle(HitCircle h) : base(h)
|
||||
public DrawableHitCircle(OsuHitObject h) : base(h)
|
||||
{
|
||||
Origin = Anchor.Centre;
|
||||
|
||||
osuObject = h;
|
||||
|
||||
Origin = Anchor.Centre;
|
||||
Position = osuObject.StackedPosition;
|
||||
Scale = new Vector2(osuObject.Scale);
|
||||
|
||||
@ -156,5 +156,7 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public Drawable ProxiedLayer => ApproachCircle;
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
using System.ComponentModel;
|
||||
using osu.Game.Modes.Objects;
|
||||
using osu.Game.Modes.Objects.Drawables;
|
||||
using osu.Framework.Graphics;
|
||||
|
||||
namespace osu.Game.Modes.Osu.Objects.Drawables
|
||||
{
|
||||
|
@ -3,7 +3,6 @@
|
||||
|
||||
using OpenTK;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Modes.Objects.Drawables;
|
||||
using osu.Game.Modes.Osu.Objects.Drawables.Pieces;
|
||||
using System.Collections.Generic;
|
||||
@ -11,7 +10,7 @@ using System.Linq;
|
||||
|
||||
namespace osu.Game.Modes.Osu.Objects.Drawables
|
||||
{
|
||||
class DrawableSlider : DrawableOsuHitObject
|
||||
public class DrawableSlider : DrawableOsuHitObject, IDrawableHitObjectWithProxiedApproach
|
||||
{
|
||||
private Slider slider;
|
||||
|
||||
@ -157,6 +156,8 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
|
||||
|
||||
FadeOut(800);
|
||||
}
|
||||
|
||||
public Drawable ProxiedLayer => initialCircle.ApproachCircle;
|
||||
}
|
||||
|
||||
internal interface ISliderProgress
|
||||
|
140
osu.Game.Modes.Osu/Objects/Drawables/DrawableSpinner.cs
Normal file
140
osu.Game.Modes.Osu/Objects/Drawables/DrawableSpinner.cs
Normal file
@ -0,0 +1,140 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Transformations;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Game.Modes.Objects.Drawables;
|
||||
using osu.Game.Modes.Osu.Objects.Drawables.Pieces;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
|
||||
namespace osu.Game.Modes.Osu.Objects.Drawables
|
||||
{
|
||||
public class DrawableSpinner : DrawableOsuHitObject
|
||||
{
|
||||
private Spinner spinner;
|
||||
|
||||
private SpinnerDisc disc;
|
||||
private SpinnerBackground background;
|
||||
private DrawableHitCircle circle;
|
||||
private NumberPiece number;
|
||||
|
||||
public DrawableSpinner(Spinner s) : base(s)
|
||||
{
|
||||
Origin = Anchor.Centre;
|
||||
Position = s.Position;
|
||||
|
||||
//take up full playfield.
|
||||
Size = new Vector2(512);
|
||||
|
||||
spinner = s;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
background = new SpinnerBackground
|
||||
{
|
||||
Alpha = 0,
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
DiscColour = Color4.Black
|
||||
},
|
||||
disc = new SpinnerDisc
|
||||
{
|
||||
Alpha = 0,
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
DiscColour = s.Colour
|
||||
},
|
||||
circle = new DrawableHitCircle(s)
|
||||
{
|
||||
Interactive = false,
|
||||
Position = Vector2.Zero,
|
||||
Anchor = Anchor.Centre,
|
||||
}
|
||||
};
|
||||
|
||||
circle.ApproachCircle.Colour = Color4.Transparent;
|
||||
|
||||
background.Scale = scaleToCircle;
|
||||
disc.Scale = scaleToCircle;
|
||||
}
|
||||
|
||||
public override bool Contains(Vector2 screenSpacePos) => true;
|
||||
|
||||
protected override void CheckJudgement(bool userTriggered)
|
||||
{
|
||||
if (Time.Current < HitObject.StartTime) return;
|
||||
|
||||
var j = Judgement as OsuJudgementInfo;
|
||||
|
||||
disc.ScaleTo(Interpolation.ValueAt(Math.Sqrt(Progress), scaleToCircle, Vector2.One, 0, 1), 100);
|
||||
|
||||
if (!userTriggered && Time.Current >= HitObject.EndTime)
|
||||
{
|
||||
if (Progress >= 1)
|
||||
{
|
||||
j.Score = OsuScoreResult.Hit300;
|
||||
j.Result = HitResult.Hit;
|
||||
}
|
||||
else if (Progress > .9)
|
||||
{
|
||||
j.Score = OsuScoreResult.Hit100;
|
||||
j.Result = HitResult.Hit;
|
||||
}
|
||||
else if (Progress > .75)
|
||||
{
|
||||
j.Score = OsuScoreResult.Hit50;
|
||||
j.Result = HitResult.Hit;
|
||||
}
|
||||
else
|
||||
{
|
||||
j.Score = OsuScoreResult.Miss;
|
||||
j.Result = HitResult.Miss;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Vector2 scaleToCircle => new Vector2(circle.Scale * circle.DrawWidth / DrawWidth) * 0.95f;
|
||||
|
||||
private float spinsPerMinuteNeeded = 100 + (5 * 15); //TODO: read per-map OD and place it on the 5
|
||||
|
||||
private float rotationsNeeded => (float)(spinsPerMinuteNeeded * (spinner.EndTime - spinner.StartTime) / 60000f);
|
||||
|
||||
public float Progress => MathHelper.Clamp(disc.RotationAbsolute / 360 / rotationsNeeded, 0, 1);
|
||||
|
||||
protected override void UpdatePreemptState()
|
||||
{
|
||||
base.UpdatePreemptState();
|
||||
|
||||
FadeIn(200);
|
||||
|
||||
background.Delay(TIME_PREEMPT - 100);
|
||||
background.FadeIn(200);
|
||||
background.ScaleTo(1, 200, EasingTypes.OutQuint);
|
||||
|
||||
disc.Delay(TIME_PREEMPT - 50);
|
||||
disc.FadeIn(200);
|
||||
}
|
||||
|
||||
protected override void UpdateState(ArmedState state)
|
||||
{
|
||||
base.UpdateState(state);
|
||||
|
||||
Delay(HitObject.Duration, true);
|
||||
|
||||
FadeOut(160);
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case ArmedState.Hit:
|
||||
ScaleTo(Scale * 1.2f, 320, EasingTypes.Out);
|
||||
break;
|
||||
case ArmedState.Miss:
|
||||
ScaleTo(Scale * 0.8f, 320, EasingTypes.In);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
namespace osu.Game.Modes.Osu.Objects.Drawables.Pieces
|
||||
{
|
||||
public class SpinnerBackground : SpinnerDisc
|
||||
{
|
||||
public override bool HandleInput => false;
|
||||
}
|
||||
}
|
168
osu.Game.Modes.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs
Normal file
168
osu.Game.Modes.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs
Normal file
@ -0,0 +1,168 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Colour;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Transformations;
|
||||
using osu.Framework.Input;
|
||||
using osu.Framework.Logging;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
|
||||
namespace osu.Game.Modes.Osu.Objects.Drawables.Pieces
|
||||
{
|
||||
public class SpinnerDisc : CircularContainer
|
||||
{
|
||||
public override bool Contains(Vector2 screenSpacePos) => true;
|
||||
|
||||
protected Sprite Disc;
|
||||
|
||||
public SRGBColour DiscColour
|
||||
{
|
||||
get { return Disc.Colour; }
|
||||
set { Disc.Colour = value; }
|
||||
}
|
||||
|
||||
class SpinnerBorder : Container
|
||||
{
|
||||
public SpinnerBorder()
|
||||
{
|
||||
Origin = Anchor.Centre;
|
||||
Anchor = Anchor.Centre;
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
|
||||
layout();
|
||||
}
|
||||
|
||||
private int lastLayoutDotCount;
|
||||
private void layout()
|
||||
{
|
||||
int count = (int)(MathHelper.Pi * ScreenSpaceDrawQuad.Width / 9);
|
||||
|
||||
if (count == lastLayoutDotCount) return;
|
||||
|
||||
lastLayoutDotCount = count;
|
||||
|
||||
while (Children.Count() < count)
|
||||
{
|
||||
Add(new CircularContainer
|
||||
{
|
||||
Colour = Color4.White,
|
||||
RelativePositionAxes = Axes.Both,
|
||||
Origin = Anchor.Centre,
|
||||
Size = new Vector2(1 / ScreenSpaceDrawQuad.Width * 2000),
|
||||
Children = new[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Anchor = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var size = new Vector2(1 / ScreenSpaceDrawQuad.Width * 2000);
|
||||
|
||||
int i = 0;
|
||||
foreach (var d in Children)
|
||||
{
|
||||
d.Size = size;
|
||||
d.Position = new Vector2(
|
||||
0.5f + (float)Math.Sin((float)i / count * 2 * MathHelper.Pi) / 2,
|
||||
0.5f + (float)Math.Cos((float)i / count * 2 * MathHelper.Pi) / 2
|
||||
);
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
layout();
|
||||
}
|
||||
}
|
||||
|
||||
public SpinnerDisc()
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
Disc = new Box
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Anchor = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Alpha = 0.2f,
|
||||
},
|
||||
new SpinnerBorder()
|
||||
};
|
||||
}
|
||||
|
||||
bool tracking;
|
||||
public bool Tracking
|
||||
{
|
||||
get { return tracking; }
|
||||
set
|
||||
{
|
||||
if (value == tracking) return;
|
||||
|
||||
tracking = value;
|
||||
|
||||
Disc.FadeTo(tracking ? 0.5f : 0.2f, 100);
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
|
||||
{
|
||||
Tracking = true;
|
||||
return base.OnMouseDown(state, args);
|
||||
}
|
||||
|
||||
protected override bool OnMouseUp(InputState state, MouseUpEventArgs args)
|
||||
{
|
||||
Tracking = false;
|
||||
return base.OnMouseUp(state, args);
|
||||
}
|
||||
|
||||
protected override bool OnMouseMove(InputState state)
|
||||
{
|
||||
Tracking |= state.Mouse.HasMainButtonPressed;
|
||||
mousePosition = state.Mouse.Position;
|
||||
return base.OnMouseMove(state);
|
||||
}
|
||||
|
||||
private Vector2 mousePosition;
|
||||
|
||||
private float lastAngle;
|
||||
private float currentRotation;
|
||||
public float RotationAbsolute;
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
var thisAngle = -(float)MathHelper.RadiansToDegrees(Math.Atan2(mousePosition.X - DrawSize.X / 2, mousePosition.Y - DrawSize.Y / 2));
|
||||
if (tracking)
|
||||
{
|
||||
if (thisAngle - lastAngle > 180)
|
||||
lastAngle += 360;
|
||||
else if (lastAngle - thisAngle > 180)
|
||||
lastAngle -= 360;
|
||||
|
||||
currentRotation += thisAngle - lastAngle;
|
||||
RotationAbsolute += Math.Abs(thisAngle - lastAngle);
|
||||
}
|
||||
lastAngle = thisAngle;
|
||||
|
||||
RotateTo(currentRotation, 100, EasingTypes.OutExpo);
|
||||
}
|
||||
}
|
||||
}
|
@ -31,19 +31,19 @@ namespace osu.Game.Modes.Osu.Objects
|
||||
|
||||
Scale = (1.0f - 0.7f * (beatmap.BeatmapInfo.BaseDifficulty.CircleSize - 5) / 5) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
[Flags]
|
||||
internal enum HitObjectType
|
||||
{
|
||||
Circle = 1,
|
||||
Slider = 2,
|
||||
NewCombo = 4,
|
||||
CircleNewCombo = 5,
|
||||
SliderNewCombo = 6,
|
||||
Spinner = 8,
|
||||
ColourHax = 122,
|
||||
Hold = 128,
|
||||
ManiaLong = 128,
|
||||
}
|
||||
[Flags]
|
||||
public enum HitObjectType
|
||||
{
|
||||
Circle = 1,
|
||||
Slider = 2,
|
||||
NewCombo = 4,
|
||||
CircleNewCombo = 5,
|
||||
SliderNewCombo = 6,
|
||||
Spinner = 8,
|
||||
ColourHax = 122,
|
||||
Hold = 128,
|
||||
ManiaLong = 128,
|
||||
}
|
||||
}
|
||||
|
@ -18,21 +18,22 @@ namespace osu.Game.Modes.Osu.Objects
|
||||
public override HitObject Parse(string text)
|
||||
{
|
||||
string[] split = text.Split(',');
|
||||
var type = (OsuHitObject.HitObjectType)int.Parse(split[3]);
|
||||
bool combo = type.HasFlag(OsuHitObject.HitObjectType.NewCombo);
|
||||
type &= (OsuHitObject.HitObjectType)0xF;
|
||||
type &= ~OsuHitObject.HitObjectType.NewCombo;
|
||||
var type = (HitObjectType)int.Parse(split[3]);
|
||||
bool combo = type.HasFlag(HitObjectType.NewCombo);
|
||||
type &= (HitObjectType)0xF;
|
||||
type &= ~HitObjectType.NewCombo;
|
||||
OsuHitObject result;
|
||||
switch (type)
|
||||
{
|
||||
case OsuHitObject.HitObjectType.Circle:
|
||||
result = new HitCircle();
|
||||
case HitObjectType.Circle:
|
||||
result = new HitCircle
|
||||
{
|
||||
Position = new Vector2(int.Parse(split[0]), int.Parse(split[1]))
|
||||
};
|
||||
break;
|
||||
case OsuHitObject.HitObjectType.Slider:
|
||||
Slider s = new Slider();
|
||||
|
||||
case HitObjectType.Slider:
|
||||
CurveTypes curveType = CurveTypes.Catmull;
|
||||
int repeatCount = 0;
|
||||
int repeatCount;
|
||||
double length = 0;
|
||||
List<Vector2> points = new List<Vector2>();
|
||||
|
||||
@ -79,29 +80,28 @@ namespace osu.Game.Modes.Osu.Objects
|
||||
if (split.Length > 7)
|
||||
length = Convert.ToDouble(split[7], CultureInfo.InvariantCulture);
|
||||
|
||||
s.RepeatCount = repeatCount;
|
||||
|
||||
s.Curve = new SliderCurve
|
||||
result = new Slider
|
||||
{
|
||||
ControlPoints = points,
|
||||
Length = length,
|
||||
CurveType = curveType
|
||||
CurveType = curveType,
|
||||
RepeatCount = repeatCount,
|
||||
Position = new Vector2(int.Parse(split[0]), int.Parse(split[1]))
|
||||
};
|
||||
|
||||
s.Curve.Calculate();
|
||||
|
||||
result = s;
|
||||
break;
|
||||
case OsuHitObject.HitObjectType.Spinner:
|
||||
result = new Spinner();
|
||||
case HitObjectType.Spinner:
|
||||
result = new Spinner
|
||||
{
|
||||
Length = Convert.ToDouble(split[5], CultureInfo.InvariantCulture) - Convert.ToDouble(split[2], CultureInfo.InvariantCulture),
|
||||
Position = new Vector2(512, 384) / 2,
|
||||
};
|
||||
break;
|
||||
default:
|
||||
//throw new InvalidOperationException($@"Unknown hit object type {type}");
|
||||
return null;
|
||||
throw new InvalidOperationException($@"Unknown hit object type {type}");
|
||||
}
|
||||
result.Position = new Vector2(int.Parse(split[0]), int.Parse(split[1]));
|
||||
result.StartTime = double.Parse(split[2]);
|
||||
result.Sample = new HitSampleInfo {
|
||||
result.StartTime = Convert.ToDouble(split[2], CultureInfo.InvariantCulture);
|
||||
result.Sample = new HitSampleInfo
|
||||
{
|
||||
Type = (SampleType)int.Parse(split[4]),
|
||||
Set = SampleSet.Soft,
|
||||
};
|
||||
|
@ -1,11 +1,11 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Game.Beatmaps;
|
||||
using OpenTK;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.Samples;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace osu.Game.Modes.Osu.Objects
|
||||
{
|
||||
@ -22,11 +22,28 @@ namespace osu.Game.Modes.Osu.Objects
|
||||
set
|
||||
{
|
||||
stackHeight = value;
|
||||
if (Curve != null)
|
||||
Curve.Offset = StackOffset;
|
||||
Curve.Offset = StackOffset;
|
||||
}
|
||||
}
|
||||
|
||||
public List<Vector2> ControlPoints
|
||||
{
|
||||
get { return Curve.ControlPoints; }
|
||||
set { Curve.ControlPoints = value; }
|
||||
}
|
||||
|
||||
public double Length
|
||||
{
|
||||
get { return Curve.Length; }
|
||||
set { Curve.Length = value; }
|
||||
}
|
||||
|
||||
public CurveTypes CurveType
|
||||
{
|
||||
get { return Curve.CurveType; }
|
||||
set { Curve.CurveType = value; }
|
||||
}
|
||||
|
||||
public double Velocity;
|
||||
public double TickDistance;
|
||||
|
||||
@ -43,9 +60,9 @@ namespace osu.Game.Modes.Osu.Objects
|
||||
TickDistance = (100 * baseDifficulty.SliderMultiplier) / baseDifficulty.SliderTickRate / (multipliedStartBeatLength / startBeatLength);
|
||||
}
|
||||
|
||||
public int RepeatCount;
|
||||
public int RepeatCount = 1;
|
||||
|
||||
public SliderCurve Curve;
|
||||
internal readonly SliderCurve Curve = new SliderCurve();
|
||||
|
||||
public IEnumerable<SliderTick> Ticks
|
||||
{
|
||||
|
@ -15,7 +15,7 @@ namespace osu.Game.Modes.Osu.Objects
|
||||
|
||||
public List<Vector2> ControlPoints;
|
||||
|
||||
public CurveTypes CurveType;
|
||||
public CurveTypes CurveType = CurveTypes.PerfectCurve;
|
||||
|
||||
public Vector2 Offset;
|
||||
|
||||
@ -172,6 +172,9 @@ namespace osu.Game.Modes.Osu.Objects
|
||||
/// <param name="p1">End progress. Ranges from 0 (beginning of the slider) to 1 (end of the slider).</param>
|
||||
public void GetPathToProgress(List<Vector2> path, double p0, double p1)
|
||||
{
|
||||
if (calculatedPath.Count == 0 && ControlPoints.Count > 0)
|
||||
Calculate();
|
||||
|
||||
double d0 = progressToDistance(p0);
|
||||
double d1 = progressToDistance(p1);
|
||||
|
||||
@ -196,6 +199,9 @@ namespace osu.Game.Modes.Osu.Objects
|
||||
/// <returns></returns>
|
||||
public Vector2 PositionAt(double progress)
|
||||
{
|
||||
if (calculatedPath.Count == 0 && ControlPoints.Count > 0)
|
||||
Calculate();
|
||||
|
||||
double d = progressToDistance(progress);
|
||||
return interpolateVertices(indexOfDistance(d), d) + Offset;
|
||||
}
|
||||
|
@ -1,9 +1,14 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Game.Beatmaps;
|
||||
|
||||
namespace osu.Game.Modes.Osu.Objects
|
||||
{
|
||||
public class Spinner : OsuHitObject
|
||||
{
|
||||
public double Length;
|
||||
|
||||
public override double EndTime => StartTime + Length;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user