부트캠프

코루틴으로 적 움직임 구현해보기

noyyo 2023. 9. 14. 00:10

적을 만들어야 할 때 어떻게 움직일지에 대해서 매번 일일이 지정해줄 수는 없는 노릇이다.

그래서 코루틴을 통해 움직임을 구현해 보았다.

 

private List<IEnumerator> _movePatterns = new List<IEnumerator>();
//
//중략
//
protected virtual IEnumerator OnMove()
{
    //패턴이 없으면 기본 패턴 추가
    if (_movePatterns.Count == 0)
    {
        AddMovePattern(DefaultMovePattern());
    }

    foreach (IEnumerator pattern in _movePatterns)
    {
        yield return StartCoroutine(pattern);
    }
    // 패턴을 다 끝마쳤으면 기본 패턴으로 움직여서 멈추는 것을 방지.
    StartCoroutine(DefaultMovePattern());

}
//
//중략
//
public void AddMovePattern(IEnumerator movePattern)
{
    _movePatterns.Add(movePattern);
}

위 코드가 EnemyController에서 이동과 관련된 코드이다.

핵심은 List로 적 움직임에 대한 내용이 담겨있는 코루틴들을 가지고 있는 것이다.

 

    public static IEnumerator CircleMoveXDegree(TopDownCharacterController controller, float radius, float degree, MovePatternDirection centerPointDirection, MovePatternRotation rotateDirection)
    {
        TopDownCharacter character = controller.Character;
        Vector2 characterPosition = character.transform.position;
        float angle = 0f;
        Vector2 centerPoint = Vector2.zero;
        float diagonalAxisValue = Mathf.Cos(45 * Mathf.Deg2Rad);
        float initialAngle = 0;
        // 중심 원 위치에 따라 초기 각 설정.
        switch (centerPointDirection)
        {
            case MovePatternDirection.UpperLeft:
                centerPoint = new Vector2(characterPosition.x - diagonalAxisValue, characterPosition.y + diagonalAxisValue);
                initialAngle = -90 + 45;
                break;
            case MovePatternDirection.UpperRight:
                centerPoint = new Vector2(characterPosition.x + diagonalAxisValue, characterPosition.y + diagonalAxisValue);
                initialAngle = -90 - 45;
                break;
            case MovePatternDirection.LowerLeft:
                centerPoint = new Vector2(characterPosition.x - diagonalAxisValue, characterPosition.y - diagonalAxisValue);
                initialAngle = 90 - 45;
                break;
            case MovePatternDirection.LowerRight:
                centerPoint = new Vector2(characterPosition.x - diagonalAxisValue, characterPosition.y - diagonalAxisValue);
                initialAngle = 90 + 45;
                break;
            case MovePatternDirection.Up:
                centerPoint = new Vector2(characterPosition.x, characterPosition.y + radius);
                initialAngle = -90;
                break;
            case MovePatternDirection.Down:
                centerPoint = new Vector2(characterPosition.x, characterPosition.y - radius);
                initialAngle = 90;
                break;
            case MovePatternDirection.Left:
                centerPoint = new Vector2(characterPosition.x - radius, characterPosition.y);
                initialAngle = 90 - 90;
                break;
            case MovePatternDirection.Right:
                centerPoint = new Vector2(characterPosition.x + radius, characterPosition.y);
                initialAngle = 90 + 90;
                break;
        }
        int rotateCoefficient = 0;
        switch (rotateDirection)
        {
            case MovePatternRotation.Clockwise:
                rotateCoefficient = -1;
                break;
            case MovePatternRotation.CounterClockwise:
                rotateCoefficient = 1;
                break;
        }
        Vector2 direction = Vector2.down;


        while (angle < degree)
        {
            characterPosition = character.transform.position;
            angle += 360 * ((character.Speed * Time.deltaTime) / (2f * (float)Math.PI * radius));

            // 경로 계산 (실제 원은 아니고 프레임이 낮을수록 오차가 커짐)
            float x = centerPoint.x + Mathf.Cos((angle * rotateCoefficient + initialAngle) * Mathf.Deg2Rad) * radius;
            float y = centerPoint.y + Mathf.Sin((angle * rotateCoefficient + initialAngle) * Mathf.Deg2Rad) * radius;

            Vector2 targetPosition = new Vector2(x, y);
            direction = targetPosition - characterPosition;
            direction = direction.normalized;

            controller.CallMoveEvent(direction);
            yield return null;
        }
    }

위 내용은 MovePatternFactory라고 이름지은 클래스 내부에 스태틱으로 정의한 코루틴이다. 위와 같이 움직이는 패턴을 만들어놓고 게임 매니저에서 적을 생성할 때 패턴들을 불러와서 List에 넣고 코루틴을 통해 실행하도록 했다.

 

직접 트랜스폼을 지정해주는 것보다는 훨씬 복잡한 움직임들도 가능하고 한 번 만들어놓으면 재사용하기도 쉽지만 처음 만들 때는 훨씬 복잡한 점이 있다.