DropItem

Dev-Blog: Finalizing the Inventory System in Cockfite

March 2025 – by the Cockfite Dev Team


Overview

In this development blog, we’re highlighting the final structure of our player inventory system, with a particular focus on how items are picked up and added to a player’s inventory. This includes robust validation logic, Fusion state synchronization, and flexible support for weapons and ammunition. Below, we’ll walk you through the most important components and share code insights.


StaticPickup: Our World Item Blueprint

We use a StaticPickup base class to represent world-spawned collectables. It includes cooldowns, validation, and visibility logic.

public bool CanPickup()
{
    return Object != null &&
           Object.IsValid &&
           !m_consumed &&
           m_despawnCooldown.ExpiredOrNotRunning(Runner) &&
           !m_isDisabled &&
           m_dropCooldown.ExpiredOrNotRunning(Runner);
}

public void ConsumePickup(PlayerRef _owner)
{
    m_owner = _owner;
    m_consumed = true;

    if (m_despawnDelay > 0f)
    {
        m_despawnCooldown = TickTimer.CreateFromSeconds(Runner, m_despawnDelay);
    }
}

The actual WeaponPickup subclass extends this for specific item types (weapons with ammo):

public sealed class WeaponPickup : StaticPickup, IInventoryItem
{
    [SerializeField] int AmmoAmount = 1;

    public short CurrentAmmo => (short)AmmoAmount;

    public override void DropPickup(short _ammo)
    {
        base.DropPickup(_ammo);
        AmmoAmount = _ammo;
    }
}

Collision & Item Collection

In the PlayerInventory, we use a FixedUpdateNetwork() loop with a OverlapCapsule() check to detect items:

private void CheckForCollision()
{
    int hits = Runner.GetPhysicsScene().OverlapCapsule(
        transform.position,
        transform.position + Vector3.up * m_capsuleColliderHeight,
        m_capsuleColliderRadius,
        m_collisionTestColliders,
        m_collisionTestMask,
        QueryTriggerInteraction.Collide);

    for (int i = 0; i < hits; i++)
    {
        if (!HasStateAuthority)
            return;

        if (m_collisionTestColliders[i].TryGetComponent(out StaticPickup pickup))
        {
            if (pickup.CanPickup())
            {
                if (AddItemToInventory(pickup))
                {
                    pickup.ConsumePickup(Object.InputAuthority);
                }
            }
        }
    }
}

Adding Items to the Inventory

The method AddItemToInventory() handles stacking and slot allocation. It first tries to merge ammo with an existing item:

for (int i = 0; i < m_itemSlots.Length && rest > 0; i++)
{
    var iitem = m_itemSlots[i].GetComponent<IInventoryItem>();
    if (iitem.ItemId.Equals(_inventoryItem.ItemId))
    {
        if (iitem.InventoyItemType == InventoyItemType.Weapon)
        {
            var item = Runner.FindObject(iitem.ItemNetworkId);
            if (item != null && item.TryGetComponent(out Weapon weapon))
            {
                if (weapon.UpdateAmmo(rest, out short newRest))
                {
                    rest = newRest;
                    if (rest == 0) return true;
                }
            }
        }
    }
}

If there’s leftover ammo and an empty slot, a new item is spawned:

var weapon = Runner.Spawn(prefab, null, null, Object.InputAuthority, (_rnr, _no) =>
{
    _no.GetComponent<IInventoryItem>().Initalize(
        GetComponent<CF_Avatar>().GetSpawnPointTransform(_inventoryItem.SpawnTransform),
        (sbyte)i,
        Object.InputAuthority,
        Context,
        ammoToAssign);
});

Inventory Debugging

We use gizmos in-editor to visualize drop and collision zones. This has been essential for debugging:

private void OnDrawGizmosSelected()
{
    Gizmos.color = Color.cyan;
    Vector3 start = transform.position;
    Vector3 end = transform.position + Vector3.up * m_capsuleColliderHeight;
    Gizmos.DrawWireSphere(start, m_capsuleColliderRadius);
    Gizmos.DrawWireSphere(end, m_capsuleColliderRadius);
}

Summary

  • Pickup logic is handled via a dedicated class that validates cooldowns, state, and consumption.
  • Inventory merging of ammo is deterministic and synchronized with Fusion’s network state.
  • Fallback spawning fills empty slots when merging isn’t possible.
  • State Authority only controls sensitive updates like despawning and inventory logic.

This foundation now allows us to confidently build gameplay systems around reliable item interactions. Coming up next: synced projectile logic and weapon cooldown refactors.


Thanks for reading!

Schreibe einen Kommentar