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
2022-06-17 15:37:17 +08:00
#nullable disable
2020-10-02 12:41:22 +08:00
using System.Diagnostics ;
2020-12-03 13:28:37 +08:00
using JetBrains.Annotations ;
2020-10-02 12:41:22 +08:00
using osu.Framework.Allocation ;
2018-01-30 15:24:23 +08:00
using osu.Framework.Graphics ;
2020-10-02 12:41:22 +08:00
using osu.Framework.Graphics.Containers ;
2024-06-26 22:26:32 +08:00
using osu.Framework.Utils ;
2020-10-02 12:41:22 +08:00
using osu.Game.Rulesets.Objects.Drawables ;
2021-05-27 04:21:05 +08:00
using osu.Game.Rulesets.Objects.Types ;
2020-10-02 12:41:22 +08:00
using osu.Game.Skinning ;
2018-11-20 15:51:59 +08:00
using osuTK ;
2024-06-19 19:18:56 +08:00
using osuTK.Graphics ;
2018-04-13 17:19:50 +08:00
2018-01-30 15:24:23 +08:00
namespace osu.Game.Rulesets.Osu.Objects.Drawables
{
2023-12-15 15:13:32 +08:00
public partial class DrawableSliderTail : DrawableOsuHitObject
2018-01-30 15:24:23 +08:00
{
2020-11-12 14:59:48 +08:00
public new SliderTailCircle HitObject = > ( SliderTailCircle ) base . HitObject ;
2018-10-29 14:36:43 +08:00
2020-12-03 13:28:37 +08:00
[CanBeNull]
2020-12-03 19:10:16 +08:00
public Slider Slider = > DrawableSlider ? . HitObject ;
protected DrawableSlider DrawableSlider = > ( DrawableSlider ) ParentHitObject ;
2020-12-03 13:28:37 +08:00
2021-04-02 15:54:35 +08:00
/// <summary>
2021-04-02 17:00:28 +08:00
/// Whether the hit samples only play on successful hits.
/// If <c>false</c>, the hit samples will also play on misses.
2021-04-02 15:54:35 +08:00
/// </summary>
2021-04-02 16:56:23 +08:00
public bool SamplePlaysOnlyOnHit { get ; set ; } = true ;
2021-04-02 15:54:35 +08:00
2021-04-26 14:22:17 +08:00
public SkinnableDrawable CirclePiece { get ; private set ; }
2020-11-05 12:51:46 +08:00
private Container scaleContainer ;
2020-10-02 12:41:22 +08:00
2020-11-12 14:59:48 +08:00
public DrawableSliderTail ( )
: base ( null )
{
}
2020-11-05 12:51:46 +08:00
public DrawableSliderTail ( SliderTailCircle tailCircle )
2020-10-02 13:20:55 +08:00
: base ( tailCircle )
2018-01-30 15:24:23 +08:00
{
2020-11-05 12:51:46 +08:00
}
2018-04-13 17:19:50 +08:00
2020-11-05 12:51:46 +08:00
[BackgroundDependencyLoader]
private void load ( )
{
Origin = Anchor . Centre ;
2023-09-20 11:48:15 +08:00
Size = OsuHitObject . OBJECT_DIMENSIONS ;
2018-04-13 17:19:50 +08:00
2022-09-22 13:46:37 +08:00
AddRangeInternal ( new Drawable [ ]
2020-10-02 12:41:22 +08:00
{
scaleContainer = new Container
{
RelativeSizeAxes = Axes . Both ,
Origin = Anchor . Centre ,
Anchor = Anchor . Centre ,
Children = new Drawable [ ]
{
// no default for this; only visible in legacy skins.
2022-11-09 15:04:56 +08:00
CirclePiece = new SkinnableDrawable ( new OsuSkinComponentLookup ( OsuSkinComponents . SliderTailHitCircle ) , _ = > Empty ( ) )
2020-10-02 12:41:22 +08:00
}
} ,
2022-09-22 13:46:37 +08:00
} ) ;
2018-04-13 17:19:50 +08:00
2020-11-12 14:59:48 +08:00
ScaleBindable . BindValueChanged ( scale = > scaleContainer . Scale = new Vector2 ( scale . NewValue ) ) ;
2020-10-02 12:41:22 +08:00
}
2018-11-14 13:29:22 +08:00
2022-03-14 16:08:26 +08:00
protected override void LoadSamples ( )
{
// Tail models don't actually get samples, as the playback is handled by DrawableSlider.
// This override is only here for visibility in explaining this weird flow.
}
public override void PlaySamples ( )
{
// Tail models don't actually get samples, as the playback is handled by DrawableSlider.
// This override is only here for visibility in explaining this weird flow.
}
2020-10-02 12:41:22 +08:00
protected override void UpdateInitialTransforms ( )
{
base . UpdateInitialTransforms ( ) ;
2019-10-08 16:56:56 +08:00
2023-05-02 15:27:17 +08:00
// When snaking in is enabled, the first end circle needs to be delayed until the snaking completes.
2023-05-02 15:36:43 +08:00
bool delayFadeIn = DrawableSlider . SliderBody ? . SnakingIn . Value = = true & & HitObject . RepeatIndex = = 0 ;
2023-05-02 15:27:17 +08:00
CirclePiece
. FadeOut ( )
2023-05-02 15:36:43 +08:00
. Delay ( delayFadeIn ? ( Slider ? . TimePreempt ? ? 0 ) / 3 : 0 )
2023-05-02 15:27:17 +08:00
. FadeIn ( HitObject . TimeFadeIn ) ;
2020-10-02 12:41:22 +08:00
}
2020-11-04 15:19:07 +08:00
protected override void UpdateHitStateTransforms ( ArmedState state )
2020-10-02 12:41:22 +08:00
{
2020-11-04 15:19:07 +08:00
base . UpdateHitStateTransforms ( state ) ;
2020-10-02 12:41:22 +08:00
Debug . Assert ( HitObject . HitWindows ! = null ) ;
switch ( state )
{
case ArmedState . Idle :
this . Delay ( HitObject . TimePreempt ) . FadeOut ( 500 ) ;
break ;
case ArmedState . Miss :
this . FadeOut ( 100 ) ;
break ;
case ArmedState . Hit :
// todo: temporary / arbitrary
this . Delay ( 800 ) . FadeOut ( ) ;
break ;
}
2018-01-30 15:24:23 +08:00
}
2018-04-13 17:19:50 +08:00
2023-12-15 15:13:32 +08:00
protected override void CheckForResult ( bool userTriggered , double timeOffset ) = > DrawableSlider . SliderInputManager . TryJudgeNestedObject ( this , timeOffset ) ;
2018-10-29 14:36:43 +08:00
2021-05-27 04:21:05 +08:00
protected override void OnApply ( )
{
base . OnApply ( ) ;
if ( Slider ! = null )
Position = Slider . CurvePositionAt ( HitObject . RepeatIndex % 2 = = 0 ? 1 : 0 ) ;
}
2024-06-19 19:18:56 +08:00
#region FOR EDITOR USE ONLY , DO NOT USE FOR ANY OTHER PURPOSE
internal void SuppressHitAnimations ( )
{
2024-06-26 22:26:32 +08:00
UpdateState ( ArmedState . Idle ) ;
2024-06-19 19:18:56 +08:00
UpdateComboColour ( ) ;
2024-06-26 22:26:32 +08:00
// This method is called every frame in editor contexts, thus the lack of need for transforms.
2024-06-19 19:18:56 +08:00
2024-06-26 22:26:32 +08:00
if ( Time . Current > = HitStateUpdateTime )
{
// More or less matches stable (see https://github.com/peppy/osu-stable-reference/blob/bb57924c1552adbed11ee3d96cdcde47cf96f2b6/osu!/GameplayElements/HitObjects/Osu/HitCircleOsu.cs#L336-L338)
AccentColour . Value = Color4 . White ;
Alpha = Interpolation . ValueAt ( Time . Current , 1f , 0f , HitStateUpdateTime , HitStateUpdateTime + 700 ) ;
}
LifetimeEnd = HitStateUpdateTime + 700 ;
2024-06-19 19:18:56 +08:00
}
internal void RestoreHitAnimations ( )
{
UpdateState ( ArmedState . Hit ) ;
UpdateComboColour ( ) ;
}
#endregion
2018-01-30 15:24:23 +08:00
}
}