본문 바로가기
게임 프로그래밍/게임개발 중급

게임개발 중급(47) - Monster Killer(9)

by jyppro 2023. 6. 7.

Monster Killer(9)

어제는 사소한 줄 알았지만, 생각보다 어려웠던 문제점을 해결했습니다. 연사를 못하도록 막아 무기 오브젝트끼리 부딪히는 현상을 해결했습니다. 오늘은 미뤄져 하지 못한 몬스터 소환과 죽음에 대해서 다뤄보겠습니다.

 

몬스터 소환 및 죽음

몬스터가 소환되고 죽는 것은 애니메이션 동작과 함께 진행됩니다. 현재까지 구현한 바로는 게임을 시작하면 몬스터가 생성되고, 해당 몬스터의 체력을 전부 깎으면 몬스터가 죽고 다음 몬스터가 바로 생성됩니다. 이때 죽은 몬스터는 바로 사라지는 것이 아닌 죽는 애니메이션을 3초간 실행한 뒤에 사라집니다. 현재 이것 때문에 발생한 문제는 체력이 전부 깎이면 몬스터 소환은 바로 이뤄지는데, 죽는 몬스터는 3초뒤에 사라져 두 몬스터가 약 3초간 겹치는 현상이 발생합니다. 게임진행에는 문제를 일으키지 않지만, 겹쳐있는 동안 두 몬스터가 같은 위치에 콜라이더를 가진채로 존재하기 때문에 공격을 했을 시에 이미 잡은 몬스터의 체력바가 깎이고, 소환된 다음 몬스터에게 공격이 들어가지 않는 현상이 발생합니다. 이제 코드를 수정해 보겠습니다.

 

MonsterController

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using TMPro;

public class MonsterController : MonoBehaviour
{
    public float maxHealth = 100f; // 최대 체력
    public float currentHealth = 100f; // 현재 체력
    public Slider healthSlider; // 체력바 슬라이더 컴포넌트
    public Slider healthSliderCopy;
    public TextMeshProUGUI textHP; // 체력바 텍스트
    public TextMeshProUGUI textHPCopy;
    private Animator animator; // 애니메이션

    // 다음 몬스터로 전환할 때 사용할 프리팹
    public GameObject nextMonsterPrefab;

    void Start()
    {
        animator = GetComponent<Animator>();
        healthSliderCopy = this.healthSlider;
        textHPCopy = this.textHP;
        UpdateHealthSlider();
    }

    public void TakeDamage(int damage)
    {
        currentHealth -= damage;
        if (currentHealth <= 0f)
        {
            currentHealth = maxHealth;
            // 체력이 전부 소진되면 다른 몬스터로 전환하고 체력 증가
            animator.SetBool("Death", true);
            Invoke("SpawnNextMonster", 2.5f);
        }
        UpdateHealthSlider();
    }

    private void SpawnNextMonster()
    {
        if (nextMonsterPrefab != null)
        {
            GameObject nextMonster = Instantiate(nextMonsterPrefab, transform.position, transform.rotation);
            MonsterController nextMonsterController = nextMonster.GetComponent<MonsterController>();
            nextMonsterController.healthSlider = healthSliderCopy;
            nextMonsterController.textHP = textHPCopy;
            nextMonsterController.maxHealth = maxHealth;
            nextMonsterController.currentHealth = currentHealth;
            nextMonsterController.UpdateHealthSlider();
            nextMonsterController.IncreaseHealth();
        }

        Destroy(gameObject);
    }

    public void UpdateHealthSlider()
    {
        float decreaseHp = currentHealth / maxHealth;
        // 체력바 슬라이더의 값을 현재 체력 비율로 설정
        healthSlider.value = decreaseHp;
        textHP.text = $"{currentHealth} / {maxHealth}";
    }

    public void IncreaseHealth()
    {
        maxHealth = (maxHealth + 23f) * 2.2f;

        if (currentHealth != maxHealth)
        {
            currentHealth = maxHealth;
            UpdateHealthSlider();
        }
    }
}

MonsterController의 코드입니다. 해당 문제도 역시 딜레이를 통해서 해결할 수 있습니다. 하지만 이전과 다른점은 디스트로이와 생성이 동시에 딜레이를 가지고 있어도 된다는 점입니다. 그래서 저는 SpawnNextMonster() 함수를 만들어 기존에 다음 몬스터 생성 코드를 전부 넣어주고, 3초의 딜레이를 준 뒤에, 기존 몬스터 삭제와 다음 몬스터 생성을 동시에 진행시켜 줍니다. 3초라는 시간은 죽는 애니메이션을 보기위한 시간입니다. 그리고 기존에는 다음 몬스터에게 넘겨줄 정보들을 그대로 가져와 세팅해줬는데, 좀 더 알아보기 쉽게 MonsterController 타입의 nextMonsterController를 만들어 넣어주었습니다. 이렇게 작성해주고 실행하면, 몬스터가 체력이 전부 깎이면 죽는 애니메이션을 실행하고, 3초 뒤에 삭제 및 다음 몬스터 생성이 자연스럽게 이어집니다.

 

게임의 속도감 조절

이전에 무기 발사시간에 딜레이를 설정하여 무기끼리 겹치지 않도록 하였는데, 직접 테스트 플레이를 진행해보니 게임의 진행속도가 너무 느려졌습니다. 때문에 무기생성 및 발사 후 삭제의 간격을 최소화하여 부딪히지 않을 정도로만 딜레이를 줄여 보겠습니다. 기존에는 2초의 딜레이타임이 있었지만, 저는 확인해본 결과 0.7초로 설정하면 아무리 빠르게 클릭하여도 두 무기가 겹치지 않는 것을 확인했습니다. 이제 모든 변경사항을 적용한 게임을 실행해보겠습니다.

 

몬스터-사망
몬스터 사망

체력을 전부 깎아 몬스터가 사망한 모습입니다. 다음몬스터가 겹쳐서 생성되지 않는 것을 확인할 수 있습니다.

약 3초가 지나고 다음 몬스터가 생성됩니다.

다음-몬스터-소환
다음 몬스터 소환

다음 몬스터가 소환되었습니다. 현재 무기를 던지고 생성되는 속도는 0.7초로 같은 자리에 즉시 던졌을 때, 겹치지 않는 것도 확인할 수 있었습니다.

 

<NEXT>

이번에는 몬스터 소환 및 죽음이 동시에 일어나며 겹치지 않도록 고쳤습니다. 또한, 무기 생성속도가 느려 게임 진행속도가 전체적으로 느려진 것을 해결하기 위해 딜레이타임을 최소한으로 변경해 주었습니다. 다음에는 부위별 데미지 문제점에 대해 고쳐보는 시간을 갖도록 하겠습니다. 감사합니다.