원문 보기
유니티에서 정적(static) 변수 사용하기
이 글은 유니티3D 엔진에서 스크립트를 작성할 때, 정적 변수를 사용하는 방법에 대해서 설명하는 글이다. 이 글에 나와있는 예제 스크립트는 C#으로 작성되었지만, 똑같은 가이드라인을 자바스크립트에서도 적용할 수 있다.
이들은 클래스에 속해 있는 변수이며, 클래스가 생성하는 객체에는 존재하지 않는다. 이것은 정적 변수가 특정 클래스의 객체에 상관없이, 같은 값을 유지한다는 것을 의미한다. 또, 클래스가 메모리에 있는 한, 항상 참조가 가능한 특성이 있다. 정적 변수는 클래스가 만들어지기 직전에, 그리고 다른 변수와 메소드보다 먼저 컴파일러에 의해서 초기화 된다. 이러한 사실이 유니티3D 스크립트에서는 어떤 의미를 가질까?
예를 들어: 한 씬에 50개의 적이 있고, 모든 적들은 Player의 Transform을 필요로 하는 A.I 스크립트를 가지고 있다고 생각 해보자. 각 적들의 Awake()에서 정적 변수를 사용하지 않는다고 했을 경우:
- public class EnemyBehaviour: MonoBehaviour
- {
- private Transform playerTransform;
- void Awake()
- {
- playerTransform = GameObject.FindWithTag("Player").GetComponent<Transform>();
- }
- void Update()
- {
- //do something based on the player's position
- if(playerTransform.postion.x>100)
- {
- //Do something
- }
- }
- }
딱 한번의 정적 변수를 사용하여, 위와 동일하기 위해서 'GameController'라는 이름의 스크립트를 만들었다.
Player의 Transform을 한번 얻고, 이 값을 정적 변수에 저장한다:
- public class GameController : MonoBehaviour
- {
- //creating a static variable
- public static Transform playerTransform;
- void Awake()
- {
- playerTransform = GameObject.FindWithTag("Player").GetComponent<Transform>();
- }
- }
그리고 나서, 적의 A.I가 Player의 캐릭터 위치를 알아야 할 때, 단지 다음과 같이 변수를 사용하면 된다.
- public class EnemyBehaviour: MonoBehaviour
- {
- void Update()
- {
- //acessing the static variable
- if(GameController.playerTransform.position.x > 100)
- {
- //Do something
- }
- }
- }
두번째 예제에서, Player의 Transform을 알기 위해 단 한번의 Awake()를 호출했는 반면에, 첫 번째 예제에서는 각 적마다 Awake()를 호출함으로써, 총 50번의 호출을 하였다.
유니티3D에서 정적변수는 언제 반드시 사용되어야 하는가?
이 뿐만 아니라, 게임의 룰에 관련된 기본형 변수 또한 정적 변수를 사용하는 좋은 예가 될 수 있는데, 간단히 예를 들면, 게임 점수, 플레이어의 체력, 게임의 상태(playing, paused, game over), 플레이어의 상태(respawning, alive, dead)같은 것을 말한다.
그렇다면 언제 정적 변수를 사용하지 말아야 하는가?
다른 방법이 없거나, 싱글톤 패턴을 구현하는 경우가 아니라면, 무슨 수를 써서라도 정적 변수의 사용을 피해야 한다.
다양한 스크립트에 있는 모든 객체의 참조를 정적 변수로 만드는 것은 그렇지 않는 것보다 더 쉽지만, 이는 이미 만들어진 클래스에 불필요한 코드 리펙토링을 초래할 수도 있다. 유니티에서, 정적 변수에 관련해서는, 적은 것이 많은 것보다 확실히 낫다.
스크립트의 시작부분에 항상 정적 변수의 값을 초기화 하자
- public class GameController : MonoBehaviour
- {
- /*creates a static variable to check if
- the main character has died*/
- public static bool isDead = false;
- void Update ()
- {
- //if the main character is dead
- if(isDead)
- {
- //Loads the 'Game Over' scene
- Application.LoadLevel("GameOver");
- }
- }
- }
위의 스크립트는 잘 작동하고, 메인 캐릭터가 죽은 다음, 유니티3D는 'GameOver' 씬을 로드할 것이다.
그리고, 다시 플레이하기 위해 게임 씬으로 돌아 왔을 때, 유니티3D는 즉시 'GameOver' 씬으로 바꾸어버릴 것이다. 정적 변수는 클래스 변수이고, 이 값은 클래스가 메모리에 존재하는 한 계속해서 유지 될 것이며, 이 말은 5번째 라인은 게임이 실행될 때 딱 한번 실행될 것이라는 의미이다.
위의 예제를 본 다면, isDead는 계속 true일 것이다. 만약 스크립트의 시작 부분에 isDead변수를 초기화하지 않는다면, 계속해서 이런 일이 발생할 것이다.
이를 방지하기 위해, 정적 변수는 Awake() 혹은 Start()에서 값을 초기화 해야 한다.
위의 예제를 다시 재작성해보면, 정적 변수는 Awake()에서 값이 false로 리셋될 것이다:
- public class GameController : MonoBehaviour
- {
- /*creates a static variable to check if
- the main character has died*/
- public static bool isDead = false;
- void Awake()
- {
- //resetting isDead value to 'false'
- isDead = false;
- }
- void Update ()
- {
- //if the main character is dead
- if(isDead)
- {
- //Loads the game over scene
- Application.LoadLevel("GameOver");
- }
- }
- }
위 스크립트는 우리가 예상한대로 정상적으로 작동할 것이다. 정적 변수는 스크립트의 앞부분에 초기화 해야한다는 것을 언제나 명심하자.
'유니티 개발 정보 > 프로그래밍' 카테고리의 다른 글
Singleton VS Static Class (0) | 2015.07.17 |
---|---|
New Unity Messaging System (0) | 2015.03.18 |
유니티에서 Static IEnumerator 호출하기 (0) | 2013.12.03 |
C#의 Virtual과 Abstract 속성(Property)에 대해서 (0) | 2013.11.12 |
유니티에서 싱글톤을 만드는 4가지 방법 (4) | 2013.11.12 |