Créer un système d'inventaire et de fabrication d'objets dans Unity

Dans ce tutoriel, je vais montrer comment créer un système d'inventaire et de fabrication d'objets de style Minecraft en Unity.

La fabrication d'objets dans les jeux vidéo est un processus consistant à combiner des objets spécifiques (généralement plus simples) en objets plus complexes, avec des propriétés nouvelles et améliorées. Par exemple, combiner du bois et de la pierre pour créer une pioche, ou combiner une tôle et du bois pour créer une épée.

Le système de fabrication ci-dessous est adapté aux mobiles et entièrement automatisé, ce qui signifie qu'il fonctionnera avec n'importe quelle disposition d'interface utilisateur et avec la possibilité de créer des recettes de fabrication personnalisées.

Sharp Coder Lecteur vidéo

Étape 1: Configurer l'interface utilisateur d'artisanat

Nous commençons par configurer l'interface utilisateur de création:

  • Créez un nouveau canevas (Unity Barre des tâches supérieure: GameObject -> UI -> Canvas)
  • Créez une nouvelle image en cliquant avec le bouton droit sur l'objet Canvas -> UI -> Image
  • Renommez l'objet image en "CraftingPanel" et modifiez son image source par défaut "UISprite"
  • Remplacez les valeurs "CraftingPanel" RectTransform par (Pos X: 0 Pos Y: 0 Largeur: 410 Hauteur: 365)

  • Créez deux objets à l'intérieur de "CraftingPanel" (clic droit sur CraftingPanel -> Créer vide, 2 fois)
  • Renommez le premier objet en "CraftingSlots" et modifiez ses valeurs RectTransform en (« Alignement en haut à gauche » Pivot X: 0 Pivot Y: 1 Pos X: 50 Pos Y: -35 Largeur: 140 Hauteur: 140). Cet objet contiendra des emplacements de fabrication.
  • Renommez le deuxième objet en "PlayerSlots" et modifiez ses valeurs RectTransform en ("Top Stretch Horizontally" Pivot X: 0,5 Pivot Y: 1 Gauche: 0 Pos Y: -222 Droite: 0 Hauteur: 100). Cet objet contiendra des emplacements de joueurs.

Section titre:

  • Créez un nouveau texte en cliquant avec le bouton droit sur l'objet "PlayerSlots" -> UI -> Texte et renommez-le en "SectionTitle"
  • Remplacez les valeurs "SectionTitle" RectTransform par (« Alignement en haut à gauche » Pivot X: 0 Pivot Y: 0 Pos X: 5 Pos Y: 0 Largeur: 160 Hauteur: 30)
  • Remplacez le texte "SectionTitle" par "Inventory" et définissez sa taille de police sur 18, son alignement sur le milieu gauche et sa couleur sur (0,2, 0,2, 0,2, 1).
  • Dupliquez l'objet "SectionTitle", remplacez son texte par "Crafting" et déplacez-le sous l'objet "CraftingSlots", puis définissez les mêmes valeurs RectTransform que le précédent "SectionTitle".

Emplacement de fabrication:

L'emplacement de fabrication sera composé d'une image d'arrière-plan, d'une image d'objet et d'un texte de décompte:

  • Créez une nouvelle image en cliquant avec le bouton droit sur l'objet Canvas -> UI -> Image
  • Renommez la nouvelle image en "slot_template", définissez ses valeurs RectTransform sur (Post X: 0 Pos Y: 0 Largeur: 40 Hauteur: 40) et changez sa couleur en (0,32, 0,32, 0,32, 0,8).
  • Dupliquez "slot_template" et renommez-le en "Item", déplacez-le à l'intérieur de l'objet "slot_template", changez ses dimensions RectTransform en (Largeur: 30 Hauteur: 30) et Couleur en (1, 1, 1, 1)
  • Créez un nouveau texte en cliquant avec le bouton droit sur l'objet "slot_template" -> UI -> Texte et renommez-le en "Count"
  • Remplacez les valeurs "Count" RectTransform par (« Alignement en bas à droite » Pivot X: 1 Pivot Y: 0 Pos X: 0 Pos Y: 0 Largeur: 30 Hauteur: 30)
  • Définissez "Count" Texte sur un nombre aléatoire (ex. 12), Style de police sur Gras, Taille de police sur 14, Alignement en bas à droite et Couleur sur (1, 1, 1, 1).
  • Ajoutez le composant Shadow au texte "Count" et définissez la couleur de l'effet sur (0, 0, 0, 0,5).

Le résultat final devrait ressembler à ceci:

Emplacement de résultat (qui sera utilisé pour la création de résultats):

  • Dupliquez l'objet "slot_template" et renommez-le en "result_slot_template"
  • Changez la largeur et la hauteur de "result_slot_template" en 50

Bouton de fabrication et graphiques supplémentaires:

  • Créez un nouveau bouton en cliquant avec le bouton droit sur l'objet "CraftingSlots" -> UI -> Bouton et renommez-le en "CraftButton"
  • Définissez les valeurs "CraftButton" RectTransform sur ("Alignement du milieu à gauche" Pivot X: 1 Pivot Y: 0,5 Pos X: 0 Pos Y: 0 Largeur: 40 Hauteur: 40)
  • Changer le texte de "CraftButton" en "Craft"

  • Créez une nouvelle image en cliquant avec le bouton droit sur l'objet "CraftingSlots" -> UI -> Image et renommez-la en "Arrow"
  • Définissez les valeurs "Arrow" RectTransform sur (« Alignement au milieu à droite » Pivot X: 0 Pivot Y: 0,5 Pos X: 10 Pos Y: 0 Largeur: 30 Hauteur: 30)

Pour l'image source, vous pouvez utiliser l'image ci-dessous (clic droit -> Enregistrer sous... pour la télécharger). Après l'importation, définissez son type de texture sur "Sprite (2D and UI)" et son mode de filtre sur "Point (no filter)"

Flèche Droite Icône Pixel

  • Faites un clic droit sur "CraftingSlots" -> Créer un vide et renommez-le en "ResultSlot", cet objet contiendra l'emplacement de résultat
  • Définissez les valeurs "ResultSlot" RectTransform sur (« Alignement au milieu à droite » Pivot X: 0 Pivot Y: 0,5 Pos X: 50 Pos Y: 0 Largeur: 50 Hauteur: 50)

La configuration de l'interface utilisateur est prête.

Étape 2: Système de création de programme

Ce système de fabrication sera composé de 2 scripts, SC_ItemCrafting.cs et SC_SlotTemplate.cs.

  • Créez un nouveau script, nommez-le "SC_ItemCrafting" puis collez le code ci-dessous à l'intérieur:

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);
            }
        }
    }
}
  • Créez un nouveau script, nommez-le "SC_SlotTemplate" puis collez-y le code ci-dessous:

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();
    }
}

Préparation des modèles de slot:

  • Attachez le script SC_SlotTemplate à l'objet "slot_template" et attribuez ses variables (le composant Image sur le même objet va à la variable "Container", l'image enfant "Item" va à la variable "Item" et un enfant "Count" Le texte va à la variable "Count")
  • Répétez le même processus pour l'objet "result_slot_template" (attachez-y le script SC_SlotTemplate et attribuez les variables de la même manière).

Préparation du système d'artisanat:

  • Attachez le script SC_ItemCrafting à l'objet Canvas et affectez ses variables (l'objet "PlayerSlots" va à la variable "Player Slots Container", "CraftingSlots" l'objet va à la variable "Crafting Slots Container", l'objet "ResultSlot" va à la variable "Result Slot Container" variable, "CraftButton" L'objet va à la variable "Craft Button", "slot_template" L'objet avec le script SC_SlotTemplate attaché va à la variable "Slot Template" et "result_slot_template" L'objet avec le script SC_SlotTemplate attaché va à la variable "Result Slot Template"):

Comme vous l'avez déjà remarqué, il existe deux tableaux vides nommés "Player Slots" et "Items". "Player Slots" contiendra le nombre d'emplacements disponibles (avec Objet ou vides) et "Items" contiendra tous les objets disponibles ainsi que leurs recettes (facultatif).

Configuration des éléments:

Vérifiez les sprites ci-dessous (dans mon cas, j'aurai 5 éléments):

Objet de roche (rocher)

Objet en diamant (diamant)

Article en bois (bois)

Objet d'épée (épée)

Épée de diamant (épée de diamant)

  • Téléchargez chaque sprite (clic droit -> Enregistrer sous...) et importez-les dans votre projet (dans les paramètres d'importation, définissez leur type de texture sur "Sprite (2D and UI)" et leur mode de filtre sur "Point (no filter)"

  • Dans SC_ItemCrafting, modifiez la taille des éléments à 5 et attribuez chaque sprite à la variable Item Sprite.

"Stackable" La variable contrôle si les éléments peuvent être empilés ensemble dans un seul emplacement (par exemple, vous souhaiterez peut-être autoriser l'empilement uniquement pour des matériaux simples tels que la roche, le diamant et le bois).

"Craft Recipe" une variable contrôle si cet objet peut être fabriqué (vide signifie qu'il ne peut pas être fabriqué)

  • Pour le "Player Slots", définissez la taille du tableau sur 27 (la meilleure solution pour le panneau d'artisanat actuel, mais vous pouvez définir n'importe quel nombre).

Lorsque vous appuyez sur Play, vous remarquerez que les emplacements sont correctement initialisés, mais qu'il n'y a aucun élément:

Pour ajouter un élément à chaque emplacement, nous devrons attribuer un Sprite d'élément à la variable "Item Sprite" et définir "Item Count" sur n'importe quel nombre positif (tout ce qui est inférieur à 1 et/ou les éléments non empilables seront interprétés comme 1).:

  • Assignez le sprite "rock" à l'élément 0 / "Item Count" 14, le sprite "wood" à l'élément 1 / "Item Count" 8, le sprite "diamond" à l'élément 2 / "Item Count" 8 (assurez-vous que les sprites sont les mêmes que dans "Items" Array, sinon ça ne marchera pas).

Les objets devraient maintenant apparaître dans les emplacements des joueurs, vous pouvez modifier leur position en cliquant sur l'élément, puis en cliquant sur l'emplacement vers lequel vous souhaitez le déplacer.

Recettes d'artisanat:

Les recettes d'artisanat vous permettent de créer un objet en combinant d'autres objets dans un ordre spécifique:

Le format de la recette de fabrication est le suivant: [item_sprite_name]([item count])*optional... répété 9 fois, séparés par une virgule (,)

Un moyen simple de découvrir la recette est d'appuyer sur Play, puis de placer les objets dans l'ordre que vous souhaitez fabriquer, puis d'appuyer sur "Craft", après cela, appuyez sur (Ctrl + Shift + C) pour ouvrir la console Unity et voir le ligne nouvellement imprimée (vous pouvez cliquer plusieurs fois sur "Craft" pour réimprimer la ligne), la ligne imprimée est la recette de fabrication.

Par exemple, la combinaison ci-dessous correspond à cette recette: rock,,rock,,rock,,rock,,wood (REMARQUE: cela peut être différent pour vous si vos sprites ont des noms différents).

Recette de fabrication d'objets d'épée

Nous utiliserons la recette ci-dessus pour fabriquer une épée.

  • Copiez la ligne imprimée et dans le tableau "Items", collez-la dans la variable "Craft Recipe" sous "sword" Item:

Désormais, en répétant cette même combinaison, vous devriez pouvoir fabriquer une épée.

La recette d'une épée en diamant est la même, mais au lieu de roche, c'est du diamant:

Recette d'épée d'objet en diamant Inspecteur de l'Unité

Système d'inventaire Unity et fabrication d'objets

Le système de fabrication est maintenant prêt.

Source
📁ItemCrafting.unitypackage36.13 KB
Articles suggérés
Codage d'un système d'inventaire simple avec glisser-déposer de l'interface utilisateur dans Unity
Introduction à la machine d'état dans Unity
Comment déclencher une cinématique dans Unity
Création d'un système de puces 2D simple dans Unity
Implémentation du pooling d'objets dans Unity
Créer un jeu de puzzle dans Unity
Créer un jeu inspiré de Pac-Man dans Unity