2017-02-07 04:59:30 +00:00
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
2016-12-03 12:56:35 +00:00
2017-02-12 19:38:05 +00:00
using OpenTK ;
2016-11-28 07:52:57 +00:00
using osu.Framework.Graphics ;
2017-04-18 07:05:58 +00:00
using osu.Game.Rulesets.Objects.Drawables ;
using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces ;
2017-02-12 19:38:05 +00:00
using System.Collections.Generic ;
using System.Linq ;
2017-02-16 08:02:36 +00:00
using osu.Framework.Graphics.Containers ;
2016-11-17 08:20:51 +00:00
2017-04-18 07:05:58 +00:00
namespace osu.Game.Rulesets.Osu.Objects.Drawables
2016-11-17 08:20:51 +00:00
{
2017-02-14 01:22:28 +00:00
public class DrawableSlider : DrawableOsuHitObject , IDrawableHitObjectWithProxiedApproach
2016-11-17 08:20:51 +00:00
{
2017-03-23 04:41:50 +00:00
private readonly Slider slider ;
2016-11-28 08:05:30 +00:00
2017-03-23 04:41:50 +00:00
private readonly DrawableHitCircle initialCircle ;
2016-12-06 09:54:32 +00:00
2017-03-23 04:41:50 +00:00
private readonly List < ISliderProgress > components = new List < ISliderProgress > ( ) ;
2016-11-28 03:40:24 +00:00
2017-03-23 04:41:50 +00:00
private readonly Container < DrawableSliderTick > ticks ;
2017-02-16 08:02:36 +00:00
2017-03-23 04:41:50 +00:00
private readonly SliderBody body ;
private readonly SliderBall ball ;
2016-12-06 15:02:27 +00:00
2017-03-23 04:41:50 +00:00
private readonly SliderBouncer bouncer2 ;
2016-12-06 15:02:27 +00:00
2016-11-28 03:15:25 +00:00
public DrawableSlider ( Slider s ) : base ( s )
2016-11-17 08:20:51 +00:00
{
2017-03-16 08:38:36 +00:00
// Since the DrawableSlider itself is just a container without a size we need to
// pass all input through.
AlwaysReceiveInput = true ;
2017-03-09 06:52:40 +00:00
SliderBouncer bouncer1 ;
2016-11-28 03:40:24 +00:00
slider = s ;
2016-11-27 14:36:31 +00:00
2016-11-28 03:40:24 +00:00
Children = new Drawable [ ]
2016-11-28 03:15:25 +00:00
{
2016-12-06 09:54:32 +00:00
body = new SliderBody ( s )
2016-11-28 18:04:03 +00:00
{
2017-03-23 08:11:51 +00:00
AccentColour = AccentColour ,
2017-02-09 07:29:21 +00:00
Position = s . StackedPosition ,
2017-02-06 13:17:29 +00:00
PathWidth = s . Scale * 64 ,
2016-12-11 09:11:22 +00:00
} ,
2017-02-16 08:02:36 +00:00
ticks = new Container < DrawableSliderTick > ( ) ,
2016-12-11 09:11:22 +00:00
bouncer1 = new SliderBouncer ( s , false )
{
Position = s . Curve . PositionAt ( 1 ) ,
Scale = new Vector2 ( s . Scale ) ,
} ,
bouncer2 = new SliderBouncer ( s , true )
{
2017-02-09 07:29:21 +00:00
Position = s . StackedPosition ,
2016-12-11 09:11:22 +00:00
Scale = new Vector2 ( s . Scale ) ,
} ,
ball = new SliderBall ( s )
{
Scale = new Vector2 ( s . Scale ) ,
2017-03-23 06:37:16 +00:00
AccentColour = AccentColour
2016-11-28 18:04:03 +00:00
} ,
2016-12-06 15:02:27 +00:00
initialCircle = new DrawableHitCircle ( new HitCircle
2016-11-28 03:40:24 +00:00
{
2017-02-15 14:23:55 +00:00
//todo: avoid creating this temporary HitCircle.
2016-11-28 03:40:24 +00:00
StartTime = s . StartTime ,
2017-02-09 07:29:21 +00:00
Position = s . StackedPosition ,
2017-02-15 14:23:55 +00:00
ComboIndex = s . ComboIndex ,
2016-12-11 09:11:22 +00:00
Scale = s . Scale ,
2017-03-13 10:15:25 +00:00
ComboColour = s . ComboColour ,
2017-04-06 02:41:16 +00:00
Samples = s . Samples ,
2016-12-08 12:07:20 +00:00
} ) ,
2016-11-28 03:40:24 +00:00
} ;
2016-11-17 12:29:35 +00:00
2016-12-06 09:54:32 +00:00
components . Add ( body ) ;
components . Add ( ball ) ;
2016-12-06 15:02:27 +00:00
components . Add ( bouncer1 ) ;
components . Add ( bouncer2 ) ;
2017-02-16 08:02:36 +00:00
AddNested ( initialCircle ) ;
2017-03-15 03:52:25 +00:00
var repeatDuration = s . Curve . Distance / s . Velocity ;
2017-02-16 08:02:36 +00:00
foreach ( var tick in s . Ticks )
{
var repeatStartTime = s . StartTime + tick . RepeatIndex * repeatDuration ;
var fadeInTime = repeatStartTime + ( tick . StartTime - repeatStartTime ) / 2 - ( tick . RepeatIndex = = 0 ? TIME_FADEIN : TIME_FADEIN / 2 ) ;
var fadeOutTime = repeatStartTime + repeatDuration ;
var drawableTick = new DrawableSliderTick ( tick )
{
FadeInTime = fadeInTime ,
FadeOutTime = fadeOutTime ,
Position = tick . Position ,
} ;
ticks . Add ( drawableTick ) ;
AddNested ( drawableTick ) ;
}
2016-12-03 12:56:19 +00:00
}
2017-03-07 01:59:19 +00:00
private int currentRepeat ;
2016-12-08 10:54:22 +00:00
2016-12-06 09:54:32 +00:00
protected override void Update ( )
2016-11-17 12:29:35 +00:00
{
2016-12-06 09:54:32 +00:00
base . Update ( ) ;
2016-11-17 08:20:51 +00:00
2016-12-06 09:54:32 +00:00
double progress = MathHelper . Clamp ( ( Time . Current - slider . StartTime ) / slider . Duration , 0 , 1 ) ;
2016-11-28 07:31:19 +00:00
2017-03-06 02:11:29 +00:00
int repeat = slider . RepeatAt ( progress ) ;
2017-03-15 03:52:25 +00:00
progress = slider . ProgressAt ( progress ) ;
2016-11-28 07:31:19 +00:00
2016-12-08 10:54:22 +00:00
if ( repeat > currentRepeat )
{
2017-02-22 04:51:40 +00:00
if ( repeat < slider . RepeatCount & & ball . Tracking )
2017-04-05 12:34:28 +00:00
PlaySamples ( ) ;
2016-12-08 10:54:22 +00:00
currentRepeat = repeat ;
}
2017-02-09 07:29:21 +00:00
bouncer2 . Position = slider . Curve . PositionAt ( body . SnakedEnd ? ? 0 ) ;
2016-12-07 05:52:34 +00:00
//todo: we probably want to reconsider this before adding scoring, but it looks and feels nice.
if ( initialCircle . Judgement ? . Result ! = HitResult . Hit )
2017-02-09 07:29:21 +00:00
initialCircle . Position = slider . Curve . PositionAt ( progress ) ;
2016-12-06 15:02:27 +00:00
2017-02-16 08:02:36 +00:00
foreach ( var c in components ) c . UpdateProgress ( progress , repeat ) ;
foreach ( var t in ticks . Children ) t . Tracking = ball . Tracking ;
2016-12-03 13:40:35 +00:00
}
2016-11-29 12:40:24 +00:00
protected override void CheckJudgement ( bool userTriggered )
{
2017-03-13 10:15:25 +00:00
if ( ! userTriggered & & Time . Current > = slider . EndTime )
2016-11-29 12:40:24 +00:00
{
2017-02-12 19:38:05 +00:00
var ticksCount = ticks . Children . Count ( ) + 1 ;
var ticksHit = ticks . Children . Count ( t = > t . Judgement . Result = = HitResult . Hit ) ;
2017-03-15 09:58:41 +00:00
if ( initialCircle . Judgement . Result = = HitResult . Hit )
2017-02-12 19:38:05 +00:00
ticksHit + + ;
var hitFraction = ( double ) ticksHit / ticksCount ;
2017-03-15 09:58:41 +00:00
if ( hitFraction = = 1 & & initialCircle . Judgement . Score = = OsuScoreResult . Hit300 )
Judgement . Score = OsuScoreResult . Hit300 ;
else if ( hitFraction > = 0.5 & & initialCircle . Judgement . Score > = OsuScoreResult . Hit100 )
Judgement . Score = OsuScoreResult . Hit100 ;
2017-02-12 19:38:05 +00:00
else if ( hitFraction > 0 )
2017-03-15 09:58:41 +00:00
Judgement . Score = OsuScoreResult . Hit50 ;
2017-02-12 19:38:05 +00:00
else
2017-03-15 09:58:41 +00:00
Judgement . Score = OsuScoreResult . Miss ;
2017-02-12 19:38:05 +00:00
2017-03-15 09:58:41 +00:00
Judgement . Result = Judgement . Score ! = OsuScoreResult . Miss ? HitResult . Hit : HitResult . Miss ;
2016-11-29 12:40:24 +00:00
}
}
2016-12-06 15:02:27 +00:00
protected override void UpdateInitialState ( )
{
base . UpdateInitialState ( ) ;
body . Alpha = 1 ;
2016-12-08 12:07:20 +00:00
2017-02-05 08:40:58 +00:00
//we need to be present to handle input events. note that we still don't get enough events (we don't get a position if the mouse hasn't moved since the slider appeared).
ball . AlwaysPresent = true ;
ball . Alpha = 0 ;
2016-12-06 15:02:27 +00:00
}
2017-04-27 08:37:38 +00:00
protected override void UpdateCurrentState ( ArmedState state )
2016-11-17 08:20:51 +00:00
{
2016-12-08 12:07:20 +00:00
ball . FadeIn ( ) ;
2017-03-13 10:15:25 +00:00
Delay ( slider . Duration , true ) ;
2016-12-08 12:07:20 +00:00
2016-12-06 15:02:27 +00:00
body . FadeOut ( 160 ) ;
2016-12-08 12:07:20 +00:00
ball . FadeOut ( 160 ) ;
2016-12-06 15:02:27 +00:00
FadeOut ( 800 ) ;
2017-03-17 06:30:19 +00:00
Expire ( ) ;
2016-11-17 08:20:51 +00:00
}
2017-02-14 01:22:28 +00:00
public Drawable ProxiedLayer = > initialCircle . ApproachCircle ;
2016-12-06 09:54:32 +00:00
}
2016-11-28 08:05:30 +00:00
2016-12-06 09:54:32 +00:00
internal interface ISliderProgress
{
void UpdateProgress ( double progress , int repeat ) ;
2016-11-17 08:20:51 +00:00
}
2017-04-27 08:37:38 +00:00
}