인터페이스와 TryGetComponent
Coddy Unity 여정의 Unity 게임 아키텍처 섹션에 포함된 레슨. 64개 중 8번째.
TryGetComponent은 한 번의 호출로 컴포넌트를 요청하고 찾았는지 알려 줍니다. 인터페이스에도 사용할 수 있으므로, 무엇에 부딪혔든 피해를 줄 수 있는지 확인할 때 일반적으로 사용합니다. 이 지뢰는 주변에 있는 것 중 IDamageable인 모든 대상에게 피해를 줍니다.
public class Mine : MonoBehaviour
{
public float radius = 3f;
public int damage = 5;
void OnTriggerEnter(Collider other)
{
foreach (Collider c in Physics.OverlapSphere(transform.position, radius))
{
if (c.TryGetComponent(out IDamageable target))
{
target.TakeDamage(damage);
}
}
Destroy(gameObject);
}
}out IDamageable target은 호출 안에서 변수를 선언합니다. 오브젝트에 IDamageable을 구현하는 컴포넌트가 있으면 TryGetComponent는 true를 반환하고 target에 값을 넣습니다. 그렇지 않으면 false를 반환하고 target은 null입니다. TryGetComponent는 해당 오브젝트 하나만 확인하며, 부모나 자식은 확인하지 않습니다.
GetComponent는 클래스가 없는 경우와 인터페이스가 없는 경우를 다르게 처리합니다. 에디터에서 Rigidbody가 없는 오브젝트에 GetComponent<Rigidbody>()를 호출하면 Unity의 가짜 null을 반환합니다. 즉, == null은 true이지만 ?.는 이를 감지하지 못하고 호출 시 MissingComponentException이 발생합니다. 인터페이스에는 가짜 null이 없습니다. GetComponent<IDamageable>()은 실제 C# null을 반환하므로 == null과 ?.를 모두 사용할 수 있습니다. TryGetComponent는 두 경우 모두 이런 문제를 피하며, 에디터에서 컴포넌트가 없을 때 메모리를 할당하지 않습니다.
챌린지
쉬움Laser에 Fire()를 작성하세요. 광선 하나로 네 가지 결과가 나옵니다.
- 탑에서
transform.forward방향으로range거리만큼Physics.Raycast를 쏘세요. 맞지 않으면Missed를 로그에 기록하세요. hit.collider.TryGetComponent(out IDamageable target)이면TakeDamage(damage)를 호출하고"Hit " + hit.collider.name을 로그에 기록하세요.- 그렇지 않고
Rigidbody가 있으면AddForce(transform.forward * push, ForceMode.Impulse)를 호출하고 이름 앞에"Pushed "를 붙여 로그에 기록하세요. 그렇지 않으면 이름 앞에"Blocked by "를 붙여 로그에 기록하세요.
‘플레이’를 누르고, 모든 방향으로 회전하며 발사하세요. 그런 다음 ‘확인’을 누르세요.
직접 해보기
using UnityEngine;
using UnityEngine.InputSystem;
public class Laser : MonoBehaviour
{
public float range = 10f;
public int damage = 1;
public float push = 5f;
public float turnSpeed = 90f;
private InputAction moveAction;
void Start()
{
moveAction = InputSystem.actions.FindAction("Move");
}
void Update()
{
float turn = moveAction.ReadValue<Vector2>().x;
transform.Rotate(0f, turn * turnSpeed * Time.deltaTime, 0f);
if (Keyboard.current.spaceKey.wasPressedThisFrame)
{
Fire();
}
}
void Fire()
{
// 앞쪽으로 길이가 range 단위인 광선을 쏘고, 광선에 맞은 대상을 처리합니다
}
}
Unity 게임 아키텍처의 모든 레슨
직접 연습해 보세요: Unity 플레이그라운드