티스토리 뷰
C#은 매우 강력한 기능인 Reflection을 사용할 수 있습니다.
Reflection을 한 마디로 정의하면 "런타임 때 컴파일 타임에 정의된 정보를 가져올 수 있는 기능"입니다.
설명만 보면 "이것이 정확히 어떤 의미인지, 어떤 상황에서 필요한 기능인지" 잘 이해하기 어렵습니다.
하지만 좀만 시간을 들여 파악해보면 이것이 무엇을 의미하는지 알 수 있고, 생각보다 활용할 수 있는 곳이 많다는 것을 알 수 있습니다.
이런 것이 가능한 이유는 닷넷 프레임 워크 용어 정리 포스팅에서 간단하게 설명했지만 C#으로 만들어진 EXE 파일은 CLR이라는 또 다른 프로그램에 의해 관리를 받고 있기 때문입니다.
예시
그럼 Reflection을 통해 어떤 것들을 할 수 있는지 예시를 통해 간단히 살펴보겠습니다.
설명 드릴 예제는 드릴로 땅을 파는 게임을 개발하던 도중 겪었던 상황이었습니다.
(예제에서는 Unity를 사용하고 있기에 Unity 관련 내용이 들어가 있지만, Reflection 자체를 이해하는데는 크게 어려움이 없을 겁니다.)
드릴은 아래 코드를 통해 미리 정의한 속도로 움직이고 있었습니다.
속도에 따라 플레이어가 느끼는 경험이 다르기 때문에, 값을 기획자가 세심하게 조절할 필요가 있었습니다.
물론 직접 값을 코드로 수정하거나, Unity Inspector에서 설정해도 원하는 바를 이룰 수 있습니다.
다만 이렇게 구현할 경우, 모바일로 테스트를 하면서 값을 변경하고 싶은 경우, 값을 변경한 후 모바일로 다시 빌드를 해서 테스트해야만 합니다.
테스트 -> 값 변경 -> 빌드 하는 번거로운 과정을 줄이기 위해 슬라이더 UI를 통해 게임 플레이 도중 값을 수정할 수 있는 기능을 만들었습니다.
Reflection 없이 해결
가장 먼저 한 일은 새로 Canvas와 Sample용 Slider를 하나 만들고 DrillUI라는 스크립트를 추가한 것입니다.
DrillUI 스크립트의 내부 코드는 아래와 같습니다.
위 코드에서 Awake 함수는 게임이 시작되면 자동으로 불리는 함수입니다. Awake 함수가 하는 일은 크게 4가지 입니다.
1) 게임에 존재하는 Drill 타입 객체를 가져와서 drill 변수에 할당해줍니다. (추후 drill을 사용하기 위해 필요)
2) 샘플 슬라이더를 이용해 슬라이더를 2개 생성합니다.
3) 2에서 만들어둔 Slider에 각각 값이 변경되었을 때 호출할 함수를 연결해줍니다. (호출할 함수들은 아래에 정의)
4) 기존 샘플 Slider를 삭제합니다.
OnChangedAccSlider와 OnChangedMaxSpeedSlider는 각각 유저가 슬라이더를 움직였을 때 호출되는 함수입니다.
하는 일은 슬라이더로 바꾼 값을 drill에 적용하는 것 뿐입니다.
이로써 유저는 인게임에서 슬라이더를 움직임으로써 캐릭터 속도를 여러 방식으로 테스트해볼 수 있었습니다.
다만, 위와 같이 구현한 경우 한 가지 문제가 있습니다. 그것은 바로 Drill에 다른 변수가 추가되고, 그 값 역시 기획자가 조절하고 싶은 경우에 추가할 코드가 꽤나 많다는 것입니다.
예를 들어 Drill이 회전하는 기능이 추가되었다고 생각해봅시다.
기획자는 Drill의 회전 속도를 조절하고 싶을 것이고, 그렇다면 프로그래머는
1) Drill에 RotSpeed라는 변수를 추가하고
2) DrillUI에 Slider를 하나 추가한 후
3) 해당 Slider 값이 변경되면 Drill의 RotSpeed 값을 변경하는 로직을 추가해야합니다.
이런 일이 빈번하지 않다면 상관 없지만 개발 도중에는 비일비재할 것입니다.
위와 같은 문제를 해결할 수 있는 방법이 바로 Reflection을 사용하는 것입니다.
Reflection을 통한 해결
포스트 가장 처음에 말했던 것처럼 Reflection은 "런타임 때 컴파일 타임에 정의된 정보를 가져올 수 있는 기능"입니다.
위 예제에서 가져올 "컴파일 타입에 정의된 정보"는 바로, 슬라이더로 컨트롤할 Drill의 속성 값입니다.
프로그래머는 단순히 어떤 값들이 슬라이더로 컨트롤할 Drill의 속성 값인지만 정해주면 됩니다.
그러면 코드를 통해
1) 슬라이더 생성
2) 생성된 슬라이더를 움직일 경우 알맞는 Drill의 속성 값 수정
을 할 수 있게 됩니다.
어떻게 위와 같은 기능이 구현되는지 코드를 통해 살펴보겠습니다.
먼저 해야할 일은 TestAttribute라는 Attribute를 추가하고, 슬라이더로 컨트롤할 Drill의 속성들에게 Attribute를 달아주는 것입니다. 아래 이미지 처럼 가속도와 최대 속도 변수에 TestAttribute를 추가합니다.
그 이후에는 DrillUI의 Awake 함수를 수정합니다.
변경된 Awake 함수가 하는 일은 크게 5가지입니다.
1) 게임에 존재하는 Drill 타입 객체를 가져와서 drill 변수에 할당해줍니다. (추후 drill을 사용하기 위해 필요)
2) Drill 클래스의 모든 필드를 가져옵니다.
3) Drill 클래스의 모든 필드를 순회하며 TestAttribute가 있는 필드들을 따로 모아둡니다.
예제에서는 Acc와 MaxSpeed 필드입니다.
4) 생성된 슬라이더들에 알맞는 Listener를 연결해줍니다.
Acc 슬라이더가 변경되면 Acc 값이 변경되게 하고, MaxSpeed 슬라이더가 변경되면 MaxSpeed 값이 변경되게 합니다.
5) 기존 샘플 Slider를 삭제합니다.
앞서 본 예제과 코드 수 차이는 얼마 없지만 이렇게 구현하면 변수가 추가되거나 했을 때의 대응이 훨씬 쉽습니다.
단순히 아래 이미지처럼 TestAttribute만 추가해주면 모든 기능이 그대로 동작하기 때문입니다.
1) Drill 클래스의 필드들을 가져오는 것
2) 필드에 특정 Attribute가 있는지 확인하는 것
3) 특정 인스턴스의 필드의 값을 변경하는 것 등의 기능이 모두 Reflection 기능입니다.
결국 포스트 처음에 설명한 것처럼 Reflection을 사용한다는 것은 런타임에 코드가 어떻게 구성되었는지에 대한 정보를 알 수 있는것이라고 볼 수 있습니다, 이 기능을 사용하면 예시처럼 매우 강력한 기능을 구현할 수 있습니다.
'프로그래밍' 카테고리의 다른 글
C#의 StackTrace (0) | 2021.08.27 |
---|---|
로슬린 MakeConst 튜토리얼 (1/2) (0) | 2021.08.27 |
C#의 Pass by reference와 ref, out, in 키워드 (1) | 2021.02.21 |
C#의 Pass by value (0) | 2021.02.14 |
C# Value Type과 Reference Type (1) | 2021.02.12 |
- Total
- Today
- Yesterday
- NDC
- SRP
- 참조 형식
- 루빅스큐브
- dynamic batching
- Mesh Processing
- RL
- Transformation
- MeshProcessing
- AABB
- 유니티
- 강화학습
- VTK
- RubiksCube
- reference type
- normalized device coordinate
- value type
- opengl
- CollisionDetection
- perspective projection
- batching
- Mesh
- static batching
- collision detection
- C#
- 값 형식
- Unreal
- Unity
- transform
- Scriptable Render Pipeline
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |