본문 바로가기
Laboratory

RPG Maker MV에서 루비의 alias 모방 방식을 대체할 방법이 있을까? -

by biud436 2020. 2. 3.

자바스크립트는 프로토타입 기반의 언어로 프로토타입 체인을 기반으로 상속을 흉내낸다. 핵심은 어떤 객체에서 특정 속성이나 함수를 찾을 때 상위 객체로 거슬러 올라가면서 탐색을 한다는 것이다. MV에서는 프로토타입에 연결된 함수의 링크를 바꾸는 방식으로 스크립트를 작성하게 된다.

  var alias_Window_Command_lineHeight = Window_Command.prototype.lineHeight;
  Window_Command.prototype.lineHeight = function() {
    return alias_Window_Command_lineHeight.call(this) - 18;
  };  

ES6의 클래스는 루비나 C#처럼 분할 정의가 되지 않기 때문에 재정의가 불가능하고, 따라서 프로토타입에 연결된 함수의 링크를 바꿔야 할 때가 많다. 프로토타입을 써야 하는 이유는 명확하다. 예를 들면, 자바스크립트에서는 상위 객체를 게임 실행 도중에도 변경할 수 있다.

class Window_CommandImpl extends Window_Command {
  lineHeight() {
    return 6;
  }
}

window.Window_Command = Window_CommandImpl;

그런데 ES6에 도입된 클래스는 닫힌 방식이기 때문에 한 번 정의하면 추가 정의할 수가 없다. 따라서 위와 같이 Window_Command를 상속 받는 Window_CommandImpl 클래스를 만들고, Window_CommandImpl를 상위 객체로 대체하는 방법을 써야 한다. 이 방법을 쓰게 되면 기존 함수와의 링크가 끊어지고 새로 만든 상위 객체로 새롭게 연결된다.

하지만 큰 문제 중 하나는 MV에서는 플러그인이 소스 파일보다 더 느리게 로드된다는 점에 있다. 따라서 플러그인보다 빨리 정의되는 객체라면 동작이 전혀 바뀌지 않게 된다. 반면 더 느리게 정의되거나 프로토타입 체이닝의 말단에 있는 객체라면 동작이 바뀌게 된다. 따라서 이 디자인 패턴은 메뉴나 메시지 플러그인처럼 플러그인보다 나중 시점에 있는 객체에서만 사용할 수 있다. 따라서 위 예시에 있는 Window_Command는 동작이 전혀 바뀌지 않게 된다. 하지만 다음 예제에 있는 Window_Gold의 경우에는 잘 동작하게 된다.

class Window_Gold2 extends Window_Gold {
     lineHeight() { 
       return 200; 
     }
}

window.Window_Gold = Window_Gold2;

차이는 생성되는 시점에 있다.Window_Gold는 특정 상황에서나 생성되므로 충분히 변경이 가능하다. 반면 Window_Command의 경우, 플러그인으로는 도저히 변경할 수 없는 시점에 할당되며 프로토타입 체이닝으로 연결까지 되어있다. 따라서 Window_Command를 변경할 땐 프로토타입에 연결된 함수 자체를 바꿔야 한다.