Code/ItemPickup.cs
using Sandbox;
using System;
public enum PickupMode
{
/// <summary>Automatically picks up when a player walks within PickupRadius.</summary>
Proximity,
/// <summary>Picked up via PlayerPickupHandler raycast (E key).</summary>
Raycast,
/// <summary>Only picked up when Pickup() is called directly from code.</summary>
Manual
}
public class ItemPickup : Component
{
/// <summary>How this item can be picked up.</summary>
[Property] public PickupMode Mode { get; set; } = PickupMode.Proximity;
/// <summary>The item to give to the player on pickup.</summary>
[Property] public InventoryItem Item { get; set; }
/// <summary>How many of the item to give.</summary>
[Property, Range( 1, 999 )] public int Quantity { get; set; } = 1;
/// <summary>If true, the GameObject is destroyed after a successful pickup.</summary>
[Property] public bool DestroyOnPickup { get; set; } = true;
/// <summary>Proximity pickup radius in world units.</summary>
[Property] public float PickupRadius { get; set; } = 100f;
/// <summary>Fired when the item is successfully picked up.</summary>
public event Action<InventoryComponent> OnPickupSuccess;
/// <summary>Fired when a pickup attempt fails (e.g. inventory full).</summary>
public event Action<InventoryComponent> OnPickupFailed;
private TimeSince _lastProximityCheck;
protected override void OnUpdate()
{
if ( Mode != PickupMode.Proximity ) return;
if ( Item == null ) return;
if ( _lastProximityCheck < 0.25f ) return;
_lastProximityCheck = 0;
var allInventory = Scene.GetAllComponents<InventoryComponent>();
foreach ( var inv in allInventory )
{
float dist = inv.Transform.Position.Distance( Transform.Position );
if ( dist <= PickupRadius )
{
if ( Pickup( inv ) )
break;
}
}
}
/// <summary>
/// Attempt to give this item to the given inventory.
/// Returns true on success. Fires OnPickupSuccess or OnPickupFailed accordingly.
/// </summary>
public bool Pickup( InventoryComponent inventory )
{
if ( Item == null || inventory == null )
return false;
if ( !CanPickup( inventory ) )
return false;
int leftover = inventory.GiveItem( Item, Quantity );
if ( leftover > 0 )
{
OnPickupFailed?.Invoke( inventory );
return false;
}
OnPickupSuccess?.Invoke( inventory );
if ( DestroyOnPickup )
GameObject.Destroy();
return true;
}
/// <summary>Override to add custom pickup conditions. Returns true by default.</summary>
protected virtual bool CanPickup( InventoryComponent inventory ) => true;
}