유니티_5 Coroutine과 Event

avatar
2025.04.18
·
4 min read

Coroutine과 Event 구현하기

  1. 연사 기능 구현하기

    • Space를 누르는 중에는 일정한 간격으로 탄환을 발사하는 기능을 구현한다.

    • Space를 떼면 연사를 멈추고 탄환을 발사하지 않는다.

  2. 차징 기능 구현하기

    • Space를 누르는 중에 탄환을 더 멀리 날리기 위한 차징 기능을 구현한다.

    • Space를 누르는 시간에 따라 탄환의 속도가 달라져야 한다.

[SerializeField] Coroutine coroutine1;
[SerializeField] float reloadTime;
[SerializeField] Shot shot;


private void Update()
{
    if (Input.GetKey(KeyCode.Space))
    {
        if (coroutine1 == null)
        {
            coroutine1 = StartCoroutine(AutoF());
        }
    }
}

IEnumerator AutoF()
{
    shot.Fire();
    yield return new WaitForSeconds(reloadTime);
    coroutine1 = null;
}
5274

아주 쉽게 잘 되었다.

이번엔 차지샷을 구현해보자.

public void Fire(float speed)
    {
        GameObject bullet = Instantiate(bulletPrefab, bulletSpawnPoint.position, bulletSpawnPoint.rotation);
        Rigidbody bulletRigidbody = bullet.GetComponent<Rigidbody>();
        bulletRigidbody.velocity = bulletSpawnPoint.forward * speed;
    }

먼저 Shot에서 오버로드로 탄환 속도를 받을 함수를 만든다.

[SerializeField] Shot shot;
[SerializeField] Coroutine chargeCoroutine;

private float chargeTime = 0f;

void Update()
{
    if(Input.GetKeyDown(KeyCode.Space))
    {
        if (chargeCoroutine == null)
        {
            chargeCoroutine = StartCoroutine(ChargeF());
        }
    }
    if (Input.GetKeyUp(KeyCode.Space))
    {
        if (chargeCoroutine != null)
        {
            StopCoroutine(chargeCoroutine);
            chargeCoroutine = null;
            shot.Fire(Mathf.Clamp(chargeTime, 5f, 40f));
        }
    }
}

IEnumerator ChargeF()
{
    while (true)
    {
        chargeTime += Time.deltaTime * 20f;
        yield return null;
    }
}
5275

좋아! 원하는 대로 잘 구현 된... 줄 알았는데

한번 차지하고 나면 유지된다...

지금보니 chargeTime을 0으로 초기화 하는 코드가 없다.

if (chargeCoroutine != null)
{
    StopCoroutine(chargeCoroutine);
    chargeCoroutine = null;
    shot.Fire(Mathf.Clamp(chargeTime, 5f, 40f));
    chargeTime = 0f;
}

큰 문제는 아니라 쉽게 해결했다.

Coroutine과 Event 구현 심화

  • 트리거 충돌체로 탱크가 진입 할 수 있는 구역을 구현한다.

  • 구역에는 여러 몬스터를 배치하여 대기시킨다.

  • 구역 진입시 구역은 이벤트를 발생시킨다.

  • 이벤트에 반응하여 구역에 있는 몬스터들이 탱크를 향해 이동할 수 있도록 구현한다.

5276

먼저 트리거로 영역을 만들어주자.

public UnityEvent zoneInEvent;
public UnityEvent zoneOutEvent;
[SerializeField] Monster monster;

void Awake()
{
    Init();
}

void OnDrawGizmos()
{
    Gizmos.color = Color.red;
    Gizmos.DrawWireSphere(transform.position, 15f);
}

void OnTriggerEnter(Collider other)
{
    if (other.CompareTag("Player"))
    {
        zoneInEvent.Invoke();
    }
}
void OnTriggerExit(Collider other)
{
    if (other.CompareTag("Player"))
    {
        zoneOutEvent.Invoke();
    }
}
    
void Init()
{
    zoneInEvent.AddListener(() => monster.PlayerInZone());
    zoneOutEvent.AddListener(() => monster.PlayerOutZone());
}

트리거에 해당하는 코드는 다음과 같이 적용했다.

[SerializeField] GameObject tank;

public void ZoneTrace()
{  
    if (isInZone)
    {
        monsterRigidbody.transform.LookAt(new Vector3(tank.transform.position.x, tank.transform.position.y, tank.transform.position.z));
        monsterRigidbody.transform.position = Vector3.MoveTowards(monsterRigidbody.transform.position, tank.transform.position, monsterSpeed * Time.delta
    }
}
public void PlayerInZone()
{
    isInZone = true;
}
public void PlayerOutZone()
{
    isInZone = false;
}

몬스터에겐 탱크의 위치를 받아 탱크를 추격할 코드를 추가했다.

5278

돌려보았더니 에러가 발생했다.

5285

아주 멍청한 실수였다..

프리팹의 몬스터를 넣고 실행해보자

5286

?

설마

52875288

...

52895290

인스펙터에서 이벤트에 직접 추가하는걸로 해결했다.