적을 만들어야 할 때 어떻게 움직일지에 대해서 매번 일일이 지정해줄 수는 없는 노릇이다.
그래서 코루틴을 통해 움직임을 구현해 보았다.
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에 넣고 코루틴을 통해 실행하도록 했다.
직접 트랜스폼을 지정해주는 것보다는 훨씬 복잡한 움직임들도 가능하고 한 번 만들어놓으면 재사용하기도 쉽지만 처음 만들 때는 훨씬 복잡한 점이 있다.
'부트캠프' 카테고리의 다른 글
오브젝트 풀 만들기 (0) | 2023.09.18 |
---|---|
팀 프로젝트 마무리(협업을 잘하자) (0) | 2023.09.14 |
플레이어가 화면 밖으로 나가지 못하게 만들기 (0) | 2023.09.13 |
HP bar를 스프라이트로 구현하기 (0) | 2023.09.11 |
버튼에 리스너 달기 (0) | 2023.09.07 |