Matter.js를 이용한 웹 물리엔진 구현

류승찬·2024년 10월 1일
40

Study

목록 보기
1/1

Matter.js란?

웹 브라우저에서 물리엔진을 구현하기 위한 JavaScript 라이브러리이다.
HTML5 canvas를 기반으로, 그린 요소에 중력, 다른 요소와의 충돌, 드래그 기능 등을 추가 할 수 있다.

Matter.js 핵심 요소

Engine

  • 물리 시뮬레이션의 핵심으로, 물리 법칙에 따라 객체들의 움직임을 계산한다.
  • 엔진을 생성, 조작하는 방법이 포함되어 있다.
  • Matter.Engine 으로 선언한다.
  • Engine.create()를 통해서 엔진을 생성하고,
  • Engine.run(engine) 으로 실행할 수 있다.

Render

  • Engine으로 계산된 움직임들 시각화 한다. 즉, 각 요소(body)들의 움직임을 그려준다.
  • HTML5 canvas를 기반으로 렌더링을 한다.
  • Matter.Render 으로 선언한다.
  • wireframe(선만 따는 것), 스프라이트, 벡터 등 다양한 그리기 옵션을 제공한다.

Bodies

  • body 객체를 생성, 조작하는 방법이 포함되어 있다.
  • body란? render가 그리게 되는 요소이다.(Rectangle, Circle, SVG파일 등)
    즉, body는 물리엔진을 받는 물체이다.
  • body는 위치, 속도, 질량, 회전 등 다양한 속성을 가질 수 있다.
  • Bodies.rectangle(x,y,width,height,options); : 직사각형 바디를 생성한다(생성)
  • Bodies.setPosition(body,{ x:200, y:300 }); : 위치를 옮긴다(조작)

World

  • body 객체를 포함하는 공간이다. body 요소들은 world 위에서 표현된다.
  • engine.world에 자동으로 포함된다.
  • body를 추가하거나 제거할 수 있으며, world 자체의 속성을 설정 가능하다.
  • World.add(world, body); 월드에 body 객체 추가
  • world.gravity.x = 0 월드에 gravity x방향에 관한 속성 설정

Matter.js 사용해보기

이제 Matter.js와 리액트로 간단하게 웹사이트에서 중력, 드래그, 충돌 기능을 구현해보자.

시작을 위한 라이브러리 설치

npm i matter-js

기초설정(Canvas.js)

div를 선언하고 useRef로 div를 참조한다.
또한 사용하기 편하도록 Matter안의 모듈들을 다시 선언해주었다.

import React,{ useRef, useEffect } from 'react'
import Matter from 'matter-js'

function Canvas(){
    const canvasRef = useRef();
    
    useEffect(()=>{
        //기초 설정
        const Engine = Matter.Engine;
        const World = Matter.World;
        const Bodies = Matter.Bodies;
        const Render = Matter.Render;
        const engine = Engine.create(); //엔진 생성
        const world = engine.world;
      	const runner = Matter.Runner.create(); //러너도 만들어줘야함.
    })
    return(
        <div ref={canvasRef}>
      		//여기에 canvas 생성
        </div>
    );
}
export default Canvas;

렌더 설정 (useEffect 안)

//렌더 설정
        const render = Render.create({
            element: canvasRef.current,
            engine: engine,
            options: {
                width:800,
                height:600,
                wireframes:false, //색까지 칠하기
            }
        });

엔진 구동 및 렌더링

runner를 create 해야 하는줄 모르고 겁나 헤맸다..

//엔진 구동 및 렌더 진행
        Matter.Runner.run(runner,engine); //러너 추가해야함.
        Render.run(render);

모양, 위치가 랜덤인 바디 생성

//위치와 모양이 랜덤인 바디 6개 생성
        for(let i=0;i<=5;i++){
            let x = Math.random()*400+300;
            let y = Math.random()*150;
            let shape = (Math.random() <= 0.5) ? (Bodies.rectangle(x,y,40,40)):(Bodies.circle(x,y,40,40));
            World.add(world,shape);
        }

컴포넌트가 언마운트 될 때 초기화

return () => {
            Render.stop(render);
            World.clear(world, false);
            Engine.clear(engine);
            render.canvas.remove();
          }; // 컴포넌트가 unmount 될 때 초기화

여기까지 했다면 아래와 같은 화면이 나올 것이다.

이제 마우스로 드래그 하여 요소들을 움직여 보자.

//마우스 드래그 기능
        const mouse = Matter.Mouse.create(render.canvas) //마우스 객체 생성
        const mouseConstraint = 
              //마우스로 화면에서 바디를 클릭, 드래그 할 수 있도록 함
              Matter.MouseConstraint.create(engine,{ 
                mouse: mouse,
                constraint: {
                    stiffness: 0.2, // 탄성정도
                    render:{
                        visible: false //마우스 드래그 시 제약조건 보이기X
                    }
                }
            })
        World.add(world,mouseConstraint)
  • Matter.js의 Mouse 모듈을 사용하여 캔버스 위에 마우스 위치를 추적, 이벤트를 발생시킨다.
  • MouseConstraint : 드래그 시 마우스와 물체를 결합시키는 역할을 한다.

이제 실행을 시켜보자.

전체코드

import React,{ useRef, useEffect } from 'react'
import Matter from 'matter-js'

function Canvas(){
    const canvasRef = useRef();
    
    useEffect(()=>{
        //기초 설정
        const Engine = Matter.Engine;
        const World = Matter.World;
        const Bodies = Matter.Bodies;
        const Render = Matter.Render
        const engine = Engine.create(); //엔진 생성
        const world = engine.world;
        engine.gravity.y = 1.5;
        const runner = Matter.Runner.create();
        
        //렌더 설정
        const render = Render.create({
            element: canvasRef.current,
            engine: engine,
            options: {
                width:800,
                height:600,
                isStatic:false,
                wireframes:false, //색까지 칠하기
                background: "white"
            }
        });
        
        // 바닥&벽 만들고 world에 추가
        const ground = Bodies.rectangle(400,590,810,20,{isStatic:true});
        const wallLeft = Bodies.rectangle(0,300,30,600,{isStatic:true});
        const wallRight = Bodies.rectangle(800,300,30,600,{isStatic:true});
        World.add(world,[ground,wallLeft,wallRight]);


        //마우스 드래그 기능
        const mouse = Matter.Mouse.create(render.canvas) //마우스 객체 생성
        const mouseConstraint = Matter.MouseConstraint.create(engine,{ //마우스로 화면에서 바디를 클릭, 드래그 할 수 있도록 함
                mouse: mouse,
                constraint: {
                    stiffness: 0.2, // 탄성정도
                    render:{
                        visible: false //마우스 드래그 시 제약조건 보이기X
                    }
                }
            })
        World.add(world,mouseConstraint)



        //엔진 구동 및 렌더 진행
        Matter.Runner.run(runner,engine);
        Render.run(render);
        
        // 위치와 모양이 랜덤인 바디 6개 생성
        for(let i=0;i<=5;i++){
            let x = Math.random()*400+300;
            let y = Math.random()*150;
            let shape = (Math.random() <= 0.5) ? 
            (Bodies.rectangle(x,y,40,40)):(Bodies.circle(x,y,40,40));
            World.add(world,shape);
        }

        
        return () => {
            Render.stop(render);
            World.clear(world, false);
            Engine.clear(engine);
            render.canvas.remove();
          }; // 컴포넌트가 unmount 될 때 초기화

    },[]);
    return(
        <div ref={canvasRef}>
        </div>
    );
}
export default Canvas;

이번 포스팅에서는 간단한 예시를 만들며 Matter.js가 무엇이고 어떻게 적용하는지 알아보았다.

참고
Github-matter-js
velog-Matter.js로 브라우저에서 물리엔진 구현하기
tstory-Matter.js 맛보기

1개의 댓글

comment-user-thumbnail
2024년 10월 15일

우와 모션이 되게 부드럽네요!!

답글 달기