2019-01-24 16:43:03 +08:00
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
2018-04-13 17:19:50 +08:00
2019-04-08 17:32:05 +08:00
using System.Collections.Generic ;
2020-11-20 16:28:06 +08:00
using System.Linq ;
2021-04-21 18:44:17 +08:00
using osu.Framework.Allocation ;
using osu.Framework.Bindables ;
2020-11-20 16:28:06 +08:00
using osu.Framework.Graphics ;
2017-11-30 18:19:34 +08:00
using osu.Game.Beatmaps ;
2021-04-21 18:44:17 +08:00
using osu.Game.Configuration ;
2019-04-08 17:32:05 +08:00
using osu.Game.Rulesets.Mods ;
2020-11-20 16:28:06 +08:00
using osu.Game.Rulesets.Objects.Drawables ;
using osu.Game.Rulesets.Osu.Objects.Drawables ;
2021-04-26 14:23:21 +08:00
using osu.Game.Rulesets.Osu.Skinning.Default ;
2017-11-30 18:19:34 +08:00
using osu.Game.Rulesets.Osu.UI ;
2018-09-21 14:08:43 +08:00
using osu.Game.Rulesets.UI ;
2018-11-20 15:51:59 +08:00
using osuTK ;
2018-04-13 17:19:50 +08:00
2017-11-30 18:19:34 +08:00
namespace osu.Game.Rulesets.Osu.Edit
{
2021-04-26 13:33:30 +08:00
public class DrawableOsuEditorRuleset : DrawableOsuRuleset
2017-11-30 18:19:34 +08:00
{
2021-06-18 20:57:04 +08:00
/// <summary>
/// Hit objects are intentionally made to fade out at a constant slower rate than in gameplay.
/// This allows a mapper to gain better historical context and use recent hitobjects as reference / snap points.
/// </summary>
public const double EDITOR_HIT_OBJECT_FADE_OUT_EXTENSION = 700 ;
2021-04-26 13:33:30 +08:00
public DrawableOsuEditorRuleset ( Ruleset ruleset , IBeatmap beatmap , IReadOnlyList < Mod > mods )
2019-04-08 17:32:05 +08:00
: base ( ruleset , beatmap , mods )
2017-11-30 18:19:34 +08:00
{
}
2018-04-13 17:19:50 +08:00
2021-04-26 13:33:30 +08:00
protected override Playfield CreatePlayfield ( ) = > new OsuEditorPlayfield ( ) ;
2019-03-31 00:29:37 +08:00
public override PlayfieldAdjustmentContainer CreatePlayfieldAdjustmentContainer ( ) = > new OsuPlayfieldAdjustmentContainer { Size = Vector2 . One } ;
2018-09-21 14:08:43 +08:00
2021-04-26 13:33:30 +08:00
private class OsuEditorPlayfield : OsuPlayfield
2019-03-06 11:34:58 +08:00
{
2021-04-21 18:44:17 +08:00
private Bindable < bool > hitAnimations ;
2019-03-26 12:39:19 +08:00
protected override GameplayCursorContainer CreateCursor ( ) = > null ;
2020-11-14 00:03:23 +08:00
2021-08-12 09:08:54 +08:00
public OsuEditorPlayfield ( )
{
HitPolicy = new AnyOrderHitPolicy ( ) ;
}
2021-04-21 18:44:17 +08:00
[BackgroundDependencyLoader]
private void load ( OsuConfigManager config )
{
hitAnimations = config . GetBindable < bool > ( OsuSetting . EditorHitAnimations ) ;
}
2020-11-21 14:20:33 +08:00
protected override void OnNewDrawableHitObject ( DrawableHitObject d )
2020-11-20 16:28:06 +08:00
{
2020-11-21 14:20:33 +08:00
d . ApplyCustomUpdateState + = updateState ;
2020-11-20 16:28:06 +08:00
}
private void updateState ( DrawableHitObject hitObject , ArmedState state )
{
2021-04-21 18:44:17 +08:00
if ( state = = ArmedState . Idle | | hitAnimations . Value )
2020-11-20 16:28:06 +08:00
return ;
2021-04-26 14:23:21 +08:00
if ( hitObject is DrawableHitCircle circle )
2020-11-20 16:28:06 +08:00
{
2021-08-18 13:27:05 +08:00
using ( circle . BeginAbsoluteSequence ( circle . HitStateUpdateTime ) )
{
circle . ApproachCircle
. FadeOutFromOne ( EDITOR_HIT_OBJECT_FADE_OUT_EXTENSION * 4 )
. Expire ( ) ;
2021-04-21 18:44:17 +08:00
2021-08-18 13:27:05 +08:00
circle . ApproachCircle . ScaleTo ( 1.1f , 300 , Easing . OutQuint ) ;
}
2021-04-26 14:23:21 +08:00
}
2021-04-21 18:44:17 +08:00
2021-04-26 14:23:21 +08:00
if ( hitObject is IHasMainCirclePiece mainPieceContainer )
{
// clear any explode animation logic.
2021-06-18 21:30:45 +08:00
// this is scheduled after children to ensure that the clear happens after invocations of ApplyCustomUpdateState on the circle piece's nested skinnables.
ScheduleAfterChildren ( ( ) = >
{
if ( hitObject . HitObject = = null ) return ;
2021-06-18 21:32:51 +08:00
mainPieceContainer . CirclePiece . ApplyTransformsAt ( hitObject . StateUpdateTime , true ) ;
mainPieceContainer . CirclePiece . ClearTransformsAfter ( hitObject . StateUpdateTime , true ) ;
2021-06-18 21:30:45 +08:00
} ) ;
2021-04-26 14:23:21 +08:00
}
2021-04-21 18:44:17 +08:00
2021-04-26 14:23:21 +08:00
if ( hitObject is DrawableSliderRepeat repeat )
{
2021-06-18 21:32:51 +08:00
repeat . Arrow . ApplyTransformsAt ( hitObject . StateUpdateTime , true ) ;
repeat . Arrow . ClearTransformsAfter ( hitObject . StateUpdateTime , true ) ;
2020-11-20 16:28:06 +08:00
}
2021-04-26 14:23:21 +08:00
// adjust the visuals of top-level object types to make them stay on screen for longer than usual.
switch ( hitObject )
{
case DrawableSlider _ :
case DrawableHitCircle _ :
// Get the existing fade out transform
var existing = hitObject . Transforms . LastOrDefault ( t = > t . TargetMember = = nameof ( Alpha ) ) ;
2020-11-20 16:28:06 +08:00
2021-04-26 14:23:21 +08:00
if ( existing = = null )
return ;
2020-11-20 16:28:06 +08:00
2021-04-26 14:23:21 +08:00
hitObject . RemoveTransform ( existing ) ;
2020-11-20 16:28:06 +08:00
2021-04-26 14:23:21 +08:00
using ( hitObject . BeginAbsoluteSequence ( hitObject . HitStateUpdateTime ) )
2021-06-18 20:57:04 +08:00
hitObject . FadeOut ( EDITOR_HIT_OBJECT_FADE_OUT_EXTENSION ) . Expire ( ) ;
2021-04-26 14:23:21 +08:00
break ;
}
2020-11-20 16:28:06 +08:00
}
2019-03-06 11:34:58 +08:00
}
2017-11-30 18:19:34 +08:00
}
}