Membuat Sistem Inventory dan Item Crafting dalam Kesatuan

Dalam tutorial ini, saya akan menunjukkan cara membuat sistem inventaris dan pembuatan item gaya Minecraft di Unity.

Pembuatan item dalam video game adalah proses menggabungkan item tertentu (biasanya lebih sederhana) menjadi item yang lebih kompleks, dengan properti baru dan ditingkatkan. Misalnya menggabungkan kayu dan batu menjadi beliung, atau menggabungkan lembaran logam dan kayu menjadi pedang.

Sistem kerajinan di bawah ini mobile-friendly dan sepenuhnya otomatis, artinya sistem ini dapat digunakan dengan tata letak UI apa pun dan dengan kemampuan membuat resep kerajinan khusus.

Sharp Coder Pemutar video

Langkah 1: Siapkan UI Kerajinan

Kita mulai dengan menyiapkan UI kerajinan:

  • Buat Canvas baru (Unity Taskbar Teratas: GameObject -> UI -> Canvas)
  • Buat Gambar baru dengan Klik Kanan pada Objek Canvas -> UI -> Image
  • Ganti nama Objek Gambar menjadi "CraftingPanel" dan ubah Gambar Sumbernya menjadi default "UISprite"
  • Ubah nilai "CraftingPanel" RectTransform menjadi (Pos X: 0 Pos Y: 0 Lebar: 410 Tinggi: 365)

  • Buat dua Objek di dalam "CraftingPanel" (Klik kanan pada CraftingPanel -> Buat Kosong, 2 kali)
  • Ganti nama Objek pertama menjadi "CraftingSlots" dan ubah nilai RectTransformnya menjadi ("Rata Kiri Atas" Pivot X: 0 Pivot Y: 1 Pos X: 50 Pos Y: -35 Lebar: 140 Tinggi: 140). Objek ini akan berisi slot kerajinan.
  • Ganti nama Objek kedua menjadi "PlayerSlots" dan ubah nilai RectTransformnya menjadi ("Regangan Atas Secara Horizontal" Pivot X: 0.5 Pivot Y: 1 Kiri: 0 Pos Y: -222 Kanan: 0 Tinggi: 100). Objek ini akan berisi slot pemain.

Judul Bagian:

  • Buat Teks baru dengan Mengklik Kanan pada "PlayerSlots" Objek -> UI -> Teks dan ganti namanya menjadi "SectionTitle"
  • Ubah "SectionTitle" nilai RectTransform menjadi ("Rata Kiri Atas" Pivot X: 0 Pivot Y: 0 Pos X: 5 Pos Y: 0 Lebar: 160 Tinggi: 30)
  • Ubah teks "SectionTitle" menjadi "Inventory" dan atur Font Size menjadi 18, Alignment menjadi Left Middle, dan Color menjadi (0.2, 0.2, 0.2, 1)
  • Duplikat Object "SectionTitle", ubah Text-nya menjadi "Crafting" dan pindahkan ke bawah Object "CraftingSlots", lalu atur nilai RectTransform yang sama dengan "SectionTitle" sebelumnya.

Slot Kerajinan:

Slot kerajinan akan terdiri dari gambar latar belakang, gambar item, dan teks hitungan:

  • Buat Gambar baru dengan Klik Kanan pada Objek Canvas -> UI -> Image
  • Ganti nama Gambar baru menjadi "slot_template", atur nilai RectTransform menjadi (Post X: 0 Pos Y: 0 Lebar: 40 Tinggi: 40), dan ubah warnanya menjadi (0.32, 0.32, 0.32, 0.8)
  • Duplikat "slot_template" dan ubah namanya menjadi "Item", pindahkan ke dalam objek "slot_template", ubah dimensi RectTransform menjadi (Lebar: 30 Tinggi: 30) dan Warna menjadi (1, 1, 1, 1)
  • Buat Teks baru dengan Mengklik Kanan pada "slot_template" Objek -> UI -> Teks dan ganti namanya menjadi "Count"
  • Ubah "Count" nilai RectTransform menjadi ("Rata Kanan Bawah" Pivot X: 1 Pivot Y: 0 Pos X: 0 Pos Y: 0 Lebar: 30 Tinggi: 30)
  • Atur "Count" Teks ke nomor acak (mis. 12), Gaya Font ke Tebal, Ukuran Font ke 14, Perataan ke Kanan Bawah, dan Warna ke (1, 1, 1, 1)
  • Tambahkan komponen Shadow ke "Count" Teks dan atur Effect Color ke (0, 0, 0, 0.5)

Hasil akhirnya akan terlihat seperti ini:

Slot Hasil (Yang akan digunakan untuk hasil kerajinan):

  • Gandakan Objek "slot_template" dan ganti namanya menjadi "result_slot_template"
  • Ubah Lebar dan Tinggi "result_slot_template" menjadi 50

Tombol Kerajinan dan Grafik Tambahan:

  • Buat Tombol baru dengan Mengklik Kanan pada "CraftingSlots" Objek -> UI -> Tombol dan ganti namanya menjadi "CraftButton"
  • Tetapkan "CraftButton" nilai RectTransform ke ("Rata Kiri Tengah" Pivot X: 1 Pivot Y: 0,5 Pos X: 0 Pos Y: 0 Lebar: 40 Tinggi: 40)
  • Ubah Teks "CraftButton" ke "Craft"

  • Buat Gambar baru dengan Klik Kanan pada "CraftingSlots" Objek -> UI -> Gambar dan ganti namanya menjadi "Arrow"
  • Tetapkan "Arrow" nilai RectTransform ke ("Rata Tengah Kanan" Pivot X: 0 Pivot Y: 0,5 Pos X: 10 Pos Y: 0 Lebar: 30 Tinggi: 30)

Untuk Sumber Gambarnya bisa menggunakan gambar dibawah ini (Klik kanan -> Save as.. untuk mendownloadnya). Setelah mengimpor, atur jenis Teksturnya ke "Sprite (2D and UI)" dan Mode Filter ke "Point (no filter)"

Piksel Ikon Panah Kanan

  • Klik kanan pada "CraftingSlots" -> Buat Kosong dan ubah namanya menjadi "ResultSlot", objek ini akan berisi slot hasil
  • Tetapkan "ResultSlot" nilai RectTransform ke ("Perataan Kanan Tengah" Pivot X: 0 Pivot Y: 0,5 Pos X: 50 Pos Y: 0 Lebar: 50 Tinggi: 50)

Pengaturan UI sudah siap.

Langkah 2: Sistem Pembuatan Program

Sistem Kerajinan ini akan terdiri dari 2 skrip, SC_ItemCrafting.cs, dan SC_SlotTemplate.cs

  • Buat skrip baru, beri nama "SC_ItemCrafting" lalu tempel kode di bawah ini di dalamnya:

SC_ItemCrafting.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class SC_ItemCrafting : MonoBehaviour
{
    public RectTransform playerSlotsContainer;
    public RectTransform craftingSlotsContainer;
    public RectTransform resultSlotContainer;
    public Button craftButton;
    public SC_SlotTemplate slotTemplate;
    public SC_SlotTemplate resultSlotTemplate;

    [System.Serializable]
    public class SlotContainer
    {
        public Sprite itemSprite; //Sprite of the assigned item (Must be the same sprite as in items array), or leave null for no item
        public int itemCount; //How many items in this slot, everything equal or under 1 will be interpreted as 1 item
        [HideInInspector]
        public int tableID;
        [HideInInspector]
        public SC_SlotTemplate slot;
    }

    [System.Serializable]
    public class Item
    {
        public Sprite itemSprite;
        public bool stackable = false; //Can this item be combined (stacked) together?
        public string craftRecipe; //Item Keys that are required to craft this item, separated by comma (Tip: Use Craft Button in Play mode and see console for printed recipe)
    }

    public SlotContainer[] playerSlots;
    SlotContainer[] craftSlots = new SlotContainer[9];
    SlotContainer resultSlot = new SlotContainer();
    //List of all available items
    public Item[] items;

    SlotContainer selectedItemSlot = null;

    int craftTableID = -1; //ID of table where items will be placed one at a time (ex. Craft table)
    int resultTableID = -1; //ID of table from where we can take items, but cannot place to

    ColorBlock defaultButtonColors;

    // Start is called before the first frame update
    void Start()
    {
        //Setup slot element template
        slotTemplate.container.rectTransform.pivot = new Vector2(0, 1);
        slotTemplate.container.rectTransform.anchorMax = slotTemplate.container.rectTransform.anchorMin = new Vector2(0, 1);
        slotTemplate.craftingController = this;
        slotTemplate.gameObject.SetActive(false);
        //Setup result slot element template
        resultSlotTemplate.container.rectTransform.pivot = new Vector2(0, 1);
        resultSlotTemplate.container.rectTransform.anchorMax = resultSlotTemplate.container.rectTransform.anchorMin = new Vector2(0, 1);
        resultSlotTemplate.craftingController = this;
        resultSlotTemplate.gameObject.SetActive(false);

        //Attach click event to craft button
        craftButton.onClick.AddListener(PerformCrafting);
        //Save craft button default colors
        defaultButtonColors = craftButton.colors;

        //InitializeItem Crafting Slots
        InitializeSlotTable(craftingSlotsContainer, slotTemplate, craftSlots, 5, 0);
        UpdateItems(craftSlots);
        craftTableID = 0;

        //InitializeItem Player Slots
        InitializeSlotTable(playerSlotsContainer, slotTemplate, playerSlots, 5, 1);
        UpdateItems(playerSlots);

        //InitializeItemResult Slot
        InitializeSlotTable(resultSlotContainer, resultSlotTemplate, new SlotContainer[] { resultSlot }, 0, 2);
        UpdateItems(new SlotContainer[] { resultSlot });
        resultTableID = 2;

        //Reset Slot element template (To be used later for hovering element)
        slotTemplate.container.rectTransform.pivot = new Vector2(0.5f, 0.5f);
        slotTemplate.container.raycastTarget = slotTemplate.item.raycastTarget = slotTemplate.count.raycastTarget = false;
    }

    void InitializeSlotTable(RectTransform container, SC_SlotTemplate slotTemplateTmp, SlotContainer[] slots, int margin, int tableIDTmp)
    {
        int resetIndex = 0;
        int rowTmp = 0;
        for (int i = 0; i < slots.Length; i++)
        {
            if (slots[i] == null)
            {
                slots[i] = new SlotContainer();
            }
            GameObject newSlot = Instantiate(slotTemplateTmp.gameObject, container.transform);
            slots[i].slot = newSlot.GetComponent<SC_SlotTemplate>();
            slots[i].slot.gameObject.SetActive(true);
            slots[i].tableID = tableIDTmp;

            float xTmp = (int)((margin + slots[i].slot.container.rectTransform.sizeDelta.x) * (i - resetIndex));
            if (xTmp + slots[i].slot.container.rectTransform.sizeDelta.x + margin > container.rect.width)
            {
                resetIndex = i;
                rowTmp++;
                xTmp = 0;
            }
            slots[i].slot.container.rectTransform.anchoredPosition = new Vector2(margin + xTmp, -margin - ((margin + slots[i].slot.container.rectTransform.sizeDelta.y) * rowTmp));
        }
    }

    //Update Table UI
    void UpdateItems(SlotContainer[] slots)
    {
        for (int i = 0; i < slots.Length; i++)
        {
            Item slotItem = FindItem(slots[i].itemSprite);
            if (slotItem != null)
            {
                if (!slotItem.stackable)
                {
                    slots[i].itemCount = 1;
                }
                //Apply total item count
                if (slots[i].itemCount > 1)
                {
                    slots[i].slot.count.enabled = true;
                    slots[i].slot.count.text = slots[i].itemCount.ToString();
                }
                else
                {
                    slots[i].slot.count.enabled = false;
                }
                //Apply item icon
                slots[i].slot.item.enabled = true;
                slots[i].slot.item.sprite = slotItem.itemSprite;
            }
            else
            {
                slots[i].slot.count.enabled = false;
                slots[i].slot.item.enabled = false;
            }
        }
    }

    //Find Item from the items list using sprite as reference
    Item FindItem(Sprite sprite)
    {
        if (!sprite)
            return null;

        for (int i = 0; i < items.Length; i++)
        {
            if (items[i].itemSprite == sprite)
            {
                return items[i];
            }
        }

        return null;
    }

    //Find Item from the items list using recipe as reference
    Item FindItem(string recipe)
    {
        if (recipe == "")
            return null;

        for (int i = 0; i < items.Length; i++)
        {
            if (items[i].craftRecipe == recipe)
            {
                return items[i];
            }
        }

        return null;
    }

    //Called from SC_SlotTemplate.cs
    public void ClickEventRecheck()
    {
        if (selectedItemSlot == null)
        {
            //Get clicked slot
            selectedItemSlot = GetClickedSlot();
            if (selectedItemSlot != null)
            {
                if (selectedItemSlot.itemSprite != null)
                {
                    selectedItemSlot.slot.count.color = selectedItemSlot.slot.item.color = new Color(1, 1, 1, 0.5f);
                }
                else
                {
                    selectedItemSlot = null;
                }
            }
        }
        else
        {
            SlotContainer newClickedSlot = GetClickedSlot();
            if (newClickedSlot != null)
            {
                bool swapPositions = false;
                bool releaseClick = true;

                if (newClickedSlot != selectedItemSlot)
                {
                    //We clicked on the same table but different slots
                    if (newClickedSlot.tableID == selectedItemSlot.tableID)
                    {
                        //Check if new clicked item is the same, then stack, if not, swap (Unless it's a crafting table, then do nothing)
                        if (newClickedSlot.itemSprite == selectedItemSlot.itemSprite)
                        {
                            Item slotItem = FindItem(selectedItemSlot.itemSprite);
                            if (slotItem.stackable)
                            {
                                //Item is the same and is stackable, remove item from previous position and add its count to a new position
                                selectedItemSlot.itemSprite = null;
                                newClickedSlot.itemCount += selectedItemSlot.itemCount;
                                selectedItemSlot.itemCount = 0;
                            }
                            else
                            {
                                swapPositions = true;
                            }
                        }
                        else
                        {
                            swapPositions = true;
                        }
                    }
                    else
                    {
                        //Moving to different table
                        if (resultTableID != newClickedSlot.tableID)
                        {
                            if (craftTableID != newClickedSlot.tableID)
                            {
                                if (newClickedSlot.itemSprite == selectedItemSlot.itemSprite)
                                {
                                    Item slotItem = FindItem(selectedItemSlot.itemSprite);
                                    if (slotItem.stackable)
                                    {
                                        //Item is the same and is stackable, remove item from previous position and add its count to a new position
                                        selectedItemSlot.itemSprite = null;
                                        newClickedSlot.itemCount += selectedItemSlot.itemCount;
                                        selectedItemSlot.itemCount = 0;
                                    }
                                    else
                                    {
                                        swapPositions = true;
                                    }
                                }
                                else
                                {
                                    swapPositions = true;
                                }
                            }
                            else
                            {
                                if (newClickedSlot.itemSprite == null || newClickedSlot.itemSprite == selectedItemSlot.itemSprite)
                                {
                                    //Add 1 item from selectedItemSlot
                                    newClickedSlot.itemSprite = selectedItemSlot.itemSprite;
                                    newClickedSlot.itemCount++;
                                    selectedItemSlot.itemCount--;
                                    if (selectedItemSlot.itemCount <= 0)
                                    {
                                        //We placed the last item
                                        selectedItemSlot.itemSprite = null;
                                    }
                                    else
                                    {
                                        releaseClick = false;
                                    }
                                }
                                else
                                {
                                    swapPositions = true;
                                }
                            }
                        }
                    }
                }

                if (swapPositions)
                {
                    //Swap items
                    Sprite previousItemSprite = selectedItemSlot.itemSprite;
                    int previousItemConunt = selectedItemSlot.itemCount;

                    selectedItemSlot.itemSprite = newClickedSlot.itemSprite;
                    selectedItemSlot.itemCount = newClickedSlot.itemCount;

                    newClickedSlot.itemSprite = previousItemSprite;
                    newClickedSlot.itemCount = previousItemConunt;
                }

                if (releaseClick)
                {
                    //Release click
                    selectedItemSlot.slot.count.color = selectedItemSlot.slot.item.color = Color.white;
                    selectedItemSlot = null;
                }

                //Update UI
                UpdateItems(playerSlots);
                UpdateItems(craftSlots);
                UpdateItems(new SlotContainer[] { resultSlot });
            }
        }
    }

    SlotContainer GetClickedSlot()
    {
        for (int i = 0; i < playerSlots.Length; i++)
        {
            if (playerSlots[i].slot.hasClicked)
            {
                playerSlots[i].slot.hasClicked = false;
                return playerSlots[i];
            }
        }

        for (int i = 0; i < craftSlots.Length; i++)
        {
            if (craftSlots[i].slot.hasClicked)
            {
                craftSlots[i].slot.hasClicked = false;
                return craftSlots[i];
            }
        }

        if (resultSlot.slot.hasClicked)
        {
            resultSlot.slot.hasClicked = false;
            return resultSlot;
        }

        return null;
    }

    void PerformCrafting()
    {
        string[] combinedItemRecipe = new string[craftSlots.Length];

        craftButton.colors = defaultButtonColors;

        for (int i = 0; i < craftSlots.Length; i++)
        {
            Item slotItem = FindItem(craftSlots[i].itemSprite);
            if (slotItem != null)
            {
                combinedItemRecipe[i] = slotItem.itemSprite.name + (craftSlots[i].itemCount > 1 ? "(" + craftSlots[i].itemCount + ")" : "");
            }
            else
            {
                combinedItemRecipe[i] = "";
            }
        }

        string combinedRecipe = string.Join(",", combinedItemRecipe);
        print(combinedRecipe);

        //Search if recipe match any of the item recipe
        Item craftedItem = FindItem(combinedRecipe);
        if (craftedItem != null)
        {
            //Clear Craft slots
            for (int i = 0; i < craftSlots.Length; i++)
            {
                craftSlots[i].itemSprite = null;
                craftSlots[i].itemCount = 0;
            }

            resultSlot.itemSprite = craftedItem.itemSprite;
            resultSlot.itemCount = 1;

            UpdateItems(craftSlots);
            UpdateItems(new SlotContainer[] { resultSlot });
        }
        else
        {
            ColorBlock colors = craftButton.colors;
            colors.selectedColor = colors.pressedColor = new Color(0.8f, 0.55f, 0.55f, 1);
            craftButton.colors = colors;
        }
    }

    // Update is called once per frame
    void Update()
    {
        //Slot UI follow mouse position
        if (selectedItemSlot != null)
        {
            if (!slotTemplate.gameObject.activeSelf)
            {
                slotTemplate.gameObject.SetActive(true);
                slotTemplate.container.enabled = false;

                //Copy selected item values to slot template
                slotTemplate.count.color = selectedItemSlot.slot.count.color;
                slotTemplate.item.sprite = selectedItemSlot.slot.item.sprite;
                slotTemplate.item.color = selectedItemSlot.slot.item.color;
            }

            //Make template slot follow mouse position
            slotTemplate.container.rectTransform.position = Input.mousePosition;
            //Update item count
            slotTemplate.count.text = selectedItemSlot.slot.count.text;
            slotTemplate.count.enabled = selectedItemSlot.slot.count.enabled;
        }
        else
        {
            if (slotTemplate.gameObject.activeSelf)
            {
                slotTemplate.gameObject.SetActive(false);
            }
        }
    }
}
  • Buat skrip baru, beri nama "SC_SlotTemplate" lalu tempel kode di bawah ini di dalamnya:

SC_SlotTemplate.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;

public class SC_SlotTemplate : MonoBehaviour, IPointerClickHandler
{
    public Image container;
    public Image item;
    public Text count;

    [HideInInspector]
    public bool hasClicked = false;
    [HideInInspector]
    public SC_ItemCrafting craftingController;

    //Do this when the mouse is clicked over the selectable object this script is attached to.
    public void OnPointerClick(PointerEventData eventData)
    {
        hasClicked = true;
        craftingController.ClickEventRecheck();
    }
}

Mempersiapkan Template Slot:

  • Lampirkan skrip SC_SlotTemplate ke objek "slot_template", dan tetapkan variabelnya (Komponen gambar pada Objek yang sama masuk ke variabel "Container", anak "Item" Gambar masuk ke variabel "Item", dan anak "Count" Teks masuk ke variabel "Count")
  • Ulangi proses yang sama untuk Objek "result_slot_template" (lampirkan skrip SC_SlotTemplate ke dalamnya dan tetapkan variabel dengan cara yang sama).

Mempersiapkan Sistem Kerajinan:

  • Lampirkan skrip SC_ItemCrafting ke objek Canvas, dan tetapkan variabelnya. Objek ("PlayerSlots" ke variabel "Player Slots Container", "CraftingSlots" Objek ke variabel "Crafting Slots Container", "ResultSlot" Objek ke "Result Slot Container" variabel, "CraftButton" Objek masuk ke variabel "Craft Button", "slot_template" Objek dengan skrip SC_SlotTemplate terlampir masuk ke variabel "Slot Template" dan "result_slot_template" Objek dengan skrip SC_SlotTemplate terlampir masuk ke variabel "Result Slot Template"):

Seperti yang telah Anda ketahui, ada dua array kosong bernama "Player Slots" dan "Items". "Player Slots" akan berisi jumlah slot yang tersedia (dengan Item atau kosong) dan "Items" akan berisi semua item yang tersedia beserta resepnya (opsional).

Menyiapkan Item:

Periksa sprite di bawah ini (dalam kasus saya, saya akan memiliki 5 item):

Barang Batu (batu)

Barang Berlian (berlian)

Barang Kayu (kayu)

Barang Pedang (pedang)

Pedang berlian (pedang berlian)

  • Unduh setiap sprite (Klik Kanan -> Simpan sebagai...) dan impor ke proyek Anda (Dalam Pengaturan Impor, atur Jenis Teksturnya ke "Sprite (2D and UI)" dan Mode Filter ke "Point (no filter)"

  • Di SC_ItemCrafting ubah Ukuran Item menjadi 5 dan tetapkan setiap sprite ke variabel Item Sprite.

"Stackable" variabel mengontrol apakah item dapat ditumpuk menjadi satu slot (mis. Anda mungkin hanya mengizinkan penumpukan untuk material sederhana seperti batu, berlian, dan kayu).

"Craft Recipe" kontrol variabel apakah item ini dapat dibuat (kosong berarti tidak dapat dibuat)

  • Untuk "Player Slots" atur Ukuran Array ke 27 (paling cocok untuk Panel Kerajinan saat ini, tetapi Anda dapat mengatur nomor berapa pun).

Saat Anda menekan Mainkan, Anda akan melihat bahwa slot diinisialisasi dengan benar, tetapi tidak ada item:

Untuk menambahkan item ke setiap slot kita perlu menetapkan item Sprite ke variabel "Item Sprite" dan mengatur "Item Count" ke angka positif apa pun (semua yang di bawah 1, dan/atau item yang tidak dapat ditumpuk akan ditafsirkan sebagai 1):

  • Tetapkan sprite "rock" ke Elemen 0 / "Item Count" 14, sprite "wood" ke Elemen 1 / "Item Count" 8, "diamond" sprite ke Elemen 2 / "Item Count" 8 (Pastikan spritenya sama dengan di "Items" Array, jika tidak maka tidak akan berfungsi).

Item sekarang akan muncul di Slot Pemain, Anda dapat mengubah posisinya dengan mengklik item tersebut, lalu mengklik slot tempat Anda ingin memindahkannya.

Resep Kerajinan:

Resep kerajinan memungkinkan Anda membuat item dengan menggabungkan item lain dalam urutan tertentu:

Format resep kerajinan adalah sebagai berikut: [nama_sprite_item]([jumlah item])*opsional... diulang sebanyak 9 kali, dipisahkan dengan koma (,)

Cara mudah untuk mengetahui resepnya adalah dengan menekan Play, lalu menyusun item sesuai urutan yang ingin Anda buat, lalu menekan "Craft", setelah itu tekan (Ctrl + Shift + C) untuk membuka Unity Console dan melihat garis yang baru dicetak (Anda dapat mengklik "Craft" beberapa kali untuk mencetak ulang garis), garis yang dicetak adalah resep kerajinan.

Misalnya, kombinasi di bawah ini sesuai dengan resep ini: rock,,rock,,rock,,rock,,wood (CATATAN: mungkin berbeda untuk Anda jika sprite Anda memiliki nama yang berbeda).

Resep Pembuatan Benda Pedang

Kami akan menggunakan resep di atas untuk membuat pedang.

  • Salin baris yang dicetak, dan dalam Array "Items" tempelkan di variabel "Craft Recipe" di bawah "sword" Item:

Sekarang ketika mengulangi kombinasi yang sama, Anda seharusnya bisa membuat pedang.

Resep untuk membuat pedang berlian juga sama, tetapi yang digunakan sebagai pengganti batu adalah berlian:

Inspektur Persatuan Resep Pedang Item Berlian

Sistem Inventaris Persatuan dan Pembuatan Barang

Sistem Kerajinan sekarang siap.

Sumber
📁ItemCrafting.unitypackage36.13 KB
Artikel yang Disarankan
Mengkodekan Sistem Inventaris Sederhana Dengan UI Drag and Drop di Unity
Pengantar Mesin Negara di Unity
Cara Memicu Cutscene di Unity
Membuat Koleksi dan Power-up di Unity
Logika Penembakan Flare Gun dalam Kesatuan
Membuat Kelas dan Objek dalam Kode Unity
Membuat Game Terinspirasi Pac-Man di Unity