유니티 2D 아이템 장착 - yuniti 2D aitem jangchag

오늘도 아래 강좌 이어서,

https://youtu.be/APS9OY_p6wo

유니티 2D 아이템 장착 - yuniti 2D aitem jangchag

- 오브젝트 감지

    private void OnTriggerStay(Collider other)
    {
        if (other.tag == "Weapon")
        {
            nearObject = other.gameObject;
        }

        Debug.Log(nearObject.name);
    }

    private void OnTriggerExit(Collider other)
    {
        if (other.tag == "Weapon")
        {
            nearObject = null;
        }
    }

> OnTriggerStay와 OnTriggerExit를 통해 충돌 물체 감지
 - OnTriggerStay : Trigger와 접촉하고 있는 모든 Collider other에 대해 프레임당 한번 호출
 - OnTriggerExit : Collider other가 접촉을 중단한 경우 호출
> Weapon 오브젝트와 충돌시 nearObject를 충돌한 오브젝트로 설정.

- 무기입수 : 충돌이 발생한 오브젝트에 E키를 눌렀을 경우 입수.

    void Interaction()
    {
        if(iDown && nearObject != null && !isJump && !isDodge)
        {
            if(nearObject.tag == "Weapon")
            {
                Item item = nearObject.GetComponent<Item>();
                int weaponIndex = item.value;
                hasWeapon[weaponIndex] = true;

                Destroy(nearObject);
            }
        }
    }

 > iDown : Input System에서 알파벳 E키를 눌렀을 경우 동작.
  - 객체에 붙은 'Item' 스크립트를 통해 접근. 설정한 무기 Index값으로 hasWeapon 활성화.
   충돌 발생한 오브젝트는 Destroy()

- 무기 장착
 1) 캐릭터 손 위치에 Cylinder 모양의 객체 추가(Renderer는 꺼서 게임 화면에는 안보이게)
 2) 생성한 실린더 아래에 무기 프리팹을 하나씩 위치(비활성화)
 3) 숫자 1~3키(sDown1~3) 입력 시 무기 교체

    void Swap()
    {
        //이미 장착하고 있는 경우는 교체하지 않는다.
        if(sDown1 && (!hasWeapon[0] || equipWeaponIndex == 0))
        {
            return;
        }
        if (sDown2 && (!hasWeapon[1] || equipWeaponIndex == 1))
        {
            return;
        }
        if (sDown3 && (!hasWeapon[2] || equipWeaponIndex == 2))
        {
            return;
        }

        //키 입력에 따라 무기 인덱스 활성화
        int weaponIndex = -1;
        if (sDown1) weaponIndex = 0;
        if (sDown2) weaponIndex = 1;
        if (sDown3) weaponIndex = 2;

        //각 키 입력이 들어오고, 다른 동작 중이 아닐 경우
        if ((sDown1 || sDown2 || sDown3) && !isJump && !isDodge)
        {
            //장착중인 무기는 비활성화
            equipWeapon?.SetActive(false);

            //장착할 무기 활성화
            equipWeaponIndex = weaponIndex;
            equipWeapon = weapons[weaponIndex];
            equipWeapon.SetActive(true);

            //장착 애니메이션 활성화
            animator.SetTrigger("doSwap");

            isSwap = true;
            //스왑종료 알리기
            Invoke("SwapOut", 0.4f);
        }
    }
    
    void SwapOut()
    {
        isSwap = false;
    }

* isSwap은 다른 동작중(점프나 dodge, 이동중) 동작되는 것을 방지.

장착 완료!

유니티 2D 아이템 장착 - yuniti 2D aitem jangchag

안녕하세요.

골드메탈입니다.

오늘은 액션 RPG에서는 없어선 안될

아이템을 줍고 장착하는 기능을 구현해보는

시간을 갖도록 하겠습니다.

자, 먼저 플레이어 오브젝트를 살펴보도록 합시다.

오브젝트를 펼쳐보면

애니메이션 뼈대와 각 파츠별 메쉬들이 들어가 있습니다.

(뼈대 이름은 애니메이션 작업 환경에 따라 다를 수 있습니다.)

애니메이션 뼈대와 메쉬들은

서로 부모-자식 관계로 이루어져 있는데,

이러한 관계를 종속관계라고 합니다.

부모 오브젝트에 종속된 자식 오브젝트는

서로 위치가 다를 수 있지만

부모의 움직임에 따라 자식도 같이 움직이게 됩니다.

플레이어를 이루는 각 파츠 메쉬들도

애니메이션의 뼈대의 움직임에 따라 움직여서

실제로 우리 눈에 보여지는 애니메이션이 되는 것이지요.

우리는 이 점을 이용하여

외부 오브젝트가 플레이어 애니메이션에 참여하여

움직일 수 있도록 할 것입니다.

먼저 아이템을 장착할 곳의 애니메이션 뼈대에

장착 위치가 될 자식 오브젝트를 만듭니다.

필자는 오른손에 아이템을 장착하기 위해 오른손 뼈대에 만들었습니다.

그런 다음 장착 위치를 적당히 조절합니다.

여기서 좌표 기준(0,0,0)은 부모 오브젝트의 위치가 됩니다.

이걸 지역위치(localPosition)라고 부르지요.

마지막으로 스크립트에서 불러오기 위해

이름과 태그를 설정합니다.

이제 아이템의 스크립트로 들어가봅시다.

필자는 프리펩으로 저장해둔 공을 재사용하겠습니다.

위에서 지정했던 태그를 통해서 장착 위치 오브젝트를 불러옵니다.

그리고 플레이어의 스크립트도 불러와줍시다.

플레이어가 충돌체에 접근한 상태로 액션 키를 누르면

아이템을 장착하려면 먼저 장착 위치 오브젝트에 자식으로 종속되야 합니다.

(결국 애니메이션 뼈대의 손자가 되는 격.)

transform.SetParent(tranform) 함수를 사용해서 부모를 지정해준 다음,

위치가 정확히 장착 위치에 오도록 지역 위치를 원점으로 설정해줍시다.

이 상태로 한번 작동시켜보죠.

생각과는 달리 바로 놓쳐버리면서

움직임이 멋대로 왔다갔다하네요.

이유는 아이템의 여러 충돌체와 리지드바디의 물리효과로 인해

부모의 움직임에 방해를 주고 있기 때문입니다.

유니티 2D 아이템 장착 - yuniti 2D aitem jangchag

(하긴 이렇게 쉽게 끝날리가 없지..)

플레이어 스크립트로 들어가서

이 문제점을 해결해야겠습니다.

아이템 줍기와 버리기, 그리고 장착에 대한 함수를 새로 만들어주었습니다.

특히 줍기는 아이템 스크립트에서 불러올거니까 public 키워드로 꼭 공개해둡시다.

버리기 함수를 잠깐 살펴보면

장착된 아이템 오브젝트를 불러오기 위해

GetComponentInChildren<T>() 함수를 사용한 것을 볼 수 있지요.

GameObject를 바로 불러올 수는 없기 때문에

아이템의 필수 컴포넌트(리지드바디 혹은 충돌체)를 잠시 빌려서

장착 함수에서는 움직임을 방해하는 요소인

물리효과나 트리거 이벤트를 모두 끄거나 켜는 로직을 구현해 놓습니다.

모든 컴포넌트는 enabled 속성을 사용해서 켜고 끌 수 있습니다.

리지드바디는 isKinematic(스크립트에 의해서만 움직임)을 사용하면 됩니다.

마무리 단계로 줍는 함수에 애니메이션도 넣으면서

아이템을 가지고 있다는 플래그 변수도 하나 만들어놓습니다.

버리기 함수에서는

더 이상 종속관계가 되지 않도록

transform.DetachChildren() 함수로 떼어놓습니다.

Update 사이클에서 버리기 로직도 넣어주어야겠죠?

필자는 마우스 클릭으로 아이템을 버리도록 설정해두겠습니다.

마지막으로 아이템 스크립트에서

플레이어의 줍기 로직을 호출합니다.

이렇게해서 스크립트 로직까지 완료!

유니티 2D 아이템 장착 - yuniti 2D aitem jangchag

아주 완벽합니다!

아이템을 줍고 놓고~

정말 게임 같아보이네요.

---------------------------------------------

이렇게하여

열일곱번째 강좌를 마무리하였습니다.

부모-자식 관계만 잘 이해하신다면

그리 어렵지 않을 것입니다.

다음은 마우스를 이용하여

투사체를 발사하는 액션에 대해 다뤄보도록 하겠습니다.

그럼.