Unity ์ˆ™๋ จ - 4

์ด์ค€ํ˜ธยท2023๋…„ 12์›” 14์ผ
0

๐Ÿ“Œ Unity ๊ฒŒ์ž„ ๊ฐœ๋ฐœ ์ˆ™๋ จ



๐Ÿ“Œ ์ธ๋ฒคํ† ๋ฆฌ ๋งŒ๋“ค๊ธฐ & ์•„์ดํ…œ ์‚ฌ์šฉํ•˜๊ธฐ

โž” ์ธ๋ฒคํ† ๋ฆฌ UI๋งŒ๋“ค๊ธฐ

Inventory Canvas ์ƒ์„ฑ

- BG ์ƒ์„ฑ

- Slots ์ƒ์„ฑ

-- ItemSlot ์ƒ์„ฑ & ํ”„๋ฆฌํŒน ๋งŒ๋“ค๊ธฐ

  • ItemSlot ์ƒ์„ฑ

  • Image & Text ์ถ”๊ฐ€

  • Ctrl + D - 2์ค„(14๊ฐœ) ๋ณต์ œ

- InfoBG ์ƒ์„ฑ

  • ๋ฐฐ๊ฒฝ ์˜ค๋ธŒ์ ํŠธ

  • ์•„์ดํ…œ ์ •๋ณด๋ฅผ ๋ณด์—ฌ์ค„ ํ…์ŠคํŠธ ์ถ”๊ฐ€

  • ๋ฒ„ํŠผ ์ถ”๊ฐ€






โž” ์ธ๋ฒคํ† ๋ฆฌ ์Šคํฌ๋ฆฝํŠธ ์ž‘์„ฑ

Inventory.cs

public class ItemSlot
{
    public ItemData item;
    public int quantity;
}

public class Inventory : MonoBehaviour
{
    // ์•„์ดํ…œ ํ‚ค๊ณ  ๋„๊ธฐ, ๋“œ๋ž ๋“ฑ ๋ณ€์ˆ˜ ์ค€๋น„
    public ItemSlotUI[] uiSlot;
    public ItemSlot[] slots;

    public GameObject inventoryWindow;  // ์ธ๋ฒคํ† ๋ฆฌ ์ฐฝ
    public Transform dropPosition;  // ๋ฒ„๋ฆฌ๋Š” ์œ„์น˜

    [Header("Selected Item")]
    private ItemSlot selectedItem;
    private int selectedItemIndex;
    public TextMeshProUGUI selectedItemName;    // Inventory์˜ TextMeshPro๋“ค (์•„์ดํ…œ ์ด๋ฆ„, ์„ค๋ช…, ์Šคํƒฏ์ด ๋ฆ„, ์Šคํƒฏ ์ˆ˜์น˜)
    public TextMeshProUGUI selectedItemDesciption;
    public TextMeshProUGUI selectedItemStatNames;
    public TextMeshProUGUI selectedItemStatValues;
    public GameObject useButton;    // Inventory์˜ Button๋“ค (์‚ฌ์šฉ, ์ฐฉ์šฉ, ํ•ด์ œ, ๋ฒ„๋ฆฌ๊ธฐ)
    public GameObject equipButton;
    public GameObject unEquipButton;
    public GameObject dropButton;

    private int curEquipIndex;

    private PlayerController controller;
    private PlayerConditions condition;

    [Header("Events")]
    public UnityEvent onOpenInventory;
    public UnityEvent onCloseInventory;

    public static Inventory instance;

    private void Awake()
    {
        instance = this;
        controller = GetComponent<PlayerController>();
        condition = GetComponent<PlayerConditions>();
    }

    private void Start()
    {
        inventoryWindow.SetActive(false);   // ์ฒ˜์Œ์—๋Š” ์ธ๋ฒคํ† ๋ฆฌ๋ฅผ ๊บผ์ค€๋‹ค.
        slots = new ItemSlot[uiSlot.Length];

        
        // UI ์Šฌ๋กฏ๋“ค ์ดˆ๊ธฐํ™”
        for(int i = 0; i < slots.Length; i++)
        {
            slots[i] = new ItemSlot();
            uiSlot[i].index = i;
            uiSlot[i].Clear();
        }

        ClearSeletecItemWindow();
    }

    // ๋ฒ„ํŠผ(Tap)์„ ๋ˆ„๋ฅด๋ฉด
    public void OnInventoryButton(InputAction.CallbackContext callbackContext)
    {
        if(callbackContext.phase == InputActionPhase.Started)
        {
            Toggle();       // Toggle() : ์ผœ์ ธ์žˆ์œผ๋ฉด ๊บผ์ฃผ๊ณ  ๊บผ์ ธ์žˆ์œผ๋ฉด ์ผœ์ค€๋‹ค.
        }
    }

    public void Toggle()
    {
        if(inventoryWindow.activeInHierarchy)   // activeInHierarchy : Hierarchy ์ƒ์—์„œ ์ผœ์ ธ์žˆ๋Š”๊ฐ€?
        {
            inventoryWindow.SetActive(false);
            onCloseInventory?.Invoke();
            controller.ToggleCursor(false);
        }
        else
        {
            inventoryWindow.SetActive(true);
            onOpenInventory?.Invoke();
            controller.ToggleCursor(true);
        }
    }

    public bool IsOpen()
    {
        return inventoryWindow.activeInHierarchy;
    }

    // Eํ‚ค๋ฅผ ๋ˆŒ๋Ÿฌ ์•„์ดํ…œ์„ ์ฃผ์› ์„ ๋•Œ, ์ฒ˜๋ฆฌ
    public void AddItem(ItemData item)
    {
        if(item.canStack)   // .canStack : ์•„์ดํ…œ์ด ์Œ“์ผ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด๋ƒ?
        {                   
            ItemSlot slotToStackTo = GetItemStack(item);
            if(slotToStackTo != null)
            {
                slotToStackTo.quantity++;   // ์ฐธ์ด๋ฉด ์Šคํƒ์„ ์Œ“์•„๋ผ
                UpdateUI();
                return;
            }
        }

        // ์Œ“์„์ˆ˜ ์žˆ๋Š”๊ฒŒ ์•„๋‹ˆ๋ฉด ๋นˆ์นธ(Empty)์„ ์ฐพ์•„ ๊ฐ€๋ผ

        ItemSlot emptySlot = GetEmptySlot();

        if(emptySlot != null)
        {
            emptySlot.item = item;
            emptySlot.quantity = 1;
            UpdateUI();
            return;
        }

        // ๊ฝ‰ ์ฐผ๋‹ค๋ฉด?
        ThrowItem(item);    // ์•„์ดํ…œ์„ ๋‹ค์‹œ ๋˜์ง„๋‹ค.
    }

    void ThrowItem(ItemData item)
    {
        // ๋‚ด ์•ž์— ๋“œ๋ž์ง€์ (dropPosition)์— ์žก์•„๋‘” ๊ณณ์— ๋žœ๋คํ•œ ํšŒ์ „์„ ๋ฐ›๊ณ ์„œ ๋‹ค์‹œ ์ถœ๋ ฅํ•ด๋ผ (์ธ๋ฒคํ† ๋ฆฌ๊ฐ€ ๊ฝ‰ ์ฐผ์„ ๋•Œ)
        Instantiate(item.dropPrefab, dropPosition.position, Quaternion.Euler(Vector3.one * Random.value * 360f));
    }

    // slots์— ์žˆ๋Š” ๋ฐ์ดํ„ฐ๋กœ uislot์— ์ตœ์‹ ํ™”๋ฅผ ์‹œ์ผœ์ค€๋‹ค.
    void UpdateUI()
    {
        for(int i = 0; i < slots.Length; i++)
        {
            if (slots[i].item != null)
                uiSlot[i].Set(slots[i]);    // slots[i]์— ์•„์ดํ…œ์ด ์žˆ๋‹ค๋ฉด ui์— Set
            else
                uiSlot[i].Clear();      // ์—†๋‹ค๋ฉด Clear
        }
    }

    ItemSlot GetItemStack(ItemData item)
    {
        for(int i = 0; i < slots.Length; i++)   // slots์„ ๋Œ๋ฉด์„œ
        {
            // slots์— ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋“ค์–ด์˜จ item์ด ์กด์žฌํ•˜๊ณ  ๊ทธ ๊ฐฏ์ˆ˜๊ฐ€ ๊ทธ ์•„์ดํ…œ์˜ ์ตœ๋Œ€์Šคํƒ๊ฐฏ์ˆ˜๋ฅผ ๋„˜์ง€ ์•Š๋‹ค๋ฉด
            if (slots[i].item == item && slots[i].quantity < item.maxStackAmount)
                return slots[i];
        }
        return null;
    }

    ItemSlot GetEmptySlot()
    {
        for (int i = 0; i < slots.Length; i++)   // slots์„ ๋Œ๋ฉด์„œ
        {
            if (slots[i].item == null)  // ๋นˆ์นธ์„ ์ฐพ์•„๋ผ
                return slots[i];
        }

        return null;
    }

    public void SelectItem(int index)
    {
        if (slots[index].item == null)
            return;     // ์•„์ดํ…œ์ด ์—†์œผ๋ฉด Select์„ ํ•  ์ˆ˜ ์—†์œผ๋‹ˆ return

        selectedItem = slots[index];
        selectedItemIndex = index;

        selectedItemName.text = selectedItem.item.displayName;
        selectedItemDesciption.text = selectedItem.item.description;

        selectedItemStatNames.text = string.Empty;
        selectedItemStatValues.text = string.Empty;

        for(int i = 0; i < selectedItem.item.consumables.Length; i++)
        {
            selectedItemStatNames.text += selectedItem.item.consumables[i].type.ToString() + "\n";
            selectedItemStatValues.text += selectedItem.item.consumables[i].value.ToString() + "\n";
        }

        useButton.SetActive(selectedItem.item.type == ItemType.Consumable); // ์†Œ๋ชจ ๋ฒ„ํŠผ
        equipButton.SetActive(selectedItem.item.type == ItemType.Equipable && !uiSlot[index].equipped);   // ์žฅ์ฐฉ , && !uiSlot[index].equipped : ์žฅ์ฐฉ์„ ์•ˆํ•˜๊ณ  ์žˆ๋‚˜?
        unEquipButton.SetActive(selectedItem.item.type == ItemType.Equipable && uiSlot[index].equipped);  // ํ•ด์ œ , ์žฅ์ฐฉ์„ ํ•˜๊ณ  ์žˆ๋Š”๊ฐ€
        dropButton.SetActive(true); // ๋“œ๋ž ๋ฒ„ํŠผ
    }

    // ์ดˆ๊ธฐํ™” ์ž‘์—…
    private void ClearSeletecItemWindow()
    {
        selectedItem = null;
        selectedItemName.text = string.Empty;
        selectedItemDesciption.text = string.Empty;

        selectedItemStatNames.text = string.Empty;
        selectedItemStatValues.text = string.Empty;

        useButton.SetActive(false);
        useButton.SetActive(false);
        unEquipButton.SetActive(false);
        dropButton.SetActive(false);
    }

    // ๊ฐ๊ฐ์˜ ๋ฒ„ํŠผ๋“ค์ด ๋ˆŒ๋ ธ์„ ๋•Œ, ์‹คํ–‰ํ•  ๋ฉ”์„œ๋“œ๋“ค OnUseButton() ~ OnDropButton()
    public void OnUseButton()
    {
        if(selectedItem.item.type == ItemType.Consumable)   // ์†Œ๋ชจ์„ฑ ์•„์ดํ…œ์ธ๊ฐ€?
        {
            for(int i = 0; i < selectedItem.item.consumables.Length; i++)
            {
                switch(selectedItem.item.consumables[i].type)
                {
                    case ConsumableType.Health:
                        condition.Heal(selectedItem.item.consumables[i].value);
                        break;
                    case ConsumableType.Hunger:
                        condition.Eat(selectedItem.item.consumables[i].value);
                        break;
                }
            }
        }
        RemoveSelectedItem();   // ์‚ฌ์šฉํ•œ ์•„์ดํ…œ์€ ์‚ญ์ œ
    }

    public void OnEquipButton()
    {

    }

    void UnEquip(int index)
    {

    }

    public void OnUnEquipButton()
    {

    }

    public void OnDropButton()
    {
        ThrowItem(selectedItem.item);
        RemoveSelectedItem();
    }


    private void RemoveSelectedItem()
    {
        selectedItem.quantity--;    // quantity : ๊ฐฏ์ˆ˜

        if(selectedItem.quantity <= 0)
        {
            if (uiSlot[selectedItemIndex].equipped)
            {
                UnEquip(selectedItemIndex); // ์•„์ดํ…œ์„ Removeํ–ˆ๋Š”๋ฐ ์žฅ์ฐฉ์ค‘์ด๋ฉด UnEquip ํ•ด๋ผ
            }

            selectedItem.item = null;
            ClearSeletecItemWindow();
        }

        UpdateUI();
    }

    public void RemoveItem(ItemData item)
    {

    }

    public bool HasItems(ItemData item, int quantity)
    {
        return false;
    }
}

ItemSlotUI.cs

public class ItemSlotUI : MonoBehaviour
{
    public Button button;
    public Image icon;
    public TextMeshProUGUI quatityText;
    private ItemSlot curSlot;
    private Outline outline;

    public int index;
    public bool equipped;

    private void Awake()
    {
        outline = GetComponent<Outline>();
    }

    private void OnEnable()
    {
        outline.enabled = equipped;
    }

    // ItemSlot์˜ ์ •๋ณด๋ฅผ ๋ณด๋‚ด์ฃผ๋ฉด ์—ฌ๊ธฐ์„œ ์…‹ํŒ…์„ ํ•ด์ค€๋‹ค.
    public void Set(ItemSlot slot)
    {
        curSlot = slot;
        icon.gameObject.SetActive(true);
        icon.sprite = slot.item.icon;
        quatityText.text = slot.quantity > 1 ? slot.quantity.ToString() : string.Empty;

        if (outline != null)
        {
            outline.enabled = equipped;
        }
    }

    // ์Šฌ๋กฏ ์ดˆ๊ธฐํ™”
    public void Clear()
    {
        curSlot = null;
        icon.gameObject.SetActive(false);
        quatityText.text = string.Empty;
    }

    public void OnButtonClick()
    {
        Inventory.instance.SelectItem(index);
    }
}

ItemSlot Prefab Object ์„ค์ •

  • ์œ„์— "- - ItemSlot ์ƒ์„ฑ & ํ”„๋ฆฌํŒน ๋งŒ๋“ค๊ธฐ" ์™€ ๊ฐ™์ด ์„ค์ •

Player Object ์„ค์ •

  • Item Drop Position ์ถ”๊ฐ€

  • Player - Inventory ์ถ”๊ฐ€

  • UI Slots 14๊ฐœ๋ฅผ ์ดˆํ•จํ•˜์—ฌ UI์—ฐ๊ฒฐ












๐Ÿ“Œ ์•„์ดํ…œ ์žฅ์ฐฉ๊ณผ ๋ชจ์…˜

โž” ์žฅ์ฐฉ ์นด๋ฉ”๋ผ ์ค€๋น„

Equip Camera ๋งŒ๋“ค๊ธฐ

  • ์นด๋ฉ”๋ผ๋ฅผ ํ•˜๋‚˜๋งŒ ์“ฐ๋Š”๊ฒฝ์šฐ ์žฅ์ฐฉ๋œ ๋ฌด๊ธฐ๊ฐ€ (๋‹ค๋ฅธ๋ฌผ์ฒด์—)๊ฐ€๋ ค์ง€๋Š” ๋ฌธ์ œ ๋ฐœ์ƒ

  • ๋ฌด๊ธฐ๋งŒ์„ ์ฐ๋Š” ์นด๋ฉ”๋ผ ์ค€๋น„

  • ์•„๋ž˜์™€ ๊ฐ™์ด ์„ค์ •






โž” ๋ฌด๊ธฐ ์ค€๋น„

๋ ˆ์ด์–ด ์ถ”๊ฐ€

๋ฌด๊ธฐ ์˜ค๋ธŒ์ ํŠธ ์ค€๋น„

  • ๋นˆ ์˜ค๋ธŒ์ ํŠธ๋กœ ๋ฌด๊ธฐ ์˜ค๋ธŒ์ ํŠธ ์ƒ์„ฑ

  • ๋ ˆ์ด์–ด "Equip" ์„ค์ •

  • ๊ด€๋ จ ๋ฌด๊ธฐ ๋ชจ๋ธ์„ ํ•˜์œ„์— ์ถ”๊ฐ€






Equip.cs

public class Equip : MonoBehaviour
{
    public virtual void OnAttackInput()
    {

    }
}

EquipManager.cs

public class EquipManager : MonoBehaviour
{
    public Equip curEquip;
    public Transform equipParent;

    private PlayerController controller;
    private PlayerConditions conditions;

    // SingleTon
    public static EquipManager instance;

    private void Awake()
    {
        instance = this;
        controller = GetComponent<PlayerController>();
        conditions = GetComponent<PlayerConditions>();
    }
    
    public void OnAttackInput(InputAction.CallbackContext context)
    {
        if (context.phase == InputActionPhase.Performed && curEquip != null && controller.canLook)
        {
            curEquip.OnAttackInput();
        }
    }

    public void EquipNew(ItemData item)
    {
        UnEquip();
        curEquip = Instantiate(item.equipPrefab, equipParent).GetComponent<Equip>();
    }

    public void UnEquip()
    {
        if (curEquip != null)   // ๋ญ”๊ฐ€ ์žฅ์ฐฉ ํ•˜๊ณ ์žˆ๋‹ค๋ฉด?
        {
            Destroy(curEquip.gameObject);
            curEquip = null;
        }
    }
}

Equip ๋ฒ„ํŠผ & UnEquip ๋ฒ„ํŠผ ์ด๋ฒคํŠธ ์—ฐ๊ฒฐ

Player ์˜ค๋ธŒ์ ํŠธ ์„ค์ •






EquipTool.cs

public class EquipTool : Equip
{
    public float attackRate;
    private bool attacking;
    public float attackDistance;

    [Header("Resource Gathering")]
    public bool doesGatherResources;

    [Header("Combat")]
    public bool doseDealDamage;
    public int damage;

    private Animator animator;
    private Camera _camera;

    private void Awake()
    {
        _camera = Camera.main;
        animator = GetComponent<Animator>();
    }

    public override void OnAttackInput()
    {
        if(!attacking)
        {
            attacking = true;
            animator.SetTrigger("Attack");
            Invoke("OnCanAttack", attackRate);
        }
    }

    void OnCanAttack()
    {
        attacking = false;
    }
}

Equip_Axe ์˜ค๋ธŒ์ ํŠธ ์„ค์ •

  • ์ค€๋น„๋œ ์˜ค๋ธŒ์ ํŠธ์— Equip Tool ์ถ”๊ฐ€

  • ์•„๋ž˜์™€ ๊ฐ™์ด ์„ค์ •






โž” ๋ฌด๊ธฐ ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ค€๋น„

๋ฌด๊ธฐ ์• ๋‹ˆ๋ฉ”์ด์…˜ ๋งŒ๋“ค๊ธฐ

  • Animator ์ถ”๊ฐ€

  • Animator Controller ์ƒ์„ฑ ๋ฐ ์ถ”๊ฐ€

  • ์• ๋‹ˆ๋ฉ”์ด์…˜ ๋…นํ™” ๋ฒ„ํŠผ์„ ํ™œ์šฉํ•˜์—ฌ ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ƒ์„ฑ
    *Axe_Attack : Loop (์ฒดํฌํ•ด์ œ)

์• ๋‹ˆ๋ฉ”์ดํ„ฐ ์ปจํŠธ๋กค๋Ÿฌ ์ˆ˜์ •

  • Attack Trigger ์ƒ์„ฑ

  • ์• ๋‹ˆ๋ฉ”์ด์…˜ Transition ์ƒ์„ฑ

  • Idel โž” Attack : Conditions (Attack), Has Exit Time (์ฒดํฌ ํ•ด์ œ)
    Attack โž” Idle : Has Exit Time (์ฒดํฌ)

Player Input Event - Attack ์„ค์ •






โž” ์•„์ดํ…œ ๋ฐ์ดํ„ฐ ์ˆ˜์ •ํ•˜๊ธฐ

IteamData.cs ์ˆ˜์ •

''' ์ถ”๊ฐ€
[Header("Equip")]
public GameObject equipPrefab;

Axe ItemData - Equip Prefab ์ถ”๊ฐ€






โž” Sword ์•„์ดํ…œ ๋งŒ๋“ค๊ธฐ

๋™์ผํ•œ ์ž‘์—… ์ง„ํ–‰












๐Ÿ“Œ ์ž์› ์ฑ„์ทจ

โž” ์ž์› ์˜ค๋ธŒ์ ํŠธ ๋งŒ๋“ค๊ธฐ

๋‚˜๋ฌด ์˜ค๋ธŒ์ ํŠธ ๋งŒ๋“ค๊ธฐ

  • ๋นˆ ์˜ค๋ธŒ์ ํŠธ ์ƒ์„ฑ - Resource_Tree ์ด๋ฆ„ ๋ณ€๊ฒฝ

  • ํŠธ๋ฆฌ ๋ชจ๋ธ ์ถ”๊ฐ€

  • Layer "Resource"๋ณ€๊ฒฝ

Resource ์Šคํฌ๋ฆฝํŠธ ์ž‘์„ฑ

public class Resource : MonoBehaviour
{
    public ItemData itemToGive;
    public int quantityPerHit = 1;  // ์ˆ˜๋Ÿ‰
    public int capacity;    // ์ด๋Ÿ‰

    public void Gather(Vector3 hitpoint, Vector3 hitNormal)
    {
        for(int i = 0; i < quantityPerHit; i++)
        {
            if(capacity <= 0) { break; }
            capacity -= 1;
            // ์ถฉ๋Œ์— ๋Œ€ํ•œ ๋ฐฉํ–ฅ๋ฒกํ„ฐ๋ฅผ ๋„˜๊ฒจ์ค€๋‹ค. (์ถฉ๋Œ์ด ์ผ์–ด๋‚œ ๊ณณ์—์„œ ๋‚˜๋ฅผ ๋ฐ”๋ผ๋ณด๋Š” ๋ฐฉํ–ฅ์œผ๋กœ ์ƒ์„ฑ์„ ํ•œ๋‹ค.)
            Instantiate(itemToGive.dropPrefab, hitpoint + Vector3.up, Quaternion.LookRotation(hitNormal, Vector3.up));
        }

        if (capacity <= 0)
            Destroy(gameObject);
            
    }
}

ํ”„๋ฆฌํŒน ์„ค์ •






โž” ๊ณต๊ฒฉ ์ด๋ฒคํŠธ ์„ค์ •

EquipTool.cs ์ˆ˜์ •

-----------------------------------์ƒ๋žต ์•„๋ž˜ ๋‚ด์šฉ ์ถ”๊ฐ€
    public void OnHit()
    {
        // ํ™”๋ฉด ๊ฐ€์šด๋ฐ์— Ray๋ฅผ ์ด์„œ 
        Ray ray = _camera.ScreenPointToRay(new Vector3(Screen.width / 2, Screen.height / 2, 0));
        RaycastHit hit;

        if (Physics.Raycast(ray, out hit, attackDistance)) // attackDistance : ์‚ฌ๊ฑฐ๋ฆฌ
        {
            // ์–ด๋–ค ํƒ€์ž…์ธ์ง€ ์ฒดํฌ
            if (doesGatherResources && hit.collider.TryGetComponent(out Resource resource)) // ์ž์› ๋„๊ตฌ ํƒ€์ž…
            {
                resource.Gather(hit.point, hit.normal); // (์œ„์น˜, ๋ฐฉํ–ฅ)
            }

            // ๋งž์€ ๋Œ€์ƒ์ด IDamagable ๋ฅผ ์ƒ์†๋ฐ›์•˜๋‹ค๋ฉด (๋ฐ๋ฏธ์ง€๋ฅผ ์ž…๋Š” ํƒ€์ž… ์ด๋ผ๋Š”๊ฒƒ)
            if (doesDealDamage && hit.collider.TryGetComponent(out IDamagable damageable))  // ์ „ํˆฌ์šฉ ๋„๊ตฌ ํƒ€์ž…
            {
                damageable.TakePhysicalDamage(damage);  // ๋ฐ๋ฏธ์ง€๋ฅผ ์ค€๋‹ค.
            }
        }
    }

Attack Animation - Event ์ถ”๊ฐ€












๐Ÿ“Œ ์Šคํƒœ๋ฏธ๋‚˜ ์‚ฌ์šฉํ•˜๊ธฐ

  • PlayerConditions.cs์— ๋งŒ๋“ค์–ด ๋‘์—ˆ๋˜ UseStamina ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด Equip.cs์— OnAttackInput ๋ฉ”์„œ๋“œ๋ฅผ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ PlayerConditionsํƒ€์ž…์˜ conditions๋ฅผ ๋ฐ›๊ฒŒ ๋ฐ”๊ฟ” ์ˆ˜์ •ํ•˜์˜€๋‹ค.

โž” ์Šคํ…Œ๋ฏธ๋‚˜ ์‚ฌ์šฉ

Equip.cs ์ˆ˜์ •

    public virtual void OnAttackInput(PlayerConditions conditions)
    {

    }

EquipTool.cs ์ˆ˜์ •

''' ์ƒ๋žต
public float useStamina;
''' ์ƒ๋žต

-    //public override void OnAttackInput()
+    public override void OnAttackInput(PlayerConditions conditions)
     {
         if(!attacking)
         {
-            //attacking = true;
-            //animator.SetTrigger("Attack");
-            //Invoke("OnCanAttack", attackRate);
+            if (conditions.UseStamina(useStamina))
+            {
+                attacking = true;
+                animator.SetTrigger("Attack");
+                Invoke("OnCanAttack", attackRate);
+            }
         }
     }

EquipManager.cs ์ˆ˜์ •

''' ์ƒ๋žต
if(context.phase == InputActionPhase.Performed && curEquip != null && controller.canLook)
         {
-            //curEquip.OnAttackInput();
+            curEquip.OnAttackInput(conditions);
         }
     }











1๊ฐœ์˜ ๋Œ“๊ธ€

comment-user-thumbnail
2024๋…„ 3์›” 13์ผ

Discover the simplicity of checking today's Bonoloto results on our website. Just enter your ticket number, and we'll promptly generate the outcome for you. Our platform provides a user-friendly interface, ensuring a seamless experience every time. Don't forget to bookmark our website for easy access to the Bonoloto results. Additionally, you https://comprobar-bonoloto.es/ can verify the Bonoloto QR on our platform by entering your ticket number, and we'll instantly display the results. Checking Bonoloto with QR code is straightforward on our website. Make sure to save it to your favorites for quick access.

๋‹ต๊ธ€ ๋‹ฌ๊ธฐ