본문 바로가기

유니티 게임 개발 일지

[일지 / 개발] 4. Reverie 에 Undo 시스템 추가

한동안 방학을 맞아 Reverie 작업을 이것저것 하였는데, 귀찮은 나머지 일지 작성은 거의 못 했었다.

이번에 그래도 새로운 시스템 하나를 추가하게 되어 기념으로 일지를 써 본다.

 

Undo 시스템

z키를 꾹 누르고 있는 동안 게임을 이전 상태로 되감아 준다.

Baba is you, snakebird 등 턴제 퍼즐 게임에서는 이미 널리 사용되고 있는 시스템이다.

아직 연속적인 퍼즐 게임에서는 본 적은 없는데, 충분히 열심히 찾아보면 어딘가에는 있을지도....?

 

구현 방식

다행히도 게임 개발 초기여서, 구현을 위해 수정해야 할 내용이 그렇게 많지는 않았다.

 

1. 각 물체 관련 코드에서 물체의 State 를 결정해주는 값들을 모두 변수로 지정했다.

예: 위치, 색깔, 플레이 중인 애니메이션, 속도 등등... (물론 이미 변수인 것들이 많았다)

 

2. 이러한 변수를 감싸기 위한 wrapper class 인 RecordedVariable<T> 를 만들고, 변수들을 모두 이 클래스로 감쌌다.

예: bool isJumping;  =>  RecordedVariable<bool> isJumping;

 

3. RecordedVariable 은 자기 자신의 값이 수정되면 UndoManager 에 자동으로 (자신에 대한 reference, 과거의 변수값)이 두가지를 저장해 준다.

 

4. z를 누르면 UndoManager은 남아있는 기록 리스트를 뒤에서부터 적용한다. 고쳐야 할 변수에 대한 reference 와, 어떤 값으로 돌려놓아야 하는지가 모두 저장되어 있으므로 이것을 그대로 반영하면 된다.

 

이때 중요한 점은, RecordedVariable 로 감싸진 변수가 모두 과거 상태가 되면, 그 물체가 그 당시와 완전히 똑같게 동작해야 한다는 것이다. Animator.Play() 등등 유니티 함수의 적용은 변수와 무관하기 때문에, 이를 위해 변수 세팅과 함수 호출을 분리해서 관리해 둘 필요가 있다.

 

(예를 들어 Animator.Play("jumpAnimation") 이 불린 이후 아무리 RecordedVariable 이 과거로 돌아가도 플레이 중이었던 애니메이션까지 과거로 돌아가진 않는다.

따라서 RecordedVariable<string> curAnimation 을 만들고 대부분의 로직은 이 변수를 수정하게만 하고 Play() 함수를 호출하지는 않게 한다. 대신 FixedUpdate에서 항상 Animator.Play(curAnimation); 과 같이 함수 호출을 모두 한 번에 해 준다.

이런 코드 구조를 갖고 있다면 변수가 과거로 돌아가면 자동으로 올바른 애니메이션이 틀어진다.)