유니티에서 Debug.Assert() 베스트 프랙티스

2024. 10. 6. 17:00·유니티

코드 검증이 필요한 상황

  • 코드의 의도 명확화
  • 버그를 조기에 발견
  • 코드의 안정성이 향상
  • 문서화 효과

코드 검증 메시지 작성 팁

  • 구체적이고 명확한 메시지 사용
  • 문제의 원인과 위치 포함

실행 시점에 따른 검증 위치

  • Awake/Start 메소드에서 컴포넌트 검증
  • 메소드 시작 부분에서 매개변수 검증
  • 상태 변경 직후 검증

검증 사용을 피해야 할 경우

  • 실제 게임 로직의 일부로 사용
  • 외부 입력 검증 (대신 일반적인 유효성 검사 사용)
  • 성능에 민감한 부분

 

싱글톤 참조 검증

public void ProcessGameLogic()
{
    Debug.Assert(GameManager.Instance != null, "GameManager instance is missing!");
    GameManager.Instance.UpdateGame();
}

 

직렬화 객체 검증

public class EnemySpawner : MonoBehaviour
{
    [SerializeField] private GameObject _enemyPrefab;
    
    private void Start()
    {
        Debug.Assert(_enemyPrefab != null, "Enemy prefab not assigned in inspector!");
    }
}

 

컴포넌트 참조 검증

public class PlayerController : MonoBehaviour
{
    private Rigidbody _rigidbody;
    
    private void Awake()
    {
        _rigidbody = GetComponent<Rigidbody>();
        Debug.Assert(_rigidbody != null, "PlayerController requires Rigidbody component!");
    }
}

 

메소드 매개변수 검증

public void Initialize(Player owner)
{
    Debug.Assert(owner != null, "WeaponSystem initialized with null owner!");
    _owner = owner;
}

 

동적 생성 객체 검증

public UIPanel CreatePanel(string panelName)
{
    GameObject panelObject = Instantiate(Resources.Load<GameObject>($"UI/{panelName}"));
    UIPanel panel = panelObject.GetComponent<UIPanel>();
    Debug.Assert(panel != null, $"Created UI panel '{panelName}' missing UIPanel component!");
    return panel;
}

 

리소스 로딩 검증

public GameObject LoadPrefab(string path)
{
    GameObject prefab = Resources.Load<GameObject>(path);
    Debug.Assert(prefab != null, $"프리팹을 찾을 수 없습니다: {path}");
    return prefab;
}

 

열거형 범위 검증

public void HandleWeaponType(WeaponType weaponType)
{
    Debug.Assert(Enum.IsDefined(typeof(WeaponType), weaponType), 
        $"Invalid weapon type: {weaponType}");
}

 

컬렉션 인덱스 검증

public Item GetItem(int index)
{
    Debug.Assert(index >= 0 && index < _items.Length, 
        $"Inventory index out of range: {index}");
    return _items[index];
}

 

상태 전이 검증

public void TransitionTo(GameState newState)
{
    Debug.Assert(_currentState != newState, 
        $"Attempting to transition to the same state: {newState}");
}

 

예시 템플릿: 검증을 활용한 코드 작성 예시

public class BestPracticeExample : MonoBehaviour
{
    [SerializeField] private GameObject _prefab;
    private Rigidbody _rigidbody;
    
    private void Awake()
    {
        // 1. 직렬화 객체 검증
        Debug.Assert(_prefab != null, $"{nameof(_prefab)} not assigned in {nameof(BestPracticeExample)}!");
        
        // 2. Required 컴포넌트 검증
        _rigidbody = GetComponent<Rigidbody>();
        Debug.Assert(_rigidbody != null, $"{nameof(BestPracticeExample)} requires Rigidbody component!");
    }
    
    public void Initialize(GameManager gameManager, int initialValue)
    {
        // 3. 싱글톤 및 매개변수 검증
        Debug.Assert(gameManager != null, $"{nameof(Initialize)} called with null {nameof(gameManager)}!");
        Debug.Assert(initialValue >= 0, $"{nameof(initialValue)} must be non-negative, got {initialValue}!");
    }
    
    private GameObject CreateObject(string objectName, ObjectType type)
    {
        // 4. 열거형 및 동적 생성 검증
        Debug.Assert(!string.IsNullOrEmpty(objectName), "CreateObject called with null or empty name!");
        Debug.Assert(Enum.IsDefined(typeof(ObjectType), type), $"Invalid ObjectType: {type}");
        
        GameObject newObject = Instantiate(_prefab);
        Debug.Assert(newObject != null, $"Failed to instantiate object of type {type}!");
        
        return newObject;
    }
}

 

리팩토링 예시

리팩토링 전

public class BeforeRefactor
{
    public void ProcessPlayer(Player player)
    {
        if (player == null) return;
        if (player.Weapon == null) return;
        if (player.Health <= 0) return;
        
        // 로직...
    }
}

 

리팩토링 후

public class AfterRefactor
{
    public void ProcessPlayer(Player player)
    {
        Debug.Assert(player != null, "ProcessPlayer called with null player!");
        Debug.Assert(player.Weapon != null, "Player weapon is null in ProcessPlayer!");
        Debug.Assert(player.Health > 0, "ProcessPlayer called with dead player!");
        
        // 로직...
    }
}
'유니티' 카테고리의 다른 글
  • 유니티에서 SerializeField를 사용하는 두 가지 방식
  • Unity Assembly Definition
  • DestroyImmediate 사용시 주의점
  • Rich Text와 예측 가능한 오류 방지
뇌장하드 주인장
뇌장하드 주인장
  • 뇌장하드 주인장
    뇌장하드
    뇌장하드 주인장
    • 분류 전체보기 (86)
      • C++ (9)
      • C# (15)
      • CS (9)
      • 유니티 (38)
      • 유니팁 (7)
      • 유니티 패턴 (8)
      • - (0)
  • 블로그 메뉴

    • 홈
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
뇌장하드 주인장
유니티에서 Debug.Assert() 베스트 프랙티스
상단으로

티스토리툴바