Chapter 6-2. 퀵슬롯 : 퀵슬롯 심화

Date:     Updated:

카테고리:

태그:

인프런에 있는 케이디님의 [유니티 3D] 실전! 생존게임 만들기 - Advanced 강의를 듣고 정리한 필기입니다. 😀
🌜 강의 들으러 가기 Click

Chapter 6. 퀵슬롯

무기 뿐만 아니라 활성화 퀵슬롯에 있는 다른 아이템들도 사용 가능 하도록 구현 할 것.

🚖 맨 손에 아이템 들기

  • 활성화 된 퀵슬롯의 포션 같은 소모품 아이템을 맨손 오른손 끝에 들고 있을 수 있게 (무기 제외)

아이템 들 위치

image

맨손 Hand의 자식들 중 오른손 끝에 해당하는 오브젝트인 DownArmR_End 오브젝트 자식으로, 아이템을 들고 있는 위치로서 기능할 빈 오브젝트 ItemPos를 추가해주었다.

image

  • ItemPos 이 오브젝트가 아이템을 들고 있는 위치가 될 것이다. 이 위치에 아이템 프리팹을 생성할 것.
  • 로컬 회전축이 월드 기준 회전축과 일치할 수 있도록 z 축으로 90 도 회전하였다.


📜QuickSlotController.cs

    [SerializeField] private Transform tf_ItemPos;  // 손 끝 오브젝트. 손 끝에 아이템이 위치도록 Transform 정보 받아올 것
    public static GameObject go_HandItem;   // 손에 든 아이템. static인 이유는 이거 하나 받아오려고 📜QuickSlotController 로딩하는건 낭비라서

    private void Execute()
    {
        if (quickSlots[selectedSlot].item != null)
        {
            if (quickSlots[selectedSlot].item.itemType == Item.ItemType.Equipment)
                StartCoroutine(theWeaponManager.ChangeWeaponCoroutine(quickSlots[selectedSlot].item.weaponType, quickSlots[selectedSlot].item.itemName));
            else if (quickSlots[selectedSlot].item.itemType == Item.ItemType.Used)
                ChangeHand(quickSlots[selectedSlot].item);
            else
                ChangeHand();
        }
        else
        {
            ChangeHand();
        }
    }

    private void ChangeHand(Item _item = null)
    {
        StartCoroutine(theWeaponManager.ChangeWeaponCoroutine("HAND", "맨손"));

        if (_item != null)
            StartCoroutine(HandItemCoroutine());
    }

    IEnumerator HandItemCoroutine()
    {
        HandController.isActivate = false;
        yield return new WaitUntil(() => HandController.isActivate);  // 맨손 교체의 마지막 과정

        go_HandItem = Instantiate(quickSlots[selectedSlot].item.itemPrefab, tf_ItemPos.position, tf_ItemPos.rotation);
        go_HandItem.GetComponent<Rigidbody>().isKinematic = true;  // 중력 영향 X 
        go_HandItem.GetComponent<Collider>().enabled = false;  // 콜라이더 끔 (플레이어와 충돌하지 않게)
        go_HandItem.tag = "Untagged";   // 획득 안되도록 레이어 태그 바꿈
        go_HandItem.layer = 8;  // "Weapon" 레이어는 int
        go_HandItem.transform.SetParent(tf_ItemPos);
    }
  • tf_ItemPos : 손 끝 오브젝트. 오른손의 ItemPos 할당할 것.
  • go_HandItem : 현재 손에 들고 있는 아이템.
    • 파괴하거나 생성하거나 할 수 있도록 GameObject로 선언하였고
    • static으로 선언하여 다른 스크립트에서도 접근할 수 있도록 한다.
      • 이거 하나로 📜QuickSlotController.cs 전체를 로딩하기엔 낭비라 statc 으로 선언
  • Execute()
    • 활성화된 퀵슬롯에 무기가 있다면 해당 무기로 교체
    • 활성화된 퀵슬롯에 포션같은 소비 아이템이 있다면 맨손으로 교체하고 해당 아이템을 손에 들도록
      • ChangeHand(quickSlots[selectedSlot].item); 호출
    • 활성화된 퀵슬롯에 기타 아이템이 있다면 그냥 맨손으로 교체까지만
      • ChangeHand(); 호출
  • ChangeHand(Item _item = null)
    • 맨손으로 교체한 후
    • 해당 아이템 손에 들기
      • HandItemCoroutine() 호출
  • HandItemCoroutine()
    • 👉 손에 아이템 들기!
      • 우선 맨손 교체가 완료될 때까지 기다린다. (이래서 코루틴) 맨손이 된 후 아이템을 들어야 하니까
        • isActivate false 한번 해주고 StartCoroutine(theWeaponManager.ChangeWeaponCoroutine(“HAND”, “맨손”)); 실행이 전부 끝나면 isActivate가 True가 되는데, isActivate가 True가 될 때까지 기다린다.
        • ⭐ 코루틴 WaitUntil
            • Bool 타입을 리턴하는 함수의 포인터 혹은 람다 함수를 인수로 넘기고 True 값을 리턴할 때까지 대기한다.
      • 해당 아이템을 go_HandItem에 생성
        • 아이템 프리팹을 손 위치에 생성
      • 생성한 아이템의 Rigidbody 의 물리를 꺼준다.
        • isKinematic을 True로.
          • 물리 현상이 활성화 되면 손에 붙지 않고 중력을 받아 떨어지게 된다.
      • 생성한 아이템의 Collider 를 꺼준다.
        • 플레이어의 손과 충돌하여 튕겨나가지 않고 손에 얌전히 붙어있도록
      • 손에 들고 있을 아이템은 획득이 안되도록 Item으로 되어 있던 태그, 레이어를 바꾼다.
        • 생성한 아이템의 태그를 “Untagged” 로 바꾼다.
        • 생성한 아이템의 레이어를 “Weapon”으로 바꾼다. 레이어는 int 이므로 “Weapon”에 해당하는 정수로 할당
          • Weapon Camera에 렌더링 될 수 있도록 한다. 메인 카메라보다 깊이가 우선되어 렌더링 되는 카메라이므로 손 위에 아이템이 그려질 것이다.
      • 생성한 아이템의 부모를 오른손 끝 위치 오브젝트로.

image

tf_ItemPos에 오른 손 끝 오브젝트였던 ItemPos 할당

image


🚖 활성화 퀵슬롯 아이템 소비하기

먹는 애니메이션

image

  • Any State 👉 Hand_Item
    • Item 트리거 파라미터가 발동될 때
    • Has Exit Time 해제
  • Hand_Item 👉 Hand_Idle
    • Has Exit Time 체크
    • Exit Time 1
      • 끝까지 다 재생되면 정지 애니메이션으로


📜QuickSlotController.cs

    [SerializeField]
    private ItemEffectDatabase theItemEffectDatabase;

    public void EatItem()
    {
        theItemEffectDatabase.UseItem(quickSlots[selectedSlot].item);
        quickSlots[selectedSlot].SetSlotCount(-1);

        if (quickSlots[selectedSlot].itemCount <= 0)
            Destroy(go_HandItem);
    }
  • EatItem() 👉 아이템 소비. 📜HandController.cs 에서 인벤토리 안켜져 있고 그냥 우클할 때 호출된다. 활성화 퀵슬롯에 있는 아이템이 바로 소비될 수 있도록.
    • 실제로 소비하는 처리 (스태미나, 배고픔 증가 등등 이런 처리)
      • 📜ItemEffectDatabase.cs 의 UseItem 함수에 퀵슬롯 아이템 넘겨 줌
        • 강의에선 다루지 않았던 부분인데 추가해보았다.
        • 실제로 아이템을 먹는 처리가 이루어 져야 하므로
    • 슬롯에서 갯수 1 차감
    • 슬롯 아이템 갯수가 0 이하면
      • 손에 들고 있는 아이템 파괴

image


📜Slot.cs

    public void OnPointerClick(PointerEventData eventData)
    {
        if(eventData.button == PointerEventData.InputButton.Right)
        {
            if (item != null)
            {
                theItemEffectDatabase.UseItem(item);

                if(item.itemType == Item.ItemType.Used)
                    SetSlotCount(-1);
            }
        }
    }

    public void SetSlotCount(int _count)
    {
        itemCount += _count;
        text_Count.text = itemCount.ToString();

        if (itemCount <= 0)
        {
            ClearSlot();
            if (isQuickSlot)
                if (QuickSlotController.go_HandItem != null)
                    if (QuickSlotController.go_HandItem.GetComponent<ItemPickUp>().item.itemType == Item.ItemType.Used)
                        Destroy(QuickSlotController.go_HandItem);
        }     
    }

아이템 ‘슬롯’에다가 우클릭 하여 소비할 때 (활성화 퀵슬롯 말고 그냥 인벤토리에서든 어디서든)

  • 아이템 갯수가 0 이하에 도달했을 때
    • 만약 우클릭 한 슬롯이 퀵슬롯이었다면!! 게다가 아이템도 들고 있는 상태이며 심지어 포션 같은 아이템이라면!
      • 손에 든 아이템도 파괴해 주어야 한다.

강의에선 다루지 않았던 부분인데 추가해보았다. 활성화 퀵슬롯을 직접 슬롯에다가 우클릭으로 다 소비할 땐 손에 든 아이템이 파괴되지 않길래


📜HandController.cs

    [SerializeField]
    private QuickSlotController theQuickSlotController;

    void Update()
    {
        if (isActivate && !Inventory.invectoryActivated)
        {
            if (QuickSlotController.go_HandItem == null)
                TryAttack();
            else
                TryEating();
        }         
    }

    private void TryEating()
    {
        if (Input.GetButtonDown("Fire2"))
        {
            currentCloseWeapon.anim.SetTrigger("Eat");
            theQuickSlotController.EatItem();
        }
    }

인벤토리 안켜진 상태 + 그냥 아이템 들고 있는 상태에서 아이템을 소비하려면

  • 맨손 상태에서 좌클릭 - 공격
  • 아이템 들고 있는 맨손 산태에서 우클릭 - 아이템 먹기
    • 아무것도 안들고 있다면 맨손 공격
  • 맨손인 상태고 인벤토리가 활성화 되어 있지 않을 때
    • 손에 들고 있는 아이템이 없다면 공격을 할 수 있는 상태다. (좌클릭 감지)
    • 손에 들고 있는 아이템이 있다면 아이템 소비를 할 수 있는 상태다.(우클릭 감지)
      • TryEating()
        • 마우스 우클릭이 들어온다면
          • 아이템 먹는 애니메이션 재생 후
          • EatItem() 아이템 갯수 1 차감 후 0 에 도달했다면 아이템 파괴

image


📜WeaponManager.cs

    private void CancelPreWeaponAction()
    {
        switch(currentWeaponType)
        {
            case "GUN":
                theGunController.CancelFineSight();
                theGunController.CancelReload();
                GunController.isActivate = false;
                break;
            case "HAND":
                HandController.isActivate = false;
                if (QuickSlotController.go_HandItem != null)
                    Destroy(QuickSlotController.go_HandItem);
                break;
            case "AXE":
                AxeController.isActivate = false;
                break;
            case "PICKAXE":
                PickaxeController.isActivate = false;
                break;
        }
    }

맨손인 상태에서 다른 무기로 바꾼다면 (맨손 👉 맨손 도 포함)

  • 아이템을 들고 있는 맨손인 상태에서 그냥 맨손이든 총이든 다른 무기로 교체하려면 현재 손에 들고 있는 아이템만 파괴한다.


📜InputNumber.cs

    IEnumerator DropItemCorountine(int _num)
    {
        for (int i = 0; i < _num; i++)
        {
            if(DragSlot.instance.dragSlot.item.itemPrefab != null)
            {
                Instantiate(DragSlot.instance.dragSlot.item.itemPrefab,
                            thePlayer.transform.position + thePlayer.transform.forward,
                            Quaternion.identity);
            }
            DragSlot.instance.dragSlot.SetSlotCount(-1);
            yield return new WaitForSeconds(0.05f);
        }

        if (int.Parse(text_Preview.text) == _num)  // 모두 버리는거면
            if (QuickSlotController.go_HandItem != null)  // 손에 아이템 들고 있다면
                Destroy(QuickSlotController.go_HandItem);

        DragSlot.instance.dragSlot = null;
        go_Base.SetActive(false);
        activated = false;
    }
        if (int.Parse(text_Preview.text) == _num)  // 모두 버리는거면
            if (QuickSlotController.go_HandItem != null)  // 손에 아이템 들고 있다면
                Destroy(QuickSlotController.go_HandItem);

아이템을 드래그 하여 버릴 때 인풋 필드

  • 만약 모두 버리는거면 손에 들고 있는 아이템도 파괴되도록
    • Placeholder 에는 자동으로 해당 아이템을 갖고 잇는 최대 개수가 들어가도록 하였으므로 입력한 수와 Placeholder 텍스트가 같다면 모두 버리겠다는 뜻


🚖 퀵슬롯의 쿨타임

쿨타임이 지나야만 아이템 사용이 가능하도록.

  • 쿨타임을 가질 때
    • 퀵슬롯에 방금 가져다 놓은 아이템일 때
    • 해당 아이템을 사용했을 때

쿨타임 UI 만들기

image

image

퀵슬롯의 슬롯들에게 자식으로 쿨타임 이미지 CoolTime_Image 오브젝트를 추가해주었다. 이미지 컴포넌트를 추가한 빈 오브젝트다.

  • 8 개의 CoolTime_Image를 PosX 를 0 으로 해준다.
    • 자신의 부모인 슬롯과 동일한 위치에 있을 수 있도록
  • 쿨타임은 360도 Filled 로 표현할 것이기 때문에 100 % 의 상태, 즉 Fill Amount 값이 1 일 때의 상태를 좀 더 까만 슬롯 이미지로 해주기 위하여 CoolTime_Image 들의 소스 이미지는 기본 슬롯 이미지에 검정 컬러에 투명함을 올려준 이미지로 사용하였다.
  • 이미지 타입은 Filled
    • 360도
    • Fill Origin 은 Top 부터 시작하도록.
    • Fill Amount 기본 값은 0 으로 일단 해두기.


📜QuickSlotController.cs

    [SerializeField] private Image[] img_CoolTime;  // 퀵슬롯 쿨타임 이미지들 

    // 쿨타임 내용
    [SerializeField]
    private float coolTime;  // 정해짐 쿨타임  [SerializeField]로 유니티 인스펙터에서 결정
    private float currentCoolTime;  // coolTime 을 시작점으로 0 이 될 때까지 감소 업뎃
    private bool isCoolTime;  // 현재 쿨타임 중인지

    void Update()
    {
        TryInputNumber();
        CoolTimeCalc();
    }

    private void CoolTimeReset()
    {
        currentCoolTime = coolTime;
        isCoolTime = true;
    }

    private void CoolTimeCalc()
    {
        if (isCoolTime)
        {
            currentCoolTime -= Time.deltaTime;  // 1 초에 1 씩 감소

            for (int i = 0; i < img_CoolTime.Length; i++)
                img_CoolTime[i].fillAmount = currentCoolTime / coolTime;

            if (currentCoolTime <= 0)
                isCoolTime = false;
        }
    }

    private void TryInputNumber()
    {
        if(!isCoolTime)
        {
            if (Input.GetKeyDown(KeyCode.Alpha1))
                ChangeSlot(0);
            else if (Input.GetKeyDown(KeyCode.Alpha2))
                ChangeSlot(1);
            else if (Input.GetKeyDown(KeyCode.Alpha3))
                ChangeSlot(2);
            else if (Input.GetKeyDown(KeyCode.Alpha4))
                ChangeSlot(3);
            else if (Input.GetKeyDown(KeyCode.Alpha5))
                ChangeSlot(4);
            else if (Input.GetKeyDown(KeyCode.Alpha6))
                ChangeSlot(5);
            else if (Input.GetKeyDown(KeyCode.Alpha7))
                ChangeSlot(6);
            else if (Input.GetKeyDown(KeyCode.Alpha8))
                ChangeSlot(7);
        }
    }

    private void Execute()
    {
        CoolTimeReset();

        if (quickSlots[selectedSlot].item != null)
        {
            if (quickSlots[selectedSlot].item.itemType == Item.ItemType.Equipment)
                StartCoroutine(theWeaponManager.ChangeWeaponCoroutine(quickSlots[selectedSlot].item.weaponType, quickSlots[selectedSlot].item.itemName));
            else if (quickSlots[selectedSlot].item.itemType == Item.ItemType.Used)
                ChangeHand(quickSlots[selectedSlot].item);
            else
                ChangeHand();
        }
        else
        {
            ChangeHand();
        }
    }

    public void EatItem()
    {
        CoolTimeReset();
        theItemEffectDatabase.UseItem(quickSlots[selectedSlot].item);
        quickSlots[selectedSlot].SetSlotCount(-1);

        if (quickSlots[selectedSlot].itemCount <= 0)
            Destroy(go_HandItem);
    }

    public bool GetIsCoolTime()
    {
        return isCoolTime;
    }
  • CoolTimeCalc() 👉 현재 쿨타임 상태라면 매 프레임마다 currentCoolTime 쿨타임 시간 업데이트
    • 쿨타임 중일 때만 isCoolTime, 매프레임마다 실행 된다.
    • currentCoolTime은 1 프레임당 Time.deltaTime 씩 차감 (= 1 초에 1 씩 차감)
      • 정해진 coolTime 에서 시작하여 0 이 될 때까지 감소
        • coolTime 값이 3 이라면 currentCoolTime은 3 초 동안 0 을 향해 감소한다.
    • 퀵슬롯 슬롯들의 쿨타임 이미지의 Fill Amount 값을 업데이트 한다.
    • currentCoolTime 가 0 에 도달하면 isCoolTime을 False로 만들어, 다음 프레임부터는 CoolTimeCalc() 함수가 더 이상 실행 되지 않음.
  • CoolTimeReset() 👉 쿨타임을 돌리기 시작한다!
    • currentCoolTime을 다시 coolTime으로 초기화
    • isCoolTime을 True 로 만듬. 다음 프레임 부터 CoolTimeCalc() 함수가 실행될 것
  • GetIsCoolTime()
    • 📜Slot.cs 에서 마우스 우클로 슬롯에 있는 아이템 소비시 쿨타임 중인 아이템을 사용하지 못하게 하기 위하여 isCoolTime을 리턴받기 위한 함수
  • 쿨타임 돌릴 때
    • TryInputNumber()
      • 쿨타임 중이 아닐 때만 키보드 넘버 입력할 수 잇음 (활성화 퀵슬롯 바꾸기)
    • Execute()
      • 활성화 슬롯 (무기 교체 혹은 아이템) 사용하고나면 쿨타임 有
      • CoolTimeReset() 쿨타임 돌리기
    • EatItem()
      • 활성화 슬롯 아이템 소비할 때 쿨타임 有
      • CoolTimeReset() 쿨타임 돌리기

image

  • 쿨타임 이미지 배열 할당
  • coolTime 쿨타임 3 초로 설정


📜HandController.cs

    private void TryEating()
    {
        if (Input.GetButtonDown("Fire2") && theQuickSlotController.GetIsCoolTime())
        {
            currentCloseWeapon.anim.SetTrigger("Eat");
            theQuickSlotController.EatItem();
        }
    }

인벤토리 활성화 되있을 때말고 그냥 게임 중에 우클릭 입력이 들어오면 손에 들고 있는 아이템을 소비한다. 이때 쿨타임 중이면 못 먹게 하도록 조건을 추가해주었다.


📜ItemEffectDatabase.cs

    // 📜QuickSlotController 👉 📜Slot 징검다리
    public bool GetIsCoolTime()
    {
        return theQuickSlotController.GetIsCoolTime();
    }

강의에선 다루지 않았던 부분인데 추가해보았다. 📜Slot.cs 에서 마우스 우클로 슬롯에 있는 아이템 소비시 쿨타임 중인 아이템을 사용하지 못하게 하기 위하여 추가. 📜Slot.cs 은 프리팹이므로 로딩을 줄이기 위하여 📜Slot.cs 에서 필요한 컴포넌트들은 📜ItemEffectDatabase.cs에서 징검 다리 역할로 로딩하여 가져오고 있음


📜Slot.cs

    // 마우스 클릭 이벤트
    public void OnPointerClick(PointerEventData eventData)
    {
        if(eventData.button == PointerEventData.InputButton.Right)
        {
            if (item != null)
            {
                if (!isQuickSlot)  // 인벤토리 우클
                {
                    theItemEffectDatabase.UseItem(item);
                    if (item.itemType == Item.ItemType.Used)
                        SetSlotCount(-1);
                } 
                else if (!theItemEffectDatabase.GetIsCoolTime())  // 퀵슬롯 우클 + ✨쿨타임 중이 아닐 때✨
                {
                    theItemEffectDatabase.UseItem(item);
                    if (item.itemType == Item.ItemType.Used)
                        SetSlotCount(-1);
                }
            }
        }
    }

강의에선 다루지 않았던 부분인데 추가해보았다. 퀵슬롯에 있는 슬롯에다가 우클을 했을 땐 쿨타임이 아닐 때만 사용할 수 있어야 한다.


🚖 퀵슬롯 ON OFF

필요할 때만 퀵슬롯이 등장하도록

  • 인벤토리 활성화 될 때 퀵슬롯도 같이 ON
  • 인벤토리 비활성화 될 때 퀵슬롯도 같이 OFF
  • 퀵슬롯을 바꿀 때 퀵슬롯 ON
  • 활성화 퀵슬롯에 있는 아이템 소비할 때도 ON

퀵슬롯에 애니메이션 추가

크로스 헤어 애니메이션 만들던 과정과 비슷. 참고하기.

애니메이션 클립

image

QuickSlot 오브젝트에 Animator 컴포넌트를 추가한 후, “QuickSlotAnimController” 애니메이션 컨트롤러를 할당했다. 그런 후 QuickSlot 오브젝트를 클릭한 상태에서 Animation 윈도우를 켜서 QuickSlot 오브젝트의 애니메이션 생성

image

  • 1️⃣ QuickSlot_Anim_Appear
    • 퀵슬롯 나타나기
      • PosX 를 대충 0 으로 녹화하기 (원래 위치로 녹화)
  • 2️⃣ QuickSlot_Anim_Disappear
    • 퀵슬롯 사라지게 하기
      • PosY 를 -100 정도로 녹화하여 사라지게 하기
  • 두 애니메이션 파일의 Loop Time를 해제해준다.

애니메이션 컨트롤러

image

  • Bool Appear 파라미터 추가
  • 퀵슬롯 사라지기(디폴트) 👉 퀵슬롯 나타나기
    • Appear가 True 일 때
    • Has Exit Time 해제
  • 퀵슬롯 나타나기 👉 퀵슬롯 사라지기
    • Appear가 False 일 때
    • Has Exit Time 해제


📜QuickSlotController.cs

    // 퀵슬롯 등장 내용
    [SerializeField] private float appearTime;  // 퀵슬롯이 나타나는 동안의 시간
    private float currentAppearTime;
    private bool isAppear;

    private Animator anim;

    void Start()
    {
        quickSlots = tf_parent.GetComponentsInChildren<Slot>();
        selectedSlot = 0;
        anim = GetComponent<Animator>();
    }

    void Update()
    {
        TryInputNumber();
        CoolTimeCalc();
        AppearCalc();
    }

    private void AppearReset()
    {
        currentAppearTime = appearTime;
        isAppear = true;
        anim.SetBool("Appear", isAppear);
    }

    private void AppearCalc()
    {
        if (Inventory.invectoryActivated)  // 인벤토리 켜져있을 땐 퀵슬롯도 늘 활성화
            AppearReset();
        else  // 인벤토리가 켜져 있지 않을때만 쿨타임 깎아야 함
        {
            if (isAppear)
            {
                currentAppearTime -= Time.deltaTime; // 1초에 1감소
                if (currentAppearTime <= 0)
                {
                    isAppear = false;
                    anim.SetBool("Appear", isAppear);
                }
            }
        }
        
    }
  • AppearCalc() 👉 현재 퀵슬롯 활성화 상태라면 매 프레임마다 currentAppearTime 퀵슬롯 활성화 시간 업데이트
    • 인벤토리가 활성화 되있을 땐 퀵슬롯도 내내 활성화 하도록 한다.
    • 인벤토리가 비활성화 상태일땐 퀵슬롯은 appearTime 시간 동안만 활성화 된 후 그 이후엔 비활성화
      • 퀵슬롯 활성화 중일 때만 isCoolTime, 매프레임마다 실행 된다.
        • currentAppearTime은 1 프레임당 Time.deltaTime 씩 차감 (= 1 초에 1 씩 차감)
        • 정해진 appearTime 에서 시작하여 0 이 될 때까지 감소
        • appearTime 값이 3 이라면 currentAppearTime은 3 초 동안 0 을 향해 감소한다.
    • currentAppearTime 가 0 에 도달하면
      • isAppearTime을 False로 만들어, 다음 프레임부터는 AppearCalc() 함수가 더 이상 실행 되지 않음.
      • 퀵슬롯이 사라지는 애니메이션 재생
  • AppearReset() 👉 퀵슬롯을 활성화 한다.
    • currentAppearTime을 다시 isAppearTime으로 초기화
    • isAppearTime을 True 로 만듬. 다음 프레임 부터 AppearCalc() 함수가 실행될 것
    • 퀵슬롯이 생성되는 애니메이션 재생

image

  • appearTime 3 으로 설정 👉 퀵슬롯은 인벤토리 비활성 상태라면 3 초 있다가 사라지게 됨


📜Slot.cs

    // 마우스 드래그가 시작 됐을 때 발생하는 이벤트
    public void OnBeginDrag(PointerEventData eventData)
    {
        if(item != null && Inventory.invectoryActivated)
        {
            DragSlot.instance.dragSlot = this;
            DragSlot.instance.DragSetImage(itemImage);
            DragSlot.instance.transform.position = eventData.position;
        }
    }

인벤토리 상태가 아닐 땐 슬롯 드래그가 안되게 한다. (인벤토리 끄면 퀵슬롯도 곧 사라지니 인벤토리 상태가 아닐 때는 퀵슬롯에서 아이템 드래그 못하게 했다.)


🚖 아이템 획득시 퀵슬롯부터 채우기

아이템을 획득하면 기본으로 인벤토리로 가게 되는데, 아이템을 먹으면 퀵슬롯에 우선적으로 채워지도록 하자.

📜Inventory.cs

    [SerializeField]
    private GameObject go_QuickSlotParent;  // 퀵슬롯 영역

    private Slot[] slots;  // 인벤토리 슬롯들
    private Slot[] quickSlots; // 퀵슬롯의 슬롯들
    private bool isNotPut;

    void Start()
    {
        slots = go_SlotsParent.GetComponentsInChildren<Slot>();
        quickSlots = go_QuickSlotParent.GetComponentsInChildren<Slot>();
    }

    public void AcquireItem(Item _item, int _count = 1)
    {
        PutSlot(quickSlots, _item, _count);
        if (isNotPut)
            PutSlot(slots, _item, _count);

        if (isNotPut)
        {
            Debug.Log("아이템이 꽉 찼습니다.");
        }
            
    }

    private void PutSlot(Slot[] _slots, Item _item, int _count)
    {
        if (Item.ItemType.Equipment != _item.itemType)
        {
            for (int i = 0; i < _slots.Length; i++)
            {
                if (_slots[i].item != null)
                {
                    if (_slots[i].item.itemName == _item.itemName)
                    {
                        _slots[i].SetSlotCount(_count);
                        isNotPut = false;
                        return;
                    }
                }
            }
        }

        for (int i = 0; i < _slots.Length; i++)
        {
            if (_slots[i].item == null)
            {
                _slots[i].AddItem(_item, _count);
                isNotPut = false;
                return;
            }
        }

        isNotPut = true;
    }
  • isNotPut 아이템을 슬롯에 넣었다면 True, 못 넣었다면 False.
  • slots 인벤토리 슬롯들, quickSlots 퀵슬롯의 슬롯들.
  • PutSlot(Slot[] _slots, Item _item, int _count)
    • Slot 타입의 배열 (slots, quickSlots 받을 수 있음) 중에서 아이템을 넣을 수 있는 슬롯을 찾아 넣는다.
    • 아이템 넣을 슬롯을 찾을 때마다 isNotPut을 False로 하고 끝냄. 아이템 넣을 슬롯을 못 찾았다면 최종적으로 isNotPut이 True가 됨.
  • AcquireItem(Item _item, int _count = 1)
    • 우선 퀵슬롯의 슬롯들에게 넣기 시도
      • quickSlotsPutSlot 에 넘김
    • 퀵슬롯에 못 넣었다면 인벤토리에 넣기 시도
      • slotsPutSlot 에 넘김
    • 둘 다 못 넣었다면, 즉 아직도 isNotPut가 true라면 인벤토리, 퀵슬롯 둘 다 꽉차서 넣을 수 없는 상태

image

go_QuickSlotParent에 퀵슬롯 영역인 Contents 할당.


🚖 아이템을 꽉 차서 먹을 수가 없다면

강의에선 다루지 않았던 부분인데 추가해보았다.

인벤토리, 퀵슬롯 둘 다 꽉차서 넣을 수 없다면 아이템을 먹을 수 없다는 텍스트 띄우기.

📜ActionController.cs

먹을 수 있는 아이템 텍스트를 띄우는 곳이 여기였기 때문에 이번에도 여기서 텍스트 처리.

    [SerializeField]
    private Text itemFullText;  // 아이템이 꽉 찼다는 경고 메세지를 보여줄 텍스트

    public IEnumerator WhenInventoryIsFull()
    {
        itemFullText.gameObject.SetActive(true);
        itemFullText.text = "아이템이 꽉 찼습니다.";

        yield return new WaitForSeconds(3.0f);  // 3 초 후 메세지는 사라짐. 메세지는 3 초만 띄움.
        itemFullText.gameObject.SetActive(false);
    }

아이템이 꽉 찼다는 경고 메세지로 쓸 텍스트 UI 를 추가하고 해당 텍스트를 itemFullText에 할당. WhenInventoryIsFull() 함수가 활성화 될 때 이 텍스트를 활성화 하고 “아이템이 꽉 찼습니다.” 메세지를 딱 3 초 동안만 띄우 비활한다.

image


📜Inventory.cs

    private bool isFull = false;  // 인벤토리 퀵슬롯 모두 꽉 찼는지

    [SerializeField]
    private ActionController theActionController;

    public void AcquireItem(Item _item, int _count = 1)
    {
        PutSlot(quickSlots, _item, _count);
        if (isNotPut)
            PutSlot(slots, _item, _count);

        if (isNotPut)
        {
            isFull = true;
            StartCoroutine(theActionController.WhenInventoryIsFull());
        }      
    }

    public bool GetIsFull()
    {
        return isFull;
    }

    public void SetIsFull(bool _flag)
    {
        isFull = _flag;
    }
  • 외부 스크립트에서 인벤토리, 퀵슬롯 둘다 꽉찼는지 알 수 있게 isFull 멤버 추가 (접근 함수까지)
  • 인벤토리, 퀵슬롯 둘 다 꽉차면
    • isFull True로 업뎃
    • 📜ActionController.cs 의 WhenInventoryIsFull() 함수 실행하여 텍스트 띄움


📜ItemEffectDatabase.cs

    [SerializeField]
    private Inventory theInventory;

    // 📜Inventory 👉 📜Slot 징검다리
    public bool GetIsFull()
    {
        return theInventory.GetIsFull();
    }

    // 📜Inventory 👉 📜Slot 징검다리
    public void SetIsFull(bool _flag)
    {
        theInventory.SetIsFull(_flag);
    }

📜Slot.cs 징검 다리

image


📜Slot.cs

    // 해당 슬롯의 아이템 갯수 업데이트
    public void SetSlotCount(int _count)
    {
        itemCount += _count;
        text_Count.text = itemCount.ToString();

        if (_count < 0)
        {
            if (theItemEffectDatabase.GetIsFull())
                theItemEffectDatabase.SetIsFull(false);
        }

        if (itemCount <= 0)
        {
            ClearSlot();
            if (isQuickSlot)
                if (QuickSlotController.go_HandItem != null)
                    if (QuickSlotController.go_HandItem.GetComponent<ItemPickUp>().item.itemType == Item.ItemType.Used)
                        Destroy(QuickSlotController.go_HandItem);
        }
    }

    // 해당 슬롯 하나 삭제
    private void ClearSlot()
    {
        item = null;
        itemCount = 0;
        itemImage.sprite = null;
        SetColor(0);

        text_Count.text = "0";
        go_CountImage.SetActive(false);

        if (theItemEffectDatabase.GetIsFull())
            theItemEffectDatabase.SetIsFull(false);
    }
if (theItemEffectDatabase.GetIsFull())
    theItemEffectDatabase.SetIsFull(false);

슬롯이 하나 비거나 아이템 갯수가 줄어들면 📜Inventory.cs 의 isFull을 False 로.



🌜 개인 공부 기록용 블로그입니다. 오류나 틀린 부분이 있을 경우 
언제든지 댓글 혹은 메일로 지적해주시면 감사하겠습니다! 😄

맨 위로 이동하기

Unity Lesson 3 카테고리 내 다른 글 보러가기

댓글 남기기