[Unity, C#] 제일 가까운 아이템 줍기

이삭을 줍는 사람들

유니티에서 아이템 줍기 기능을 구현하려면,
1) 플레이어가 아이템을 인식할 조건을 추가하고
2) 해당 조건을 만족할 때 아이템을 줍는 기능을 구현하면 된다.

  1. 플레이어의 자식으로 빈 GameObject를 추가한다.
  2. 추가한 GameObject의 컴포넌트로 Circle Collider(콜라이더)를 추가해준다. 해당 Collider의 Is Trigger를 체크해준다.
  3. 추가한 GameObject의 컴포넌트로 스크립트를 추가해준다. (OnTriggerEnter)
💡

Trigger?
GameObject끼리 충돌이 발생한 경우, 인식은 하되 물리적으로 부딪치지는 않게 하고 싶을 때 설정한다.
일반적으로 플레이어가 Trigger가 아닌 경우, Trigger가 아닌 GameObject와의 충돌은 플레이어가 벽에 부딪히는 경우, TriggerGameObject와의 충돌은 코인과 접촉했을 때 코인이 획득되는 경우를 생각하면 된다.

💡

OnTriggerEnter 사용 시 주의
OnTriggerEnter는 기본적으로 두 GameObject가 충돌할 때 호출된다. 그러나 충돌하는 두 GameObject가 모두 Collider를 포함해야 하며, 적어도 하나의 GameObjectisTrigger = true여야 한다.

플레이어의 자식으로 ItemScope라는 GameObject를 추가해주었고, 스크립트는 다음과 같다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ItemScope : MonoBehaviour
{
    List<Item> ItemsInScope;

    private void Awake()
    {
        ItemsInScope = new List<Item>();
    }

    private void Update()
    {
        // 인식 범위 내에 아이템이 없을 경우
        if (ItemsInScope.Count == 0)
        {
            Player.Instance.LetterF.SetActive(false);
        }
        // 인식 범위 내에 아이템이 하나라도 있을 경우
        else
        {
            Player.Instance.LetterF.SetActive(true);
            // F키를 누르면
            if (Input.GetKeyDown(KeyCode.F))
            {
                // 가장 가까운 아이템을 찾아 그 아이템을 획득한다.
                Vector3 playerPos = Player.Instance.transform.position;
                Item nearestItem = ItemsInScope[0];
                for (int i=0; i<ItemsInScope.Count; ++i)
                {
                    if (Vector3.Distance(playerPos, nearestItem.transform.position) >
                        Vector3.Distance(playerPos, ItemsInScope[i].transform.position))
                    {
                        nearestItem = ItemsInScope[i];
                    }
                }
                nearestItem.PickUp();
            }
        }
    }

    private void OnTriggerEnter2D(Collider2D collision)
    {
        Item item = collision.GetComponent<Item>();
        if (item != null)
            ItemsInScope.Add(item);
    }

    private void OnTriggerExit2D(Collider2D collision)
    {
        Item item = collision.GetComponent<Item>();
        if (item != null)
            ItemsInScope.Remove(item);
    }
}

ItemScope 내에 아이템이 하나라도 있을 시 플레이어 위에 F키 이미지(LetterF)가 표시된다. 또한 ItemScope 내에 아이템이 하나 이상 있을 때 F키를 누르면 가장 가까운 아이템이 획득되도록 구현해보았다.

ItemScope 내의 모든 아이템을 획득하도록 짜고 싶다면 nearestItem을 찾지 않고 ItemsInScope의 모든 아이템에서 PickUp 함수를 실행하면 된다.