Coroutine과 Event 구현하기
연사 기능 구현하기
Space를 누르는 중에는 일정한 간격으로 탄환을 발사하는 기능을 구현한다.
Space를 떼면 연사를 멈추고 탄환을 발사하지 않는다.
차징 기능 구현하기
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;
}

아주 쉽게 잘 되었다.
이번엔 차지샷을 구현해보자.
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;
}
}

좋아! 원하는 대로 잘 구현 된... 줄 알았는데
한번 차지하고 나면 유지된다...
지금보니 chargeTime을 0으로 초기화 하는 코드가 없다.
if (chargeCoroutine != null)
{
StopCoroutine(chargeCoroutine);
chargeCoroutine = null;
shot.Fire(Mathf.Clamp(chargeTime, 5f, 40f));
chargeTime = 0f;
}
큰 문제는 아니라 쉽게 해결했다.
Coroutine과 Event 구현 심화
트리거 충돌체로 탱크가 진입 할 수 있는 구역을 구현한다.
구역에는 여러 몬스터를 배치하여 대기시킨다.
구역 진입시 구역은 이벤트를 발생시킨다.
이벤트에 반응하여 구역에 있는 몬스터들이 탱크를 향해 이동할 수 있도록 구현한다.

먼저 트리거로 영역을 만들어주자.
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;
}
몬스터에겐 탱크의 위치를 받아 탱크를 추격할 코드를 추가했다.

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

아주 멍청한 실수였다..
프리팹의 몬스터를 넣고 실행해보자

?
설마


...


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