http://jsbin.com/qosigic/edit?html,js,output
소스는 이쪽.
게임과 같은 분야는 타이밍 처리가 매우 중요하기 때문에 UI를 갱신하는 무한 루프를 놓고 delta 시간을 얻어와서 처리하는 로직을 많이 쓰는데
이걸 Javascript 에서 할 땐 전통적으로 setTimeout 을 걸어놓은 함수를 재귀하는 식으로 썼는데 문제는 setTimeout(setInterval도 마찬가지)이 굉장히 부정확한 타이밍을 가지고 있었고 이를 보완하기 위해 requestAnimationFrame 이라는 것을 만들어 사용하기 시작했다.
문제는 역시 지원하지 않는 몇몇 브라우저(ex. IE < 10)들 때문에 안타깝게도 RxJS 5.x 의 defaultScheduler에선 setTimeout(https://github.com/Reactive-Extensions/RxJS/blob/6dac0365ad22f87a92197fc4dcee70e72a11ddbb/src/modular/scheduler/defaultscheduler.js#L119)을 쓰고 있는데
물론 권장하는 방식은 https://github.com/Reactive-Extensions/RxJS/tree/8fa95ac884181fb6cbff8ce7c1d669ffb190f5e4/examples/crop 의 예처럼 RequestAnimationFrameScheduler 를 사용하는 것이지만
RxLua 처럼 기본으로 타이머가 없고 외부패키지에 의존하는 환경도 있고해서
기본 RxJS 환경에서 직접 만들어보기로 했다.
Scope 을 위해 일단 function으로 감싸보았다.
그러면 Rx 에서 subscribe 일때 처리해야하는 부분은 어디일까?
실제로 UI를 갱신하는 ctx 부분일 것이다.
소스는 이쪽.
게임과 같은 분야는 타이밍 처리가 매우 중요하기 때문에 UI를 갱신하는 무한 루프를 놓고 delta 시간을 얻어와서 처리하는 로직을 많이 쓰는데
이걸 Javascript 에서 할 땐 전통적으로 setTimeout 을 걸어놓은 함수를 재귀하는 식으로 썼는데 문제는 setTimeout(setInterval도 마찬가지)이 굉장히 부정확한 타이밍을 가지고 있었고 이를 보완하기 위해 requestAnimationFrame 이라는 것을 만들어 사용하기 시작했다.
문제는 역시 지원하지 않는 몇몇 브라우저(ex. IE < 10)들 때문에 안타깝게도 RxJS 5.x 의 defaultScheduler에선 setTimeout(https://github.com/Reactive-Extensions/RxJS/blob/6dac0365ad22f87a92197fc4dcee70e72a11ddbb/src/modular/scheduler/defaultscheduler.js#L119)을 쓰고 있는데
물론 권장하는 방식은 https://github.com/Reactive-Extensions/RxJS/tree/8fa95ac884181fb6cbff8ce7c1d669ffb190f5e4/examples/crop 의 예처럼 RequestAnimationFrameScheduler 를 사용하는 것이지만
RxLua 처럼 기본으로 타이머가 없고 외부패키지에 의존하는 환경도 있고해서
기본 RxJS 환경에서 직접 만들어보기로 했다.
Scope 을 위해 일단 function으로 감싸보았다.
(function() {이게 아마 보통 requestAnimationFrame 을 사용하는 패턴일 것이다.
var canvas=document.getElementById('canvas1');
var ctx = canvas.getContext('2d');
var start = 0;
var step = function(timestamp) {
if (!start) start = timestamp;
var progress = timestamp - start;
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.fillText("legacy: "+progress.toFixed(2), 10,10);
window.requestAnimationFrame(step);
}
window.requestAnimationFrame(step);
})();
그러면 Rx 에서 subscribe 일때 처리해야하는 부분은 어디일까?
실제로 UI를 갱신하는 ctx 부분일 것이다.
(function() {
var canvas=document.getElementById('canvas1');
var ctx = canvas.getContext('2d');
var start = 0;
var step = function(timestamp) {
if (!start) start = timestamp;
var progress = timestamp - start;
/* 여기부터 */
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.fillText("legacy: "+progress.toFixed(2), 10,10);
/* 여기까지 */
window.requestAnimationFrame(step);
}
window.requestAnimationFrame(step);
})();
이 부분을 분리해보자.
가장 간단한 방법은 역시 Subject 로 만드는 방법이겠다.
가장 간단한 방법은 역시 Subject 로 만드는 방법이겠다.
stepSubject.subscribe(progress=>{
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.fillText("Rx Subjeect: "+progress.toFixed(2), 10,10);
});
이렇게 실제로 progess 가 넘어오는 것을 받는 subscribe 를 만들고
stepSubject 를 생성한 뒤 루프 안에서 stepSubject.next 에서 progress 를 건내주도록 하자.
scope을 생각했을 때 반복하는 step function이 Observable 안에 있으면 좋겠다 싶은 생각이 든다.
start 와 step을 Observable.create 안에 넣고 .next 로 쏘아보자. subscribe는 동일하다.
개인적으로는 이런 상황이라면 start 와 step 의 Observable 안에 scope 을 가지고 있는 후자를 더 추천한다.
stepSubject 를 생성한 뒤 루프 안에서 stepSubject.next 에서 progress 를 건내주도록 하자.
(function() {간단하다. 별로 크게 건들지 않고 분리를 했다.
var canvas=document.getElementById('canvas2');
var ctx = canvas.getContext('2d');
var stepSubject = new Rx.Subject();
var start = 0;
var step = function(timestamp) {
if (!start) start = timestamp;
var progress = timestamp - start;
stepSubject.next(progress);
window.requestAnimationFrame(step);
}
window.requestAnimationFrame(step);
stepSubject.subscribe(progress=>{
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.fillText("Rx Subjeect: "+progress.toFixed(2), 10,10);
});
})();
scope을 생각했을 때 반복하는 step function이 Observable 안에 있으면 좋겠다 싶은 생각이 든다.
start 와 step을 Observable.create 안에 넣고 .next 로 쏘아보자. subscribe는 동일하다.
(function() {이렇게 옮기면 Rx.Observable 안에서 requestAnimationFrame 을 제어할 수 있다.
var canvas=document.getElementById('canvas3');
var ctx = canvas.getContext('2d');
var stepObservable = Rx.Observable.create(observer=>{
var start = 0;
var step = function(timestamp) {
if (!start) start = timestamp;
var progress = timestamp - start;
observer.next(progress);
window.requestAnimationFrame(step);
}
window.requestAnimationFrame(step);
});
stepObservable.subscribe(progress=>{
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.fillText("Rx Observable: "+progress.toFixed(2), 10,10);
});
})();
개인적으로는 이런 상황이라면 start 와 step 의 Observable 안에 scope 을 가지고 있는 후자를 더 추천한다.
댓글
댓글 쓰기