2017-02-07 12:59:30 +08: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 20:56:35 +08:00
using System.Collections.Generic ;
2016-11-28 15:52:57 +08:00
using osu.Framework.Graphics ;
2016-11-17 20:29:35 +08:00
using osu.Game.Modes.Objects.Drawables ;
2016-12-06 17:54:32 +08:00
using osu.Game.Modes.Osu.Objects.Drawables.Pieces ;
2016-11-17 20:29:35 +08:00
using OpenTK ;
2016-12-08 20:07:20 +08:00
using osu.Framework.Input ;
2016-11-17 16:20:51 +08:00
namespace osu.Game.Modes.Osu.Objects.Drawables
{
2016-11-26 15:51:51 +08:00
class DrawableSlider : DrawableOsuHitObject
2016-11-17 16:20:51 +08:00
{
2016-11-28 11:40:24 +08:00
private Slider slider ;
2016-11-28 16:05:30 +08:00
2016-12-06 23:02:27 +08:00
private DrawableHitCircle initialCircle ;
2016-12-06 17:54:32 +08:00
private List < ISliderProgress > components = new List < ISliderProgress > ( ) ;
2016-11-28 11:40:24 +08:00
2016-12-06 23:02:27 +08:00
SliderBody body ;
2016-12-08 18:54:22 +08:00
SliderBall ball ;
2016-12-06 23:02:27 +08:00
SliderBouncer bouncer1 , bouncer2 ;
2016-11-28 11:15:25 +08:00
public DrawableSlider ( Slider s ) : base ( s )
2016-11-17 16:20:51 +08:00
{
2016-11-28 11:40:24 +08:00
slider = s ;
2016-11-27 22:36:31 +08:00
2016-11-28 11:40:24 +08:00
Children = new Drawable [ ]
2016-11-28 11:15:25 +08:00
{
2016-12-06 17:54:32 +08:00
body = new SliderBody ( s )
2016-11-29 02:04:03 +08:00
{
2017-02-09 15:29:21 +08:00
Position = s . StackedPosition ,
2017-02-06 21:17:29 +08:00
PathWidth = s . Scale * 64 ,
2016-12-11 17:11:22 +08:00
} ,
bouncer1 = new SliderBouncer ( s , false )
{
Position = s . Curve . PositionAt ( 1 ) ,
Scale = new Vector2 ( s . Scale ) ,
} ,
bouncer2 = new SliderBouncer ( s , true )
{
2017-02-09 15:29:21 +08:00
Position = s . StackedPosition ,
2016-12-11 17:11:22 +08:00
Scale = new Vector2 ( s . Scale ) ,
} ,
ball = new SliderBall ( s )
{
Scale = new Vector2 ( s . Scale ) ,
2016-11-29 02:04:03 +08:00
} ,
2016-12-06 23:02:27 +08:00
initialCircle = new DrawableHitCircle ( new HitCircle
2016-11-28 11:40:24 +08:00
{
StartTime = s . StartTime ,
2017-02-09 15:29:21 +08:00
Position = s . StackedPosition ,
2016-12-11 17:11:22 +08:00
Scale = s . Scale ,
2016-11-28 11:40:24 +08:00
Colour = s . Colour ,
2016-12-08 18:54:22 +08:00
Sample = s . Sample ,
2016-12-08 20:07:20 +08:00
} ) ,
2016-11-28 11:40:24 +08:00
} ;
2016-11-17 20:29:35 +08:00
2016-12-06 17:54:32 +08:00
components . Add ( body ) ;
components . Add ( ball ) ;
2016-12-06 23:02:27 +08:00
components . Add ( bouncer1 ) ;
components . Add ( bouncer2 ) ;
2016-12-03 20:56:19 +08:00
}
2016-12-11 17:11:22 +08:00
// Since the DrawableSlider itself is just a container without a size we need to
// pass all input through.
public override bool Contains ( Vector2 screenSpacePos ) = > true ;
2016-12-08 18:54:22 +08:00
int currentRepeat ;
2016-12-06 17:54:32 +08:00
protected override void Update ( )
2016-11-17 20:29:35 +08:00
{
2016-12-06 17:54:32 +08:00
base . Update ( ) ;
2016-11-17 16:20:51 +08:00
2016-12-06 17:54:32 +08:00
double progress = MathHelper . Clamp ( ( Time . Current - slider . StartTime ) / slider . Duration , 0 , 1 ) ;
2016-11-28 15:31:19 +08:00
2016-12-06 17:54:32 +08:00
int repeat = ( int ) ( progress * slider . RepeatCount ) ;
2016-12-03 21:40:35 +08:00
progress = ( progress * slider . RepeatCount ) % 1 ;
2016-11-28 15:31:19 +08:00
2016-12-08 18:54:22 +08:00
if ( repeat > currentRepeat )
{
if ( ball . Tracking )
PlaySample ( ) ;
currentRepeat = repeat ;
}
2016-12-03 21:40:35 +08:00
if ( repeat % 2 = = 1 )
progress = 1 - progress ;
2016-12-03 20:25:31 +08:00
2017-02-09 15:29:21 +08:00
bouncer2 . Position = slider . Curve . PositionAt ( body . SnakedEnd ? ? 0 ) ;
2016-12-07 13:52:34 +08: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 15:29:21 +08:00
initialCircle . Position = slider . Curve . PositionAt ( progress ) ;
2016-12-06 23:02:27 +08:00
2016-12-06 17:54:32 +08:00
components . ForEach ( c = > c . UpdateProgress ( progress , repeat ) ) ;
2016-12-03 21:40:35 +08:00
}
2016-11-29 20:40:24 +08:00
protected override void CheckJudgement ( bool userTriggered )
{
var j = Judgement as OsuJudgementInfo ;
2016-12-06 23:02:27 +08:00
var sc = initialCircle . Judgement as OsuJudgementInfo ;
2016-11-29 20:40:24 +08:00
if ( ! userTriggered & & Time . Current > = HitObject . EndTime )
{
j . Score = sc . Score ;
j . Result = sc . Result ;
}
}
2016-12-06 23:02:27 +08:00
protected override void UpdateInitialState ( )
{
base . UpdateInitialState ( ) ;
body . Alpha = 1 ;
2016-12-08 20:07:20 +08:00
2017-02-05 16:40:58 +08: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 23:02:27 +08:00
}
2016-11-17 16:20:51 +08:00
protected override void UpdateState ( ArmedState state )
{
2016-11-28 17:40:54 +08:00
base . UpdateState ( state ) ;
2016-11-17 20:29:35 +08:00
2016-12-08 20:07:20 +08:00
ball . FadeIn ( ) ;
2016-12-06 23:02:27 +08:00
Delay ( HitObject . Duration , true ) ;
2016-12-08 20:07:20 +08:00
2016-12-06 23:02:27 +08:00
body . FadeOut ( 160 ) ;
2016-12-08 20:07:20 +08:00
ball . FadeOut ( 160 ) ;
2016-12-06 23:02:27 +08:00
FadeOut ( 800 ) ;
2016-11-17 16:20:51 +08:00
}
2016-12-06 17:54:32 +08:00
}
2016-11-28 16:05:30 +08:00
2016-12-06 17:54:32 +08:00
internal interface ISliderProgress
{
void UpdateProgress ( double progress , int repeat ) ;
2016-11-17 16:20:51 +08:00
}
2016-12-06 17:54:32 +08:00
}