Notice
Recent Posts
Recent Comments
Link
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
Tags
more
Archives
Today
Total
관리 메뉴

1vdlrwnsv1 님의 블로그

유니티 개발 숙련주차4. 아이템 상호작용 본문

Unity숙련주차

유니티 개발 숙련주차4. 아이템 상호작용

1vdlrwnsv1 2025. 3. 6. 20:26

아이템 상호작용 구현

 

인터페이스 정의

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

public interface IInteractable
{
    public string GetInteractPromp();
    public void OnInteract();
}
public class ItemObject : MonoBehaviour , IInteractable
{
    public ItemData  data;

    public string GetInteractPromp()
    {
        string str = $"{data.displayName}\n{data.description}";
        return str;
    }
    public void OnInteract()
    {
        CharacterManager.instance.player.itemData = data;
        CharacterManager.instance.player.addItem?.Invoke();
        Destroy(gameObject);
    }
}

 

  • IInteractable 인터페이스는 상호작용 가능한 오브젝트들이 공통적으로 가져야 할 메서드를 정의한다.
  • GetInteractPromp(): 플레이어가 오브젝트를 바라볼 때 출력할 프롬프트(설명) 문자열을 반환.
  • OnInteract(): 플레이어가 상호작용할 때 실행되는 로직.

 

  • IInteractable을 구현하여 ItemObject가 상호작용 가능하도록 설정.
  • GetInteractPromp(): 아이템의 이름과 설명을 반환하여 UI에 표시.
  • OnInteract(): 플레이어가 아이템과 상호작용하면,
    1. CharacterManager.instance.player.itemData에 아이템 데이터 저장.
    2. addItem 이벤트 호출.
    3. Destroy(gameObject);를 통해 아이템을 게임 내에서 삭제.

 

ItemData (아이템 데이터) 정의

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

public enum ItemType
{
    Equipable,
    Cusmable,
    Resource
}

public enum ConsumableType
{
    Health,
    Hunger
}
public class ItemDataConsumable
{
    public ConsumableType type;
    public float value;
}

[CreateAssetMenu(fileName = "Item", menuName = "New Item")]

public class ItemData : ScriptableObject
{
   [Header("Info")]
   public string displayName;
   public string description;
   public ItemType type;
   public Sprite icon;
   public GameObject dropPrefab;
   [Header("Stacking")]
    public bool canStack;
    public int maxStackAmount;
    [Header("Cunsumable")]
    public ItemDataConsumable[] consumables;



}

 

 

  • ScriptableObject를 이용해 아이템 정보를 저장하는 데이터 클래스.
  • displayName: 아이템 이름.
  • description: 아이템 설명.
  • type: 아이템 유형(장비, 소비, 자원).
  • icon: UI에서 사용할 아이콘.
  • dropPrefab: 아이템을 드롭할 때 사용할 프리팹.
  • canStack: 아이템 중첩 가능 여부.
  • maxStackAmount: 최대 중첩 개수.
  • consumables: 소비형 아이템일 경우 효과 값 저장.

Interaction 상호작용

using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.InputSystem;

public class Interaction : MonoBehaviour
{
    public float checkRate = 0.05f;
    private float lastCheckTime ;
    public float  maxCheckDistance;
    public LayerMask layerMask;
    public GameObject curInteractGameObject;
    private IInteractable curInteractable;
    public TextMeshProUGUI promptText;
    private Camera camera;


    // Start is called before the first frame update
    void Start()
    {
        camera = Camera.main;
    }

    // Update is called once per frame
    void Update()
    {
        if(Time.time - lastCheckTime > checkRate)
        {

            lastCheckTime = Time.time;

            Ray ray = camera.ScreenPointToRay(new Vector3(Screen.width / 2, Screen.height / 2));
            RaycastHit hit;

            if(Physics.Raycast(ray, out hit, maxCheckDistance, layerMask))
            {
                if(hit.collider.gameObject != curInteractGameObject)
                {
                    curInteractGameObject = hit.collider.gameObject;
                    curInteractable = hit.collider.GetComponent<IInteractable>();
                    SetPromptText();
                }
            }
            else
            {
                curInteractGameObject = null;
                curInteractable = null;
                promptText.gameObject.SetActive(false);
            }
        }
    }
    private void SetPromptText()
    {
        promptText.gameObject.SetActive(true);
        promptText.text = curInteractable.GetInteractPromp();
    }
    public void OnInteractInput(InputAction.CallbackContext context)
    {
        if(context.phase == InputActionPhase.Started && curInteractable != null)
        {
            curInteractable.OnInteract();
            curInteractGameObject = null;
            curInteractable = null;
            promptText.gameObject.SetActive(false);

        }
    }
}

 

  • 플레이어의 시야 중앙에서 레이를 쏴서 상호작용 가능한 오브젝트를 감지.
  • curInteractGameObject가 변경될 때 SetPromptText() 호출하여 프롬프트 UI 표시.
  • OnInteractInput(): 플레이어가 상호작용 키를 누르면 OnInteract() 호출.

 

5. Player 클래스에서 아이템 추가 이벤트 설정

 
public class Player : MonoBehaviour
{
    public PlayerController controller;
    public PlayerCondition condition;
    public ItemData itemData;
    public Action addItem;

    private void Awake()
    {
        CharacterManager.instance.player = this;
        controller = GetComponent<PlayerController>();
        condition = GetComponent<PlayerCondition>();
    }
}

 

  • itemData: 현재 플레이어가 얻은 아이템 저장.
  • CharacterManager.instance.player = this;를 통해 싱글톤 방식으로 플레이어 참조 설정.
  • https://1vdlrwnsv1.tistory.com/15(플레이어 만드는 법)

상호작용 과정 정리

  1. 플레이어의 Interaction 스크립트가 Raycast를 통해 상호작용 가능한 오브젝트 감지.
  2. 감지된 오브젝트가 IInteractable을 구현하고 있으면 SetPromptText() 실행.
  3. 플레이어가 상호작용 키를 누르면 OnInteractInput()이 실행되어 OnInteract() 호출.
  4. 아이템(ItemObject)의 OnInteract()가 실행되어 플레이어가 아이템을 얻음.
  5. 아이템 정보(ItemData)가 Player 클래스에 저장되고, addItem 이벤트가 호출됨.
  6. 아이템을 습득한 후 Destroy(gameObject);를 실행하여 씬에서 아이템 제거.

이번 학습내용은 상당히 어려워서 이해하는데 시간이 꽤 걸림 사실 아직도 이해안됨  혼자 개발하긴 조금 무리가 있다