Matter.js is a 2D physics engine for the web
Matter.js는 브라우저 환경에서 물리 엔진 구현을 위한 라이브러리입니다. canvas로 그린 요소에 대한 중력 및 충돌, 드래그를 이용한 조작 등을 구현할 수 있습니다.
Matter.Engine
으로 선언합니다.Matter.Render
로 선언합니다.먼저 canvas와 이를 감싼 container를 선언하고 useRef을 이용해 참조를 구성합니다.
import { useRef } from "react";
const Canvas = () => {
const containerRef = useRef<HTMLDivElement | null>(null);
const canvasRef = useRef<HTMLCanvasElement | null>(null);
return (
<section
ref={containerRef}
>
<canvas
ref={canvasRef}
id="viewport"
width="500"
height="500"
/>
</section>
);
};
export default Canvas;
이후 Matter.Bodies모듈을 통해 요소를 생성합니다. 사각형, 원, SVG, 이미지 등의 생성이 가능합니다.
const Bodies = Matter.Bodies;
const element = Bodies.rectangle(
x,
y,
width,
height
{
chamfer: {
radius: [10, 10] // border-radius 설정이 가능합니다.
},
render: {
fillStyle: "#fff",
sprite: {
texture: "/assets/main/logo.png", // 이미지를 입힐 수 있습니다.
xScale: 0.75,
yScale: 0.75,
},
},
restitution: 0.6, // 충격을 받으면 튀어오르는 정도를 조절합니다.
}
);
이제 이를 엔진을 통해 그려봅니다.
useEffect(() => {
const Engine = Matter.Engine;
const Render = Matter.Render;
const World = Matter.World;
const engine = Engine.create();
engine.gravity.y = 1.5; // 중력의 세기를 설정합니다.
const render = Render.create({
element: containerRef.current,
engine: engine,
canvas: canvasRef.current,
bounds: {
min: { x: 0, y: 0 },
max: { x: canvasWidth, y: canvasHeight },
},
options: {
showSeparations: true,
width: canvasWidth,
height: canvasHeight,
background: "",
wireframes: false,
},
});
// 마우스를 이용해 조작을 가능하게 해줍니다.
const mouse = Matter.Mouse.create(render.canvas),
mouseConstraint = Matter.MouseConstraint.create(engine, {
mouse: mouse,
constraint: {
stiffness: 0.2,
render: {
visible: false,
},
},
});
// 그릴 요소들을 world에 모읍니다.
World.add(engine.world, [
element,
mouseConstraint,
]);
Matter.Runner.run(engine); // 엔진을 구동합니다.
Render.run(render); // 렌더를 진행합니다.
Body.rotate(element, Math.PI / 6);
return () => {
Render.stop(render);
World.clear(engine.world, false);
Engine.clear(engine);
render.canvas.remove();
};
}, []);
구현이 완료되면 아래와 같이 아래로 떨어지는 요소를 확인할 수 있습니다.
만약 요소가 떨어져서 사라지는 것이 아닌 특정 지점에 고정하고 싶다면 아래에 벽을 만들어 떨어지지 않도록 막아야합니다.
좌/우/위/아래를 막을 벽을 세워줍니다.
// props: (x: number, y: number, width: number, height: number)
const floor = Bodies.rectangle(clientWidth / 2, clientHeight, clientWidth, 100, {
isStatic: true,
render: {
fillStyle: "#121212",
},
});
const floorLeft = Bodies.rectangle(0, clientHeight / 2, 50, clientHeight, {
isStatic: true,
render: {
fillStyle: "#121212",
},
});
const floorRight = Bodies.rectangle(clientWidth, clientHeight / 2, 50, clientHeight, {
isStatic: true,
render: {
fillStyle: "#121212",
},
});
const floorTop = Bodies.rectangle(clientWidth / 2, -10, clientWidth, 50, {
isStatic: true,
render: {
fillStyle: "#121212",
},
});
useEffect(()=>{
// ...
World.add(engine.world, [
// 벽을 world에 추가합니다.
floor,
floorLeft,
floorRight,
floorTop,
logo,
mouseConstraint,
]);
// ...
}, [])
이제 다음과 같이 특정 공간 안에 요소를 가둬 둘 수 있게됩니다.
만약 구현하고 싶은 대상을 찾아보고 싶다면 공식으로 지원하는 데모를 확인해 보실 수 있습니다.
Matter.js Demo · code by @liabru
여러가지 옵션들을 제공하며 직접 만져보면서 느낌을 확인해 볼 수 있습니다.
공식 깃허브를 통해 Matter.js를 사용해 만든 다양한 사이트 예시도 확인 가능합니다.
Google - Game of the Year
Fuse.kiwi – Interesting Internet
Patrick Heng - Creative Developer Portfolio
USELESS