I'm FanJae.

[Unity] Initialize()가 호출되지 않은 총알이 데미지를 주던 문제 - Trigger 이벤트와 객체 소멸 타이밍 분석 본문

Unity/Troubleshooting

[Unity] Initialize()가 호출되지 않은 총알이 데미지를 주던 문제 - Trigger 이벤트와 객체 소멸 타이밍 분석

FanJae 2026. 6. 1. 02:01

1. 문제 상황

- 기능을 추가하고 테스트 하던 중 타워 데미지가 정상적으로 반영되지 않는 문제가 발생했다. 처음에는 나에게만 발생하는 문제가 아닐 수 있다고 판단하여, 타워 구현을 담당한 팀원과 함께 원인을 확인했다.

- 일반 타워와 빠른 공격력 속도를 가진 타워 등등.. 일부 타워에서 데미지가 들어가지 않는 형태로 나타났다. 그런데 같은 총알 계열을 쓰는 소환 타워는 데미지가 제대로 반영되는 문제였다. (추후 알게된 것은 이 타워 역시 제대로 공격을 하지 못했다.)


2. 원인 추적

① 범위 좁히기

- 일단 타워의 문제인지 적(Enemy)의 문제인지에 대해 확인이 필요했다. 

- 같은 적을 대상으로 여러 타워를 테스트해보며, 데미지가 반영되지 않는 타워와 반영되는 것처럼 보이는 타워를 구분했다.
- 확인 결과 일반 타워와 빠른 공격 속도를 가진 타워에서는 데미지가 정상적으로 들어가지 않았지만, SummonerTower는 데미지가 들어가는 것처럼 보였다.
- 이 때문에 처음에는 타워별 공격 로직 차이, 총알 생성 위치, Enemy의 Collider 및 피격 처리 로직을 함께 의심했다.

 

② Enemy 로직 검증

- 먼저 Enemy의 피격 처리 로직에 문제가 있는지 확인했다.
- SummonerTower의 공격으로는 실제 체력이 감소하고 있었기 때문에, Enemy의 체력 감소 로직 자체는 정상적으로 동작하고 있다고 판단했다.

- 또한 동일한 Enemy 객체에 대해 어떤 타워는 데미지가 들어가고, 어떤 타워는 들어가지 않는 현상이 발생하고 있었기 때문에 문제의 원인이 Enemy보다는 공격을 수행하는 타워 또는 총알 로직에 있을 가능성이 높다고 생각했다.

 

③ 총알 생성 및 충돌 과정 확인
- 공격 판정이 발생하는 경로를 추적하기 위해 총알 생성부터 충돌까지의 흐름을 확인했다.
- 총알은 생성 이후 Initialize()를 통해 타겟 정보를 전달받고, 이후 OnTriggerEnter를 통해 적에게 데미지를 주는 구조였다.

- 따라서, Initialize()가 정상적으로 호출되고 있는지 먼저 확인 해본 결과 호출이 되지 않고 있었다.


3. 왜 호출이 안되고 있었는가?

// 총알 타겟 관련 로직
public void Initialize(Enemy target, int damage, float moveSpeed)
{
    _target = target;
    if (target != null)
    {
        _targetTransform = target.transform;
    }
    this.damage = damage;
    this.moveSpeed = moveSpeed;
}
// 타워 발사 로직
protected virtual void Fire()
{
    GameObject bulletObj = Instantiate(bulletPrefab, firePoint.position, firePoint.rotation);
    if (bulletObj.TryGetComponent(out bullet bullet))
    {
        bullet.Initialize(CurrentEnemy, damage, bulletSpeed);
    }
}

- 기존 팀원이 짰던 로직이다.

- 기존 bullet 컴포넌트를 NormalBaseBullet 구조로 재구성했음에도 TryGetComponent에서 참조하는 타입은 기존 bullet으로 남아있었다.

- 따라서, bulletObj.TryGetComponent(out bullet bullet) 조건문이 실패했고, 내부의 Initialize()가 호출되지 않았다.

- 그 결과 총알은 타겟 정보과 데미지 정보를 전달받지 못했고, 일반 타워에서는 데미지가 들어가지 않는 문제가 발생한 것이다.

protected virtual void Fire()
{
    GameObject bulletObj = Instantiate(bulletPrefab, firePoint.position, firePoint.rotation);
    if (bulletObj.TryGetComponent(out NormalBaseBullet bullet))
    {
        bullet.Initialize(CurrentEnemy, damage, bulletSpeed);
    }
}

- 해당 내용을 수정한 뒤, 총알이 타겟 정보를 제대로 받을 수 있었고, 타워가 데미지를 잘 적용할 수 있었다.


4. 그럼 SummonerTower는 왜 데미지가 들어갔을까?

① 의문점

- 사실 주 원인은 TryGetComponent 타입 변경 누락으로 인해 Initialize()가 호출되지 않은 것이다.
- 그렇다면 같은 총알 계열을 사용하는 SummonerTower 역시 데미지가 들어가지 않아야 했다.


- 하지만 테스트 당시 SummonerTower는 데미지가 들어가는 것처럼 보였고, 이 지점 때문에 원인 파악이 늦어졌다.

- 이를 알기 위해서는 우리 SummonerTower의 공격 흐름에 대한 약간의 이해가 필요하다.

② SummonerTower의 공격 흐름

- 적 근처에 보조 타워를 생성한다.

- 보조 타워가 총알을 생성하여 발사한다.

- 적과 충돌시 데미지가 적용된다.

- 빨간색으로 표시된 검정색 연필깎이가 Summoner Tower가 소환한 공격 타워다.

- 이 보조 타워들은 적이 지나가는 길 위에 소환된다.

 

③ 이 짧은 순간에 일어나던 현상

- Hierarchy 창을 자세히 보면 순식간에 PencilBuilet이 나타났다가 사라지는 것을 볼 수 있다.

- 즉, 코드를 수정하기 전에도 Summoner Tower가 소환하는 Mini Tower에서는 Bullet을 발사하고, 그 짧은 순간에 OnTriggerEnter 이벤트가 발생하면서 데미지가 들어갔던 것이다.

- 따라서 Initialize()가 호출되지 않아 총알이 `Destroy()`를 호출했더라도, 실제로 제거되기 전에 OnTriggerEnter가 먼저 실행될 수 있었다.

- 결과적으로 SummonerTower 역시 정상적으로 동작한 것이 아니었지만, 총알 생성 위치가 적과 가까워 데미지가 들어가는 것처럼 보였다.


5. 결론

- 이번 문제의 직접적인 원인은 TryGetComponent에서 참조하던 타입을 변경하지 않아 Initialize()가 호출되지 않은 것이었다.
- 기존에는 bullet 컴포넌트를 가져오도록 되어 있었지만, 총알 구조를 NormalBaseBullet로 재구성한 뒤에도 Fire() 코드에서는 여전히 기존 타입을 찾고 있었다.
- 그 결과 TryGetComponent()가 실패했고, 총알은 타겟 정보와 데미지 정보를 전달받지 못했다.반 타워에서는 이 문제가 바로 드러났다. Initialize()가 호출되지 않았다.

- 총알은 즉시, FixedUpdate()에서 Destroy()를 호출했고, 데미지가 들어가지 않았다.

- 하지만 SummonerTower는 보조 타워를 적 근처에 생성하는 구조였다. 총알이 생성되자마자 Enemy Collider와 충돌할 수 있었다.
- 이때 총알은 아직 정상 초기화되지 않았지만, Destroy()로 실제 삭제되기 전에 OnTriggerEnter()가 먼저 실행되면서 데미지가 들어간 것처럼 보였다.
- 즉, SummonerTower가 정상 동작한 것이 아니라, 총알 생성 위치와 Trigger 이벤트 타이밍 때문에 버그가 가려진 것이다.

 

 

Comments