OnEnable에서 구독하기
Coddy Unity 여정의 Unity 게임 아키텍처 섹션에 포함된 레슨. 64개 중 13번째.
소멸된 리스너는 이벤트에서 저절로 제거되지 않습니다. 이벤트가 여전히 해당 메서드를 보유하고 있으므로 다음 Invoke가 소멸된 컴포넌트에서 그 메서드를 호출합니다. 해당 메서드에서 transform을 처음 사용하는 순간 MissingReferenceException이 발생하고, 예외가 Invoke를 끝내므로 그 뒤의 리스너도 건너뜁니다. 따라서 모든 +=에는 -=가 필요하며, Unity에서 이를 위한 메서드 쌍은 OnEnable과 OnDisable입니다:
public class Guard : MonoBehaviour
{
public Alarm alarm;
void OnEnable()
{
alarm.OnTriggered += RunTo;
}
void OnDisable()
{
alarm.OnTriggered -= RunTo;
}
void RunTo(Vector3 spot)
{
transform.LookAt(spot);
}
}Unity는 SetActive(false)로 오브젝트가 비활성화될 때, 스크립트가 비활성화될 때, 그리고 오브젝트가 소멸될 때 OnDestroy보다 먼저 OnDisable을 호출합니다. 다시 활성화될 때마다 OnEnable이 실행됩니다. 이 메서드 쌍을 사용하면 경비병은 활성 상태인 동안에만 정확히 이벤트를 수신합니다. 소멸된 경비병은 이벤트에서 제거되고, 컷신 때문에 비활성화된 경비병은 경보를 무시하며, 다시 활성화되면 이벤트를 다시 수신합니다.
다른 두 가지 조합은 잘못 작동합니다. Start에서 +=를 하고 OnDisable에서 -=를 하면, 비활성화되었다가 다시 활성화된 경비병은 Start가 한 번만 실행되기 때문에 이벤트를 다시 수신하지 않습니다. OnEnable에서 +=를 하고 -=를 하지 않으면, 활성화될 때마다 RunTo가 다시 추가되어 경보 한 번에 두 번 호출됩니다. 구독되지 않은 메서드를 제거해도 아무 일도 일어나지 않으므로 OnDisable의 -=에는 확인 절차가 필요하지 않습니다.
챌린지
쉬움각 마을 주민이 활성화된 동안에만 종 소리를 듣도록 하세요.
Villager.cs에서bell.OnRing += Hop;을Start()에서 새void OnEnable()로 옮기고,Start()를 삭제하세요.void OnDisable()을 추가하고 그 안에bell.OnRing -= Hop;을 넣으세요. ‘확인’에서는 이를 테스트하기 위해 Cleo를 껐다가 켭니다.
‘플레이’를 누르고 종을 네 번 울리세요. Ana는 두 번째 종소리 후 집으로 돌아가고, 오류는 표시되지 않습니다. 그런 다음 ‘확인’을 누르세요.
직접 해보기
using UnityEngine;
public class Villager : MonoBehaviour
{
public Bell bell;
public int ringsToLeave = 3;
public int hops;
void Start()
{
bell.OnRing += Hop;
}
void Update()
{
// 한 번 뛰어오른 뒤 다시 땅으로 내려오기
Vector3 p = transform.position;
transform.position = new Vector3(p.x, Mathf.MoveTowards(p.y, 0.5f, 4f * Time.deltaTime), p.z);
}
void Hop(int ring)
{
hops++;
transform.position += Vector3.up * 0.8f;
if (hops == ringsToLeave)
{
Debug.Log(name + " goes home");
Destroy(gameObject);
}
}
}
Unity 게임 아키텍처의 모든 레슨
직접 연습해 보세요: Unity 플레이그라운드