unity

[unity 3d] - 바라보는 오브젝트를 키 입력을 통해 인벤토리에 저장하기

chyam_eun 2025. 3. 3. 19:40

< 구현 목표 >

나무 오브젝트를 바라보고 "G"키를 누르면 나무가 파괴되면서 인벤토리에 저장되도록 하기!

 

추후에 다른 오브젝트들도 추가하게되면 코드를 수정할 예정입니다!

먼저, 인벤토리 만드는 방식은 아래 블로그를 참고하였습니다.

 

유니티 (Unity) - 처음 만들어 보는 인벤토리 이해하기 (Inventory)

인벤토리를 만들기 위한 기본 구조를 살펴보겠습니다.인벤토리가 어떻게 작동하는지 알아보기 위한 아주 간단한 프로그램입니다. 사용된 아이콘 및 슬롯 이미지https://assetstore.unity.com/packages/2d/

geojun.tistory.com

 

 

Player 스크립트에서 필요한 전체 코드는 아래와 같습니다.

public Inventory inven11;
...

void ColliderObject()
{
    Vector3 startPosition = transform.position + Vector3.up * 15f;
    Debug.DrawRay(startPosition, transform.forward * 12f, Color.red);

    RaycastHit hit;

    if (Physics.Raycast(startPosition, transform.forward, out hit, 12))
    {
        int hitLayer = hit.collider.gameObject.layer;

        if (hitLayer == LayerMask.NameToLayer("Logs"))
        {
            if (Input.GetKeyDown(KeyCode.G)) // 나무 얻기
            {
                string hitname = hit.collider.gameObject.name;
                if (hitname.Substring(0, 3) == "log")
                {
                    print(hit.collider.gameObject.name);
                    inven11.Check("log");
                }
                Destroy(hit.collider.gameObject);
            }
        }
        ...
    }
}
    
}

...

void Inven()
{
    
    if (Input.GetKeyDown(KeyCode.I))
    {
        
        if (!isClick) // 인벤토리 닫기
        {
            inven.SetActive(false);
            isClick = true;
        }
        else // 인벤토리 열기
        {
            inven.SetActive(true);
            isClick = false;
        }
        
    }
}

 

먼저 캐릭터에서 레이저를 쏘아서 닿은 물체의 정보를 얻기 위해서 레이저의 위치와 길이를 설정해주어야합니다.

 

position 값은 발 아래를 기준으로 하기 때문에 레이저를 상체에서 발사하도록 Vector3.up을 더해주었습니다.

Debug.DrawRay를 사용하면 시각적으로 레이저를 확인할 수 있습니다.

(시작 위치, 방향*길이, 색깔) 을 매개변수로 가집니다. 저는 레이저의 길이를 앞으로 12배만큼으로 설정했습니다.

Vector3 startPosition = transform.position + Vector3.up * 15f;
Debug.DrawRay(startPosition, transform.forward * 12f, Color.red);

 

 

hit은 레이저가 어떤 물체에 닿았을 때 그 충돌 정보를 저장하는 변수입니다.

첫 번째 if문에서 12는 transform.forward방향으로 길이 12배만큼 레이저를 발사해줍니다.

 

저는 충돌한 물체의 정보 중 충돌한 물체의 collider을 가져와주었습니다!

 

hitLayer은 충돌한 물체의 layer의 번호를 저장합니다.

나무들의 이름이 "log_a1" 이런식이라서 Substring을 통해 처음부터 3자리를 잘라서 "log"이면

Inventory의  Check 메서드를 실행해줍니다.

다 실행한 후에는 Destroy()를 통해 나무 오브젝트를 제거합니다.

    RaycastHit hit;

    if (Physics.Raycast(startPosition, transform.forward, out hit, 12))
    {
        int hitLayer = hit.collider.gameObject.layer;

        if (hitLayer == LayerMask.NameToLayer("Logs")) //"Logs"라는 레이어의 번호와 같을때 
        {
            if (Input.GetKeyDown(KeyCode.G)) // G를 눌러 나무 얻기
            {
                string hitname = hit.collider.gameObject.name;
                if (hitname.Substring(0, 3) == "log")
                {
                    print(hit.collider.gameObject.name);
                    inven11.Check("log");
                }
                Destroy(hit.collider.gameObject);
            }
        }
    	...
    }

 

 

 

아래는 기본적으로 위의 블로그에서 구현했던 Inventory 스크립트를 수정한 코드입니다.

public List<Item> items;
public TextMeshProUGUI[] slotText;
private Slot[] slots;
...

void Awake()
{
    FreshSlot();

    for (int i = 0; i < slots.Length; i++)
    {
        slotText[i].text = "0"; // 처음엔 0으로 초기화
        slotText[i].gameObject.SetActive(false);
    }
}

public void Check(string name)
{
    ...
    int i = 0;
    for (;i < slots.Length; i++)
    {
        slotText[i].gameObject.SetActive(true);
        if (slots[i].item != null && slots[i].item.itemName == name)
        {
            print("correct");
            slotText[i].text = (int.Parse(slotText[i].text) + 1).ToString();
        }

        if (int.Parse(slotText[i].text) == 5)
        {
            print("나무를 5개 모았습니다!");
            bridge.SetActive(true);
        }
    }
}

 

 

먼저 items에는 등록할 아이템들을 저장해주고, slotText는 각 아이템의 갯수를 나타냅니다.

slots는 인벤토리의 각 슬롯들을 저장해줍니다.

public List<Item> items;
public TextMeshProUGUI[] slotText;
private Slot[] slots;

 

slotText를 각각 "0"으로 초기화해주고, 보이지 않게 해줍니다.

void Awake()
{
    ...
    for (int i = 0; i < slots.Length; i++)
    {
        slotText[i].text = "0"; // 처음엔 0으로 초기화
        slotText[i].gameObject.SetActive(false);
    }
}

 

 

각 slotText가 보이게 해주고, 해당 슬롯이 비어있지 않고, item의 이름이 매개변수로 받아온 name과 같으면, 해당 슬롯의 숫자를 1 증가시켜서 text를 새로 저장해주었습니다.

 

그리고 총 5개를 모으면 다리가 나타나도록 설정했습니다.

public void Check(string name)
{
    ...
    int i = 0;
    for (;i < slots.Length; i++)
    {
        slotText[i].gameObject.SetActive(true);
        if (slots[i].item != null && slots[i].item.itemName == name)
        {
            slotText[i].text = (int.Parse(slotText[i].text) + 1).ToString();
        }

        if (int.Parse(slotText[i].text) == 5)
        {
            print("나무를 5개 모았습니다!");
            bridge.SetActive(true);
        }
    }
}