핵심 정리
[SerializeField] private float moveSpeed = 5f;
[SerializeField] private Transform target;구조 이해
왜 SerializeField를 쓰는가
SerializeField는 private 필드를 인스펙터에 노출할 때 사용합니다. 외부 스크립트에서 무분별하게 값을 바꾸지 못하게 막으면서도, 디자이너가 값 조정은 할 수 있게 해줍니다. Unity에서는 캡슐화와 에디터 편의성을 동시에 챙길 때 가장 자주 쓰는 속성입니다.
Header와 함께 쓰는 패턴
[Header] 속성과 함께 쓰면 인스펙터에서 관련 필드를 그룹화해 가독성을 높일 수 있습니다. 여러 컴포넌트가 붙은 오브젝트에서 값을 찾아야 할 때 훨씬 편리합니다.
[Header("Combat")]
[SerializeField] private int maxHp = 100;
[SerializeField] private GameObject hitEffect;public 대신 SerializeField를 써야 하는 이유
public 필드로 선언하면 인스펙터에서는 보이지만, 다른 스크립트에서도 자유롭게 읽고 쓸 수 있어 코드 결합도가 높아집니다. [SerializeField] private로 선언하면 직렬화는 유지하면서 외부 접근을 차단할 수 있어, 의도하지 않은 값 변경 버그를 줄이는 데 도움이 됩니다.
체크포인트
| 선언 방식 | 인스펙터 | 외부 접근 |
|---|---|---|
public int hp; | 보임 | 가능 |
[SerializeField] private int hp; | 보임 | 불가 |
private int hp; | 안 보임 | 불가 |
| 값 종류 | 더 잘 맞는 선택 | 이유 |
|---|---|---|
| 디자이너가 조절할 설정값 | [SerializeField] private | 인스펙터 노출과 캡슐화를 같이 가져감 |
| 외부 스크립트가 읽어야 하는 상태 | private + 읽기 전용 프로퍼티 | 쓰기 경로를 제한할 수 있음 |
| 외부에서도 자유롭게 수정해야 하는 API | 명시적 프로퍼티/메서드 | 단순 public field보다 의도가 선명함 |
| 완전 내부 구현 세부값 | private | 인스펙터 노출이 필요 없음 |
주의할 점
인스펙터에서 보이는데 코드에서 null이면 연결이 빠진 것입니다. 프리팹과 씬 인스턴스의 연결을 각각 확인하세요.
// ❌ 연결 확인 없이 사용 — NullReferenceException
[SerializeField] private Transform target;
private void Update()
{
transform.LookAt(target); // target이 null이면 예외
}
// ✅ null 체크 또는 RequireComponent로 연결 강제
[SerializeField] private Transform target;
private void Update()
{
if (target != null)
transform.LookAt(target);
}
// ✅ public 대신 SerializeField 사용 — 외부 접근 차단
[SerializeField] private float moveSpeed = 5f; // 인스펙터에서 조정 가능, 외부 코드 접근 불가
public float moveSpeedPublic = 5f; // 인스펙터에서 보이고 외부에서도 변경 가능 (의도치 않은 수정 위험)public 필드가 편하다고 계속 열어 두면, 나중에 값 검증이나 side effect를 넣고 싶을 때 수정 경로를 통제하기 어려워집니다. 인스펙터 노출과 외부 API는 분리하는 편이 안전합니다.
// ❌ 인스펙터 편의 때문에 public으로 개방
public float moveSpeed = 5f;
// 다른 스크립트가 어디서든 값 변경 가능
// ✅ 인스펙터 노출과 외부 읽기 분리
[SerializeField] private float moveSpeed = 5f;
public float MoveSpeed => moveSpeed;참고 링크
2 sources