Unity 숙련주차 - Survival 게임 아이템 장착과 모션

Amberjack·2024년 2월 2일
0

Unity

목록 보기
29/44

📸 장착 카메라 준비하기

장착 아이템을 위한 Layer를 추가하자!
Resource와 Equip Layer 2개를 추가했다.

장착 카메라?

장착 중인 아이템이 우리 시야에 고정되기 위해서는 Camera의 하위 객체로 추가해줄 필요가 있다.
그러나, MainCamera에 장비를 추가하면 발생하는 문제가 있다.

바로 장비가 벽이나 오브젝트에 의해 가려지게 된다는 것이다. 보통 게임에서 벽에 의해 장비가 가려지는 경우는 없을 것이다.
때문에 이를 해결하기 위해 장착 장비들을 위한 카메라를 따로 마련하여 시야를 분리해주어야 한다.

장착 카메라 만들기

위의 문제를 해결하기 위한 EquipCamera를 추가하자!

EquipCamera를 추가하면 오류가 발생할 것이다. 이유는 Camera에는 Audio Listener가 자동으로 추가가 되기 때문이다. Main Camera와 Audio Listener가 중복이 되기 때문에 오류가 발생하는 데, 단순히 EquipCamera의 Audio Listener를 제거해주면 된다.

이후 Main Camera의 Culling Mask에서 Equip을 제거해준다. → Equip Layer에 있는 것들은 Main Camera에 찍히지 않도록 설정해주는 것!

반대로 EquipCamera에서는 Equip Layer만 찍도록 설정하고, Clear Flags를 Depth Only로 변경해준다.
Clear Flags의 기본값은 Skybox인데, EquipCamera에서도 Skybox로 설정되어 있으면 덮어씌우기가 되어서 Skybox밖에 찍히지 않게 된다.
마지막으로 Depth를 1로 변경해줄건데, 이유는 Sort Order와 같은 이유이다. 카메라가 2개가 있으면 어떤 것이 우선인지 모르기 때문에 우선 순위를 정해주는 것이다.

그 다음에는 EquipCamera 밑에 빈 오브젝트를 만들고 Equip_Axe라고 바꿔준 뒤, 도끼 프리팹을 넣어준다. 또한, Layer를 Equip으로 변경해준다.

그리고 Prefabs 폴더 밑에 Equips라는 폴더를 만든 뒤, Equip_Axe를 넣어준다.

확인해보기!

벽에 가려지지 않는 것을 확인할 수 있다.

🪓 무기 준비하기

Equip.cs 작성!

EquipTool.cs 작성!

Equip을 상속 받아서 여러 장착 아이템을 장착할 수 있도록 해주는 EquipTool을 작성해보자.
EquipTool.cs를 생성해서 미리 만든 Equip Prefab들에게 추가해준다.

using UnityEngine;

public class EquipTool : Equip
{
    public float attackRate;
    private bool attacking;
    public float attackDistance;

    // 자원을 채취 가능한 장비 여부
    [Header("Resource Gathering")]
    public bool doesGatherResources;

    // 공격 가능한 장비 여부
    [Header("Combat")]
    public bool doesDealDamage;
    public int damage;

    private Animator animator;
    private Camera _camera;

    private void Awake()
    {
        _camera = Camera.main;
        animator = GetComponent<Animator>();
    }

    public override void OnAttackInput()
    {
        // 공격 중이 아닐 경우
        if (!attacking)
        {
            attacking = true;
            animator.SetTrigger("Attack");
            // 공격 딜레이를 주어서 공격을 실행한다.
            Invoke("OnCanAttack", attackRate);
        }

    }

    void OnCanAttack()
    {
        attacking = false;
    }
}

👨‍💻 EquipManager.cs 작성!

EquipManager.cs를 생성한 뒤 Player에게 추가해주자.

using UnityEngine;
using UnityEngine.InputSystem;

public class EquipManager : MonoBehaviour
{
    public Equip curEquip;
    public Transform equipParent;

    private PlayerController controller;
    private PlayerConditions conditions;

    public static EquipManager instance;

    private void Awake()
    {
        instance = this;
        controller = GetComponent<PlayerController>();
        conditions = GetComponent<PlayerConditions>();
    }

    // 공격 버튼 클릭 시(좌측 마우스 클릭 시)
    public void OnAttackInput(InputAction.CallbackContext context)
    {
        // 공격 버튼이 입력 중일 때, 현재 장비한 아이템이 있으면서 플레이어가 볼 수 있을 때
        if(context.phase == InputActionPhase.Performed && curEquip != null && controller.canLook)
        {
            curEquip.OnAttackInput();
        }
    }

    public void EquipNew(itemData item)
    {
        UnEquip();
        curEquip = Instantiate(item.equipPrefab, equipParent).GetComponent<Equip>();
    }

    public void UnEquip()
    {
        // 뭔가 장착 중일 때
        if(curEquip != null)
        {
            // 현재 장착 중인 장비 제거
            Destroy(curEquip.gameObject);
            curEquip = null;
        }
    }
}

이후, Player의 Player Input에서 Player Event에 있는 OnAttack 이벤트에 OnAttackInput을 추가해준다.

ItemData.cs 수정

ItemData 안에 Equip에 대한 데이터를 생성해준다.

[Header("Equip")]
public GameObject equipPrefab;

Inventory.cs 수정

Inventory.cs에 있는 OnEquipButton, OnUnEquipButton이 동작하도록 수정한다.

// 장착 버튼 누르기
public void OnEquipButton()
{
    // 현재 끼고 있는 장비가 있을 때 Equip 버튼을 클릭한다면
    if (uidSlot[curEquipIndex].equipped)
    {
        // 현재 장비 제거
        UnEquip(curEquipIndex);
    }

    // 선택한 새로운 장비 장착
    uidSlot[selectedItemIndex].equipped = true;
    curEquipIndex = selectedItemIndex;
    EquipManager.instance.EquipNew(selectedItem.item);
    UpdateUI();

    // 아이템 정보 띄우기
    SelectItem(selectedItemIndex);
}

void UnEquip(int index)
{
    uidSlot[index].equipped = false;
    EquipManager.instance.UnEquip();
    UpdateUI();

    if (selectedItemIndex == index)
        SelectItem(index);
}

public void OnUnEquipButton()
{
    // 현재 선택한 장비를 해제하기.
    UnEquip(selectedItemIndex);
}

🎥 공격 애니메이션 만들기!

EquipCamera에 있는 Equip_Axe에게 add component를 통해 animator를 추가해준다.

이후 Assets 폴더 밑에 Animations 폴더를 만든다.
그후 Animations 폴더 밑에 Animation Controller를 추가해서 이름을 Axe라 변경해준 뒤, Equip_Axe의 animator에 추가해준다.

Axe_Attack과 Axe_idle 애니메이션을 만들고, Animation Controller에서 Transition을 만들어준다.

Parameter로 Trigger인 Attack을 만들고, idle에서 Attack으로 갈 때의 Conditions로 Attack을 추가해준다. Has Exit Time을 체크 해제한 뒤, Transition Duration을 0으로 변경하여 애니메이션이 바로 전환되도록 만들어 준다.

이후 Attack에서 idle로 돌아가는 것을 수정해준다.
Has Exit Time을 체크하고 Exit Time을 1로 만들어 Attack 애니메이션이 전부 끝난 뒤에 idle 모션으로 돌아가도록 설정해준다.

이후 Attack 애니메이션은 Loop Time을 해제하자.

확인해보기!

이제 같은 방식으로 Sword의 애니메이션을 만들어 주면 된다.
Player의 EquipManager에 Equip Parent를 추가해준다.

그리고 Axe와 Sword ItemData에 equipPrefab을 추가해준다.

😎 최종 확인!

2개의 댓글

comment-user-thumbnail
2024년 5월 16일

Equip.cs를 작성하는건 없던거 같은데 혹시 다른 포스팅에 있나요?

1개의 답글