2020-03-18 05:32:07 +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.
using System ;
using osu.Framework.Allocation ;
2020-03-30 18:59:39 +08:00
using osu.Framework.Bindables ;
2020-04-09 13:33:11 +08:00
using osu.Framework.Extensions.Color4Extensions ;
2020-03-18 05:32:07 +08:00
using osu.Framework.Graphics ;
2020-04-09 13:33:11 +08:00
using osu.Framework.Graphics.Colour ;
using osu.Framework.Graphics.Containers ;
2020-03-18 05:32:07 +08:00
using osu.Framework.Graphics.Shapes ;
2020-03-26 19:14:44 +08:00
using osu.Framework.Utils ;
2020-03-30 18:59:39 +08:00
using osu.Game.Configuration ;
2020-03-18 05:32:07 +08:00
using osu.Game.Graphics ;
2020-04-09 13:31:25 +08:00
using osu.Game.Rulesets.Scoring ;
2020-04-09 13:33:11 +08:00
using osuTK.Graphics ;
2020-03-18 05:32:07 +08:00
namespace osu.Game.Screens.Play.HUD
{
/// <summary>
2020-03-19 04:16:54 +08:00
/// An overlay layer on top of the playfield which fades to red when the current player health falls below a certain threshold defined by <see cref="LowHealthThreshold"/>.
2020-03-18 05:32:07 +08:00
/// </summary>
2020-03-19 04:16:54 +08:00
public class FailingLayer : HealthDisplay
2020-03-18 05:32:07 +08:00
{
private const float max_alpha = 0.4f ;
2020-03-26 19:14:44 +08:00
private const int fade_time = 400 ;
2020-04-14 14:09:31 +08:00
private const float gradient_size = 0.3f ;
2020-03-30 18:59:39 +08:00
2020-03-18 05:32:07 +08:00
/// <summary>
/// The threshold under which the current player life should be considered low and the layer should start fading in.
/// </summary>
2020-03-19 04:41:43 +08:00
public double LowHealthThreshold = 0.20f ;
2020-03-18 05:32:07 +08:00
2020-06-27 01:03:41 +08:00
public readonly Bindable < bool > ShowHealth = new Bindable < bool > ( ) ;
private readonly Bindable < bool > fadePlayfieldWhenHealthLow = new Bindable < bool > ( ) ;
2020-04-09 13:33:11 +08:00
private readonly Container boxes ;
2020-04-14 14:09:31 +08:00
2020-06-27 01:03:41 +08:00
private Bindable < bool > fadePlayfieldWhenHealthLowSetting ;
2020-04-14 14:07:32 +08:00
private HealthProcessor healthProcessor ;
2020-04-09 13:33:11 +08:00
2020-03-19 04:16:54 +08:00
public FailingLayer ( )
2020-03-18 05:32:07 +08:00
{
2020-03-18 05:57:47 +08:00
RelativeSizeAxes = Axes . Both ;
2020-04-09 13:33:11 +08:00
Children = new Drawable [ ]
2020-03-18 05:32:07 +08:00
{
2020-04-09 13:33:11 +08:00
boxes = new Container
{
2020-04-09 13:49:09 +08:00
Alpha = 0 ,
2020-04-09 13:33:11 +08:00
Blending = BlendingParameters . Additive ,
RelativeSizeAxes = Axes . Both ,
Children = new Drawable [ ]
{
new Box
{
RelativeSizeAxes = Axes . Both ,
Colour = ColourInfo . GradientVertical ( Color4 . White , Color4 . White . Opacity ( 0 ) ) ,
2020-04-09 13:55:02 +08:00
Height = gradient_size ,
2020-04-09 13:33:11 +08:00
} ,
new Box
{
RelativeSizeAxes = Axes . Both ,
2020-04-09 13:55:02 +08:00
Height = gradient_size ,
2020-04-09 13:33:11 +08:00
Colour = ColourInfo . GradientVertical ( Color4 . White . Opacity ( 0 ) , Color4 . White ) ,
Anchor = Anchor . BottomLeft ,
Origin = Anchor . BottomLeft ,
} ,
}
} ,
2020-03-18 05:32:07 +08:00
} ;
}
[BackgroundDependencyLoader]
2020-03-30 18:59:39 +08:00
private void load ( OsuColour color , OsuConfigManager config )
2020-03-18 05:32:07 +08:00
{
2020-04-09 13:33:11 +08:00
boxes . Colour = color . Red ;
2020-06-27 01:03:41 +08:00
fadePlayfieldWhenHealthLowSetting = config . GetBindable < bool > ( OsuSetting . FadePlayfieldWhenHealthLow ) ;
fadePlayfieldWhenHealthLow . BindValueChanged ( e = > TryToFade ( fade_time , Easing . OutQuint , e . NewValue ) , true ) ;
ShowHealth . BindValueChanged ( e = > TryToFade ( fade_time , Easing . OutQuint , e . NewValue ) , true ) ;
2020-04-14 14:52:38 +08:00
}
2020-04-14 14:07:32 +08:00
2020-04-14 14:52:38 +08:00
protected override void LoadComplete ( )
{
base . LoadComplete ( ) ;
2020-04-14 14:07:32 +08:00
updateBindings ( ) ;
2020-03-18 05:32:07 +08:00
}
2020-04-09 13:31:25 +08:00
public override void BindHealthProcessor ( HealthProcessor processor )
{
base . BindHealthProcessor ( processor ) ;
2020-04-14 14:07:32 +08:00
healthProcessor = processor ;
updateBindings ( ) ;
}
private void updateBindings ( )
{
2020-04-14 14:52:38 +08:00
if ( LoadState < LoadState . Ready )
2020-04-14 14:07:32 +08:00
return ;
2020-06-27 01:03:41 +08:00
fadePlayfieldWhenHealthLow . UnbindBindings ( ) ;
2020-04-14 14:21:56 +08:00
2020-04-14 14:07:32 +08:00
// Don't display ever if the ruleset is not using a draining health display.
if ( healthProcessor is DrainingHealthProcessor )
2020-06-27 01:03:41 +08:00
fadePlayfieldWhenHealthLow . BindTo ( fadePlayfieldWhenHealthLowSetting ) ;
2020-04-14 14:07:32 +08:00
else
2020-06-27 01:03:41 +08:00
fadePlayfieldWhenHealthLow . Value = false ;
2020-04-09 13:31:25 +08:00
}
2020-06-26 20:32:01 +08:00
/// <summary>
/// Tries to fade based on "Fade playfield when health is low" setting
/// </summary>
/// <param name="fadeDuration">Duration of the fade</param>
/// <param name="easing">Type of easing</param>
/// <param name="fadeIn">True when you want to fade in, false when you want to fade out</param>
public void TryToFade ( float fadeDuration , Easing easing , bool fadeIn )
{
2020-06-27 01:03:41 +08:00
if ( ShowHealth . Value )
2020-06-26 20:32:01 +08:00
{
if ( fadeIn )
{
2020-06-27 01:03:41 +08:00
if ( fadePlayfieldWhenHealthLow . Value )
2020-06-26 20:32:01 +08:00
this . FadeIn ( fadeDuration , easing ) ;
}
else
this . FadeOut ( fadeDuration , easing ) ;
}
else
this . FadeOut ( fadeDuration , easing ) ;
}
2020-03-18 05:32:07 +08:00
protected override void Update ( )
{
2020-04-09 13:51:50 +08:00
double target = Math . Clamp ( max_alpha * ( 1 - Current . Value / LowHealthThreshold ) , 0 , max_alpha ) ;
boxes . Alpha = ( float ) Interpolation . Lerp ( boxes . Alpha , target , Clock . ElapsedFrameTime * 0.01f ) ;
2020-03-26 19:14:44 +08:00
2020-03-18 05:32:07 +08:00
base . Update ( ) ;
}
}
}