2018-01-10 17:02:49 +08:00
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
2017-08-07 17:03:44 +08:00
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
2018-01-08 10:34:37 +08:00
using osu.Framework.Allocation ;
2017-08-07 17:03:44 +08:00
using osu.Framework.Configuration ;
using osu.Framework.Graphics ;
using osu.Framework.Graphics.Transforms ;
using osu.Framework.Input ;
using osu.Framework.MathUtils ;
using osu.Game.Rulesets.Objects.Drawables ;
2018-01-04 18:22:15 +08:00
using OpenTK.Input ;
2017-08-07 17:03:44 +08:00
2018-01-04 18:22:15 +08:00
namespace osu.Game.Rulesets.UI.Scrolling
2017-08-07 17:03:44 +08:00
{
/// <summary>
2017-09-12 18:05:37 +08:00
/// A type of <see cref="Playfield"/> specialized towards scrolling <see cref="DrawableHitObject"/>s.
2017-08-07 17:03:44 +08:00
/// </summary>
2018-01-07 11:47:09 +08:00
public abstract class ScrollingPlayfield : Playfield
2017-08-07 17:03:44 +08:00
{
/// <summary>
/// The default span of time visible by the length of the scrolling axes.
/// This is clamped between <see cref="time_span_min"/> and <see cref="time_span_max"/>.
/// </summary>
private const double time_span_default = 1500 ;
/// <summary>
/// The minimum span of time that may be visible by the length of the scrolling axes.
/// </summary>
private const double time_span_min = 50 ;
/// <summary>
/// The maximum span of time that may be visible by the length of the scrolling axes.
/// </summary>
private const double time_span_max = 10000 ;
/// <summary>
/// The step increase/decrease of the span of time visible by the length of the scrolling axes.
/// </summary>
private const double time_span_step = 50 ;
/// <summary>
2017-08-08 11:59:50 +08:00
/// The span of time that is visible by the length of the scrolling axes.
2017-08-07 17:03:44 +08:00
/// For example, only hit objects with start time less than or equal to 1000 will be visible with <see cref="VisibleTimeRange"/> = 1000.
/// </summary>
2017-08-08 11:59:50 +08:00
public readonly BindableDouble VisibleTimeRange = new BindableDouble ( time_span_default )
2017-08-07 17:03:44 +08:00
{
Default = time_span_default ,
MinValue = time_span_min ,
MaxValue = time_span_max
} ;
2018-01-11 11:44:17 +08:00
/// <summary>
/// Whether the player can change <see cref="VisibleTimeRange"/>.
/// </summary>
protected virtual bool UserScrollSpeedAdjustment = > true ;
2017-08-07 17:03:44 +08:00
/// <summary>
2018-02-08 22:47:03 +08:00
/// The container that contains the <see cref="DrawableHitObject"/>s.
2017-08-07 17:03:44 +08:00
/// </summary>
2018-01-07 11:47:09 +08:00
public new ScrollingHitObjectContainer HitObjects = > ( ScrollingHitObjectContainer ) base . HitObjects ;
private readonly ScrollingDirection direction ;
2017-08-07 17:03:44 +08:00
/// <summary>
2017-09-12 18:05:37 +08:00
/// Creates a new <see cref="ScrollingPlayfield"/>.
2017-08-07 17:03:44 +08:00
/// </summary>
2018-02-08 22:47:03 +08:00
/// <param name="direction">The direction in which <see cref="DrawableHitObject"/>s in this container should scroll.</param>
2018-02-20 12:50:31 +08:00
/// <param name="customWidth">The width to scale the internal coordinate space to.
/// May be null if scaling based on <paramref name="customHeight"/> is desired. If <paramref name="customHeight"/> is also null, no scaling will occur.
/// </param>
/// <param name="customHeight">The height to scale the internal coordinate space to.
/// May be null if scaling based on <paramref name="customWidth"/> is desired. If <paramref name="customWidth"/> is also null, no scaling will occur.
/// </param>
protected ScrollingPlayfield ( ScrollingDirection direction , float? customWidth = null , float? customHeight = null )
: base ( customWidth , customHeight )
2017-08-07 17:03:44 +08:00
{
2018-01-07 11:47:09 +08:00
this . direction = direction ;
2018-01-08 10:34:37 +08:00
}
[BackgroundDependencyLoader]
private void load ( )
{
2018-01-04 17:50:17 +08:00
HitObjects . TimeRange . BindTo ( VisibleTimeRange ) ;
2017-08-07 17:03:44 +08:00
}
protected override bool OnKeyDown ( InputState state , KeyDownEventArgs args )
{
2018-01-11 11:44:17 +08:00
if ( ! UserScrollSpeedAdjustment )
return false ;
2017-08-07 17:03:44 +08:00
if ( state . Keyboard . ControlPressed )
{
switch ( args . Key )
{
case Key . Minus :
2018-01-11 12:40:46 +08:00
transformVisibleTimeRangeTo ( VisibleTimeRange + time_span_step , 200 , Easing . OutQuint ) ;
2017-08-07 17:03:44 +08:00
break ;
case Key . Plus :
2018-01-11 12:40:46 +08:00
transformVisibleTimeRangeTo ( VisibleTimeRange - time_span_step , 200 , Easing . OutQuint ) ;
2017-08-07 17:03:44 +08:00
break ;
}
}
return false ;
}
private void transformVisibleTimeRangeTo ( double newTimeRange , double duration = 0 , Easing easing = Easing . None )
{
this . TransformTo ( this . PopulateTransform ( new TransformVisibleTimeRange ( ) , newTimeRange , duration , easing ) ) ;
}
2018-01-08 10:34:37 +08:00
protected sealed override HitObjectContainer CreateHitObjectContainer ( ) = > new ScrollingHitObjectContainer ( direction ) ;
2018-01-07 11:47:09 +08:00
2017-09-12 17:19:28 +08:00
private class TransformVisibleTimeRange : Transform < double , ScrollingPlayfield >
2017-08-07 17:03:44 +08:00
{
private double valueAt ( double time )
{
if ( time < StartTime ) return StartValue ;
if ( time > = EndTime ) return EndValue ;
return Interpolation . ValueAt ( time , StartValue , EndValue , StartTime , EndTime , Easing ) ;
}
public override string TargetMember = > "VisibleTimeRange.Value" ;
2017-09-12 17:19:28 +08:00
protected override void Apply ( ScrollingPlayfield d , double time ) = > d . VisibleTimeRange . Value = valueAt ( time ) ;
protected override void ReadIntoStartValue ( ScrollingPlayfield d ) = > StartValue = d . VisibleTimeRange . Value ;
2017-08-07 17:03:44 +08:00
}
}
2017-08-21 15:14:44 +08:00
}