Part of these game systems:
beginner Inventory

Pickup / Collectible

Collectible item with bobbing animation, rotation, magnet pull, and event callbacks for coins, health, ammo, etc.

Unity 2022.3+ · 2.0 KB · Collectible.cs

How to Use

1

Attach Collectible to any pickup object

2

Add a Trigger Collider (Box, Sphere, or Circle for 2D)

3

Tag your player as 'Player'

4

Set item ID ('coin', 'health', 'ammo') and value

5

Hook OnCollected event to your score/inventory system

6

Enable magnet for auto-attract towards player

7

Works with both 3D (OnTriggerEnter) and 2D (OnTriggerEnter2D)

Features

  • Configurable bob and rotate animation with adjustable speed and height
  • Magnet attraction that pulls collectibles toward the player automatically
  • Supports both 3D and 2D trigger detection out of the box
  • UnityEvent callback on collection for easy integration
  • Customizable item ID and value for different pickup types
  • Optional destroy-on-collect toggle for reusable pickups

When to Use This

Essential for any game with collectible items — coins in platformers, power-ups in shooters, gems in endless runners, or resources in survival games. Works with both 2D and 3D projects. Pair with the Simple Inventory script for full item management.

Common Mistakes

The collectible needs a Collider (or Collider2D) with 'Is Trigger' checked — without it, OnTriggerEnter won't fire. Your player must have a Rigidbody (or Rigidbody2D) and be tagged 'Player' for detection to work. If magnet isn't pulling, make sure enableMagnet is checked and the player tag matches the playerTag field.

Source Code

Collectible.cs
C#
using UnityEngine;
using UnityEngine.Events;

/// <summary>
/// Collectible item with bob/rotate animation and magnet attraction.
/// Use for coins, health pickups, ammo, keys, etc.
/// </summary>
public class Collectible : MonoBehaviour
{
    [Header("Animation")]
    [SerializeField] private float bobHeight = 0.2f;
    [SerializeField] private float bobSpeed = 2f;
    [SerializeField] private float rotateSpeed = 90f;

    [Header("Collection")]
    [SerializeField] private string playerTag = "Player";
    [SerializeField] private bool destroyOnCollect = true;

    [Header("Magnet")]
    [SerializeField] private bool enableMagnet = false;
    [SerializeField] private float magnetRange = 3f;
    [SerializeField] private float magnetSpeed = 8f;

    [Header("Value")]
    [SerializeField] private int value = 1;
    [SerializeField] private string itemId = "coin";

    [Header("Events")]
    public UnityEvent<Collectible> OnCollected;

    private Vector3 startPosition;
    private Transform magnetTarget;
    private bool isCollected;

    /// <summary>Item ID for identification.</summary>
    public string ItemId => itemId;

    /// <summary>Value of this collectible.</summary>
    public int Value => value;

    private void Start()
    {
        startPosition = transform.position;
    }

    private void Update()
    {
        if (isCollected) return;

        // Bob animation
        float newY = startPosition.y + Mathf.Sin(Time.time * bobSpeed) * bobHeight;
        transform.position = new Vector3(transform.position.x, newY, transform.position.z);

        // Rotate
        transform.Rotate(Vector3.up, rotateSpeed * Time.deltaTime);

        // Magnet attraction
        if (enableMagnet && magnetTarget != null)
        {
            float dist = Vector3.Distance(transform.position, magnetTarget.position);
            if (dist < magnetRange)
            {
                Vector3 dir = (magnetTarget.position - transform.position).normalized;
                float speed = magnetSpeed * (1f - dist / magnetRange);
                startPosition += dir * speed * Time.deltaTime;
            }
        }
    }

    private void OnTriggerEnter(Collider other)
    {
        if (isCollected) return;

        if (other.CompareTag(playerTag))
        {
            Collect(other.gameObject);
        }
    }

    private void OnTriggerEnter2D(Collider2D other)
    {
        if (isCollected) return;

        if (other.CompareTag(playerTag))
        {
            Collect(other.gameObject);
        }
    }

    /// <summary>
    /// Collect this item. Called automatically on trigger or manually.
    /// </summary>
    public void Collect(GameObject collector)
    {
        if (isCollected) return;
        isCollected = true;

        OnCollected?.Invoke(this);

        if (destroyOnCollect)
            Destroy(gameObject);
    }

    private void OnEnable()
    {
        // Find player for magnet
        if (enableMagnet)
        {
            GameObject player = GameObject.FindGameObjectWithTag(playerTag);
            if (player != null) magnetTarget = player.transform;
        }
    }
}