몬스터의 위치를 처음에는 raycast로 앞에 ray 쏴서 체크하는 방법으로 해결하려고 하다가, 오히려 화면에 짤리면서 나타나는 적이 생길 것 같아서 위치로 바꿈. 정확한 위치에 서 있는 게 오히려 보기 좋을 듯.
public enum Position {
Left_5 = 0, Left_4 = 1, Left_3 = 2, Left_2 = 3, Left_1 = 4,
Right_1 = 5, Right_2 = 6, Right_3 = 7, Right_4 = 8, Right_5 = 9
}
그냥 이런 식으로 최대 10마리 몬스터가 있다고 만들고
private static bool initialized = false;
void Awake()
{
m_stats = GetComponent<Monster_Stats>();
m_animator = GetComponent<Animator>();
m_weaponCollider = GetComponentInChildren<WeaponCollider>();
// 첫 번째로 생성된 몬스터가 위치 포인트들을 초기화
if (!initialized)
{
InitializePositionPoints();
initialized = true;
}
}
// 모든 위치 포인트를 찾아서 초기화
private void InitializePositionPoints()
{
positionPoints = new List<Transform>();
GameObject positionsParent = GameObject.Find("MonsterPositions");
if (positionsParent != null)
{
// "Left_5", "Left_4", ... 등의 이름을 가진 자식 오브젝트들을 찾아 순서대로 추가
for (int i = 0; i < 10; i++)
{
string pointName = "";
if (i < 5)
pointName = "Left_" + (5 - i);
else
pointName = "Right_" + (i - 4);
Transform point = positionsParent.transform.Find(pointName);
if (point != null)
positionPoints.Add(point);
else
Debug.LogError("Position point not found: " + pointName);
}
}
else
{
Debug.LogError("MonsterPositions parent object not found!");
}
}
몬스터를 다 초기화 해버림 위치 따라서
void Update()
{
if (isMoving || m_stats.IsDead())
return;
attackCooldown = Mathf.Max(0f, attackCooldown - Time.deltaTime);
// 히어로와 가까운 포지션(Left_1, Right_1)에서만 공격
if (currentPosition == Position.Left_1 || currentPosition == Position.Right_1)
{
if (!IsAttacking && attackCooldown <= 0f)
{
int attackIndex = Random.Range(0, AttackNum);
StartCoroutine(PlayAttackAnimation(attackIndex + 1));
attackCooldown = Random.Range(4.0f, 6.0f);
}
}
else
{
// 앞쪽 위치 계산
Position frontPosition = GetFrontPosition(currentPosition);
// 앞에 몬스터가 없으면 전진
if (!IsMonsterAtPosition(frontPosition))
{
StartCoroutine(MoveToPosition(frontPosition));
}
}
}
Hero 앞에 도달하면 공격하지만 그 외에는 앞에 몬스터가 있나 체크, 없으면 전진이 목표
private bool IsMonsterAtPosition(Position pos)
{
Monster[] monsters = FindObjectsOfType<Monster>();
foreach (Monster monster in monsters)
{
if (monster != this && monster.currentPosition == pos && !monster.m_stats.IsDead())
return true;
}
return false;
}
몬스터 다 체크하고
private IEnumerator MoveToPosition(Position newPos)
{
isMoving = true;
// 목표 위치
Vector3 targetPos = positionPoints[(int)newPos].position;
// DOTween을 사용한 이동
float moveSpeed = 0.5f;
float duration = Vector3.Distance(transform.position, targetPos) / moveSpeed;
// DOMove 트윈 생성 및 실행
Tween moveTween = transform.DOMove(targetPos, duration)
.SetEase(Ease.Linear).SetUpdate(UpdateType.Fixed); // 선형 이동 (원하는 다른 이징 함수로 변경 가능)
m_animator.SetBool("Run", true); // 이동 애니메이션 시작
// 트윈이 완료될 때까지 대기
yield return moveTween.WaitForCompletion();
m_animator.SetBool("Run", false); // 이동 애니메이션 종료
// 최종 위치 설정 및 상태 업데이트
transform.position = targetPos; // 정확한 위치 보장
currentPosition = newPos;
UpdateFacingDirection();
isMoving = false;
}
전진하며 된다.
애니메이션 오버라이드 컨트롤러로 만들고 나머지 애니메이션 덧씌우기만 하면 됨
생각해보니 어차피 프레임 단위로 체크하면 몬스터의 공격 collider가 많을 필요가 없음. 타이밍에 맞게 collider만 켰다 끄면 되니 collider를 하나로 통일