3 분 소요

Intro

이번 포스팅에서는 플레이어가 무기를 장착하고 해제할 때 그 무기를 생성하고, 무기에맞는 애니메이션을 수행하는것을 구현해보았습니다.

image

게임이 시작되면 플레이어 데이터를 불러와서 장착중이던 장비대로 능력치 및 외관 장비가 장착되어 있어야합니다. => 이 부분은 나중에 구현 하려합니다.

  • 먼저 플레이어는 게임이 시작되면 주먹(Punch) 무기를 장착하도록 했습니다.

  • 인벤토리에서 무기를 장착하면 주먹 무기를 파괴하고, 장착한 무기정보에따라 프리팹을 생성합니다.
    • 장착중이던 무기를 해제하면 다시 주먹 무기를 장착합니다.
  • 프리팹이 생성되면, 프리팹의 무기타입에따라 플레이어의 공격 애니메이션이 달라집니다.

WeaponManager.cs

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

/*
                    WeaponManager : 무기 및 전략 관리

            - SetWeapon() : 현재 무기 설정
            - ChangeAttackStrategy() : 공격 전략 변경
            - Attack() : 현재 무기의 공격 실행
 */

public class WeaponManager : Singleton<WeaponManager>
{
    #region ** Serialized Fields **
    [SerializeField] PlayerController player;
    [SerializeField] Transform weaponTransform;
    #endregion

    #region ** Fields **
    private GameObject myWeaponGo;                      // 장착중인 무기 오브젝트
    private WeaponType myWeaponType;                    // 장착중인 무기의 타입
    private Weapon currentWeapon;

    readonly private int hashWeaponType = Animator.StringToHash("WeaponType");
    #endregion 


    // 무기 타입별 WeaponType 파라미터값 
    public int CurWeaponType
    {
        get => player.Anim.GetInteger(hashWeaponType);
        set => player.Anim.SetInteger(hashWeaponType, value);
    }

    private void Start()
    {
        InitWeapon();
    }

    // 시작 무기 세팅
    public void InitWeapon()
    {
        currentWeapon = weaponTransform.GetComponentInChildren<Weapon>();          // 현재 장착중인 무기 가져오기
        
        // 무기가 없을 때
        if(currentWeapon == null)
        {
            // 맨손 무기 생성
            ResourceManager.Instance.LoadWeaponPrefab("Punch.prefab", prefab =>
            {
                if (prefab != null)
                {
                    // 프리팹 생성
                    GameObject newWeapon = Instantiate(prefab, prefab.transform.position, prefab.transform.rotation, weaponTransform);
                    newWeapon.transform.localPosition = prefab.transform.localPosition;
                    newWeapon.transform.localRotation = prefab.transform.localRotation;

                    // 무기 설정
                    myWeaponGo = newWeapon;
                    currentWeapon = myWeaponGo.GetComponent<Weapon>();
                    myWeaponType = WeaponType.None;
                }
                else
                {
                    Debug.Log($"Failed to load prefab for item : {prefab}");
                }
            });
        }
        else
        {
            myWeaponType = currentWeapon.type;
        }

        // 현재 무기 애니메이션설정
        CurWeaponType = (int)myWeaponType;
    }

    // 현재 무기 세팅(기본값 Punch)
    public void SetWeapon(string type = "None", string weapon = "Punch")
    {
        if(Enum.TryParse(type, out WeaponType result))
        {
            ResourceManager.Instance.LoadWeaponPrefab(weapon + ".prefab", prefab =>
            {
                if (prefab != null)
                {
                    currentWeapon = null;
                    // 기존 무기 삭제
                    Destroy(myWeaponGo);
                    // 프리팹 생성
                    GameObject newWeapon = Instantiate(prefab, prefab.transform.position, prefab.transform.rotation, weaponTransform);
                    newWeapon.transform.localPosition = prefab.transform.localPosition;
                    newWeapon.transform.localRotation = prefab.transform.localRotation;

                    myWeaponGo = newWeapon;
                    currentWeapon = myWeaponGo.GetComponent<Weapon>();

                    // 새로운 무기로 설정
                    myWeaponGo = newWeapon;
                    myWeaponType = result;
                    CurWeaponType = (int)myWeaponType;
                }
                else
                {
                    Debug.Log($"Fail to load prefab for item : {prefab}");
                }
            });
        }
        else
        {
            Debug.Log($"{type} 은(는) 유효한 타입이 아닙니다.");
        }
    }

    // 공격 전략 변경
    public void ChangeAttackStrategy(IAttackStrategy newStrategy)
    {
        if(currentWeapon != null)
        {
            currentWeapon.SetAttackStrategy(newStrategy);
        }
        // 무기가 없을 때(임시)
        else
        {
            Debug.Log("무기가 장착되지 않았음");
        }
    }

    // 현재 무기 공격 실행
    public void Attack()
    {
        if(currentWeapon != null)
        {
            currentWeapon.PerformAttack();
        }
        // 무기가 없을 때(임시)
        else
        {
            Debug.Log("무기가 장착되지 않았음");
        }
    }
}
  • WeaponController 클래스를 싱글톤으로 바꿈으로써 WeaponManager 로 이름을 변경하였습니다.

  • 게임시작시 InitWeapon() 호출을 통해 주먹 무기를 장착합니다.

  • SetWeapon() 함수는 무기 장착 및 해제를 구현하는 아이템 클래스에서 호출합니다.

    • 매개변수로 아무것도 주어지지 않으면 무기 장착 해제로, 주먹 무기가 생성되도록 했습니다.

WeaponItem.cs

/*
                WeaponItem : 무기 아이템
                
                Equip() : 무기 장착
                    - 무기 데이터의 수치만큼 플레이어 능력치 상승
                Unequip() : 방어구 해제
                    - 무기 데이터의 수치만큼 플레이어 능력치 하락
 */

public class WeaponItem : EquipmentItem
{
    public WeaponItemData WeaponData { get; private set; }
    public WeaponItem(WeaponItemData data) : base(data) 
    {
        WeaponData = data;
    }

    // 장착
    public override void Equip()
    {
        // 장비에 따른 플레이어 능력치 반영
        DataManager.Instance.GetPlayerData().EquipItem(WeaponData.Damage, WeaponData.Type);
        // 장비에 따른 플레이어 무기 설정
        WeaponManager.Instance.SetWeapon(WeaponData.SubType, WeaponData.ItemPrefab);
    }

    // 장착 해제
    public override void Unequip()
    {
        // 장비에 따른 플레이어 능력치 반영
        DataManager.Instance.GetPlayerData().UnequipItem(WeaponData.Damage, WeaponData.Type);
        // 기본 무기 설정
        WeaponManager.Instance.SetWeapon();
    }
}
  • Equip() 및 Unequip() 함수에서 WeaponManager의 SetWeapon 함수를 호출하여 무기를 세팅합니다.

데이터 추가

어드레서블 에셋 그룹에 무기 프리팹을 추가해주었습니다.

image

  • 어드레서블 에셋 그룹의 프리팹을 가져오기위해서, WeaponData에 itemPrefab 필드를 추가하여 각 아이템의 프리팹 이름을 가져올 수 있도록 했습니다.

  • 어드레서블 에셋을 추가하면 반드시 Build - New Build - Default Build Script 를 통해 초기화해주어야합니다.

댓글남기기