2018-01-05 19:21:19 +08:00
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
2017-02-07 12:59:30 +08:00
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
2016-09-02 17:35:49 +08:00
2016-12-06 20:14:38 +08:00
using OpenTK ;
2017-04-18 15:05:58 +08:00
using osu.Game.Rulesets.Objects.Types ;
2017-02-15 17:48:29 +08:00
using System ;
using System.Collections.Generic ;
2017-04-18 15:05:58 +08:00
using osu.Game.Rulesets.Objects ;
2017-04-06 10:41:16 +08:00
using System.Linq ;
using osu.Game.Audio ;
2017-07-26 12:22:46 +08:00
using osu.Game.Beatmaps ;
2017-05-23 12:55:18 +08:00
using osu.Game.Beatmaps.ControlPoints ;
2016-09-02 17:35:49 +08:00
2017-04-18 15:05:58 +08:00
namespace osu.Game.Rulesets.Osu.Objects
2016-09-02 17:35:49 +08:00
{
2017-03-15 11:52:25 +08:00
public class Slider : OsuHitObject , IHasCurve
2016-09-02 17:35:49 +08:00
{
2017-04-03 13:10:20 +08:00
/// <summary>
/// Scoring distance with a speed-adjusted beat length of 1 second.
/// </summary>
private const float base_scoring_distance = 100 ;
2018-01-23 12:37:25 +08:00
public double EndTime = > StartTime + this . SpanCount ( ) * Curve . Distance / Velocity ;
2017-03-13 18:15:25 +08:00
public double Duration = > EndTime - StartTime ;
2016-11-28 14:31:54 +08:00
2018-02-23 19:51:26 +08:00
public Vector2 StackedPositionAt ( double t ) = > StackedPosition + this . PositionAt ( t ) ;
public override Vector2 EndPosition = > Position + this . PositionAt ( 1 ) ;
2018-01-23 12:37:25 +08:00
public SliderCurve Curve { get ; } = new SliderCurve ( ) ;
2017-03-06 10:11:29 +08:00
2017-04-21 19:29:27 +08:00
public List < Vector2 > ControlPoints
{
get { return Curve . ControlPoints ; }
set { Curve . ControlPoints = value ; }
}
2017-03-06 10:11:29 +08:00
2017-04-21 19:29:27 +08:00
public CurveType CurveType
{
get { return Curve . CurveType ; }
set { Curve . CurveType = value ; }
}
2017-04-21 15:18:34 +08:00
2017-04-21 19:29:27 +08:00
public double Distance
{
get { return Curve . Distance ; }
set { Curve . Distance = value ; }
}
2017-03-15 11:52:25 +08:00
2017-11-17 19:28:41 +08:00
/// <summary>
2017-11-17 20:28:59 +08:00
/// The position of the cursor at the point of completion of this <see cref="Slider"/> if it was hit
/// with as few movements as possible. This is set and used by difficulty calculation.
2017-11-17 19:28:41 +08:00
/// </summary>
2017-11-17 20:28:59 +08:00
internal Vector2 ? LazyEndPosition ;
/// <summary>
/// The distance travelled by the cursor upon completion of this <see cref="Slider"/> if it was hit
/// with as few movements as possible. This is set and used by difficulty calculation.
/// </summary>
internal float LazyTravelDistance ;
2017-11-17 19:28:41 +08:00
2017-12-25 14:35:28 +08:00
public List < List < SampleInfo > > RepeatSamples { get ; set ; } = new List < List < SampleInfo > > ( ) ;
2018-01-23 12:37:25 +08:00
public int RepeatCount { get ; set ; }
2016-12-06 20:14:38 +08:00
2018-01-22 19:36:38 +08:00
/// <summary>
2018-01-24 16:44:50 +08:00
/// The length of one span of this <see cref="Slider"/>.
2018-01-22 19:36:38 +08:00
/// </summary>
2018-01-24 16:44:50 +08:00
public double SpanDuration = > Duration / this . SpanCount ( ) ;
2018-01-22 19:36:38 +08:00
2016-11-28 17:45:50 +08:00
public double Velocity ;
2017-02-13 03:38:05 +08:00
public double TickDistance ;
2016-11-28 17:45:50 +08:00
2018-01-30 14:50:48 +08:00
public HitCircle HeadCircle ;
2018-01-30 15:24:23 +08:00
public HitCircle TailCircle ;
2018-01-30 14:50:48 +08:00
2017-12-22 20:42:54 +08:00
protected override void ApplyDefaultsToSelf ( ControlPointInfo controlPointInfo , BeatmapDifficulty difficulty )
2016-11-28 17:45:50 +08:00
{
2017-12-22 20:42:54 +08:00
base . ApplyDefaultsToSelf ( controlPointInfo , difficulty ) ;
2017-12-21 15:02:33 +08:00
2017-05-23 12:55:18 +08:00
TimingControlPoint timingPoint = controlPointInfo . TimingPointAt ( StartTime ) ;
DifficultyControlPoint difficultyPoint = controlPointInfo . DifficultyPointAt ( StartTime ) ;
2017-02-13 03:38:05 +08:00
2017-08-21 10:45:57 +08:00
double scoringDistance = base_scoring_distance * difficulty . SliderMultiplier * difficultyPoint . SpeedMultiplier ;
2017-05-23 12:55:18 +08:00
Velocity = scoringDistance / timingPoint . BeatLength ;
2017-04-03 13:10:20 +08:00
TickDistance = scoringDistance / difficulty . SliderTickRate ;
2016-11-28 17:45:50 +08:00
}
2016-09-02 17:35:49 +08:00
2017-12-22 20:42:54 +08:00
protected override void CreateNestedHitObjects ( )
2017-02-13 03:38:05 +08:00
{
2017-12-22 20:42:54 +08:00
base . CreateNestedHitObjects ( ) ;
2018-01-30 15:53:19 +08:00
createSliderEnds ( ) ;
2017-12-22 20:42:54 +08:00
createTicks ( ) ;
createRepeatPoints ( ) ;
}
2017-02-16 12:20:30 +08:00
2018-01-30 15:53:19 +08:00
private void createSliderEnds ( )
{
2018-01-30 14:50:48 +08:00
HeadCircle = new HitCircle
{
StartTime = StartTime ,
2018-02-23 19:51:26 +08:00
Position = Position ,
2018-01-30 14:50:48 +08:00
IndexInCurrentCombo = IndexInCurrentCombo ,
ComboColour = ComboColour ,
Samples = Samples ,
SampleControlPoint = SampleControlPoint
} ;
2018-01-30 15:24:23 +08:00
TailCircle = new HitCircle
{
StartTime = EndTime ,
2018-02-23 19:51:26 +08:00
Position = EndPosition ,
2018-01-30 15:24:23 +08:00
IndexInCurrentCombo = IndexInCurrentCombo ,
2018-02-08 13:40:35 +08:00
ComboColour = ComboColour
2018-01-30 15:24:23 +08:00
} ;
2018-01-30 15:53:19 +08:00
AddNested ( HeadCircle ) ;
AddNested ( TailCircle ) ;
2017-12-22 20:42:54 +08:00
}
2017-02-16 12:20:30 +08:00
2017-12-22 20:42:54 +08:00
private void createTicks ( )
{
if ( TickDistance = = 0 ) return ;
2017-02-13 03:38:05 +08:00
2017-12-22 20:42:54 +08:00
var length = Curve . Distance ;
var tickDistance = Math . Min ( TickDistance , length ) ;
2017-02-13 03:38:05 +08:00
2017-12-22 20:42:54 +08:00
var minDistanceFromEnd = Velocity * 0.01 ;
2017-02-13 03:38:05 +08:00
2018-01-23 12:37:25 +08:00
for ( var span = 0 ; span < this . SpanCount ( ) ; span + + )
2017-12-22 20:42:54 +08:00
{
2018-01-23 16:04:45 +08:00
var spanStartTime = StartTime + span * SpanDuration ;
2018-01-23 12:37:25 +08:00
var reversed = span % 2 = = 1 ;
2017-02-13 03:38:05 +08:00
2017-12-22 20:42:54 +08:00
for ( var d = tickDistance ; d < = length ; d + = tickDistance )
{
if ( d > length - minDistanceFromEnd )
break ;
var distanceProgress = d / length ;
var timeProgress = reversed ? 1 - distanceProgress : distanceProgress ;
2017-02-13 03:38:05 +08:00
2018-01-18 19:37:36 +08:00
var firstSample = Samples . FirstOrDefault ( s = > s . Name = = SampleInfo . HIT_NORMAL ) ? ? Samples . FirstOrDefault ( ) ; // TODO: remove this when guaranteed sort is present for samples (https://github.com/ppy/osu/issues/1933)
2018-01-18 18:50:26 +08:00
var sampleList = new List < SampleInfo > ( ) ;
if ( firstSample ! = null )
sampleList . Add ( new SampleInfo
{
2018-01-18 18:57:49 +08:00
Bank = firstSample . Bank ,
Volume = firstSample . Volume ,
2018-01-18 18:50:26 +08:00
Name = @"slidertick" ,
} ) ;
2017-12-22 20:42:54 +08:00
AddNested ( new SliderTick
{
2018-01-23 12:58:43 +08:00
SpanIndex = span ,
2018-01-29 19:03:22 +08:00
SpanStartTime = spanStartTime ,
2018-01-23 16:04:45 +08:00
StartTime = spanStartTime + timeProgress * SpanDuration ,
2018-02-23 19:51:26 +08:00
Position = Position + Curve . PositionAt ( distanceProgress ) ,
2017-12-22 20:42:54 +08:00
StackHeight = StackHeight ,
Scale = Scale ,
ComboColour = ComboColour ,
2018-01-18 18:50:26 +08:00
Samples = sampleList
2017-12-22 20:42:54 +08:00
} ) ;
2017-02-13 03:38:05 +08:00
}
}
}
2017-12-22 20:42:54 +08:00
private void createRepeatPoints ( )
2017-09-27 00:13:34 +08:00
{
2018-01-23 12:58:43 +08:00
for ( int repeatIndex = 0 , repeat = 1 ; repeatIndex < RepeatCount ; repeatIndex + + , repeat + + )
2017-12-22 20:42:54 +08:00
{
2017-12-27 19:37:28 +08:00
AddNested ( new RepeatPoint
2017-09-27 00:13:34 +08:00
{
2018-01-23 12:58:43 +08:00
RepeatIndex = repeatIndex ,
2018-01-23 16:04:45 +08:00
SpanDuration = SpanDuration ,
StartTime = StartTime + repeat * SpanDuration ,
2018-02-23 19:51:26 +08:00
Position = Position + Curve . PositionAt ( repeat % 2 ) ,
2017-12-27 19:37:28 +08:00
StackHeight = StackHeight ,
Scale = Scale ,
ComboColour = ComboColour ,
2018-01-23 12:58:43 +08:00
Samples = new List < SampleInfo > ( RepeatSamples [ repeatIndex ] )
2017-12-27 19:37:28 +08:00
} ) ;
2017-09-27 00:13:34 +08:00
}
}
2016-09-02 17:35:49 +08:00
}
}