[엔진 프로젝트]Enemy Walking Around with BT
이번에 학교에서 엔진 플젝을 시작하게 되었는데 그쪽에서 적을 만드는 역활을 맡아 적의 구조를 짜보았다. 앞으로도 리펙토링 해볼 것임
참고로 Behavior Desginer 에셋을 사용했음을 알린다.
여튼 오늘은 플레이어 주변을 도는 Walking Around Script를 어떻게 만들었는지 소개하겠다.
레퍼런스를 세키로에서 따와서 대충 어떤 느낌인지 보여주겠다.
뭐 잘 안보이긴 하는데 플레이를 두고 주위를 천천히 맴도는 것을 볼 수 있다. 세키로에서는 패턴의 쿨타임이나 보통 원거리 적이 저런 모습을 보이는데 저거랑 잘만 사용하면 좋을 거 같아서 한번 구현해서 공격이랑 같이 넣어봤다.
일단 저거를 구현하려면 일정 거리에 도달했을때 플레이어를 기준으로 크게 원으로 돌아야한다. 그 기능을 만들기 위해서 Sin, Cos 함수를 사용하여 원 운동을 구현했다.
3D에서 구현할 예정이니 Cos은 그대로 X축으로 보면 되고 Sin은 Y축을 Z축으로 바꾸어서 생각하면 된다.
원 운동은 지속적으로 증가하거나 감소하는 각도를 넣어주면 된다.
하지만 우리는 플레이어가 적한테 접근했을 때 그 위치에서 원 운동을 시작해야 하기 때문에 단순히 각도를 정해주면 안된다.
private void Update()
{
if(!isRun){
SettingValues(); // 값 초기화
isRun = true;
}
_enemy.MovementCompo.LookToTarget(_playerTrm.position); // 대상 바라보기
float x = 0f, z = 0f;
Vector3 point;
_currentValue += Time.deltaTime * _walkSpeed;
if(_currentValue >= _walkingLimits){
_currentValue = 0;
isRun = false;
return;
}
switch(_currentDir){
case WalkingDir.Left: // +
x = Mathf.Cos((_originAngle - _currentValue) * Mathf.Deg2Rad) * _range;
z = Mathf.Sin((_originAngle - _currentValue) * Mathf.Deg2Rad) * _range;
break;
case WalkingDir.Right: // -
x = Mathf.Cos((_originAngle + _currentValue) * Mathf.Deg2Rad) * _range;
z = Mathf.Sin((_originAngle + _currentValue) * Mathf.Deg2Rad) * _range;
break;
}
point = new Vector3(x + _playerPos.x, 0, z + _playerPos.z);
_enemy.MovementCompo.SetDirectMovement(point, false); // 넣어준 Vector3 값으로 이동해주는 함수
return;
}
일단 다른 코드를 빼고 원 운동하는 부분만 설명하겠다.
if(_currentValue >= _walkingLimits){
_currentValue = 0;
isRun = false;
return;
}
switch(_currentDir){
case WalkingDir.Left: // +
x = Mathf.Cos((_originAngle - _currentValue) * Mathf.Deg2Rad) * _range;
z = Mathf.Sin((_originAngle - _currentValue) * Mathf.Deg2Rad) * _range;
break;
case WalkingDir.Right: // -
x = Mathf.Cos((_originAngle + _currentValue) * Mathf.Deg2Rad) * _range;
z = Mathf.Sin((_originAngle + _currentValue) * Mathf.Deg2Rad) * _range;
break;
}
보이지는 않지만 처음에 방향을 설정해준다.
public enum WalkingDir{
Left, Right
}
그리고 Left(시계 방향)라면 Right(반시계 방향)으로 돈다.
gif로 보자 대충 이해될 것임
사실 원 운동은 굉장히 쉽다. 하지만 우리는 특정 위치에서 원 운동을 시작해야 하므로 그 값을 구하는 방법을 알아 보자.
일단 어떻게 구하는지 방법을 설명하자면 플레이어의 Right와 적의 위치에서 플레이어의 방향 백터의 노말을 내적하고 그 내적한 값을 ACos에 넣어주면 된다.
Vector3 dirToOwner = Owner.transform.position - _playerPos;
dirToOwner.y = 0;
_playerDir.y = 0;
_originAngle = Mathf.Acos(Vector3.Dot(dirToOwner.normalized, _playerDir.normalized)) * Mathf.Rad2Deg;
두 백터 사이의 끼인각을 구하는 공식이다. 두 백터의 normal를 내적하고 Acos에 넣으면 된다. 왜 그런지 설명하려면 너무 오래 걸리니 나중에 다루도록 하겠다.
여튼 이런식으로 하면 0~180도만 잘 작동할 거다. 그래서 우리는 외적을 해서 음수라면 360도에서 빼주는 작업을 해야한다.
if(Vector3.Cross(dirToOwner, _playerDir.normalized).y < 0)
_originAngle = 360 - _originAngle;
이러면 둘다 구했다. 이 코드들을 깔삼하게 잘 적용시켜보면 잘 된다.
BT 구조는 다음 파트에서 다루겠다.