UI/NpcHealthBar.cs

A UI PanelComponent that renders a small world-space health bar for a DemoNpc. It ensures its child panels exist, finds the NPC from the GameObject parent, hides when the NPC is dead or missing, and updates the fill width based on the NPC HealthFraction.

using AdaptiveDirectorDemo.Director;
using Sandbox;
using Sandbox.UI;

namespace AdaptiveDirectorDemo.UI;

/// <summary>Small world-space health bar that follows its Citizen NPC.</summary>
[Title( "Director NPC Health Bar" )]
[Category( "Adaptive Director Demo" )]
public sealed class NpcHealthBar : PanelComponent
{
	private Panel _fill;
	private DemoNpc _npc;

	protected override void OnStart()
	{
		EnsureVisuals();
	}

	protected override void OnUpdate()
	{
		// Component fields can be reset while the existing panel tree survives a
		// hot load. Rebuild our cached UI references before touching them.
		if ( !EnsureVisuals() )
			return;

		var root = Panel;
		if ( root is null || !root.IsValid )
			return;

		if ( _npc is null || !_npc.IsValid )
			_npc = GameObject.Parent?.Components.Get<DemoNpc>();

		if ( _npc is null || !_npc.IsAlive )
		{
			root.Style.Display = DisplayMode.None;
			return;
		}

		root.Style.Display = DisplayMode.Flex;
		_fill.Style.Width = Length.Percent( _npc.HealthFraction * 100.0f );
	}

	private bool EnsureVisuals()
	{
		var root = Panel;
		if ( root is null || !root.IsValid )
			return false;

		if ( _fill is not null && _fill.IsValid )
			return true;

		root.StyleSheet.Load( "/UI/NpcHealthBar.cs.scss" );
		var track = root.Add.Panel( "npc-health-track" );
		_fill = track.Add.Panel( "npc-health-fill" );
		return true;
	}
}