게임 개발에서 몬스터 부위 파괴 시스템은 플레이어에게 더 몰입감 있는 경험을 제공하는 중요한 요소입니다. 특히, 유니티(Unity)를 사용하여 몬스터 헌터 스타일의 부위 파괴 시스템을 구현한다면, 게임의 깊이와 전략성을 높이는 데 큰 도움이 됩니다. 본 글에서는 이러한 시스템을 어떻게 구현할 수 있는지, 그 핵심적인 부분들을 차근차근 설명하고, 유니티에서 실제로 적용 가능한 예시 코드를 제공하겠습니다.

목표

  • 몬스터의 부위마다 독립적인 HP를 관리.
  • 부위 파괴 시 애니메이션이펙트가 적용되도록 구현.
  • 부위별 상호작용을 통해 게임 플레이에 영향을 미치는 요소 추가.
  • 성능 최적화를 고려하여 각 부위에 독립적인 관리 방식 제공.

1. 몬스터 부위 클래스 설계

몬스터의 각 부위는 독립적인 클래스(MonsterPart)로 관리되며, 각 부위별 HP, 피해 처리, 파괴 애니메이션, 부위 파괴 후 상태 변경 등을 담당합니다. 각 부위는 Collider와 함께 Damageable 인터페이스를 구현하여 다른 시스템들과의 호환성을 높입니다.

MonsterPart 클래스

using System.Collections;
using UnityEngine;

public class MonsterPart : MonoBehaviour, IDamageable
{
    public string partName; // 부위 이름 (Head, Leg, Arm 등)
    public float maxHP = 100f; // 부위의 최대 HP
    private float currentHP;
    public bool isDestroyed = false; // 부위가 파괴되었는지 여부
    public GameObject destructionEffect; // 파괴 시 이펙트
    public GameObject destructionAnimation; // 파괴 애니메이션

    private Collider partCollider;

    void Start()
    {
        currentHP = maxHP;
        partCollider = GetComponent<Collider>();
    }

    // 피해를 처리하는 메소드
    public void TakeDamage(float damage)
    {
        if (isDestroyed) return;

        currentHP -= damage;
        Debug.Log($"{partName} took {damage} damage. Current HP: {currentHP}");

        if (currentHP <= 0)
        {
            DestroyPart();
        }
    }

    // 부위를 파괴하는 메소드
    private void DestroyPart()
    {
        isDestroyed = true;
        partCollider.enabled = false;  // 파괴된 부위는 더 이상 충돌하지 않음

        // 파괴 이펙트 및 애니메이션 실행
        if (destructionEffect != null)
            Instantiate(destructionEffect, transform.position, Quaternion.identity);

        if (destructionAnimation != null)
            Instantiate(destructionAnimation, transform.position, Quaternion.identity);

        // 부위 파괴 후 상태 변화 (예: 몬스터 행동 변화)
        OnDestroyed();
    }

    // 부위 파괴 후 추가적인 상태 변경 (예: 몬스터 행동)
    private void OnDestroyed()
    {
        // 부위 파괴 후 몬스터 상태 변화 로직
        // 예: 다리 파괴 시 이동속도 감소, 날개 파괴 시 비행 능력 상실 등
        Debug.Log($"{partName} has been destroyed. Update monster behavior.");
    }

    // 부위의 HP를 리셋하는 메소드 (재생성 시 활용)
    public void ResetHP()
    {
        currentHP = maxHP;
        isDestroyed = false;
        partCollider.enabled = true;
    }
}

2. 몬스터 클래스 설계

몬스터 클래스는 각 부위를 고유의 몬스터 부위로 관리하고, 부위별 피해를 처리합니다. 각 부위는 MonsterPart 클래스 인스턴스로 구성되며, 이를 통해 개별적인 HP와 파괴 상태를 관리합니다. 또한, 부위별로 게임 로직에 영향을 미치도록 설정합니다.

Monster 클래스

using System.Collections;
using UnityEngine;

public class Monster : MonoBehaviour
{
    public MonsterPart head;
    public MonsterPart leftLeg;
    public MonsterPart rightLeg;
    public MonsterPart leftWing;
    public MonsterPart rightWing;

    public float damageMultiplier = 1f; // 피해 배율

    private void Start()
    {
        // 각 부위에 대한 초기화
        InitializeParts();
    }

    // 몬스터 부위 초기화
    private void InitializeParts()
    {
        head = GetComponentInChildren<MonsterPart>(); // 각 부위에 연결된 컴포넌트
        leftLeg = transform.Find("LeftLeg").GetComponent<MonsterPart>();
        rightLeg = transform.Find("RightLeg").GetComponent<MonsterPart>();
        leftWing = transform.Find("LeftWing").GetComponent<MonsterPart>();
        rightWing = transform.Find("RightWing").GetComponent<MonsterPart>();
    }

    // 타격 이벤트 처리
    public void TakeDamage(Vector3 hitPoint, float damage)
    {
        // 가장 가까운 부위 찾기
        MonsterPart part = GetPartFromHitPoint(hitPoint);
        
        if (part != null)
        {
            part.TakeDamage(damage * damageMultiplier); // 부위에 따른 피해 적용
        }
    }

    // 타격 위치에 맞는 부위 찾기
    private MonsterPart GetPartFromHitPoint(Vector3 hitPoint)
    {
        // 가장 가까운 부위를 찾아서 반환 (간단한 거리 비교 방식)
        MonsterPart[] parts = { head, leftLeg, rightLeg, leftWing, rightWing };
        MonsterPart closestPart = null;
        float closestDistance = Mathf.Infinity;

        foreach (var part in parts)
        {
            float distance = Vector3.Distance(hitPoint, part.transform.position);
            if (distance < closestDistance && !part.isDestroyed)
            {
                closestPart = part;
                closestDistance = distance;
            }
        }
        
        return closestPart;
    }

    // 몬스터의 모든 부위 리셋
    public void ResetMonster()
    {
        head.ResetHP();
        leftLeg.ResetHP();
        rightLeg.ResetHP();
        leftWing.ResetHP();
        rightWing.ResetHP();
    }
}

3. 타격 처리 및 게임 내 상호작용

부위를 타격한 후, 몬스터의 행동전투 상황이 어떻게 변할지를 결정하는 코드입니다. 예를 들어, 다리가 파괴되면 몬스터의 이동 속도가 감소하거나, 날개가 파괴되면 비행 능력이 상실됩니다. 이를 위해 부위마다 개별적인 상태 변경 메소드를 추가할 수 있습니다.

타격 처리

void OnCollisionEnter(Collision collision)
{
    if (collision.gameObject.CompareTag("Weapon"))
    {
        // 타격 위치에 따른 부위 결정
        Vector3 hitPoint = collision.contacts[0].point;
        monster.TakeDamage(hitPoint, collision.relativeVelocity.magnitude * 10f);
    }
}

몬스터 상태 변화 (예시)

private void OnDestroyed()
{
    if (partName == "LeftLeg" || partName == "RightLeg")
    {
        // 다리가 파괴되었을 때 몬스터 이동 속도 감소
        monster.GetComponent<MonsterMovement>().ReduceSpeed();
    }

    if (partName == "LeftWing" || partName == "RightWing")
    {
        // 날개 파괴 시 비행 능력 상실
        monster.GetComponent<MonsterMovement>().DisableFlying();
    }
}

4. 성능 최적화

부위 파괴 시스템은 다수의 몬스터상호작용을 다루므로 성능 최적화가 매우 중요합니다. 이를 위해 부위별 HP 리셋이나 파괴 이펙트객체 풀링(Object Pooling) 기법을 활용하여 리소스를 효율적으로 관리할 수 있습니다. 또한, 파괴된 부위의 Collider를 비활성화하고 UI 업데이트를 최소화하여 성능을 높입니다.

5. 장점과 단점

장점

  • 다양한 상호작용: 각 부위에 따른 효과가 다르기 때문에 플레이어가 전투에서 전략적으로 접근할 수 있습니다.
  • 게임의 몰입도: 몬스터 부위 파괴로 게임의 몰입도가 높아지고, 다양한 전투 패턴이 생겨냅니다.
  • 확장성: 새로운 부위와 파괴 효과를 쉽게 추가할 수 있어 게임의 확장성이 뛰어납니다.

단점

  • 개발 시간: 몬스터의 각 부위를 독립적으로 관리해야 하므로, 초기 개발 시간과 작업량이 많습니다.
  • 성능 최적화 필요: 많은 부위와 타격 이벤트를 처리해야 하므로, 성능에 대한 세심한 관리가 필요합니다.

6. 마무리

유니티에서 몬스터 헌터 스타일의 부위 파괴 시스템을 구현하는 것은 게임의 깊이를 한층 더할 수 있는 중요한 요소입니다. 위에서 제공한 코드 예제는 실제 게임에 바로 이식할 수 있도록 세심하게 설계되었습니다.

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다