쯔꾸르식 유니티 게임 공부

32.장비창 구현

ruripanda 2025. 3. 10. 20:49

using System.Collections.Generic;
using UnityEngine;

public class DatabaseManager : MonoBehaviour
{
    static public DatabaseManager instance;

    public string[] var_name;
    public float[] var;

    public string[] switch_name;
    public bool[] switches;

    public List<Item> itemList = new List<Item>();

    private PlayerStat thePlayerStat;
    public GameObject prefabs_Floating_Text;
    public GameObject parent;

    private void FloatText(int number, string color)
    {

        Vector3 vector = thePlayerStat.transform.position;
        vector.y += 60;

        GameObject clone = Instantiate(prefabs_Floating_Text, vector, Quaternion.Euler(Vector3.zero));
        clone.GetComponent<FloatingText>().text.text = number.ToString();
        if(color == "GREEN")
            clone.GetComponent<FloatingText>().text.color = Color.green;
        else if(color == "BLUE")
            clone.GetComponent<FloatingText>().text.color = Color.blue;
        clone.GetComponent<FloatingText>().text.fontSize = 25;
        clone.transform.SetParent(parent.transform);
    }

    private void Awake()//인스턴스 설정
    {
        if (instance == null)
        {
            DontDestroyOnLoad(this.gameObject);
            instance = this;
        }
        else
        {
            Destroy(this.gameObject);
        }
    }

    public void UseItem(int _itemID)
    {
        switch (_itemID)
        {
            case 10001:
                Debug.Log("HP가 50회복되었습니다.");
                //PlayerStat.instance.currentHP += 50;//이렇게 작성하면 플레이어 스텟으로 접근해서 값에 플러스해줌
                if (thePlayerStat.hp >= thePlayerStat.currentHP + 50)
                    //조건문 현제 플레이어 hp가 높거나 같다면 50을 회복
                    thePlayerStat.currentHP += 50;
                else//그게 아니라면(쉽게 말해 HP를 회복시 상한을 넘을 경우)
                    thePlayerStat.currentHP = thePlayerStat.hp;
                FloatText(50, "GREEN");
                break;
            case 10002:
                if (thePlayerStat.mp >= thePlayerStat.currentMP + 15)
                    thePlayerStat.currentMP += 15;
                else
                    thePlayerStat.currentMP = thePlayerStat.mp;
                Debug.Log("MP가 15회복되었습니다.");
                FloatText(50, "BLUE");
                break;
        }
    }

    // Start is called once before the first execution of Update after the MonoBehaviour is created
    void Start()
    {
        thePlayerStat = FindAnyObjectByType<PlayerStat>();
        itemList.Add(new Item(10001, "빨간 포션", "체력을 50 회복시켜주는 기적의 물약", Item.ItemType.Use));
        itemList.Add(new Item(10002, "파란 포션", "마나를 15 회복시켜주는 기적의 물약", Item.ItemType.Use));
        itemList.Add(new Item(10003, "농축 빨간 포션", "체력을 350 회복시켜주는 기적의 농축 물약", Item.ItemType.Use));
        itemList.Add(new Item(10004, "농축 파란 포션", "마나를 80 회복시켜주는 기적의 농축 물약", Item.ItemType.Use));
        itemList.Add(new Item(11001, "랜덤 상자", "랜덤으로 포션이 나온다 낮은 확율로 꽝", Item.ItemType.Use));
        itemList.Add(new Item(20001, "짧은 검", "기본적인 용사의 검", Item.ItemType.Equip));
        itemList.Add(new Item(21001, "사파이어 반지", "1분에 마나 1을 회복시켜주는 마법 반지", Item.ItemType.Equip));
        itemList.Add(new Item(30001, "고대 유물의 조각1", "반으로 쪼개진 고대 유물의 파편", Item.ItemType.Quest));
        itemList.Add(new Item(30002, "고대 유물의 조각2", "반으로 쪼개진 고대 유물의 파편", Item.ItemType.Quest));
        itemList.Add(new Item(30003, "고대 유물", "고대 유적에 잠들어있던 고대의 유물", Item.ItemType.Quest));
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class Inventory : MonoBehaviour
{
    public static Inventory Instance;//인벤토리 인스턴스

    private DatabaseManager theDatabase;//데이터 베이스 접근
    private OrderManager theOrder;      //오더매니져
    private AudioManager theAudio;      //오디오매니져
    private OkOrCancel theOOC;          //아이템 선택 받아옴
    private Equipment theEquip;//<추가

    public string key_sound;
    public string enter_sound;
    public string cancel_sound;
    public string open_sound;
    public string beep_sound;               //비프음을 포함한 각종 효과음

    private InventorySlot[] slots;          //인벤토리 슬롯들

    private List<Item> inventoryItemList;   //플레이어가 소지한 아이템 리스트
    private List<Item> inventoryTabList;    //선택한 탭에 따라 다르게 보여질 아이템 리스트

    public Text Description_Text;           //아이템 부연설명
    public string[] tabDescription;         //탭 부연설명

    public Transform tf;                    //slot(슬롯)의 부모객체

    public GameObject go;                   //인벤토리 활성화 비활성화
    public GameObject[] selectedTabImages;  //4개의 탭 패널
    public GameObject go_OOC;               //선택지 활성화 비활성화
    public GameObject prefab_Floating_text; //플로팅 텍스트 아이템 획득시 이름 알림

    private int selectedItem;               //선택된 아이템
    private int selectedTab;                //선택 된 텝

    private bool activated;                 //인벤토리 활성화시 true;
    private bool tabActivated;              //탭 활성화시 true;
    private bool itemActivated;             //아이템 활성화시 true;
    private bool stopkeyInput;              //키 입력제한(소비 할때 질의가 나올텐데, 그때 입력방지)
    private bool preventExec;               //중복실행 제한

    private WaitForSeconds waitTime = new WaitForSeconds(0.01f);

    // Start is called once before the first execution of Update after the MonoBehaviour is created
    void Start()
    {
        Instance = this;//인벤토리 인스턴스
        theAudio = FindAnyObjectByType<AudioManager>();     //오디오매니져
        theOrder = FindAnyObjectByType<OrderManager>();     //오더매니져
        theDatabase = FindAnyObjectByType<DatabaseManager>();
        theOOC = FindAnyObjectByType<OkOrCancel>();         //아이템 선택 매니져
        theEquip = FindAnyObjectByType<Equipment>();//<추가
        inventoryItemList = new List<Item>();               //아이템 리스트화
        inventoryTabList = new List<Item>();                //탭 리스트화
        slots = tf.GetComponentsInChildren<InventorySlot>();//겟 컴포넌츠 인 칠드런으로 인벤토리 슬롯들을 불러옴
    }

    public void EquipToInventory(Item _item)
    {
        inventoryItemList.Add(_item);
    }

    public void GetAnItem(int _itemID, int _count = 1)
    {
        for (int i = 0; i < theDatabase.itemList.Count; i++)//데이터베이스 아이템 검색
        {
            if (_itemID == theDatabase.itemList[i].itemID)//데이터 베이스에 아이템 발견
            {
                var clone = Instantiate(prefab_Floating_text, PlayerManager.instance.transform.position, Quaternion.Euler(Vector3.zero));
                //var형식은 변수의 타입이 뭔지 모를때 사용한다
                //Instantiate는 복제값을 생성해주는 함수이다
                //prefab_Floating_text라는 프리팹의 복제를 생성해주고 생성위치는 플레이어매니저의 위치이다
                //Quaternion.Euler(Vector3.zero)으로 상하좌우 위치를 설정해 벡터를 0으로 만들어준다

                clone.GetComponent<FloatingText>().text.text = theDatabase.itemList[i].itemName + " " + _count + "개 획득 +";
                //clone를 겟컴포넌트로 불러와서 아이템을 습득할때 데이터베이스에서 반응하는 넘버를 불러와서 이름과 갯수를 띠워준다
                clone.transform.SetParent(this.transform);
                //SetParent를 부모로 지정하여 생성해준다

                for (int j = 0; j < inventoryItemList.Count; j++)//소지품에 같은 아이템이 있는지 확인
                {
                    if (inventoryItemList[j].itemID == _itemID)//소지품에 같은 아이템이 있다 -> 개수만 증감시켜줌
                    {
                        if (inventoryItemList[j].itemType == Item.ItemType.Use)
                        {
                            inventoryItemList[j].itemCount += _count;
                        }else
                        {
                            inventoryItemList.Add(theDatabase.itemList[i]);
                        }
                        return;
                    }
                }
                inventoryItemList.Add(theDatabase.itemList[i]);//없을시 해당 아이템 추가
                inventoryItemList[inventoryItemList.Count - 1].itemCount = _count;
                return;
            }
        }
        Debug.LogError("데이터 베이스에 해당 ID값을 가진 아이템이 존재하지 않습니다");//데이터베이스에 ItemID 없음
    }
    public void RemoveSlot()//모든 슬롯을 비활성화
    {
        for (int i = 0; i < slots.Length; i++)      //i = 0이고 i는 slots들보다 적고 i++로 증감
        {
            slots[i].RemoveItem();                  //InventorySlot스크립트에서 아이템이 사라지는 로직 slots[i]로 여러개를 선택
            slots[i].gameObject.SetActive(false);   //로직 slots[i]로 여러개를 선택 후 오브젝트를 비활성화
        }
    }//인벤토리 슬롯 초기화
    public void ShowTab()//탭 활성화
    {
        RemoveSlot();
        SelectedTab();
    }
    public void SelectedTab()//선택된 탭을 제외하고 다른 모든 탭의 컬러 알파값 0으로 조정
    {
        StopAllCoroutines();//모든 코루틴 정지
        Color color = selectedTabImages[selectedTab].GetComponent<Image>().color;//탭의 반짝임을 위해 배열을 받아옴
        color.a = 0f;                                                            //위에 선택된 배열의 컬러 알파값이 0
        for(int i =0; i < selectedTabImages.Length; i++)                         //i=0과 같고 i는 선택된 탭보다 작다, i++로 증감
        {
            selectedTabImages[i].GetComponent<Image>().color = color;            //위의 i번째에 선택된 오브젝트의 컬러값을 가져옴
        }
        Description_Text.text = tabDescription[selectedTab];                     //각 탭에 위치한 설명을 출력함
        StartCoroutine(SelectedTabEffectCoroutine());                            //스타트 코루틴, 탭효과를 출력!
    }
    IEnumerator SelectedTabEffectCoroutine()                                     //위의 탭 효과를 출력
    {
        while (tabActivated)                                                     //탭이 true면 반복됨
        {
            Color color = selectedTabImages[selectedTab].GetComponent<Image>().color;   //선택한 탭의 color, Image를 받아옴
            while (color.a < 0.5f)                                                      //반복문 알파값이 반절보다 작을때
            {
                color.a += 0.03f;
                selectedTabImages[selectedTab].GetComponent<Image>().color = color;     //컬러 알파값에 계속 0.03f정도 더해줌
                yield return waitTime;                                                  //0.01f 정도 대기
            }
            while (color.a > 0f)                                                        //알파값이 0보다 클 경우 반복
            {
                color.a -= 0.03f;                                                       //알파값에 0.03f정도 계속 빼서 내려줌
                selectedTabImages[selectedTab].GetComponent<Image>().color = color;     //컬러값에 적용
                yield return waitTime;                                                  //0.01f 대기
            }

            yield return new WaitForSeconds(0.3f);                                      //0.3초 대기
        }
    }//선택된 탭 반짝임 효과
    public void ShowItem()//아이템 활성화(inventoryTabList에 조건에 맞는 아이템들만 넣어주고, 인벤토리 슬롯에 출력)
    {
        inventoryTabList.Clear();                       //인벤토리 탭 리스트 초기화
        RemoveSlot();                                   //표시되는 슬롯 초기화
        selectedItem = 0;                               //선택된 아이템 배열의 0번째 선택

        switch (selectedTab)//탭에 따른 아이템 분류
        {
            case 0:
                for(int i =0; i < inventoryItemList.Count; i++)
                {
                    if(Item.ItemType.Use == inventoryItemList[i].itemType)//소모품
                        inventoryTabList.Add(inventoryItemList[i]);//Add로 쫘악 펼쳐줌
                }
                break;
            case 1:
                for (int i = 0; i < inventoryItemList.Count; i++)
                {
                    if (Item.ItemType.Equip == inventoryItemList[i].itemType)//장비품
                        inventoryTabList.Add(inventoryItemList[i]);//Add로 쫘악 펼쳐줌
                }
                break;
            case 2:
                for (int i = 0; i < inventoryItemList.Count; i++)
                {
                    if (Item.ItemType.Quest == inventoryItemList[i].itemType)//퀘스트 아이템
                        inventoryTabList.Add(inventoryItemList[i]);//Add로 쫘악 펼쳐줌
                }
                break;
            case 3:
                for (int i = 0; i < inventoryItemList.Count; i++)
                {
                    if (Item.ItemType.ETC == inventoryItemList[i].itemType)//기타
                        inventoryTabList.Add(inventoryItemList[i]);//Add로 쫘악 펼쳐줌
                }
                break;
        }//탭에 따른 아이템 분류, 그것을 인벤토리 탭 리스트에 추가

        for(int i = 0;i < inventoryTabList.Count; i++)//인벤토리 탭 리스트의 내용을 인벤토리 슬롯에 추가
        {
            slots[i].gameObject.SetActive(true);//인벤토리 아이템 리스트를 활성화
            slots[i].Additem(inventoryTabList[i]);//Additem으로 쫘악 배열을 펼쳐줌
        }

        SelectedItem();
    }
    public void SelectedItem()//선택된 아이템을 제외하고, 다른 모든 탭의 컬러 알파값을 0으로 조정
    {
        StopAllCoroutines();//모든 코루틴 종료
        if (inventoryTabList.Count > 0)//조건문 인벤토리 탭 리스트가 0보다 크다면
        {
            Color color = slots[0].selected_Item.GetComponent<Image>().color;//슬롯 0번재의 Image와 Color을 받아옴
            color.a = 0f;                                                    //초기값은 0f
            for (int i = 0; i < inventoryTabList.Count; i++)                 //반복문 i는 0이고 i는 인벤토리 탭 카운트리스트보다 작고 i++증감
                slots[i].selected_Item.GetComponent<Image>().color = color;  //반복문의 Image와 Color을 받아옴
            Description_Text.text = inventoryTabList[selectedItem].itemDescription;//설명문에 인벤토리 탭 리스트의 배열의 셀렉티드 아이템의 아이템 설명과 같다
            StartCoroutine(SelectedItemEffectCoroutine());                   //선택된 아이템 이팩트 실행
        }
        else
            Description_Text.text = "해당 타입의 아이템을 소유하고 있지 않습니다";//만약 해당탭에 해당하는 아이템이 없을 경우 메시지 출력
    }
    IEnumerator SelectedItemEffectCoroutine()//선택된 아이템 반짝임 효과
    {
        while (itemActivated)                //아이템 선택이 true가 될 경우
        {
            Color color = slots[0].GetComponent<Image>().color; //슬롯의 배열에 해당하는 슬롯의 Image와 color을 받아와서
            while (color.a < 0.5f)                              //반복문 알파값이 0.5f보다 클 경우
            {
                color.a += 0.03f;                               //0.03f만큼 계속 더해짐
                slots[selectedItem].selected_Item.GetComponent<Image>().color = color;//위의 컬러 적용
                yield return waitTime;                          //0.01초 대기
            }
            while (color.a > 0f)                                //알파값이 0보다 클 경우
            {
                color.a -= 0.03f;                               //0.03f만큼 계속 빼줌
                slots[selectedItem].selected_Item.GetComponent<Image>().color = color;//컬러에 적용
                yield return waitTime;                          //0.01초 대기
            }

            yield return new WaitForSeconds(0.3f);
        }
    }

    // Update is called once per frame
    void Update()
    {
        if (!stopkeyInput)//키 입력제한이 false일때
        {
            if (Input.GetKeyDown(KeyCode.I))//I키로 실행
            {
                activated = !activated;//true/false on/off

                if (activated)//인벤토리 활성화를 True
                {
                    theAudio.Play(open_sound);  //여는 소리 재생
                    theOrder.NotMove();         //오더매니져의 움직임 정지
                    go.SetActive(true);         //오브젝트 활성화
                    selectedTab = 0;            //탭창에서 0번째 탭을 선택
                    tabActivated = true;        //탭부터 보게 탭부분을 true화
                    itemActivated = false;      //아이템 창은 false화
                    ShowTab();
                }
                else
                {
                    theAudio.Play(cancel_sound);    //캔슬소리 재생
                    StopAllCoroutines();            //모든 코루틴 종료
                    go.SetActive(false);            //오브젝트 false로 비활성화
                    tabActivated = false;           //탭 비활성화
                    itemActivated = false;          //아이템 부분 비활성화
                    theOrder.Move();                //오더매니져 이동 활성화
                }
            }

            if (activated)                                                //인벤토리 활성화시
            {
                if (tabActivated)                                         //탭 활성화시 키 입력 처리
                {
                    if (Input.GetKeyDown(KeyCode.RightArrow))             //오른쪽 버튼을 누름
                    {
                        if (selectedTab < selectedTabImages.Length - 1)   //선택 된 탭이 선택된 탭 이미지에서 -1한 값보다 작을 경우
                            selectedTab++;                                //선택된 탭 값을 ++로 
                        else                                              //아니라면
                            selectedTab = 0;                              //탭 선택을 0으로 함
                        theAudio.Play(key_sound);                         //사운드 재생
                        SelectedTab();                                    //탭선택 실행
                    }
                    if (Input.GetKeyDown(KeyCode.LeftArrow))              //왼쪽 버튼 누름
                    {
                        if (selectedTab > 0)                              //선택된 탭 값이 0보다 크다면
                            selectedTab--;                                //-- 감소 선택
                        else                                              //아니라면 선택된 탭과 선택된 탭 이미지에서 -1한 값과 같다
                            selectedTab = selectedTabImages.Length - 1;   
                        theAudio.Play(key_sound);                         //소리재생
                        SelectedTab();                                    //탭선택 실행
                    }
                    else if (Input.GetKeyDown(KeyCode.Z))                 //Z키 입력으로 탭 선택시
                    {
                        theAudio.Play(enter_sound);                       //소리 재생
                        Color color = selectedTabImages[selectedTab].GetComponent<Image>().color;//선택된 배열 탭의 배열에 선택된 탭 넘버를 넣어준 후 해당 Image와 color을 받아와서
                        color.a = 0.25f;                                                         //선택된 컬러의 알파값을 0.25f로 바꿔 줌
                        selectedTabImages[selectedTab].GetComponent<Image>().color = color;      //위의 바꾼 컬러를 적용해 줌
                        itemActivated = true;                                                    //아이템 선택 활성화
                        tabActivated = false;                                                    //탭선택 비활성화
                        preventExec = true;                                                      //키 중복입력 방지
                        ShowItem();                                                              //Item선택 활성화
                    }
                }

                else if (itemActivated)                                                          //아이템 창 활성화시
                {
                    if(inventoryTabList.Count > 0)                                               //아이템 탭 리스트 카운트가 0보다 클 경우
                    {
                        if (Input.GetKeyDown(KeyCode.DownArrow))                                 //키보드 아래쪽 화살표 누를시
                        {
                            if (selectedItem < inventoryTabList.Count - 2)                       //조건문 선택된 아이템이 인벤토리탭리스트 카운트에서 2뺀 값보다 작을 경우
                                selectedItem += 2;                                               //2를 계속 더 해줌
                            else                                                                 //조건이 아니라면
                                selectedItem %= 2;                                               //2를 나누고 남은 값을 대입해준다
                            theAudio.Play(key_sound);
                            SelectedItem();                                                      //선택된 아이템의 알파값을 제외하고 다른 슬롯의 알파값을 초기화
                        }
                        else if (Input.GetKeyDown(KeyCode.UpArrow))                              //위쪽 버튼을 누를 경우
                        {
                            if (selectedItem > 1)                                                //조건문 1보다 클 경우
                                selectedItem -= 2;                                               //2를 빼준다
                            else                                                                 //조건이 아니라면 
                                selectedItem = inventoryTabList.Count - 1 - selectedItem;        //선택 된 아이템은 선택된 아이템 값 카운트에서 1을 빼주고 선택된 아이템을 빼준 값과 같다
                            theAudio.Play(key_sound);
                            SelectedItem();                                                      //선택된 아이템의 알파값을 제외하고 다른 슬롯의 알파값을 초기화
                        }
                        else if (Input.GetKeyDown(KeyCode.RightArrow))                           //오른쪽을 버튼을 누른 경우
                        {
                            if (selectedItem < inventoryTabList.Count - 1)                       //선택된 아이템이 인벤토리 배열에서 카운트된 숫자 -1한 값보다 적을 경우
                                selectedItem++;                                                  //선택된 아이템 번호를 증감하여 오른쪽으로 이동
                            else
                                selectedItem = 0;                                                //아니라면 0과 같다
                            theAudio.Play(key_sound);
                            SelectedItem();                                                      //선택된 아이템의 알파값을 제외하고 다른 슬롯의 알파값을 초기화
                        }
                        else if (Input.GetKeyDown(KeyCode.LeftArrow))                            //왼쪽 버튼을 누름
                        {
                            if (selectedItem > 0)                                                //0보다 클 경우
                                selectedItem--;                                                  //숫자를 감소하여 왼쪽으로 이동
                            else
                                selectedItem = inventoryTabList.Count - 1;                       //그게 아니라면 선택된 아이탬 순서는 카운트된 인벤토리 탭에서 -1 값과 같다
                            theAudio.Play(key_sound);
                            SelectedItem();                                                      //선택된 아이템의 알파값을 제외하고 다른 슬롯의 알파값을 초기화
                        }
                        else if (Input.GetKeyDown(KeyCode.Z) && !preventExec)                    //z를 클릭하면서 중복이 방지된 경우
                        {
                            if (selectedTab == 0)//소모품
                            {
                                StartCoroutine(OOCCoroutine("사용", "취소"));
                            }
                            else if (selectedTab == 1)
                            {
                                
                                StartCoroutine(OOCCoroutine("장착", "취소"));
                            }
                            else
                            {
                                theAudio.Play(beep_sound);
                            }
                        }
                    }
                                       
                    if (Input.GetKeyDown(KeyCode.X))//x버튼을 눌른 경우
                    {
                        theAudio.Play(cancel_sound);//캔슬 사운드 재생
                        StopAllCoroutines();        //모든 코루틴 종료
                        itemActivated = false;      //아이템 선택 비활성화
                        tabActivated = true;        //탭선택 활성화
                        ShowTab();
                        Debug.Log("X키가 눌렸습니다");
                    }
                }

                if (Input.GetKey(KeyCode.Z))//중복 실행 방지
                    preventExec = false;
            }
        }
    }
    IEnumerator OOCCoroutine(string _up, string _down)//OK,Cancel
    {
        theAudio.Play(enter_sound); //사운드 재생
        stopkeyInput = true;        //키 입력 활성화

        go_OOC.SetActive(true);//OkOrC panel 오브젝트를 활성화
        theOOC.ShowTwoChoice(_up, _down);//사용 취소 텍스트를 아이템 종류에 맞게 텍스트 변경
        yield return new WaitUntil(() => !theOOC.activated);//theOOC가 false가 될때 멈춤
        if (theOOC.GetResult())//레절트 값을 받아옴
        {
            for (int i = 0; i < inventoryItemList.Count; i++)//인벤토리에서 아이템 리스트를 검색
            {
                if (inventoryItemList[i].itemID == inventoryTabList[selectedItem].itemID)//검색한 아이템이 맞는지 확인
                {
                    if(selectedTab == 0)//소모품 아이템이라면
                    {
                        theDatabase.UseItem(inventoryItemList[i].itemID);//데이터베이스에서 Use아이템일 경우 효과를 검색해서 사용

                        if (inventoryItemList[i].itemCount > 1)//1보다 클 경우
                            inventoryItemList[i].itemCount--;//하나 감소
                        else
                            inventoryItemList.RemoveAt(i);//만약 하나일 경우 없셈
                        ShowItem();
                        break;
                    }
                    else if(selectedTab == 1)//장비품 아이템이라면
                    {
                        theEquip.EquipItem(inventoryItemList[i]);//EquipItem배열에 inventoryItemList[i]를 넣어주고
                        inventoryItemList.RemoveAt(i);           //장비된 아이템을 지워주고
                        ShowItem();                              //ShowItem함수를 실행
                        break;                                   //break해줌
                    }
                }
            }
        }
        stopkeyInput = false;
        go_OOC.SetActive(false);
    }
}

 

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

public class Equipment : MonoBehaviour
{
    private OrderManager theOrder;      //오더메니져
    private AudioManager theAudio;      //오디오매니져
    private PlayerStat thePlayerStat;    //플레이어 스텟
    private Inventory theInven;         //인벤토리
    private OkOrCancel theOOC;          //OKorCancel오브젝트

    public string key_sound;
    public string enter_sound;
    public string open_sound;
    public string close_sound;
    public string takeoff_sound;        //각종 사운드

    private const int WEAPON = 0, SHILED = 1, AMULT = 2, LEFT_RING = 3, RIGHT_RING = 4,//const는 변수값을 수정할 수 없다
                      HELMET = 5, ARMOR = 6, LEFT_GLOVE = 7, RIGHT_GLOVE = 8, BELT = 9,
                      LEFT_BOOTS = 10, RIGHT_BOOTS = 11;

    public GameObject go;                   //장비창 키고 끄기
    public GameObject go_OOC;               //OkOrCancel 키고 끄기

    public Text[] text;                     //스텟
    public Image[] img_slots;               //장비 아이콘들
    public GameObject go_selected_Slot_UI;  //선택된 장비 슬롯UI

    public Item[] equipItemList;            //장착된 장비 리스트

    private int selectedSlot;               //선택된 장비 슬롯

    public bool activated = false;          //Equip창 활성화
    private bool inputKey = true;           //키 입력 활성화

    // Start is called once before the first execution of Update after the MonoBehaviour is created
    void Start()//각종 메니져 장착
    {
        theInven = FindAnyObjectByType<Inventory>();
        theOrder = FindAnyObjectByType<OrderManager>();
        theAudio = FindAnyObjectByType<AudioManager>();
        thePlayerStat = FindAnyObjectByType<PlayerStat>();
        theOOC = FindAnyObjectByType<OkOrCancel>();
    }

    public void EquipItem(Item _item)
    {
        string temp = _item.itemID.ToString();
        temp = temp.Substring(0, 3);
        switch (temp)
        {
            case "200"://무기
                EquipItemCheck(WEAPON, _item);
                break;
            case "201"://방패
                EquipItemCheck(SHILED, _item);
                break;
            case "202"://아뮬렛
                EquipItemCheck(AMULT, _item);
                break;
            case "210"://반지
                EquipItemCheck(LEFT_RING, _item);
                break;
        }
    }

    public void EquipItemCheck(int _count, Item _item)
    {
        if (equipItemList[_count].itemID == 0)
        {
            equipItemList[_count] = _item;
        }
        else
        {
            theInven.EquipToInventory(equipItemList[_count]);
            equipItemList[_count] = _item;
        }
    }

    public void SelectedSlot()
    {
        go_selected_Slot_UI.transform.position = img_slots[selectedSlot].transform.position;
    }

    public void ClearEquip()
    {
        Color color = img_slots[0].color;
        color.a = 0f;                       //선택된 장비창의 이미지 알파값을 0으로 한다

        for(int i = 0; i < img_slots.Length; i++)//이미지 슬롯의 배열을 쫘알 보여준다
        {
            img_slots[i].sprite = null;     //장비 아이콘이 없으면 빈 네모칸을 비움
            img_slots[i].color = color;     //마찬가지로 빈 네모칸의 알파값을 0으로 만듬
        }
    }

    public void ShowEquip()
    {
        Color color = img_slots[0].color;
        color.a = 1f;                               //0번 슬롯 아이템의 컬러의 a값을 1로 한다

        for (int i = 0; i < img_slots.Length; i++)  //for문으로 모든 아이템 슬롯 배열을 불러온다
        {
            if (equipItemList[i].itemID != 0)       //장비된 아이템 슬롯의 아이템ID가 0이 아니라면
            {
                img_slots[i].sprite = equipItemList[i].itemIcon;//슬롯에 장비된 아이템의 아이콘을 불러온다
                img_slots[i].color = color;         //color의 컬러의 a값을 1로 한다
            }
        }
    }

    // Update is called once per frame
    void Update()
    {
        if (inputKey)
        {
            if (Input.GetKeyDown(KeyCode.E))//e키로 장비창 불러오기
            {
                activated = !activated;//On/Off

                if (activated)//활성화 됬을경우
                {
                    theOrder.NotMove();         //오더 매니져 움직임 정지
                    theAudio.Play(open_sound);  //사운드 재생
                    go.SetActive(true);         //장비창을 활성화한다
                    selectedSlot = 0;           //처음 선택된 슬롯은 0번
                    SelectedSlot();             //슬롯 선택 함수
                    ClearEquip();               //장비 아이템 클리어 함수
                    ShowEquip();                //장비된 아이템 보여주는 함수
                }
                else//그렇지 않을 경우
                {
                    theOrder.Move();            //움직임 활성화
                    theAudio.Play(close_sound); //사운드 재생
                    go.SetActive(false);        //장비창 비활성화
                    ClearEquip();               //장비 아이템 클리어 함수
                }
            }

            if (activated)
            {
                if (Input.GetKeyDown(KeyCode.DownArrow))
                {
                    if (selectedSlot < img_slots.Length - 1)
                        selectedSlot++;
                    else
                        selectedSlot = 0;
                    theAudio.Play(key_sound);
                    SelectedSlot();
                }
                else if (Input.GetKeyDown(KeyCode.RightArrow))
                {
                    if (selectedSlot < img_slots.Length - 1)
                        selectedSlot++;
                    else
                        selectedSlot = 0;
                    theAudio.Play(key_sound);
                    SelectedSlot();
                }
                else if (Input.GetKeyDown(KeyCode.LeftArrow))
                {
                    if (selectedSlot > 0)
                        selectedSlot--;
                    else
                        selectedSlot = img_slots.Length - 1;
                    theAudio.Play(key_sound);
                    SelectedSlot();
                }
                else if (Input.GetKeyDown(KeyCode.UpArrow))
                {
                    if (selectedSlot > 0)
                        selectedSlot--;
                    else
                        selectedSlot = img_slots.Length - 1;
                    theAudio.Play(key_sound);
                    SelectedSlot();
                }
                else if (Input.GetKeyDown(KeyCode.Z))
                {
                    if (equipItemList[selectedSlot].itemID != 0)
                    theAudio.Play(enter_sound);
                    inputKey = false;
                    StartCoroutine(OOCCoroutine("벗기", "취소"));
                }
            }
        }
    }
    IEnumerator OOCCoroutine(string _up,string _down)//OK,Cancel
    {
        go_OOC.SetActive(true);//OkOrC 오브젝트를 활성화
        theOOC.ShowTwoChoice(_up, _down);//사용 취소를 선택
        yield return new WaitUntil(() => !theOOC.activated);//theOOC가 false가 될때 멈춤
        if (theOOC.GetResult())//레절트 값을 받아옴
        {
            theInven.EquipToInventory(equipItemList[selectedSlot]);
            equipItemList[selectedSlot] = new Item(0, "", "", Item.ItemType.Equip);
            theAudio.Play(takeoff_sound);
            ClearEquip();
            ShowEquip();
        }
        inputKey = true;
        go_OOC.SetActive(false);
    }
}

오늘 강좌에서는 이벤토리를 구현할 것이다

장비를 장착하고 해제하는 법을 배운다

 

일단 장비창UI를 만든다

일단 캔버스에 Equipment 라는 오브젝트를 만들자

그뒤 소스파일에서 Equipment UI를 Hierachy에 먼저 넣고 다시 Hierachy의 Equipment에 넣어준다

 

그뒤 장비창이 카메라 화면의 중앙에 오게 한다

 

그뒤 Equipment UI에서 빈 오브젝트를 만들고 Slots 라고 이름지어 준다

그리고 하위에 이미지를 만들고 이름을 slot라고 지어준다

그 뒤 이미지의 크기와 위치를 장비장에 맞게 이동시켜서 조절해주고 투명도를 15정도로 세팅해준다

그 뒤 복제해서 아이템의 빈 칸마다 이동시켜 준다

 

이 순서에 맞게 복제를 해주자 이렇게 해야지 구분이 편해지고 아이콘 순서에 따라 선택창 표시가 움직인다

 

그뒤 Equipment UI - select 아이콘을 Hierarchy에 넣었다가 Slots의 아래에 넣어준다

 

 

그뒤 Sorting Layer을 UI로 바꿔준다

그 뒤 파란색에 체크한 1번부터 시작하게 준비해준다

이 슬롯이 움직이면서 선택된 아이템을 표시해 주는 것이다

이제 이름을 Selected_slot(UI)로 이름을 바꿔준다

 

이번에는 Text를 만들어 줄 것이다

Equipment UI의 아래에 빈객체를 만들어 주고 이름을 Texts라고 바꿔준 뒤에 Text파일로 각 능력치 옆에 atk_text부터

hit_text까지 쫘악 만들어준다

 

그리고 Text의 설정 값은 위 이미지를 참고한다

Overflow 꼭 잊지말자

 

이제 스크립트를 만들자 스크립트 이름은 Equipment로 해준다

 

변수 목록은 주석으로 처리하였다 참고하자

그리고 이번에 const라는 변수 키워드가 있는데 이 값이 들어가면 변수내의 수칙값이 변경이 불가능해진다

장비할 아이템에 const를 넣어서 다른 곳에서 값을 변경하지 못하게 했다

 

그리고 equipItemList는 위에 Const int에 대응해서 작성이 되었다

equipItemList[0] == equipItemList[WEAPON] 처럼 말이다

 

다음은 업데이트 함수로 넘어가자

주석으로 최대한 설명해 놨다

116번 줄에서 if문으로 키 입력이 활성화 되면 키보드 E키를 눌렀을때 장비창이 활성화 된다

activated = !activated로 간단하게 On/Off를 구현하고 On이되면 장비창 선택이 되고 Off가 되면 장비창을 비활성화 한다

 

일단 함수 설명으로 넘어간다

ClearEquip 함수이다

88번 줄에 변수로 0번 이미지 슬롯의 색을 불러오고

알파값을 0으로 해놨다

그뒤 for문으로 모든 이미지슬롯을 불러온 다음

모든 이미지의 sprite를 null로 만들고 color의 알파값을 0으로 한다

 

다음은 아이템이 장착됬을때 아이콘 상태를 나타내는 ShowEquip 함수를 보자

일단 아이템 슬롯 0번의 컬러 a값을 1로 하고

for문으로 모든 아이템 슬롯을 불러온 뒤

장비된 아이템창의  itemID가 0이 아니라면

슬롯에 장비된 아이템 아이콘을 불러오고 color의 a값을 1로 한다

a값이 1이 되면 이미지가 보이게 된다

 

이제 방향키 입력과 Z키 입력을 구현해보자

아래쪽 방향키와 오른쪽 방향키 입력은 로직이 같다

버튼을 누르면 if문으로 selectedSlot(선택된 슬롯) < img_slots.Length -1) 이미지 슬롯에서 -1한 값보다 높으면

selectedSlot(선택된 슬롯)에 ++하여 배열을 하나 늘리므로써 선택 앙이콘을 이동하고

else로 그게 아니라면 선택된 슬롯이 0이 되게 한다

그뒤 SelectedSlot()함수가 실행되게 한다

 

키보드 방향키 왼쪽 입력과 위쪽 입력은 로직이 같다

if문으로 selectedSlot(선택된 슬롯)이 0보다 작으면 --로 배열선택을 감소하여 선택을 이동시켜주고

else라면 selectedSlot(선택된 슬롯)에서 이미지슬롯을 -1하여 배열을 감소 아래쪽으로 이동시켜준다

그뒤 SelectedSlot()함수가 실행되게 한다

 

이제 Z키 입력을 보자

if문으로 equipItemList[selectedSlot]으로 장비아이템 배열에 선택된 아이템 슬롯이 있다면

.itemID !=0으로 아이템이 있다면 키 입력을 비활성화하하고 OOC코루틴 함수에서

벗기 취소를 활성화해 준다

즉 Z키를 입력시 아이템 벗기와 취소를 활성화해 줍니다

 

이제 SelectedSlot() 함수를 보자

이 함수는 선택된 아이템을 보여주는 게임오브젝트를 현재 선택된 아이템 슬롯 배열과 같은 위치로 이동시켜주는 슬롯이다

플레이어가 보기에는 해당 아이템 슬롯이 선택된게 시각적으로 보이게 된다

 

이제 Z키를 누르면 벗기 취소가 되는 OOC코루틴을 작성해보자

 

주석과 함게 설명에 들어가겠다

일단 OOC 오브젝트를 활성화해주고

 theOOC에 ShowTwoChoice를 활성화해서 인수 _up,_down을 받아온다

그뒤 theOOC가 false가 될때 코루틴을 멈춰준다

그리고

if문으로 theOOC.GetResult()가 반환되면 로직이 시작되게하고

theInven.EquipToInventory함수를 실행하여 equipItemList배열에서 selectedSlot 선택을 받아온다

여기서 기존에 Inventory함수에 EquipToInventory를 작성한 적이 없다 그래서 새로 작성해줘야 한다

 

Inventory 함수 내부에 새로 작성한 EquipToInventory함수이다

왜 이렇게 작성했냐하면 inventoryItemList 변수는 우리가 private로 공개수치를 조절했기 때문에 외부로 가져오는게 불가능하다

우리는 이걸 가져올 수 있게 함수로써 열람 가능하게 작성해준 것이다

 

이제 도로 Equipment 스크립트로 돌아와서

equipItemList 배열에 selectedSlot가 들어가있고 = new Item(0, "","",Item.ItemType.Equip와 같다고 해준다

그뒤 소리를 재생해주고

ClearEquip()함수와 ShowEquip()함수를 실행해주고

키 입력을 true로하면서 OOC 안의 panel오브젝트는 비활성화해준다

 

이제 인벤토리에서 장비를 장착하는 것을 구현해본다

 

Inventory 스크립트를 열어보자

 

 

주석으로 <-추가 라고 하는 부분을 작성해준다

 

그리고 전에 소모품과 장비아이템 구분해놓은 부분을 이렇게 수정하고 OOCCoroutine 함수를 수정해준다

 

주석과 같이 설명해주겠다

일단 소리를 재생하고 stopkeyInput를 ture로 만들어 준다

그뒤 OKOrCancal을 활성화해준다

그뒤 ShowTwoChoice 함수를 실행해준다 인수로 _up, _down로 받아와준다

그뒤 코루틴 정지로 !theOOC.activated를 해준다 그뒤

381번째 줄에 if문으로 OOC.GetResult()를 받아온다 그리고

for문으로 인벤토리에서 아이템리스트를 검샋해주고

검색한 아이템이 맞나 확인해준다

여기서 두갈래로 나뉜다

 

소모품 아이템이라면 데이터베이스에서 아이템 효과를 검색해서 사용해주고

숫자를 줄이거나 아이템을 지워준다

ShowItem()함수를 실행한다

그뒤 break;

 

장비푸 아이템이라면 인벤토리 배열에 넣어주고 인벤토리에서 장비된 아이템은 지워준다

ShowItem()함수를 실행한다

그뒤 break;

 

이제 stopkeyInput를 false해주고 OOC게임 오브젝트도 false해준다

 

그런데 우리는 EquipItem함수를 만들지 않았다

다시 Equipment 스크립트로 돌아간다

이렇게 함수를 작성해준다 주석과 같이 설명을 듣자

public void EquipItem(Item _item)으로 인수화 시켜주고

문자열로 temp라는 변수에 아이템의 아이디번호를 문자열화하여 넣어준다

temp = temp.Substring(0,3);으로 작성하여 temp에 들어간 숫자 3번째까지 검색해준다

 

이제 스위치문에 temp를 인수로 넣어주고

번호별로 장착하는 함수를 실행시켜 준다

 

이제 스위치문 부분에서 EquipItemCheck함수를 보자

주석을 참고하면서 보자

EquipItemCheck(int _count, Item _tiem)으로 숫자와 아이템을 인수로 받아온다

70번줄에 if문으로 장비 아이템 인수를 받아오고 아이템ID가 0이라면

아이템을 장착해준다

그 외의 경우라면 아이템 종류를 받아오고

인벤토리에 아이템을 장착한 것을 도로 넣어준다

 

이제 유니티엔진 인스펙터에 슬롯을 채워주자

 

그리고 밑줄 표시한 21001은 반이 아이콘 일련번호를 수정한 것이다

프로젝트에서 수정해주자

 

그리고 필자가 작성을 하면서 까먹은 부분이 있는데

Equipment 스크립트에서 182번 줄의 if문에 껍대기를  안 넣어놨다 이거 수정해주자

이렇게 해주면...

 

오늘 목표인 장비 아이템 구현이 멋지게 되었다!

'쯔꾸르식 유니티 게임 공부' 카테고리의 다른 글

34.아이템 장착과 공격 모션  (0) 2025.03.13
33.장비아이템 효과 추가  (0) 2025.03.11
26.a 오타 수정  (0) 2025.03.08
31.이팩트  (0) 2025.03.07
30.몬스터 처치, 레밸 UP  (1) 2025.03.07