RedLightPlayer.cs
using Sandbox;

public sealed class RedLightPlayer : Component
{
	public enum PlayerState
	{
		Playing,
		GameOver,
		Win
	}

	[Property]
	public RedLightGreenLight GameController { get; set; }

	[Property]
	public SkinnedModelRenderer ModelRenderer { get; set; }

	[Property]
	public SpawnPoint SpawnPoint { get; set; }

	[Property]
	public PlayerController PlayerController { get; set; }

	public PlayerState State { get; set; }

	Vector3 previousPosition;

	protected override void OnStart()
	{
		previousPosition = WorldPosition;
		State = PlayerState.Playing;
	}

	protected override void OnUpdate()
	{
		if ( State == PlayerState.GameOver )
		{
			previousPosition = WorldPosition;
			return;
		}

		if ( State != PlayerState.Playing )
			return;

		if ( GameController.State == RedLightGreenLight.GameState.Red && State != PlayerState.Win )
		{
			if ( WorldPosition != previousPosition )
			{
				Log.Info( "PLAYER MOVED!" );

				State = PlayerState.GameOver;

				// Start the death sequence
				Ragdoll();
			}
		}

		previousPosition = WorldPosition;
	}

	[Button]
	async public void Ragdoll()
	{
		if ( !ModelRenderer.IsValid() )
			return;

		if ( !PlayerController.IsValid() )
			return;

		// Disable player controls
		PlayerController.UseInputControls = false;
		PlayerController.UseLookControls = false;

		// Create ragdoll
		var ragdoll = AddComponent<ModelPhysics>();
		ragdoll.Renderer = ModelRenderer;
		ragdoll.Model = ModelRenderer.Model;

		// Death timer
		await Task.Delay( 3000 );

		// Remove ragdoll physics
		ragdoll.Destroy();

		// Respawn player
		WorldPosition = SpawnPoint.WorldPosition;

		// Reset controls
		PlayerController.UseInputControls = true;
		PlayerController.UseLookControls = true;

		// Reset position tracking
		previousPosition = WorldPosition;
		State = PlayerState.Playing;
	}
	
}