A UI Panel component (Razor) that shows a full-screen black fade transition. It listens to BlackScreenBus.OnTrigger to start a sequence of start, black, and end phases, animating opacity over time and updating style opacity each Tick.
@using System
@using Sandbox
@using Sandbox.UI
@namespace BrickJam.UI
@inherits Panel
<root />
@code {
private enum State { Idle, Starting, Black, Ending }
private State state = State.Idle;
private TimeUntil endTransition;
private float phaseDuration = 1f;
private float startTransition, blackTransition, endingTransition;
private float opacity;
public BlackScreen()
{
BlackScreenBus.OnTrigger += Begin;
}
public override void OnDeleted()
{
base.OnDeleted();
BlackScreenBus.OnTrigger -= Begin;
}
private void Begin( float black, float start, float end )
{
startTransition = start;
blackTransition = black;
endingTransition = end;
state = State.Starting;
SetPhase( start );
}
private void SetPhase( float duration )
{
phaseDuration = MathF.Max( duration, 0.0001f );
endTransition = duration;
}
private float Fraction => 1f - ((float)endTransition / phaseDuration).Clamp( 0f, 1f );
public override void Tick()
{
opacity = state switch
{
State.Starting => MathE.Slerp( 0f, 1f, Fraction ),
State.Black => 1f,
State.Ending => MathE.Slerp( 1f, 0f, Fraction ),
_ => 0f
};
Style.Opacity = opacity;
if ( state != State.Idle && endTransition <= 0f )
{
switch ( state )
{
case State.Starting: state = State.Black; SetPhase( blackTransition ); break;
case State.Black: state = State.Ending; SetPhase( endingTransition ); break;
default: state = State.Idle; break;
}
}
}
protected override int BuildHash() => HashCode.Combine( opacity );
}
<style>
BlackScreen {
position: absolute;
top: 0; left: 0;
width: 100%;
height: 100%;
background-color: black;
opacity: 0;
pointer-events: none;
z-index: 50;
}
</style>