24.01.26 TIL - Unity : Coroutine을 활용한 적 패턴 구현 | Lerp : 선형보간

JJwoo·2024년 1월 26일

메탈슬러그 3 우주 미션에 등장하는 특정한 적 UFO를 하나 구현해야 했는데 일단 조건부터 정리해보았다.

  1. 플레이어를 특정하지 않는다, 아래를 향한 단순한 수직 공격.

  2. 1회 공격 - 이동 - 1회 공격 - 이동... 이런 패턴으로 계속 반복해야 한다.

  3. 이동 시 랜덤한 범위 내로만 이동해야 한다, 수직형 공격이다 보니 플레이어와 너무 근접해서는 안된다 = 화면 반 위에서만 놀도록 해야겠다로 해석

게임의 시작과 동시에 나오는 적이다보니 임팩트가 중요했기에 위 조건을 토대로 cs를 새로 작성했고,

어떻게 구현을 할 까 고민을 해보다가 Coroutine 사용해보기로 했다.

Coroutine


using UnityEngine;
using System.Collections;

public class SmallUFOMovement : MonoBehaviour
{
    public Vector2 movementBoundsMin; // 왼쪽 아래
    public Vector2 movementBoundsMax; // 오른쪽 위, 몹 활동 범위
    public float moveTime; // 무빙 시간
    public float waitTime; // 대기 시간

    public GameObject attackPoint; // Attack_Point 오브젝트
    public RangedAttackData attackData; // 공격 데이터

    private Vector2 targetPosition;

    void Start()
    {
        StartCoroutine(MoveAndAttackRoutine());
    }

    IEnumerator MoveAndAttackRoutine()
    {
        while (true)
        {
            // 범위 내 랜덤 움직임
            targetPosition = new Vector2(
                Random.Range(movementBoundsMin.x, movementBoundsMax.x),
                Random.Range(movementBoundsMin.y, movementBoundsMax.y)
            );
            StartCoroutine(MoveToPosition(targetPosition, moveTime));

            // 움직임이 끝날 때까지 기다림
            yield return new WaitForSeconds(moveTime);

            // 공격 로직
            yield return StartCoroutine(PerformAttack());

            // 공격이 끝날 때까지 기다림
            yield return new WaitForSeconds(waitTime);
        }
    }

    IEnumerator MoveToPosition(Vector2 target, float timeToMove)
    {
        var currentPos = transform.position;
        var t = 0f;
        while (t < 1)
        {
            t += Time.deltaTime / timeToMove;
            transform.position = Vector2.Lerp(currentPos, target, t);
            yield return null;
        }
    }

    private IEnumerator PerformAttack()
    {
        
        attackPoint.SetActive(true);

        // 애니메이션 재생 시간 대기 
        yield return new WaitForSeconds(0.5f);

        // 투사체 아래로 발사
        Vector2 direction = Vector2.down;
        ProjectileManager.instance.ShootBulletStraightDown(attackPoint.transform.position, attackData.bulletNameTag);

        //Attack_Point 비활성화
        attackPoint.SetActive(false);

        // 쿨다운 시간 동안 대기
        yield return new WaitForSeconds(attackData.delay);
    }

}
  1. Start() 메서드: 스크립트가 시작될 때 코루틴을 실행

  2. MoveAndAttackRoutine() 코루틴

    • 이동 : 랜덤한 위치(targetPosition)를 생성하여 그 위치로 이동하도록 MoveToPosition() 코루틴을 시작하고 움직임이 끝날 때까지 대기

    • 공격 : 공격 동작을 수행하는 PerformAttack() 코루틴을 실행, 공격이 끝날 때까지 대기

    • 위 과정을 While을 통해 무한 반복

  3. MoveToPosition() 코루틴: 주어진 시간 동안 target 위치로 선형 보간lerp 을 사용하여 부드럽게 이동.

Lerp

"선형 보간(Linear Interpolation)"
두 개의 값을 사이에 있는 중간값으로 부드럽게 이동시킨다.
그래픽, 애니메이션, 게임 개발 등에서 사용되며, 값을 부드럽게 변화시키는 데 유용함.

  1. PerformAttack() 코루틴
    공격 동작을 정의
  • attackPoint 오브젝트를 활성화 : UFO 자체에서 투사체가 날아가는게 아닌 살짝 아래의 특정 위치에서 나가야 했음 + 특정 애니메이션이 재생되었어야 했기에 자식 오브젝트로 만들어서 평상시엔 숨겨놓고 공격시에 발동하게 함.

  • 애니메이션 재생 시간(0.5초)를 확보하기 위해 대기

  • 투사체를 아래로 발사, ProjectileManager 클래스를 사용하여 구현했고 attackData.bulletNameTag를 통해 적 UFO 고유의 투사체를 발사

  • 공격 발사가 끝났으니 attackPoint를 비활성화

  • attackData.delay만큼 대기

인스펙터 스크립트 창에서 볼 수 있는 적의 움직임 범위 설정과, 다음 위치로 이동 할 수 있는 Move time(이동 속도의 개념), 공격 딜레이를 구현하였고

Attack point 오브젝트를 담고 Attack SO를 부여하여 고유의 공격력 등을 반영 함.


최종적으로 완성된 몬스터의 무브 & 어택 패턴

profile
개발 모코코

0개의 댓글