유니티 SerializeReference
이 글은 인프런
모듈식으로 개발하는 스킬 시스템를 보고 공부한 내용을 정리한 글입니다.
SerializeField란?
유니티에서는 내가 만든 클래스를 인스펙터창에 띄우고 싶다면 직렬화를 해야한다.
이때 보통 사용하는 것이 바로 SerializeField
이다.
보통은 다음과 같이 사용된다.
[Serializable]
public class Entity
{
public string name;
}
public class Test : MonoBehaviour
{
[SerializeField]
Entity entity;
}
위 코드는 인스펙터창에서 다음과 같이 보인다
위 예시를 보면 아무런 문제 없이 잘 작동하지만 상속과 관련된다면 불편한 점이 생기게 된다.
바로 다음 예시를 보자
[Serializable]
public class Entity
{
public string name;
}
// Entity를 상속받는 자식 클래스 2개를 정의
[Serializable]
public class Human : Entity
{
public float Attack;
}
[Serializable]
public class Zombie : Entity
{
public float defense;
}
// Entity 자료형의 변수에 각각 Human, Zombie객체를 담음
public class Test : MonoBehaviour
{
[SerializeField]
Entity humanEntity = new Human();
[SerializeField]
Entity zombieEntity = new Zombie();
}
위 코드에서는 추가적으로 Entity
클래스를 상속받는 Human클래스와 Zombie클래스를 새로 작성했다.
그 뒤 Entity
를 자료형으로 하는 humanEntity변수
와 zombieEntity변수
에 각각 Human,Zombie객체를 할당
했다.
하지만 결과 사진을 보면 보이다 싶이 인스펙터창에서 나타나는 변수들은 Entity의 필드들만 나타나게 된다.
이러한 문제를 해결하기 위해 사용하는 Attribute가 바로 SerializeReference이다.
SerializeReference란
SerializeReference는 클래스의 다형성을 지원하는 직렬화 Attribute이다.
이를 사용하면 자료형을 기준으로 직렬화 하지 않고 할당된 객체를 기준으로 직렬화하게 된다.
위의 예시코드를 다음과 같이 바꿨다.
[Serializable]
public class Entity
{
public string name;
}
[Serializable]
public class Human : Entity
{
public float Attack;
}
[Serializable]
public class Zombie : Entity
{
public float defense;
}
public class Test : MonoBehaviour
{
// 수정된 부분
[SerializeReference]
Entity humanEntity = new Human();
// 수정된 부분
[SerializeReference]
Entity zombieEntity = new Zombie();
}
위의 사진을 보면 알 수 있듯 SerializeField에서 발생했던 문제가 해결된 모습을 볼 수 있다.
결론
SerializeReference는 위 처럼 할당된 객체를 기준으로 직렬화 하기 때문에 상황에 맞게 다른 자식 객체를 할당
하여 유동적인 구성
이 가능하도록 한다.
추가적인 정보
SerializeReference의 불편한점이라고 한다면 인스펙터창에서 SerializeReference변수에 할당되는 객체를 바꾸는 기능은 따로 없다는 것이다.
이러한 불편함을 해결해주는 다른 사람이 만든 코드가 있다.
이 코드는 유니티 공식 기능이 아니므로 유니티가 업데이트됨에 따라 작동하지 않을 수 있다.
사용법
패키지를 다운받아 유니티에 적용한 뒤, SerializeReference된 변수에 SubclassSelector Attribute를 추가해주면 된다.
[Serializable]
public class Entity
{
public string name;
}
[Serializable]
public class Human : Entity
{
public float Attack;
}
[Serializable]
public class Zombie : Entity
{
public float defense;
}
public class Test : MonoBehaviour
{
[SerializeReference, SubclassSelector]
Entity Entity;
}
적용된 모습
Human 객체 적용
Zombie 객체 적용
알고가야할 문제점
이 기능 자체가 유니티에서 제공하는 기능은 아니기 떄문에 한 가지 문제점이 있다.
바로 SubclassSelector로 선언된 변수를 가지고 있는 다른 클래스 리스트에서 리스트 요소를 추가하면 얕은 복사
가 일어난다는 것이다.
말로 해서는 어려운데 바로 예시로 보면 다음과 같다.
[Serializable]
public class GameInf
{
[SerializeReference, SubclassSelector]
Entity entity;
}
public class Test : MonoBehaviour
{
public GameInf[] game;
}
이 경우에는 정말 따로 깊은 복사를 구현해주거나 subClassSelecter 변수를 재선택해줘야하는 번거로움이 있다.
댓글남기기