Goodie.cs
using Sandbox;

public interface IGoodieEvents : ISceneEvent<IGoodieEvents>
{
	public void OnGoodiePickup( int value ) { }
}

public sealed class Goodie : Component, Component.ITriggerListener
{
	[Property]
	public SoundEvent PickupSound { get; set; }

	[Property]
	public TimeSince Lifetime { get; set; }

	bool jumped;

	protected override void OnEnabled()
	{
		base.OnEnabled();

		Lifetime = 0;

		var allGoodies = Scene.GetAll<Goodie>().ToList();

		if ( allGoodies.Count < 50 ) return;

		allGoodies.Sort( ( a, b ) => a.Lifetime.Relative.CompareTo( b.Lifetime.Relative ) );

		for ( var i = 49; i < allGoodies.Count; i++ )
		{
			allGoodies[i].GameObject.Parent.Destroy();
		}
	}

	protected override void OnFixedUpdate()
	{
		base.OnFixedUpdate();

		// did not work in OnEnabled, Rigidbody probably overrides any initial velocity with gravity
		if ( jumped ) return;
		jumped = true;

		SpawnJump();
	}

	void ITriggerListener.OnTriggerEnter( GameObject other )
	{
		// did we get triggered by a player?
		var playerController = other.GetComponent<PlayerController>();
		if ( playerController is null ) return;

		// notify the game
		IGoodieEvents.Post( x => x.OnGoodiePickup( 1 ) );

		// play an effect
		Sound.Play( PickupSound, WorldPosition );

		// disappear
		GameObject.Parent.Destroy();
	}

	/// <summary>
	/// Jump upwards in a random direction.
	/// 
	/// Should happen once on spawn.
	/// </summary>
	void SpawnJump()
	{
		var r = Game.Random.Angles().AsVector3();
		GetComponentInParent<Rigidbody>().Velocity = r.WithZ( 200f + (float)Game.Random.NextDouble() * 200f );
	}
}