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

게임개발 중급(93) - Monster Killer(55)

by jyppro 2024. 8. 22.

Monster Killer

 

가디언 모드 설정

저번에 이어서 가디언 모드를 위해 설정한 특수 기능에 대해 알아보겠습니다. 가장 첫번째로 가디언 모드는 다른 모드와 다르게 끝까지 버티는 게 목표입니다. 그래서 시간이 전부 소모되어도 게임오버가 되지 않고 클리어가 됩니다. 그리고 그것이 유일한 클리어 조건입니다. 그렇기 때문에 각 스테이지에 따른 시간은 플레이어가 업그레이드 하는 시간과 별개로 고정적으로 설정되어 있습니다.

디펜스-타임

 

임의로 3분으로 설정되어 있으며, 점수도 고정적으로 클리어 시 지급됩니다. 그리고 시간만 버티면 무조건 클리어 하기 때문에 무조건 3스타를 받도록 설정하였습니다. 기지의 체력에 따라 다르게 설정할까도 생각해 봤지만 아직 그 부분은 고려대상이 아닌 것 같습니다.

 

두번째로는 기지의 체력입니다. 기지의 체력도 고정적으로 설정할까 했지만 그렇게 되면 사실상 가디언 모드에서는 플레이어의 강화가 의미가 있는 부분은 공격력밖에 없기 때문에 좀 더 플레이어의 강화가 의미있게 쓰일 수 있도록 플레이어가 가진 수치의 10배의 체력을 갖도록 하였습니다.

능력치1체력1

 

위 사진처럼 체력이 140이라면 가디언 모드에서는 1400으로 적용됩니다.

 

몬스터 스폰 및 이동

이제 몬스터가 가디언 모드에서 스폰되고 이동하는 방식을 말씀드리겠습니다. 일단 이전에 말했던 것처럼 기존의 몬스터 스포너를 통해 각 포탈 위치에서 스폰이 되고 네비메쉬 설정을 통해 몬스터가 경사를 내려올 수 있도록 설정하여 경로를 뚫었습니다.

스폰-포인트네비메쉬-설정

 

그렇다면 이제 몬스터가 이동하는 방식을 설정해줘야 하는데, 기존에 사용하던 몬스터의 이동은 이동이 아니라 랜덤한 Idle 움직임 이었습니다. 그래서 가디언 모드에서 사용할 새로운 이동에 대한 스크립트를 작성해 주었습니다.

 

using System.Collections;
using UnityEngine;
using UnityEngine.AI;

public class DefenseMonsterMovement : MonoBehaviour
{
    private NavMeshAgent navMeshAgent;
    private Animator animator;
    private DefenseMonsterController monsterController;

    [SerializeField] private Transform[] targets; // 몬스터가 추적할 목표 오브젝트 배열
    [SerializeField] private float moveSpeed = 2f; // 이동 속도
    [SerializeField] private float stopDistance = 1.5f; // 목표에 도달한 것으로 간주할 거리

    private Transform currentTarget; // 현재 이동 중인 타겟

    private void Start()
    {
        navMeshAgent = GetComponent<NavMeshAgent>();
        animator = GetComponent<Animator>();
        monsterController = GetComponent<DefenseMonsterController>(); // 몬스터 컨트롤러 참조
        targets = FindTargetsWithTag("Dest"); // "destination" 태그를 가진 오브젝트 찾기

        navMeshAgent.speed = moveSpeed; // 이동 속도 설정
        navMeshAgent.autoTraverseOffMeshLink = true; // Off-Mesh Link 자동 사용 활성화

        SelectRandomTarget();
    }

    private void Update()
    {
        // Off-Mesh Link 처리
        if (navMeshAgent.isOnOffMeshLink)
        {
            StartCoroutine(HandleOffMeshLink());
        }

        if (currentTarget != null)
        {
            MoveToTarget();
        }
    }

    private Transform[] FindTargetsWithTag(string tag)
    {
        GameObject[] targetObjects = GameObject.FindGameObjectsWithTag(tag);
        Transform[] targetTransforms = new Transform[targetObjects.Length];
        for (int i = 0; i < targetObjects.Length; i++)
        {
            targetTransforms[i] = targetObjects[i].transform;
        }
        return targetTransforms;
    }

    private void SelectRandomTarget()
    {
        if (targets.Length > 0)
        {
            currentTarget = targets[Random.Range(0, targets.Length)];
            navMeshAgent.SetDestination(currentTarget.position);
            animator.SetBool("Move", true);
        }
    }

    private void MoveToTarget()
    {
        navMeshAgent.SetDestination(currentTarget.position);

        if (navMeshAgent.remainingDistance <= stopDistance)
        {
            //StopMoving();
            animator.SetBool("Move", false);

            // 이동이 완료되면 몬스터 컨트롤러에게 타겟 정보를 전달하고 공격 실행
            if (monsterController != null)
            {
                monsterController.SetTarget(currentTarget);
            }
        }
        else
        {
            animator.SetBool("Move", true);
        }
    }

    private IEnumerator HandleOffMeshLink()
    {
        OffMeshLinkData linkData = navMeshAgent.currentOffMeshLinkData;
        Vector3 endPos = linkData.endPos;

        // 간단하게 AI를 끝점으로 이동시키는 예제
        navMeshAgent.CompleteOffMeshLink();
        navMeshAgent.transform.position = endPos;

        // 필요한 경우 추가 로직 또는 애니메이션 추가
        animator.SetBool("Move", true);

        yield return null;
    }

    public void StopMoving()
    {
        navMeshAgent.isStopped = true;
        animator.SetBool("Move", false);
    }
}

 

이것은 가디언 모드에서 사용되는 몬스터가 움직이는 방식을 정의하는 무브먼트 스크립트입니다. 먼저 네비메쉬로 생성한 링크를 탈 수 있도록 설정해주고, 타겟 오브젝트를 향해 이동하도록 설정하였습니다.

 

그런데 타겟 오브젝트를 하나로 설정해놓으니 몬스터가 한 점으로 모이면서 겹치기도 하고 공격과 이동이 부자연스럽다고 느껴졌습니다. 그래서 타겟을 배열로 여러 개를 다른 위치에 배치하고 몬스터는 생성됨과 즉시 그 타겟 중에서 하나를 랜덤으로 선택하여 이동하도록 구현했습니다.

 

타겟-설정

 

요런 식으로 빈껍데기 타겟을 여러 개 만들어 다양한 방향으로 설정해 주었습니다.

 

실행 결과

결과

 

가디언 모드에서 타이머는 고정된 시간으로 진행되며, 기지의 체력은 플레이어 체력의 10배로 설정됩니다. 그리고 몬스터들은 각자 생성될 때 할당된 타겟을 향해 이동하고 도달하면 공격을 실행하여 각기 다른 위치를 향해 이동하고 공격을 수행하는 것을 볼 수 있습니다.

 

<NEXT>

이제 모든 모드의 기본적인 틀이 잡힌 것 같으니 약간의 꾸며주는 시간을 갖도록 하겠습니다. 게임이 밋밋하게 보이지 않게 약간의 폴리싱 작업을 진행해 보겠습니다. 감사합니다.