Patrick's Devlog

[Unity Project] 적 모션 수정 및 HP바 설정 본문

Project/Unity Engine

[Unity Project] 적 모션 수정 및 HP바 설정

Patrick_ 2022. 7. 13. 15:29

우선 칙칙한 맵을 숲으로 꾸며주기 위해 맵을 로드해주었다. 맵은 https://assetstore.unity.com/packages/3d/environments/landscapes/simple-low-poly-nature-pack-157552 에서 받아와 그대로 가져왔다. 맵에 대한 수정은 추후 이루어질 예정이며, 일단은 샘플맵을 통해 진행한다. 

샘플맵 로드 및 적 배치

적은 추후 다수의 적으로 진행할 예정이므로, 우선 2마리의 적을 먼저 맵에 배치해두어 테스트를 진행해보았다. 적에게 가까이 다가갔을 때, 적의 HP가 위에 보이고 애니메이션 또한 바뀌게 된다. 그리고 적에게서 멀어지면 HP가 사라지며, 애니메이션은 원래상태로 돌아간다. 하나씩 살펴보자. 

 

적 관련 애니메이터

우선 애니메이션을 위와같이 지정해주었다. 평소에는 IdleNormal 애니메이션이 보이게 되고, 메인 캐릭터가 적에게 다가갔을 때 BattleIdle로 바뀐다. 그리고 적이 메인 캐릭터에게 공격 당했을 때, Hit 애니메이션이 실행되게 되고 HP가 0일때 Die 애니메이션을 실행한다. 코드를 하나씩 살펴보자. SlimeEnemy.cs에 이어서 코드를 작성해주었다. 

public class SlimeEnemy : MonoBehaviour
{
    private Animator playerAnimator;
    private Animator animator;
    private GameObject playerObject;
    
    

    [SerializeField]
    private int SlimeHP = 100;
    [SerializeField]
    private Slider HPBar;
    [SerializeField]
    private Text textName;
    ...
}

추가된 변수이다. SlimeHP를 지정해주고, HPBar와 적의 이름을 나타낼 Text 또한 변수로 지정하였다. 

    void Start()
    {
        playerObject = GameObject.Find("MainPlayer");
        playerAnimator = playerObject.GetComponent<Animator>();
        animator = GetComponent<Animator>();
    }

    // Update is called once per frame
    void Update()
    {
        HPMark();
        SlimeDead();
    }

다음은 Start() 함수와 Update() 함수이다. 적에게 가까이 다가가면 HP를 표시해야 하므로, HPMark()라는 함수를 생성해주었다. 그리고 적이 죽었을 때 죽는 모션과 함께 적의 오브젝트를 파괴해야 하므로 SlimeDead()라는 함수 또한 만들어주었다. 

    private void HPMark()
    {
        float distance = Vector3.Distance(playerObject.transform.position,transform.position);
        HPBar.value = SlimeHP;

        if (distance < 6.0f) // 메인 캐릭터와 적의 거리가 6 이하 일때
        {
            HPBar.gameObject.SetActive(true);
            textName.text = "Slime";
            animator.SetTrigger("Battle");
        }
        else if (distance >= 6.0f)
        {
            HPBar.gameObject.SetActive(false);
            textName.text = "";
            animator.SetTrigger("Idle");
        }
    }

먼저 HPMark()를 살펴보자. 메인 캐릭터와 적 사이의 거리를 구한 다음, if문을 통해 일정 거리 이하이면 HPBar가 활성화되고,  text도 세팅이 되는것을 확인할 수 있다. 그리고 애니메이션 또한 적용되는 것을 확인할 수 있다. 일정 거리 이상이면 HPBar는 다시 비활성화되고, 적은 Idle로 돌아오게 된다. 

    private void SlimeDead()
    {
        if (SlimeHP <= 0) {
            HPBar.gameObject.SetActive(false);
            textName.text = "";
            Destroy(gameObject, 1.5f);
            animator.SetTrigger("Die");
        }
    }

다음은 적이 죽을때 진행되는 함수이다. SlimeHP가 0이하일 때, HPBar는 비활성화되고, text는 없어지게 된다. 그리고 1.5초 뒤에 오브젝트는 파괴된다. 

    private void OnTriggerEnter(Collider other)
    {
        if (other.gameObject.CompareTag("Sward") && playerAnimator.GetCurrentAnimatorStateInfo(0).IsName("Attack"))
        {
            SlimeHP -= 35;
            Debug.Log("몬스터가 맞았어!");
            animator.SetTrigger("Hit");
        }
    }

마지막으로 적과 검이 겹쳤을 때 함수이다. 저번에는 Log만 띄워주었지만, 이번에는 HP를 일정 숫자만큼 뺴주었으며, 적이 맞는 모션을 취하게 된다. 

 

이렇게 적 스크립트를 완성하고, 메인 캐릭터 스크립트를 조금 수정해주었다. 저번에 작성한 PlayerAttack을 삭제한 후, Attack 부분은 메인 캐릭터 이동 스크립트에 합쳐주었으며, PlayerDamaged라는 스크립트를 새로 만들어 적과 메인 캐릭터가 겹칠 때 아프다는 문구를 띄우게끔 하였다. 따로 코드 내에서 수정된 부분은 없으므로, 올리지는 않겠다.

그리고 메인 캐릭터에서 뛰면서 공격을 진행하면 캐릭터는 움직이지만 모션은 멈춘채로 공격을 진행하므로, 공격하는 애니메이션이 나오게 되면 Move() 함수에서 아무런 코드도 실행되지 않고 그대로 return되게끔 하였다. 아래의 코드처럼 구현을 진행하였다. 

    void Move()
    {
        if (animator.GetCurrentAnimatorStateInfo(0).IsName("Attack")) return;
        ...
    }

 

이렇게 구현을 진행하고 플레이해보면 아래의 결과처럼 나오게 된다.