1인 개발/나홀로 성 지키기

나홀로 성 지키기 개인 프로젝트 3일차

잼잼재미 2024. 3. 20. 15:15

구현 기능


1. Castle 피격 구현

 

  • 피격 시, 애니메이션 적용
  • Canvas World Space 생성, Hp 적용

 

2. ObjectPool 구현

 

  • Enemy의 재사용을 위해
  • Enemy가 죽으면, Destroy하지 않고, SetActive(false)하고, 재사용할 때, SetActive(true) 해줌

 

public void InstantiateEnemy(string poolName, Vector3 startPosition)
{
    _enemy = ObjectPool.SpawnFromPool(poolName);
    _enemy.transform.position = startPosition;

    _enemy.SetActive(true);
}

 

 

3. SpawnSystem 구현 

  • 코루틴을 실행해서 좌, 우 랜덤으로 Enemy를 생성
  • ObjectPool을 사용해서 생성

 

[SerializeField] private Transform _spawnLeft;
[SerializeField] private Transform _spawnRigth;

private void Start()
{
    StartCoroutine(COSpawnEnemy());
}

IEnumerator COSpawnEnemy()
{
    while (true)
    {
        yield return new WaitForSeconds(3f);

        int random = Random.Range(0, 2);
        if (random == 0) GameManager.I.ObjectPoolManager.InstantiateEnemy("Snail", _spawnLeft.position);
        else GameManager.I.ObjectPoolManager.InstantiateEnemy("Snail", _spawnRigth.position);
    }
}

 

트러블 슈팅


1. Enemy ObjectPool 사용 시, 동작 안함

 

 

Enemy를 ObjectPool로 재사용할 때, 정상적으로 동작하지 않고 제자리에 멈춰있는 현상을 발견.

 

 

private void Start()
{
    _enemyStateContext = new EnemyStateContext(this);

    _walkState = gameObject.AddComponent<EnemyWalkState>();
    _hitState = gameObject.AddComponent<EnemyHitState>();
    _attackState = gameObject.AddComponent<EnemyAttackState>();
    Animator = gameObject.transform.GetChild(0).GetComponent<Animator>();
    Rigdbody = GetComponent<Rigidbody2D>();

    Hp = EnemySO.Hp;
    Ishit = false;
    IsAttack = false;

    _enemyStateContext.Transition(_walkState);
}

 

EnemyController의 Start문의 기존 코드이다. Start문은 최초 1회만 실행되기 때문에 SetActive(false)를 하고 다시 SetActive(true)를 해도 Start문의 내용은 실행되지 않는다. 그래서 아마도 WalkState로 전환되지 않기 때문에 위와 같은 현상이 나타난 것으로 예상했다.

 

 

private void Start()
{
    Debug.Log("Start 실행!");
    _enemyStateContext = new EnemyStateContext(this);

    _walkState = gameObject.AddComponent<EnemyWalkState>();
    _hitState = gameObject.AddComponent<EnemyHitState>();
    _attackState = gameObject.AddComponent<EnemyAttackState>();
    Animator = gameObject.transform.GetChild(0).GetComponent<Animator>();
    Rigdbody = GetComponent<Rigidbody2D>();

    Ishit = false;
    IsAttack = false;
}

private void OnEnable()
{
    Debug.Log("OnEnable 실행!");
    Hp = EnemySO.Hp;
    _enemyStateContext.Transition(_walkState);
}

 

 

다음과 같이 코드를 수정했다. 오브젝트가 활성화 될 때마다 실행해야 할 내용을 OnEnable 함수에 입력했다. OnEnable 함수는 Start 함수와 다르게 활성화 될 때마다 실행이 된다. 

 

 

 

하지만 이번에는 처음 Enemy가 생성될 때 부터 동작을 하지 않았다.

 

 

 

Start와 OnEnable의 실행 순서에 문제가 있었다. OnEnable이 Start보다 먼저 실행되므로 WalkState로 전환할 수 없었다. 

 

 

private void Start()
{
    Debug.Log("Start 실행!");
    _enemyStateContext = new EnemyStateContext(this);

    _walkState = gameObject.AddComponent<EnemyWalkState>();
    _hitState = gameObject.AddComponent<EnemyHitState>();
    _attackState = gameObject.AddComponent<EnemyAttackState>();
    Animator = gameObject.transform.GetChild(0).GetComponent<Animator>();
    Rigdbody = GetComponent<Rigidbody2D>();

    Hp = EnemyData.Hp;
    Ishit = false;
    IsAttack = false;

    _enemyStateContext.Transition(_walkState);
}

private void OnEnable()
{
    if(_enemyStateContext != null)
    {
        Debug.Log("OnEnable 실행!");
        Hp = EnemyData.Hp;
        _enemyStateContext.Transition(_walkState);
    }
}

 

위와 같이 코드를 수정했다. OnEnable 함수가 최초에 Start문이 실행되기 전에는 실행하지 않도록 null 체크를 했다. 그리고 SetActive(true)가 실행 될 때 마다, OnEnable을 실행해서 체력을 초기화하고 WalkState로 전환되도록 했다.

 

 

 

오류 없이 잘 실행이 된다!!