Bikin Inventory System Keren di Unity: Panduan Lengkap Pakai ScriptableObjects, Dijamin Auto Jago!

Unity Inventory System Pakai ScriptableObjects: Panduan Lengkap

PPLG

PPLG

Penulis

09 Aug 2026
80 x dilihat

Halo gaes! Apa kabar nih para dev game kece? Pernah nggak sih ngerasa pusing tujuh keliling pas mau bikin sistem inventory di game Unity kalian? Ribet banget kan ngurusin data item, icon, deskripsi, plus gimana caranya biar gampang nambah item baru tanpa harus ngoprek-ngoprek code inti terus? Fix banget deh, vibes-nya tuh kayak lagi disuruh nyari jarum di tumpukan jerami!

Nah, jangan khawatir! Kali ini kita bakal spill tuntas gimana caranya bikin sistem inventory yang scalable, reusable, dan super gampang di-maintain pakai salah satu fitur paling underrated tapi powerful di Unity: ScriptableObjects! Seriusan ngab, fitur ini bakal jadi game changer banget buat project kalian. Siap-siap auto jago dan bikin game kalian makin kece badai! Skuy langsung kita gas!

Kenalan Dulu Sama ScriptableObjects: Si Penyelamat Data Kamu!

Oke, sebelum nyemplung lebih dalam ke coding-codingan, kita pahami dulu yuk, apa sih ScriptableObjects itu?

Gini gaes, bayangin kalian punya banyak banget data item di game, contohnya Pedang Api, Ramuan Penyembuh, Kunci Emas, dan sebagainya. Nah, setiap item ini punya properti sendiri kan? Nama, icon, deskripsi, damage, healing amount, dll. Biasanya, kalo kalian simpan data ini di GameObject biasa atau Prefab, bakal ada beberapa challenge:

  1. Duplikasi Data: Setiap Prefab item yang kalian taruh di scene bakal bawa data sendiri. Kalau ada 100 Pedang Api, berarti ada 100 salinan data Pedang Api di memori. Boros banget kan?
  2. Susah Dibikin Fleksibel: Kalo mau ubah stat Pedang Api, kalian harus ubah semua Prefabnya satu per satu atau bikin Prefab baru. Ribet!
  3. Data Nempel di Scene: Data item jadi terikat sama GameObject di scene. Gimana kalo mau manage item yang belum spawned?

Nah, di sinilah ScriptableObjects masuk sebagai pahlawan! ScriptableObjects itu pada dasarnya adalah aset data yang bisa kalian buat dan simpan di project Unity, terpisah dari GameObject di scene. Fungsinya mirip kayak blueprint atau template buat nyimpan data. Keunggulannya:

  • Data Terpisah dari Objek: Mereka nggak perlu nempel ke GameObject. Artinya, data item kalian bisa berdiri sendiri.
  • Reusability Tingkat Dewa: Kalian bikin satu ScriptableObject untuk "Pedang Api", terus semua Pedang Api di game kalian (baik di inventory, di tangan player, atau di toko) cuma perlu referensi ke satu aset ScriptableObject itu. Hemat memori dan gampang di-update!
  • Persistent Data: Data yang kalian simpan di ScriptableObject bakal tetap ada meskipun game di-restart atau editor ditutup. Mantap kan?

Kebayang kan vibes-nya? Data item kalian jadi rapi, terpusat, dan gampang banget diatur.

Langkah Demi Langkah Implementasi Inventory Pakai ScriptableObjects

Oke, udah cukup teorinya. Sekarang kita mulai ngoding biar makin seru!

Step 1: Bikin Base Item ScriptableObject

Pertama, kita bikin kelas dasar buat semua item kita. Ini bakal jadi "cetakan" umum buat semua jenis item.

// Item.cs
using UnityEngine;

// Attribute ini memungkinkan kita membuat aset Item dari Editor Unity
[CreateAssetMenu(fileName = "NewItem", menuName = "Inventory System/Item")]
public class Item : ScriptableObject
{
    // Setiap item punya ID unik. Bagus buat debugging atau save/load game
    public int id; 
    public string itemName = "New Item";
    public Sprite icon;
    [TextArea(5, 10)] // Bikin field deskripsi lebih lega di Inspector
    public string description = "Default item description.";
    public int value = 10; // Nilai jual/beli item

    // Contoh method dasar yang bisa di-override oleh item spesifik
    public virtual void Use()
    {
        Debug.Log($"Menggunakan item: {itemName}.");
        // Implementasi dasar (misal: play sound, show effect)
    }

    // Constructor default
    public Item()
    {
        // Biasanya tidak perlu constructor custom di ScriptableObject
        // Karena dibuat via CreateAssetMenu
    }
}

Penjelasan Kode:

  • [CreateAssetMenu(...)]: Ini magic-nya gaes! Dengan attribute ini, kalian bisa klik kanan di Project window Unity (Create -> Inventory System -> Item) untuk bikin aset Item baru. Ini yang bikin data item kalian jadi aset terpisah.
  • ScriptableObject: Wajib di-inherit dari sini biar kelas kita jadi ScriptableObject.
  • Properti kayak itemName, icon, description, value ini adalah data dasar yang akan dimiliki setiap item.
  • Use(): Ini contoh method virtual. Artinya, item-item spesifik nanti bisa punya perilaku "gunakan" yang berbeda-beda.

Step 2: Bikin Item Spesifik (Inheritance)

Sekarang kita bikin beberapa jenis item yang lebih spesifik, misal PotionItem dan WeaponItem. Mereka akan mewarisi semua properti dari Item tapi bisa punya properti dan method unik sendiri.

// PotionItem.cs
using UnityEngine;

[CreateAssetMenu(fileName = "NewPotion", menuName = "Inventory System/Potion Item")]
public class PotionItem : Item
{
    public int healthRestoreAmount = 20;
    public float duration = 0f; // Misal untuk buff, 0f berarti instan

    public override void Use()
    {
        base.Use(); // Panggil method Use() dari kelas dasar
        Debug.Log($"Minum {itemName}. Mengembalikan {healthRestoreAmount} HP.");
        // Implementasi logika healing di sini, misal:
        // PlayerHealth.Instance.RestoreHealth(healthRestoreAmount);
    }
}
// WeaponItem.cs
using UnityEngine;

[CreateAssetMenu(fileName = "NewWeapon", menuName = "Inventory System/Weapon Item")]
public class WeaponItem : Item
{
    public int damage = 10;
    public float attackSpeed = 1f;
    public WeaponType weaponType; // Enum untuk jenis senjata (sword, axe, bow, dll.)

    public override void Use()
    {
        base.Use();
        Debug.Log($"Memegang {itemName}. Damage: {damage}, Attack Speed: {attackSpeed}.");
        // Implementasi logika equip weapon, misal:
        // PlayerCombat.Instance.EquipWeapon(this);
    }
}

// Tambahan: Enum untuk jenis senjata
public enum WeaponType
{
    Sword,
    Axe,
    Bow,
    Staff,
    Shield
}

Setelah ini, kalian bisa bikin banyak aset item dengan klik kanan di Project window. Coba deh bikin aset PotionItem dengan nama "Health Potion" dan WeaponItem dengan nama "Basic Sword". Isi propertinya di Inspector! Vibesnya jadi kayak database item yang gampang diatur, kan?

Step 3: Struktur Data untuk Slot Inventory

Inventory itu kan biasanya ada slot-slotnya. Setiap slot berisi item dan jumlahnya (quantity). Kita bisa bikin struct atau class sederhana untuk representasi ini. Struct lebih efisien jika datanya kecil dan tidak banyak diubah.

// InventorySlot.cs
using System; // Untuk Serializable

// Wajib Serializable agar bisa terlihat di Inspector atau di-save
[Serializable] 
public struct InventorySlot
{
    public Item item; // Referensi ke aset ScriptableObject Item kita
    public int quantity;

    // Constructor
    public InventorySlot(Item item, int quantity)
    {
        this.item = item;
        this.quantity = quantity;
    }

    // Method untuk menambah quantity
    public void AddQuantity(int amount)
    {
        quantity += amount;
    }

    // Method untuk mengurangi quantity
    public void RemoveQuantity(int amount)
    {
        quantity -= amount;
        if (quantity < 0) quantity = 0; // Pastikan tidak minus
    }
}

Step 4: Bikin Sistem Inventory Inti (MonoBehaviour)

Ini nih bagian core-nya! Kita bakal bikin InventoryManager atau InventorySystem yang jadi tempat item-item disimpan. Karena ini akan berinteraksi dengan scene (player, UI), maka dia perlu MonoBehaviour.

// InventorySystem.cs
using UnityEngine;
using System.Collections.Generic; // Untuk List
using System.Linq; // Untuk Linq (opsional tapi berguna)

public class InventorySystem : MonoBehaviour
{
    public static InventorySystem Instance { get; private set; } // Singleton pattern

    // List untuk menyimpan semua slot inventory
    public List<InventorySlot> inventorySlots = new List<InventorySlot>();

    [SerializeField] private int maxCapacity = 20; // Kapasitas maks inventory

    // Unity Event untuk notifikasi perubahan inventory ke UI
    public delegate void OnInventoryChanged();
    public event OnInventoryChanged onInventoryChangedCallback;

    private void Awake()
    {
        if (Instance != null && Instance != this)
        {
            Destroy(gameObject);
        }
        else
        {
            Instance = this;
            // DontDestroyOnLoad(gameObject); // Opsional: Kalau inventory mau tetap ada antar scene
        }
    }

    public bool AddItem(Item itemToAdd, int quantityToAdd)
    {
        if (quantityToAdd <= 0) return false;

        // Cek apakah item sudah ada di inventory
        InventorySlot existingSlot = inventorySlots.FirstOrDefault(slot => slot.item == itemToAdd);

        if (existingSlot.item != null)
        {
            // Item sudah ada, tambahkan quantity
            int index = inventorySlots.IndexOf(existingSlot);
            existingSlot.AddQuantity(quantityToAdd);
            inventorySlots[index] = existingSlot; // Update struct di list
            Debug.Log($"Menambahkan {quantityToAdd}x {itemToAdd.itemName}. Total: {existingSlot.quantity}");
        }
        else
        {
            // Item belum ada, tambahkan slot baru jika kapasitas memungkinkan
            if (inventorySlots.Count >= maxCapacity)
            {
                Debug.Log("Inventory penuh!");
                return false;
            }
            inventorySlots.Add(new InventorySlot(itemToAdd, quantityToAdd));
            Debug.Log($"Menambahkan item baru: {itemToAdd.itemName} x{quantityToAdd}");
        }

        onInventoryChangedCallback?.Invoke(); // Trigger event untuk update UI
        return true;
    }

    public bool RemoveItem(Item itemToRemove, int quantityToRemove)
    {
        if (quantityToRemove <= 0) return false;

        InventorySlot existingSlot = inventorySlots.FirstOrDefault(slot => slot.item == itemToRemove);

        if (existingSlot.item == null || existingSlot.quantity < quantityToRemove)
        {
            Debug.Log($"Tidak cukup {itemToRemove.itemName} untuk dihapus.");
            return false;
        }

        int index = inventorySlots.IndexOf(existingSlot);
        existingSlot.RemoveQuantity(quantityToRemove);
        inventorySlots[index] = existingSlot; // Update struct di list

        if (existingSlot.quantity <= 0)
        {
            inventorySlots.RemoveAt(index); // Hapus slot jika quantity 0
            Debug.Log($"Menghapus semua {itemToRemove.itemName} dari inventory.");
        }
        else
        {
            Debug.Log($"Menghapus {quantityToRemove}x {itemToRemove.itemName}. Sisa: {existingSlot.quantity}");
        }

        onInventoryChangedCallback?.Invoke(); // Trigger event untuk update UI
        return true;
    }

    // Method untuk menggunakan item dari inventory
    public void UseItem(Item itemToUse)
    {
        if (itemToUse == null) return;

        // Cek apakah item ada di inventory dan jumlahnya > 0
        InventorySlot existingSlot = inventorySlots.FirstOrDefault(slot => slot.item == itemToUse && slot.quantity > 0);

        if (existingSlot.item != null)
        {
            itemToUse.Use(); // Panggil method Use dari ScriptableObject item
            RemoveItem(itemToUse, 1); // Hapus 1 item setelah digunakan
        }
        else
        {
            Debug.Log($"Item {itemToUse.itemName} tidak ada di inventory atau habis.");
        }
    }
    
    // Method untuk mendapatkan item di slot tertentu (misal untuk UI)
    public Item GetItemInSlot(int index)
    {
        if (index >= 0 && index < inventorySlots.Count)
        {
            return inventorySlots[index].item;
        }
        return null;
    }

    public int GetItemQuantity(Item item)
    {
        InventorySlot existingSlot = inventorySlots.FirstOrDefault(slot => slot.item == item);
        return existingSlot.item != null ? existingSlot.quantity : 0;
    }
}

Penjelasan Kode:

  • Singleton Pattern: Instance bikin InventorySystem gampang diakses dari mana aja (contoh: InventorySystem.Instance.AddItem(...)). Hati-hati pakai Singleton, pastikan memang cuma butuh satu instance.
  • inventorySlots: List<InventorySlot> ini adalah "gudang" inventory kita.
  • AddItem() & RemoveItem(): Logika utama untuk menambah dan mengurangi item, termasuk handling jika item sudah ada atau kapasitas penuh.
  • onInventoryChangedCallback: Ini adalah event. Penting banget buat komunikasi! Ketika inventory berubah, kita Invoke() event ini. UI (User Interface) kalian nanti tinggal subscribe ke event ini, jadi pas event terpanggil, UI bisa otomatis refresh tanpa harus nge-cek inventory setiap frame. Keren, kan?
  • UseItem(): Memanggil method Use() yang ada di ScriptableObject item. Ini menunjukkan decoupling yang bagus: InventorySystem nggak perlu tahu gimana item itu digunakan, dia cuma suruh si Item itu sendiri yang bertanggung jawab atas perilakunya.

Step 5: Bikin Objek Penjemput Item (Item Pick Up)

Gimana caranya player bisa ngambil item dari scene? Kita bikin script sederhana yang nempel ke GameObject item di scene.

// ItemPickup.cs
using UnityEngine;

public class ItemPickup : MonoBehaviour
{
    public Item itemData; // Referensi ke aset ScriptableObject Item
    public int quantity = 1;

    private void OnTriggerEnter(Collider other)
    {
        if (other.CompareTag("Player")) // Pastikan yang nyentuh itu player
        {
            if (InventorySystem.Instance.AddItem(itemData, quantity))
            {
                Debug.Log($"Player mengambil {quantity}x {itemData.itemName}.");
                Destroy(gameObject); // Hancurkan objek item setelah diambil
            }
            else
            {
                Debug.Log("Inventory penuh, tidak bisa mengambil item.");
            }
        }
    }
}

Cara Pakai:

  1. Bikin GameObject 3D (misal cube) sebagai representasi item di scene.
  2. Tambahkan Collider dan centang Is Trigger.
  3. Tambahkan komponen ItemPickup ke GameObject itu.
  4. Di Inspector, drag aset ScriptableObject Item (misal Health Potion) ke slot Item Data di ItemPickup.
  5. Pastikan player kalian punya Rigidbody dan Collider agar OnTriggerEnter bisa jalan.

Step 6: Integrasi UI (Sedikit Bocoran)

Untuk UI, kalian bisa bikin script InventoryUI yang punya slot-slot UI (panel, gambar icon, teks quantity). Script ini akan subscribe ke event onInventoryChangedCallback dari InventorySystem.

// Contoh sederhana (bukan kode lengkap UI)
using UnityEngine;
using UnityEngine.UI;
using System.Collections.Generic;

public class InventoryUI : MonoBehaviour
{
    public GameObject inventorySlotUIPrefab; // Prefab UI untuk satu slot item
    public Transform slotsParent; // Parent tempat semua slot UI akan diletakkan

    private List<InventorySlotUI> currentSlots = new List<InventorySlotUI>();

    void Start()
    {
        // Subscribe ke event perubahan inventory
        InventorySystem.Instance.onInventoryChangedCallback += UpdateUI;
        UpdateUI(); // Panggil pertama kali untuk inisialisasi UI
    }

    void OnDestroy()
    {
        // Penting: Unsubscribe saat objek dihancurkan untuk menghindari memory leak
        if (InventorySystem.Instance != null)
        {
            InventorySystem.Instance.onInventoryChangedCallback -= UpdateUI;
        }
    }

    public void UpdateUI()
    {
        // Hapus semua slot UI lama
        foreach (var slot in currentSlots)
        {
            Destroy(slot.gameObject);
        }
        currentSlots.Clear();

        // Buat slot UI baru sesuai dengan inventory saat ini
        foreach (var inventorySlot in InventorySystem.Instance.inventorySlots)
        {
            GameObject go = Instantiate(inventorySlotUIPrefab, slotsParent);
            InventorySlotUI slotUI = go.GetComponent<InventorySlotUI>();
            if (slotUI != null)
            {
                slotUI.SetSlotData(inventorySlot.item, inventorySlot.quantity);
                currentSlots.Add(slotUI);
            }
        }
        Debug.Log("UI Inventory di-update!");
    }
}

Di atas itu InventorySlotUI adalah script yang nempel di prefab UI slot kalian, yang punya Image untuk icon dan Text untuk quantity.

Tips Praktis & Best Practices Biar Makin Pro!

  1. Serialization (Save/Load Game): Kalau mau inventorynya kesimpen pas game di-load lagi, kalian perlu serialize data List<InventorySlot> ke JSON atau binary. Saat load, deserialize lagi. Kuncinya adalah menyimpan ID unik Item (bukan referensi Item langsung) dan quantity. Saat load, cari Item berdasarkan ID-nya dari semua aset Item yang ada.
  2. Event System untuk decoupling: Tadi kita udah pakai delegate dan event. Ini best practice banget buat memisahkan logic (InventorySystem) dari UI (InventoryUI). Jadi, UI nggak perlu tahu gimana InventorySystem kerja, dia cuma perlu tahu kapan data berubah.
  3. Unique Item IDs: Pastikan setiap Item ScriptableObject punya ID unik. Ini krusial banget buat save/load dan identifikasi item. Kalian bisa buat field id di kelas Item dan kasih [SerializeField] atau bikin editor script khusus yang meng-generate ID otomatis.
  4. Pooling untuk UI Slot: Daripada Instantiate dan Destroy terus-menerus InventorySlotUI setiap UpdateUI(), lebih efisien pakai Object Pooling. Jadi, objek UI yang nggak kepakai disimpan dulu, nanti kalau perlu tinggal diaktifkan lagi.
  5. Extensibility (Jenis Item Baru): Dengan ScriptableObjects, nambah item baru itu gampang banget! Tinggal bikin script baru yang inherit dari Item, lalu bikin asetnya di Project window. Nggak perlu ubah kode inti InventorySystem. Keren kan?
  6. Context Menu untuk Item: Kalian bisa tambahkan method ke Item untuk Right Click -> Use di UI. Contoh: di script InventorySlotUI, saat tombol 'Use' diklik, panggil InventorySystem.Instance.UseItem(itemYangAdaDiSlotIni);.

Kesimpulan: Bye-bye Pusing, Hello Inventory Keren!

Gimana gaes? Udah kebayang kan gimana powerful-nya ScriptableObjects buat nanganin sistem inventory di game Unity kalian? Dengan pendekatan ini, data item kalian jadi super rapi, gampang diatur, reusable, dan yang paling penting, scalable banget. Kalian bisa nambah ratusan item baru tanpa perlu ngoprek core logic Inventory System. Vibesnya tuh beneran kayak punya database item sendiri yang terintegrasi langsung ke editor Unity.

Jadi, tunggu apa lagi? Skuy langsung dicoba di project kalian. Jangan males eksplorasi dan bereksperimen, karena di situlah kalian bakal nemu aha! moment dan jadi dev game yang makin jago! Kalau ada pertanyaan atau mau spill tips lain, jangan sungkan komen ya! Happy coding!

5.0

Berikan Rating

Komentar (0)

Silakan login untuk memberikan komentar.

Login Sekarang

Belum ada komentar. Jadilah yang pertama!

Menyukai Artikel (2)