[React] React + Matter-js 를 이용한 수박게임 만들기 (1)

정수완·2024년 3월 16일
0

React

목록 보기
3/8
post-thumbnail

이번에 React 와 Matter-js를 이용해서 수박게임을 만들어 보겠습니다.

1. 수박게임

목표로 하는 화면입니다.
구현이 가능할 지 모르겠지만 최선을 다해보도록 하죠!


2. Matter-js

이번 수박게임 구현에 가장 큰 역할을 할 Matter-js 입니다.

Matter-js 는 2D 게임의 물리엔진 역할을 합니다.!

위의 GIF 처럼 다양한 기능들을 사용가능하게 해줍니다.


Matter-js 에서 제공하는 기본 동작 방법입니다.
이걸 참고해 React에서 사용가능하게 바꾸어 보겠습니다.


3. React 에서 사용하기

npm install matter-js 로 matter-js를 받아줍니다.

이후 사용을 위해 import 해줍니다.
import Matter from "matter-js"

이제 기본틀을 구현해 보겠습니다.

구현하고자 하는 기본 화면은 이렇습니다.


구현하기 위해서 useEffect 에 아래와 같은 코드를 작성해 주었습니다.

Matter - js 에서 제공하는 Engine, Render, World, Bodies 입니다.

  1. Engine 을 사용하기 위해 engine 변수로 선언하여 create 해줍니다.

    • 이는 물리엔진 역할을 하게 됩니다.
  2. render 역시 create로 선언하여 만들어줍니다.

    • render는 화면을 구성하게 됩니다. 또한 options로 크기, 높이, 배경색, 와이어프레임 유무를 설정해 주었습니다.

만약 와이어프레임을 유지한다면

이런 모습으로 왼쪽벽, 오른쪽벽, 바닥, 천장선 등이 구분되어 확실히 눈에 보이게 됩니다.


이제 왼쪽벽, 오른쪽벽, 바닥, 천장선을 각각 설정해 보겠습니다.

전부 useEffect 안에서 작성해 주었고, 색상과 isStatic 여부를 설정해 주었습니다.
만약 isStatic 이 true 라면 물리엔진에 의해 위에서 아래로 바닥이 떨어지게 됩니다.

또한 각각의 Bodies.rectangle( ,{}) 로 설정한 숫자들은 각각
X, Y, 너비, 높이 를 담당합니다.


아까 와이어 프레임에서 확인한 물체의 중심점이 X, Y 에 의해 설정되고 해당 물체의 너비와 높이가 각각 중심에서 퍼져나가는 형식입니다.


이제 이걸 World 에 추가하여 화면을 그려보겠습니다.

월드에 왼쪽벽, 오른쪽벽, 바닥, 천장선 을 추가해 주었고 Runner로 엔진을 동작시켜 주었습니다.
그리고 화면 렌더링을 실행해 주었습니다.

이제 이를 React와 연결해 주기 위해 useRef를 이용해 주었습니다.


전체를 감싸주는 containerRef 와 화면을 그릴 canvasRef 를 이용해 주었습니다.
전체를 감싼 div 태그 자식들을 가운데에 그리기 위해 align="center" 옵션도 넣어주었습니다.


4. 결과

원하던 대로 제대로 구현되었습니다.


5. 전체코드

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

export default function MatterGame () {
  const containerRef = useRef()
  const canvasRef = useRef()

  useEffect(() => {
    let Engine = Matter.Engine
    let Render = Matter.Render
    let World = Matter.World
    let Bodies = Matter.Bodies

    let engine = Engine.create()

    let render = Render.create({
      element: containerRef.current,
      engine: engine,
      canvas: canvasRef.current,
      options: {
        wireframes: false,
        width: 620,
        height: 850,
        background: "#F7F4C8"
      }
    })

    const leftWall = Bodies.rectangle(15, 395, 30, 790, {
      isStatic: true,
      render: { fillStyle: "#E6B143" }
    })

    const rightWall = Bodies.rectangle(605, 395, 30, 790, {
      isStatic: true,
      render: { fillStyle: "#E6B143" }
    })

    const ground = Bodies.rectangle(310, 820, 620, 60, {
      isStatic: true,
      render: { fillStyle: "#E6B143" }
    })

    const topLine = Bodies.rectangle(310, 150, 620, 2, {
      isStatic: true,
      render: { fillStyle: "#E6B143" }
    })

    World.add(engine.world, [leftWall, rightWall, ground, topLine])
    Matter.Runner.run(engine)
    Render.run(render)
  }, [])

  return (
    <div ref={containerRef} align="center">
      <canvas ref={canvasRef}></canvas>

    </div>
  )
}

0개의 댓글