일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 | 31 |
- GIT
- AWS
- 리액트
- img upload
- PongWorld
- s3 upload
- 에러
- 리엑트 네이티브 아이콘
- 문자열 대소문자
- react native font
- aws bucket 정책
- 리액트 네이티브 에러
- react native picker
- firebase 라이브러리
- Project
- react native
- 백준
- js
- 문자열 대소문자 구별
- react native 개발
- fire base
- babel.config.js
- AWS Access Key
- React
- Access Key 생성
- react native 세팅
- react native CLI
- 리액트 네이티브
- Next.js
- error
- Today
- Total
밝을희 클태
탁구채 애니메이션 최적화: setInterval vs requestAnimationFrame, position vs transform 본문
탁구채 애니메이션 최적화: setInterval vs requestAnimationFrame, position vs transform
huipark 2024. 4. 5. 16:00문제
- 게임 플레이시 프레임 드랍이 일어남
원인
- setInterval() 사용 : 기존에 아래와 같이 60FPS설정을 setInterval()로 구현을 했다. 이 방법은 JavaScript 이벤트 루프 내에서 비동기적으로 실행되며 정확한 타이머주기를 보장하지 않는다. 지연이 누적되다 보면 프레임 드랍이 생긴다.
setInterval(() => {
if (isMovingUp) {
coor = Math.max(
parseInt(style.top) - 30,
this.myPingpongStick.offsetHeight / 2,
);
this.update(coor);
} else if (isMovingDown) {
coor = Math.min(parseInt(style.top) + 30, this.maxY);
this.update(coor);
}
}, 1000 / 60); // 60프레임으로 설정
- 리렌더링 : 탁구채의 위치를 변경할때 top, botton, left, right 등 position CSS 속성를 사용한다. 해당 속성은 다른 엘리먼트에 영향을 끼치기 때문에 리플로우, 리페인트가 발생하게 된다. 탁구채가 60프레임으로 움직이는데 1초에 60번씩 새로 화면을 그리게 되면서 환경에 따라 버벅이는 현상이 생긴다.
해결
- setInterval()대신 requestAnimationFrame()을 사용 : 브라우저가 렌더링 될 타이밍에 맞춰서 미리 함수를 예약을 해서 렌더링 주기에 맞는 부르더운 애니메이션을 구현 할 수 있다.
- position말고 transform속성을 이용 : 개발자 도구로 position과 translate를 각각 사용해서 성능을 확인해보면 position은 레이아웃 변경과 더불어 리페인트, 리플로우가 많이 일어난 것을 확인 할 수 있다. 그에 반해 translate는 레이아웃 변경 없이 깔끔한 상태를 볼 수 있다.
그리고 translate는 GPU를 사용하는데 position은 연산이 많아져도 CPU로만 연산을 수행해서 과부하가 올 수 있지만 translate는 연산을 할때 GPU를 사용한다 GPU는 그래픽 처리에 특화된 하드웨어로, 병렬 처리 능력이 뛰어나 많은 양의 계산을 빠르게 처리할 수 있다.
최종 코드 :
animatePaddleMovement() {
if (!this.rAF) {
const animate = () => {
if (isMovingUp || isMovingDown) {
const myStickRect = this.myPingpongStick.getBoundingClientRect();
if (isMovingUp) {
if (myStickRect.top - this.speed <= this.tableRect.top) {
this.currentPosY =
this.currentPosY - (myStickRect.top - this.tableRect.top);
} else this.currentPosY -= this.speed;
} else if (isMovingDown) {
if (myStickRect.bottom + this.speed >= this.tableRect.bottom) {
this.currentPosY =
this.currentPosY + (this.tableRect.bottom - myStickRect.bottom);
} else this.currentPosY += this.speed;
}
this.update();
this.myPingpongStick.style.transform = `translateY(${this.currentPosY}px)`;
this.rAF = requestAnimationFrame(animate.bind(this));
} else {
cancelAnimationFrame(this.rAF);
this.rAF = null;
}
};
this.rAF = requestAnimationFrame(animate.bind(this));
}
}
'PongWorld 프로젝트' 카테고리의 다른 글
requestAnimationFrame 프레임 레이트 조정하기 (0) | 2024.04.05 |
---|---|
인증되지 않은 유저 접근 막기 (0) | 2024.04.02 |
탁구채 속도가 환경에 따라 다르게 움직임(requestAnimationFrame) (0) | 2024.03.23 |
같은 경로의 이동을 막자 (0) | 2024.03.14 |
WebSocket 이 닫히면 재연결을 해보자 (0) | 2024.03.13 |