레슨 6 / 8·20분
커스텀 렌더링
Canvas API를 이용한 커스텀 렌더링
Matter.js의 기본 Render 모듈 대신 Canvas 2D API로 직접 물리 바디를 그릴 수 있습니다. 이를 통해 스프라이트, 파티클, 트레일 효과 등 기본 렌더러로는 불가능한 비주얼을 구현할 수 있습니다. Engine.update()를 호출하여 물리를 진행하고, requestAnimationFrame 루프에서 바디 위치를 읽어 직접 그립니다.
javascript
const { Engine, World, Bodies, Composite, Body } = Matter;
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
canvas.width = 800;
canvas.height = 600;
// 엔진만 생성 (기본 Render 사용 안 함)
const engine = Engine.create({
gravity: { x: 0, y: 1 },
});
// 바디 생성
const balls = [];
for (let i = 0; i < 10; i++) {
const ball = Bodies.circle(
100 + Math.random() * 600,
50 + Math.random() * 100,
15 + Math.random() * 15,
{
restitution: 0.7,
friction: 0.05,
label: 'ball-' + i,
}
);
balls.push(ball);
}
const ground = Bodies.rectangle(400, 590, 800, 20, { isStatic: true });
const wallL = Bodies.rectangle(0, 300, 20, 600, { isStatic: true });
const wallR = Bodies.rectangle(800, 300, 20, 600, { isStatic: true });
World.add(engine.world, [...balls, ground, wallL, wallR]);javascript
// ── 커스텀 렌더 루프 ──
const colors = ['#e74c3c', '#3498db', '#2ecc71', '#f39c12', '#9b59b6'];
const trails = new Map(); // 트레일 효과용 위치 기록
function render() {
// 물리 엔진 업데이트 (60fps 기준 ~16.67ms)
Engine.update(engine, 1000 / 60);
// 캔버스 초기화
ctx.fillStyle = 'rgba(26, 26, 46, 0.3)'; // 반투명으로 잔상 효과
ctx.fillRect(0, 0, canvas.width, canvas.height);
// 공 그리기
balls.forEach((ball, i) => {
const pos = ball.position;
const radius = ball.circleRadius;
const angle = ball.angle;
// 트레일 기록
if (!trails.has(ball.id)) trails.set(ball.id, []);
const trail = trails.get(ball.id);
trail.push({ x: pos.x, y: pos.y });
if (trail.length > 15) trail.shift();
// 트레일 그리기
ctx.beginPath();
trail.forEach((p, j) => {
ctx.globalAlpha = j / trail.length * 0.3;
ctx.beginPath();
ctx.arc(p.x, p.y, radius * 0.5, 0, Math.PI * 2);
ctx.fillStyle = colors[i % colors.length];
ctx.fill();
});
ctx.globalAlpha = 1.0;
// 메인 공 그리기
ctx.save();
ctx.translate(pos.x, pos.y);
ctx.rotate(angle);
// 그라데이션 효과
const gradient = ctx.createRadialGradient(
-radius * 0.3, -radius * 0.3, radius * 0.1,
0, 0, radius
);
gradient.addColorStop(0, '#ffffff');
gradient.addColorStop(1, colors[i % colors.length]);
ctx.beginPath();
ctx.arc(0, 0, radius, 0, Math.PI * 2);
ctx.fillStyle = gradient;
ctx.fill();
ctx.restore();
});
// 바닥 그리기
ctx.fillStyle = '#2c3e50';
ctx.fillRect(0, 580, 800, 20);
requestAnimationFrame(render);
}
render();- •Engine.update(engine, delta) — Render/Runner 없이 수동으로 물리 진행
- •body.position — 바디의 현재 위치 {x, y}
- •body.angle — 바디의 현재 회전 각도 (라디안)
- •body.circleRadius — 원형 바디의 반지름
- •body.vertices — 다각형 바디의 꼭짓점 배열
- •Canvas 2D API로 그라데이션, 트레일, 파티클 등 커스텀 비주얼 구현
- •requestAnimationFrame + Engine.update 조합으로 렌더 루프 구성
💡
커스텀 렌더링 시 ctx.fillRect에 반투명 색상을 사용하면 이전 프레임이 서서히 사라지는 잔상(trail) 효과를 쉽게 만들 수 있습니다. rgba의 알파값(0.1~0.3)을 조절하여 잔상의 길이를 변경하세요.