WayPoint를 이용한 적 움직임 패턴 구현

WayPoint

  • 웨이포인트는 Vector[] 값을 지정하고 오브젝트가 해당 위치를 배열 순으로 이동하여 움직임 패턴을 만드는 방법입니다.

  • 미리 좌표값을 넣어둘수도 있으며, 메서드 내부에서 좌표를 만드는 방법도 있습니다.

웨이포인트 생성기

  • 먼저 내부에서 웨이포인트좌표를 생성하는 로직입니다.
public static Vector2[] CalculateWaypoints(Enemy enemy, int wayPointCount)  
{  
	int direction = Random.Range(0, 2) == 0 ? -1 : 1;  
	Vector2[] wayPoints = new Vector2[wayPointCount];  
	Vector2 startPosition = enemy.transform.position;  
	  
	for (int i = 0; i < wayPoints.Length; i++)  
	{  
		float nextX = Mathf.Clamp(startPosition.x + direction * WayPointWidthValue, -3.5f, 3.5f);  
		float nextY = Mathf.Clamp(startPosition.y - 2 * (i + 1), -5f, 5f);  
		wayPoints[i] = new Vector2(nextX, nextY);  
		direction *= -1;  
		startPosition = wayPoints[i];  
	}  
	return wayPoints;  
}
  1. 메소드 선언
    • public static Vector2[] CalculateWaypoints(Enemy enemy, int wayPointCount)
    • 이는 정적 메서드입니다. 즉, 클래스의 인스턴스가 아닌 클래스 자체에 속합니다.
      • 웨이포인트를 나타내는 Vector2 객체의 배열을 반환합니다.
      • 두 개의 매개변수, 즉 Enemy 객체와 생성할 경유지 수를 나타내는 int를 사용합니다.
  2. 임의 방향 초기화
    • int 방향 = Random.Range(0, 2) == 0 ? -1 : 1;
    • 이 선은 첫 번째 웨이포인트의 초기 이동 방향(왼쪽 또는 오른쪽)을 결정합니다.
      • Unity의 Random.Range를 사용하여 0과 1 사이에서 선택합니다. 0이면 방향이 -1(왼쪽)으로 설정되고, 1이면 방향이 1(오른쪽)으로 설정됩니다.
  3. 웨이포인트 배열 초기화
    • Vector2[] wayPoints = new Vector2[wayPointCount];
    • 이 줄은 길이가 wayPointCount 매개변수로 설정된 Vector2 구조의 배열을 초기화합니다.
      • 이 배열의 각 ‘Vector2’는 웨이포인트의 x 및 y 좌표를 보유합니다.
  4. 시작 위치
    • Vector2 startPosition = 적.변환.위치;
      • 이 줄은 Enemy 객체의 시작 위치를 가져와 startPosition에 저장합니다.
      • 첫 번째 웨이포인트를 계산하기 위한 기준점으로 사용됩니다.
  5. 웨이포인트 계산 루프:
    • for (int i = 0; i < wayPoints.Length; i++)
      • 이 for 루프는 waypoints 배열을 반복하여 각 waypoint를 계산합니다.
  • 루프 내에서
  • float nextX = Mathf.Clamp(startPosition.x + 방향 * WayPointWidthValue, -3.5f, 3.5f);: 다음 웨이포인트의 x 좌표를 계산합니다.

  • Mathf.Clamp를 사용하여 x 좌표가 지정된 범위(이 경우 -3.5 ~ 3.5) 내에 유지되도록 합니다.

  • WayPointWidthValue는 각 웨이포인트가 이전 웨이포인트로부터 수평으로 얼마나 떨어져 있는지를 결정하는 상수 또는 변수(제공된 코드에 정의되지 않음)입니다.

  • float nextY = Mathf.Clamp(startPosition.y - 2 * (i + 1), -5f, 5f);: 다음 웨이포인트의 y좌표를 계산합니다.

  • nextX와 유사하게 y 좌표가 범위(-5 ~ 5) 내에 유지되고 매번 아래로 이동합니다(- 2 * (i + 1)).

  • wayPoints[i] = new Vector2(nextX, nextY);: 계산된 x 및 y 좌표를 waypoints 배열의 i번째 요소에 할당합니다.

  • 방향 *= -1;: 다음 웨이포인트 계산을 위해 방향을 반대로 합니다.

  • startPosition = wayPoints[i];: 다음 반복을 위해 startPosition을 현재 경유지 위치로 업데이트합니다.
  1. 반환:
    • return wayPoints; : 루프가 완료된 후 메서드는 계산된 웨이포인트 배열을 반환합니다.

지그재그 형태의 웨이포인트

public void Zigzag()  
{  
	CoroutineInit();  
	Vector2[] wayPoints = CalculateWaypoints(this, 3);  
	_moveCoroutine = StartCoroutine(MoveZigzag(this, wayPoints));  
}

MoveZigzag()

public static IEnumerator MoveZigzag(Enemy enemy, Vector2[] wayPoints)  
{  
	int currentWaypointIndex = 0;  
	while (currentWaypointIndex < wayPoints.Length)  
	{  
		Vector2 currentWaypoint = wayPoints[currentWaypointIndex];  
		while (Vector2.Distance(enemy.transform.position, currentWaypoint) > 0.01f)  
		{  
		enemy.transform.position = Vector2.MoveTowards(  
		enemy.transform.position,  
		currentWaypoint,  
		enemy.speed * Time.deltaTime * SpeedOffset);  
		yield return null;  
		}  
		currentWaypointIndex++;  
	}  
	enemy.EndToEnemyCoroutine(enemy);  
}
  1. 메서드 선언:
    • public static IEnumerator MoveZigzag(Enemy enemy, Vector2[] wayPoints): 이것은 Unity에서 정적 코루틴 메서드입니다.
    • Enemy 객체와 웨이포인트를 나타내는 Vector2 객체 배열을 매개변수로 받습니다.
  2. 현재 웨이포인트 인덱스 초기화:
    • int currentWaypointIndex = 0;: 이 줄은 적이 현재 향하고 있는 웨이포인트를 추적하기 위한 인덱스를 초기화합니다.
  3. 웨이포인트 탐색을 위한 외부 While 루프:
    • while (currentWaypointIndex < wayPoints.Length): 이 루프는 적이 마지막 웨이포인트에 도달할 때까지 계속됩니다.
    • 적이 배열의 각 웨이포인트를 거치도록 합니다.
  4. 현재 웨이포인트 접근:
    • Vector2 currentWaypoint = wayPoints[currentWaypointIndex];: 이 줄은 현재 웨이포인트 인덱스를 사용하여 배열에서 현재 웨이포인트를 검색합니다.
  5. 현재 웨이포인트로 이동을 위한 내부 While 루프:
    • while (Vector2.Distance(enemy.transform.position, currentWaypoint) > 0.01f): 이 내부 루프는 적이 현재 웨이포인트와 매우 가까워질 때까지 계속됩니다 (0.01 유닛 미만).
    • Vector2.Distance를 사용하여 적의 현재 위치와 웨이포인트 사이의 거리를 계산합니다.
  6. 적 이동:
    • enemy.transform.position = Vector2.MoveTowards(enemy.transform.position, currentWaypoint, enemy.speed * Time.deltaTime * SpeedOffset);: 이 줄은 적을 현재 웨이포인트 쪽으로 이동시킵니다.
    • 부드럽게 이동시키기 위해 Vector2.MoveTowards를 사용합니다.
    • enemy.speed * Time.deltaTime * SpeedOffset는 이동 속도를 결정합니다. SpeedOffset은 적의 속도를 수정하는 상수나 변수로 추정됩니다.
    • Time.deltaTime은 움직임이 프레임 속도에 독립적이도록 보장합니다.
  7. Yield Return:
    • yield return null;: 이 줄은 각 프레임에서 Unity 엔진으로 제어를 반환하여 부드러운 움직임과 다른 게임 프로세스가 계속될 수 있도록 합니다.
  8. 웨이포인트 인덱스 증가:
    • currentWaypointIndex++;: 웨이포인트에 도달한 후에는 인덱스를 증가시켜 다음 웨이포인트로 이동합니다.
  9. 루틴 종료 처리:
    • enemy.EndToEnemyCoroutine(enemy);: 모든 웨이포인트에 도달하면 이 메서드가 호출됩니다. 해당 메서드 호출 시 코루틴을 종료하고, 초기화 하여 코루틴으로 인해 발생할 수 있는 문제를 예방합니다.

정해진 좌표를 이동하는 웨이포인트 메서드

public static IEnumerator BossInfinityPattern(Enemy enemy)  
{  
	Vector3[] waypoints =  
	{  
		new(0f,3.5f,0f),  
		new(-1.5f,2.5f,0f),  
		new(-3f,3.5f,0f),  
		new(-1.5f,4.5f,0f),  
		new(1.5f,2.5f,0f),  
		new(3f,3.5f,0f),  
		new(1.5f,4.5f,0f),  
		new Vector3(0f,3.5f,0f)  
		};  
		foreach (Vector3 wayPoint in waypoints)  
		{  
			while (Vector3.Distance(enemy.transform.position, wayPoint) > 0.01f)  
			{  
				enemy.transform.position = Vector3.MoveTowards(  
				enemy.transform.position,  
				wayPoint,  
				enemy.speed * Time.deltaTime * SpeedOffset);  
				yield return null;  
			}  
	}  
	BossNextPattern(enemy);  
}
  • 해당 메서드의 웨이포인트의 경우 옆으로 누운 8자 형태로 움직이는 메서드 입니다.
  • 만약 좌표를 알 수 있고 고정된 행위를 하는 오브젝트의 경우 이러한 방법이 더 직관적이고 도움이 될 수 있습니다.