유니티 아이템 교체 심화 과정

유니티 아이템 교체 심화 과정: 확장성 높은 아키텍처 설계

단순히 아이템의 3D 모델만 교체하는 것을 넘어, 게임이 커질수록 유지보수와 확장이 용이하도록 설계하는 방법을 알려드리겠습니다. 이 방식은 데이터와 동작을 분리하고, 객체 지향의 원칙을 적용하여 견고한 아이템 교체 시스템을 구축하는 데 초점을 맞춥니다.


1. 데이터와 동작의 분리: ScriptableObject와 인터페이스 활용

기존의 Item 클래스 대신, 아이템의 정적 데이터(이름, 모델 프리팹)를 관리하는 ScriptableObject와 아이템의 실제 동작을 정의하는 **인터페이스(Interface)**를 사용합니다.

  • ItemData (ScriptableObject): 아이템 자체의 정보를 담는 데이터베이스 역할을 합니다. 이 덕분에 아이템 데이터를 독립적으로 생성하고 관리할 수 있어 수많은 아이템을 효율적으로 다룰 수 있습니다.
  • IEquippable (Interface): 장착 가능한 모든 아이템이 반드시 구현해야 할 행동 규칙을 정의합니다. Equip()Unequip() 같은 메서드를 강제하여 어떤 종류의 아이템이든 일관된 방식으로 처리할 수 있습니다.

1.1. ItemData.cs – 아이템 데이터 정의 (ScriptableObject)

C#

using UnityEngine;

[CreateAssetMenu(fileName = "New Item Data", menuName = "Custom/Item Data")]
public class ItemData : ScriptableObject
{
    public string itemName;
    public string description;
    public Sprite icon;
    public GameObject itemPrefab; // 실제 게임에 나타날 아이템 모델 프리팹
}

1.2. IEquippable.cs – 장착 가능한 아이템의 행동 규칙 정의 (Interface)

C#

using UnityEngine;

public interface IEquippable
{
    void Equip(Transform parent);
    void Unequip();
}

2. 아이템의 실제 동작 구현: MonoBehaviour와 인터페이스 결합

이제 실제로 장착될 아이템 프리팹에 스크립트를 붙여 IEquippable 인터페이스를 구현합니다. 이 스크립트는 아이템의 물리적 동작이나 효과를 담당합니다.

2.1. EquippableWeapon.cs – 무기 동작 구현 (예시)

C#

using UnityEngine;

public class EquippableWeapon : MonoBehaviour, IEquippable
{
    public float damage = 10f;
    private Rigidbody rb;
    private Collider weaponCollider;

    void Awake()
    {
        rb = GetComponent<Rigidbody>();
        weaponCollider = GetComponent<Collider>();
    }

    public void Equip(Transform parent)
    {
        // 부모-자식 관계 설정 및 위치 초기화
        transform.SetParent(parent);
        transform.localPosition = Vector3.zero;
        transform.localRotation = Quaternion.identity;
        
        // 장착 시 물리 효과 비활성화 (던질 무기 등이 아닐 경우)
        if(rb != null) rb.isKinematic = true;
        if(weaponCollider != null) weaponCollider.enabled = false;
        
        Debug.Log(gameObject.name + "이(가) 장착되었습니다.");
    }

    public void Unequip()
    {
        // 장착 해제 시 부모 관계 해제
        transform.SetParent(null);
        
        // 필요한 경우 물리 효과 활성화 (예: 바닥에 떨어뜨리기)
        if(rb != null)
        {
            rb.isKinematic = false;
            rb.AddForce(Vector3.forward * 5f, ForceMode.Impulse); // 예시: 해제 시 앞으로 살짝 밀기
        }
        
        Debug.Log(gameObject.name + "이(가) 해제되었습니다.");
        Destroy(gameObject, 3f); // 3초 뒤에 아이템 오브젝트 제거
    }
}

3. 장비 관리 스크립트: 데이터와 동작을 연결하는 핵심

플레이어 캐릭터에 부착되는 **EquipmentManager**는 ItemData를 받아 IEquippable 인터페이스를 통해 아이템의 동작을 제어합니다. 이로써 EquipmentManager는 어떤 종류의 아이템이든 상관없이 동일한 방식으로 다룰 수 있게 됩니다.

3.1. EquipmentManager.cs – 최종 교체 로직

C#

using UnityEngine;

public class EquipmentManager : MonoBehaviour
{
    public Transform equipPosition;
    private IEquippable currentEquippedItem;

    public void EquipNewItem(ItemData itemData)
    {
        // 1. 기존 아이템 장착 해제
        if (currentEquippedItem != null)
        {
            currentEquippedItem.Unequip();
        }

        // 2. 새로운 아이템 프리팹 생성 및 IEquippable 컴포넌트 획득
        if (itemData.itemPrefab == null)
        {
            Debug.LogError("장착할 아이템 프리팹이 없습니다.");
            return;
        }

        GameObject newItemObject = Instantiate(itemData.itemPrefab);
        IEquippable newEquippable = newItemObject.GetComponent<IEquippable>();

        if (newEquippable == null)
        {
            Debug.LogError("새로운 아이템에 IEquippable 컴포넌트가 없습니다.");
            Destroy(newItemObject);
            return;
        }

        // 3. 새 아이템 장착
        newEquippable.Equip(equipPosition);
        currentEquippedItem = newEquippable;
        
        Debug.Log($"[{itemData.itemName}] 아이템을 성공적으로 장착했습니다.");
    }

    public void UnequipCurrentItem()
    {
        if (currentEquippedItem != null)
        {
            currentEquippedItem.Unequip();
            currentEquippedItem = null;
        }
    }
}

이 아키텍처의 장점

  • 유지보수 용이성: 새로운 아이템 종류(방패, 갑옷 등)를 추가할 때, IEquippable 인터페이스를 구현하는 새로운 스크립트만 만들면 됩니다. EquipmentManager 코드는 전혀 수정할 필요가 없습니다.
  • 높은 확장성: 아이템 데이터를 ScriptableObject로 관리하므로, 아이템을 수천 개 만들어도 메모리 사용량이 크게 늘지 않습니다. 또한, 게임 내에서 아이템의 스탯이나 속성을 쉽게 변경할 수 있습니다.
  • 데이터와 로직의 분리: ItemData는 아이템의 정보만, EquippableWeapon은 동작만 담당하므로 코드가 훨씬 깔끔하고 이해하기 쉬워집니다.

이 심화된 구조는 게임의 규모가 커지더라도 안정적으로 아이템 시스템을 관리할 수 있는 기반을 마련해줍니다.

댓글 남기기