[Unity] 방치형 게임 캐릭터 생명주기 문제해결 과정

고현규·2024년 1월 11일
0
post-custom-banner

플레이어 생명주기

  1. 몬스터가 범위 안에 있을 때 까지 우측으로 이동
  2. 몬스터가 범위 안에 들어오면 이동을 멈추고 공격을 시작한다.
  3. 범위 안의 몬스터가 다 죽을 때 까지 발사체를 몬스터에게 발사하는 것을 반복한다.

플레이어 생성 주기를 만들면서 구현에 문제를 느꼈다.

문제 발생

private void FixedUpdate()
{
    //적이 범위 밖에 있으면
    if (Range < Vector2.Distance(transform.position, _enemyList[0].transform.position))
    {
        // 평소 달리기 상태로 변경
        Idle();
    }
    else // 범위 안에 있으면 정지 후 공격
    {
        _playerRigidbody.velocity = Vector2.zero;
        Attack(); // TODO : 공격이 Update로 계속 실행되서 projectile이 반복 생성되어 수정 필요함
    }
}

 public void Attack()
 {
     // 공격 projectile 생성
     var testProjectile = Manager.Resource.InstantiatePrefab("IceProjectile", ProjectilePoint);
     testProjectile.transform.Translate(_enemyList[0].transform.position * Time.deltaTime); 

 }

Update함수에서 적을 찾을 때 가지 우측으로 이동하는 것은 구현했지만,
2번 Attack상태로 들어가는 순간 공격하는 메서드가 프레임마다 실행되어 Prefab이 대량 생성됐다.
프레임마다가 아닌, 공격 주기마다 공격을 실행해야 하는 문제를 해결해야 한다.


시도 한 내용

InvokeRepeat를 이용해서 공격주기마다 Attack()을 실행하도록 했었다.


private void FixedUpdate()
{
    //적이 범위 밖에 있으면
    if (Range < Vector2.Distance(transform.position, _enemyList[0].transform.position))
    {
        // 평소 달리기 상태로 변경
        Idle();
    }
    else // 범위 안에 있으면 정지 후 공격
    {
        _playerRigidbody.velocity = Vector2.zero;
        AttackingRepeat()  // 변경
    }
}

public void AttakingRepeat()
{
    InvokeRepeating("Attack", 0, 10); // Invoke를 활용 
}

public void Attack()
{
    // 공격 projectile 생성
    var testProjectile = Manager.Resource.InstantiatePrefab("IceProjectile", ProjectilePoint);
    testProjectile.transform.Translate(_enemyList[0].transform.position * Time.deltaTime); 

}

하지만 결국 Update안에서 실행되므로 똑같이 프레임마다 생성된다.
오히려 10초뒤에는 배로 늘어난다.

💡 그래서 Idle상태와 Attack상태에 대한 구분이 필요해 보인다는 생각이 들었다.

해결 방법

private void FixedUpdate()
{
    //적이 범위 밖에 있으면
    if (Range < Vector2.Distance(transform.position, _enemyList[0].transform.position))
    {
        // 평소 달리기 상태로 변경
        Idle();
    }
    else // 범위 안에 있으면 정지 후 공격
    {
        _playerRigidbody.velocity = Vector2.zero;
         if (_attackCoroutine == null)
 		{	
        	//수정 부분
    		 _attackCoroutine = StartCoroutine(AttackRoutine()); 
 		}
    }
}

IEnumerator AttackRoutine()
{
    while (true)
    {
        yield return new WaitForSeconds(1 / _attackSpeed);
        CreateProjectail();
    }
}

코루틴이 진행중이 아니라면 코루틴을 실행시킨다.
이것을 공격 상태로 확인하는 대용으로 사용한다.

아직 몬스터가 죽거나 코루틴이 멈추는 상태는 작성되지 않았지만,
공격 속도에 따라 공격을 반복하는 상태까지 구현했다.

알게 된 부분

이전에 배웠던 FSM의 필요성을 알게 되었다. 상태가 많지 않기 때문에 만들어 볼 수 있을 것 같다.
코루틴을 통해서 Update내부에서도 딜레이를 걸어줄 수 있는 것을 알았다.
또한 그동안 Update를 잘 안 쓰게 된 이유가 생각났다.

profile
게임 개발과 기획
post-custom-banner

0개의 댓글