2019-07-24 17:50:57 +08:00
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
2019-01-24 16:43:03 +08:00
// 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-03-10 14:30:24 +08:00
using System ;
2023-09-29 17:23:22 +08:00
using System.Collections.Generic ;
using System.Linq ;
2020-11-05 12:51:46 +08:00
using osu.Framework.Allocation ;
using osu.Framework.Bindables ;
2018-04-13 17:19:50 +08:00
using osu.Framework.Graphics ;
2022-04-18 12:57:13 +08:00
using osu.Framework.Graphics.Primitives ;
2018-08-02 19:36:38 +08:00
using osu.Game.Rulesets.Judgements ;
2022-09-22 13:30:01 +08:00
using osu.Game.Rulesets.Objects.Drawables ;
2018-08-02 19:36:38 +08:00
using osu.Game.Rulesets.Osu.Judgements ;
2022-10-05 13:25:04 +08:00
using osu.Game.Rulesets.Osu.Scoring ;
2023-07-18 11:31:21 +08:00
using osu.Game.Rulesets.Osu.UI ;
2023-08-23 19:12:18 +08:00
using osu.Game.Rulesets.Scoring ;
2020-11-05 12:51:46 +08:00
using osuTK ;
2022-10-04 16:28:15 +08:00
using osuTK.Graphics ;
2018-04-13 17:19:50 +08:00
namespace osu.Game.Rulesets.Osu.Objects.Drawables
{
2022-11-24 13:32:20 +08:00
public abstract partial class DrawableOsuHitObject : DrawableHitObject < OsuHitObject >
2018-04-13 17:19:50 +08:00
{
2020-11-05 12:51:46 +08:00
public readonly IBindable < Vector2 > PositionBindable = new Bindable < Vector2 > ( ) ;
public readonly IBindable < int > StackHeightBindable = new Bindable < int > ( ) ;
public readonly IBindable < float > ScaleBindable = new BindableFloat ( ) ;
public readonly IBindable < int > IndexInCurrentComboBindable = new Bindable < int > ( ) ;
2018-07-05 21:48:54 +08:00
2022-04-08 14:20:22 +08:00
// Must be set to update IsHovered as it's used in relax mod to detect osu hit objects.
2019-06-30 23:27:47 +08:00
public override bool HandlePositionalInput = > true ;
2022-04-18 14:18:56 +08:00
protected override float SamplePlaybackPosition = > CalculateDrawableRelativePosition ( this ) ;
2020-04-12 07:33:25 +08:00
2020-03-10 14:30:24 +08:00
/// <summary>
2023-07-18 11:31:21 +08:00
/// What action this <see cref="DrawableOsuHitObject"/> should take in response to a
/// click at the given time value.
/// If non-null, judgements will be ignored for return values of <see cref="ClickAction.Ignore"/>
/// and <see cref="ClickAction.Shake"/>, and this hit object will be shaken for return values of
/// <see cref="ClickAction.Shake"/>.
2020-03-10 14:30:24 +08:00
/// </summary>
2023-08-23 19:12:18 +08:00
public Func < DrawableHitObject , double , HitResult , ClickAction > CheckHittable ;
2020-03-10 14:30:24 +08:00
2018-04-13 17:19:50 +08:00
protected DrawableOsuHitObject ( OsuHitObject hitObject )
: base ( hitObject )
{
2020-11-05 12:51:46 +08:00
}
[BackgroundDependencyLoader]
private void load ( )
{
Alpha = 0 ;
2020-11-06 22:09:23 +08:00
}
2020-11-27 09:13:05 +08:00
protected override void OnApply ( )
2020-11-06 22:09:23 +08:00
{
2020-11-27 09:13:05 +08:00
base . OnApply ( ) ;
2019-07-16 12:45:59 +08:00
2020-11-05 12:51:46 +08:00
IndexInCurrentComboBindable . BindTo ( HitObject . IndexInCurrentComboBindable ) ;
PositionBindable . BindTo ( HitObject . PositionBindable ) ;
StackHeightBindable . BindTo ( HitObject . StackHeightBindable ) ;
ScaleBindable . BindTo ( HitObject . ScaleBindable ) ;
2018-04-13 17:19:50 +08:00
}
2020-11-27 09:13:05 +08:00
protected override void OnFree ( )
2020-11-06 23:40:26 +08:00
{
2020-11-27 09:13:05 +08:00
base . OnFree ( ) ;
2020-11-06 23:40:26 +08:00
IndexInCurrentComboBindable . UnbindFrom ( HitObject . IndexInCurrentComboBindable ) ;
PositionBindable . UnbindFrom ( HitObject . PositionBindable ) ;
StackHeightBindable . UnbindFrom ( HitObject . StackHeightBindable ) ;
ScaleBindable . UnbindFrom ( HitObject . ScaleBindable ) ;
}
2023-09-29 17:23:22 +08:00
protected virtual IEnumerable < Drawable > DimmablePieces = > Enumerable . Empty < Drawable > ( ) ;
2022-10-04 16:28:15 +08:00
protected override void UpdateInitialTransforms ( )
{
base . UpdateInitialTransforms ( ) ;
2023-09-29 17:23:22 +08:00
foreach ( var piece in DimmablePieces )
2024-02-27 18:45:03 +08:00
{
// if the specified dimmable piece is a DHO, it is generally not safe to tack transforms onto it directly
// as they may be cleared via the `updateState()` DHO flow,
// so use `ApplyCustomUpdateState` instead. which does not have this pitfall.
if ( piece is DrawableHitObject drawableObjectPiece )
2024-02-28 20:20:41 +08:00
{
// this method can be called multiple times, and we don't want to subscribe to the event more than once,
// so this is what it is going to have to be...
drawableObjectPiece . ApplyCustomUpdateState - = applyDimToDrawableHitObject ;
drawableObjectPiece . ApplyCustomUpdateState + = applyDimToDrawableHitObject ;
}
2024-02-27 18:45:03 +08:00
else
applyDim ( piece ) ;
}
void applyDim ( Drawable piece )
2022-10-05 16:48:56 +08:00
{
2023-09-29 17:23:22 +08:00
piece . FadeColour ( new Color4 ( 195 , 195 , 195 , 255 ) ) ;
using ( piece . BeginDelayedSequence ( InitialLifetimeOffset - OsuHitWindows . MISS_WINDOW ) )
piece . FadeColour ( Color4 . White , 100 ) ;
2022-10-05 16:48:56 +08:00
}
2024-02-28 20:20:41 +08:00
void applyDimToDrawableHitObject ( DrawableHitObject dho , ArmedState _ ) = > applyDim ( dho ) ;
2022-10-04 16:28:15 +08:00
}
2019-07-22 14:05:56 +08:00
protected sealed override double InitialLifetimeOffset = > HitObject . TimePreempt ;
2018-08-02 19:36:38 +08:00
2018-04-13 17:19:50 +08:00
private OsuInputManager osuActionInputManager ;
2019-11-12 18:35:08 +08:00
internal OsuInputManager OsuActionInputManager = > osuActionInputManager ? ? = GetContainingInputManager ( ) as OsuInputManager ;
2018-06-28 21:33:59 +08:00
2022-09-22 13:30:01 +08:00
/// <summary>
/// Shake the hit object in case it was clicked far too early or late (aka "note lock").
/// </summary>
public virtual void Shake ( ) { }
2018-04-13 17:19:50 +08:00
2020-03-19 18:16:24 +08:00
/// <summary>
2023-12-15 15:13:32 +08:00
/// Causes this <see cref="DrawableOsuHitObject"/> to get hit, disregarding all conditions in implementations of <see cref="DrawableHitObject.CheckForResult"/>.
/// </summary>
2024-02-05 20:21:01 +08:00
public void HitForcefully ( ) = > ApplyMaxResult ( ) ;
2023-12-15 15:13:32 +08:00
/// <summary>
2020-03-19 18:16:24 +08:00
/// Causes this <see cref="DrawableOsuHitObject"/> to get missed, disregarding all conditions in implementations of <see cref="DrawableHitObject.CheckForResult"/>.
/// </summary>
2024-02-05 20:21:01 +08:00
public void MissForcefully ( ) = > ApplyMinResult ( ) ;
2020-03-19 18:16:24 +08:00
2023-10-17 16:40:44 +08:00
private RectangleF parentScreenSpaceRectangle = > ( ( DrawableOsuHitObject ) ParentHitObject ) ? . parentScreenSpaceRectangle ? ? Parent ! . ScreenSpaceDrawQuad . AABBFloat ;
2022-04-18 14:18:56 +08:00
/// <summary>
/// Calculates the position of the given <paramref name="drawable"/> relative to the playfield area.
/// </summary>
/// <param name="drawable">The drawable to calculate its relative position.</param>
protected float CalculateDrawableRelativePosition ( Drawable drawable ) = > ( drawable . ScreenSpaceDrawQuad . Centre . X - parentScreenSpaceRectangle . X ) / parentScreenSpaceRectangle . Width ;
2019-09-02 16:14:40 +08:00
protected override JudgementResult CreateResult ( Judgement judgement ) = > new OsuJudgementResult ( HitObject , judgement ) ;
2018-04-13 17:19:50 +08:00
}
}