인터페이스와 TryGetComponent
Coddy Unity 여정의 Unity 게임 아키텍처 섹션에 포함된 레슨. 50개 중 7번째.
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입니다. 이 메서드는 해당 객체 하나만 확인하며, 부모나 자식 객체는 확인하지 않습니다.
GetComponent는 클래스가 없는 경우와 인터페이스가 없는 경우를 다르게 처리합니다. Editor에서 Rigidbody가 없는 객체에 GetComponent<Rigidbody>()를 호출하면 Unity의 가짜 null을 반환합니다. == null은 true이지만, ?.는 이를 감지하지 못하고 호출 시 MissingComponentException이 발생합니다. 인터페이스에는 가짜 null이 없습니다. GetComponent<IDamageable>()은 실제 C# null을 반환하므로, == null과 ?. 모두 사용할 수 있습니다. TryGetComponent를 사용하면 두 경우 모두 이런 문제를 피할 수 있으며, Editor에서 컴포넌트를 찾지 못해도 메모리를 할당하지 않습니다.
챌린지
쉬움레이저 타워는 왼쪽 및 오른쪽 화살표 키로 회전하고, Space 키를 누르면 Laser.cs에서 Fire()를 호출합니다. Fire를 작성하세요. 타워의 앞 방향으로 range 단위 길이만큼 광선을 쏘고(Inspector에서 10으로 설정), 다음을 수행하세요:
- IDamageable이 있는 대상을 맞히면 해당 대상에
TakeDamage(damage)를 호출하고,Hit와 대상의 이름을 로그로 출력합니다(예:Hit Robot). - 대상에 IDamageable은 없지만 Rigidbody가 있으면
AddForce(transform.forward * push, ForceMode.Impulse)로 밀고,Pushed와 대상의 이름을 로그로 출력합니다. - 그 외의 대상은
Blocked by와 대상의 이름을 로그로 출력합니다(예:Blocked by Pillar). 아무것도 맞히지 못한 광선은Missed를 로그로 출력합니다.
두 가지 검색 모두에 TryGetComponent를 사용하세요. IDamageable.cs, Robot.cs 및 Balloon.cs는 준비되어 있습니다. Play를 누르고 모든 방향으로 발사한 다음 Check를 누르세요.
직접 해보기
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 단위 길이의 광선을 쏘고, 광선에 맞은 대상을 처리합니다
}
}
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.