Go๋ฏผ๋ณด๋‹ค Go

ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ์ž

Create

[Matter.js] What's the matter???

SleepingOff 2024. 6. 11. 11:51

๐Ÿพ๋“ค์–ด๊ฐ€๋ฉฐ

์š”์ฆ˜ ํ•œ์ฐธ ๊ณต๋ถ€์ค‘์ธ Matter.js์— ๋Œ€ํ•ด ์ •๋ฆฌํ•ด๋ณด๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ์•„์ง ์ œ๋Œ€๋กœ ์‚ฌ์šฉํ•˜์ง„ ๋ชป ํ•˜์ง€๋งŒ, GPT๋ž‘ ๋†€๋ฉด์„œ ๋ฐฐ์šฐ๊ณ  ์žˆ์–ด์„œ ์‚ผ๊ฐํ•จ์ˆ˜๋งŒ ๋จธ๋ฆฌ๋ฅผ ์‹ธ๋งค๋ฉด ๋˜๊ธฐ์—... ๊ธฐ๋ณธ์ ์ธ ๋‚ด์šฉ๋ถ€ํ„ฐ ์ •๋ฆฌ๋ฅผ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹คใ…Žใ…Ž  ์ •๋ฆฌํ•˜๋‹ค๋ณด๋‹ˆ ์š•์‹ฌ์ด ์ƒ๊ฒจ์„œ ์ง€๊ธˆ ๋งŒ๋“ค๊ณ  ์žˆ๋˜ ์ธํ˜•๋ฝ‘๊ธฐ ์ง‘๊ฒŒ๊นŒ์ง€ ๊ฐ™์ด ์ฒจ๋ถ€ํ•ฉ๋‹ˆ๋‹ค!

Matter.js ๊ณต์‹ ๋ฌธ์„œ ๋ฐ”๋กœ๊ฐ€๊ธฐ > https://brm.io/matter-js/?utm_source=cdnjs&utm_medium=cdnjs_link&utm_campaign=cdnjs_library

โœจ๋ณธ๊ฒฉ์ ์œผ๋กœ

โœ…CDN์œผ๋กœ ์‹œ์ž‘ํ•ด๋ณด์ž

CDN.js๋ผ๋Š” ์‚ฌ์ดํŠธ์—์„œ Matter.js์— ๋Œ€ํ•œ CDN์„ ์ž˜ ์ œ๊ณตํ•ด์ฃผ์–ด ํ•ด๋‹น CDN์„ ์‚ฌ์šฉํ•˜์˜€์Šต๋‹ˆ๋‹ค.

<script
      src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.19.0/matter.js"
      integrity="sha512-rsntMCBgWYEWKl4HtqWmQ3vdHgvSq8CTtJd19YL7lCtKokLPWt7UEoHVabK1uiNfUdaLit8O090no5BZjcz+bw=="
      crossorigin="anonymous"
      referrerpolicy="no-referrer"
    ></script>

โœ…๊ณต์‹๋ฌธ์„œ์˜ ์ƒํƒœ๊ฐ€...

React์˜ ์ฃผ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค์˜ ๊ณต์‹๋ฌธ์„œ๋งŒ ๋ณด๋‹ค๊ฐ€ Matter.js์˜ ๊ณต์‹๋ฌธ์„œ๋ฅผ ๋ณด๋‹ˆ ์˜ˆ์‹œ์ฝ”๋“œ๊ฐ€ ์—†๊ณ  ์˜ต์…˜์— ๋Œ€ํ•œ ์„ค๋ช…๋„ ๋ถˆ์นœ์ ˆํ•˜๊ณ ... ๋ญ๋งŒ ํ•˜๋ฉด ๊นƒํ—ˆ๋ธŒ๋กœ ์—ฐ๊ฒฐํ•ด์„œ ์ง์ ‘ ์ฐพ์•„์•ผ๋˜๋Š” ๋ถˆํŽธํ•จ์ด ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์ด๋ฒˆ์—” ChatGPT(์ง€ํ”ผํ‹ฐ)๋ฅผ ์ข€ ๋” ํ™œ์šฉํ•ด๋ณด๊ธฐ๋กœ ํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ๊ธ€์„ ์“ฐ๋‹ค๊ฐ€ ๋ฐœ๊ฒฌํ•œ ์ปค๋ฎค๋‹ˆํ‹ฐ! - Matter.js์˜ ๊นƒํ—ˆ๋ธŒ ์œ„ํ‚ค๋ฅผ ๋ณด์‹œ๋ฉด ๋” ๋งŽ์€ ์ปค๋ฎค๋‹ˆํ‹ฐ ๋งํฌ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค!

webflow: https://webflow.com/made-in-webflow/matterjs

์ปค๋ฎค๋‹ˆํ‹ฐ์—์„œ ๋น„์Šทํ•œ ์˜ˆ์‹œ๋ฅผ ์ฐพ์•„ ์‹œ๋„ํ•ด๋ณด๋Š” ๊ฒƒ๋„ ์ข‹์„ ๋“ฏ ํ•ฉ๋‹ˆ๋‹ค! ์ „ ์‚ฌ์‹ค ์ฝ”๋“œํŽœ์—์„œ ์˜ˆ์ œ ์ฐพ์€ ๊ฒŒ ๋„์›€์ด ํฝ๋‹ˆ๋‹ค.

โœ…์‹œ์ž‘ํ•˜๊ธฐ

Matter.js๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์—ฌ๋Ÿฌ ๋ชจ๋“ˆ๋“ค์„ ๋ถˆ๋Ÿฌ์™€์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ •๋ง ๋งŽ์€ ๋ชจ๋“ˆ์„ ๋ถˆ๋Ÿฌ์™€์•ผ ํ•ด์„œ ๊ทธ๋Ÿฐ์ง€, ํŒŒ์ผ์„ ๋ถ„๋ฆฌํ•ด์„œ ์‚ฌ์šฉํ–ˆ์„ ๋•Œ ์ข€ ํ—ท๊ฐˆ๋ ธ์Šต๋‹ˆ๋‹ค.

// module aliases
export const Engine = Matter.Engine,
  Render = Matter.Render,
  Bodies = Matter.Bodies,
  Body = Matter.Body,
  Mouse = Matter.Mouse,
  Events = Matter.Events,
  Composite = Matter.Composite,
  Runner = Matter.Runner,
  Constraint = Matter.Constraint,
  MouseConstraint = Matter.MouseConstraint;

๋ถˆ๋Ÿฌ์˜จ ๋ชจ๋“ˆ์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๊ฐ€์žฅ ๋จผ์ € create()์— ์˜ต์…˜๋“ค์„ ๋„ฃ์–ด์„œ(ํ˜น์€ ๋น„์›Œ๋†“๊ณ ) ๋ณ€์ˆ˜๋ฅผ ์„ ์–ธํ•ด์ค๋‹ˆ๋‹ค. new ์—ฐ์‚ฐ์ž๋ฅผ ๋Œ€์‹ ํ•˜๋Š” ๋“ฏ ํ•ฉ๋‹ˆ๋‹ค.

์˜ต์…˜๋“ค์— ๋Œ€ํ•œ ์„ค๋ช…์€ ๊ณต์‹๋ฌธ์„œ๋ณด๋‹ค๋Š” ๊นƒํ—ˆ๋ธŒ ์ฝ”๋“œ์—์„œ ๋ณด๋Š” ๊ฒƒ์„ ์ถ”์ฒœํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ์€ Body ๋ชจ๋“ˆ์˜ create ์˜ต์…˜์„ ๋ณผ ์ˆ˜ ์žˆ๋Š” ๋งํฌ์ž…๋‹ˆ๋‹ค.
https://github.com/liabru/matter-js/blob/0b131a499c7479cab246d5d31c2a547dbc8b79eb/src/body/Body.js#L39

ํŒŒ์ผ ๊ฒฝ๋กœ๋Š” src/* ์ด๋ฉฐ, ํŒŒ์ผ๋ช…์ด ๋ชจ๋“ˆ์ด๋ฆ„๊ณผ ๊ฐ™์•„ ๊ธˆ๋ฐฉ ์ฐพ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด์— ๋Œ€ํ•œ ๊ธฐ๋ณธ์ ์ธ ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.

//html์˜ ํŠน์ • ์š”์†Œ๊ฐ€ ๋  ์ˆ˜๋„ ์žˆ์ง€๋งŒ, canvas๊ฐ€ ๋ฌด๋‚œ.
const canvas = document.querySelector("canvas");

// create an engine
export const engine = Engine.create();

export const canvasHeight = 500, canvasWidth = 500;

// create a renderer
//render์˜ ์˜ต์…˜์œผ๋กœ canvas๋ฅผ ๋„ฃ๊ฑฐ๋‚˜, html์š”์†Œ๋ผ๋ฉด elem ์˜ต์…˜์— ๋„ฃ์ž.
export const render = Render.create({
  canvas: canvas,
  engine: engine,
  options: {
    width: canvasWidth,
    height: canvasHeight,
    wireframes: false, //์—ฌ๋Ÿฌ ์ƒ‰์„ ์น ํ•œ ์ƒ์ž๋“ค์ด ๋‚˜์˜จ๋‹ค.
  },
});

export const runner = Runner.create();
Render.run(render);
Runner.run(runner, engine);

// Add mouse control
const mouse = Mouse.create(render.canvas);
const mouseConstraint = MouseConstraint.create(engine, {
  mouse: mouse,
  constraint: {
    stiffness: 0.2,
    render: {
      visible: false,
    },
  },
});

Composite.add(engine.world, mouseConstraint);

//code..

//render์˜ ๋งˆ์šฐ์Šค์™€ ์‹ค์ œ ๋งˆ์šฐ์Šค๋ฅผ ์—ฐ๋™
//์˜ˆ์‹œ์—์„œ ์ฝ”๋“œ์˜ ๊ฐ€์žฅ ๋งˆ์ง€๋ง‰์— ๋„ฃ๋Š”๋‹ค.
render.mouse = mouse;

โœ…๊ฐ ๋ชจ๋“ˆ์— ๋Œ€ํ•ด ์•Œ์•„๋ณด์ž

๋‹จ์ˆœํžˆ ์˜ˆ์‹œ๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒŒ ์•„๋‹Œ Matter.js์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๊ธฐ๋กœ ํ–ˆ์œผ๋‹ˆ ๊ฐ ๋ชจ๋“ˆ๋“ค์ด ์–ด๋–ค ์—ญํ• ์„ ํ•˜๋Š”์ง€ ์•Œ์•„๋ณด๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.
์ฃผ์š” ๋ชจ๋“ˆ์€ ์ง„ํ•˜๊ฒŒ ํ‘œ์‹œํ•œ ๊ธ€์”จ๋“ค์ž…๋‹ˆ๋‹ค.

๋ชจ๋“ˆ ์„ค๋ช… - ๊ณต์‹๋ฌธ์„œ ์ฐธ๊ณ  / ๋ฒˆ์—ญ: ์ง€ํ”ผํ‹ฐ
Engine ์„ธ๊ณ„ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ ์—…๋ฐ์ดํŠธ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ์ปจํŠธ๋กค๋Ÿฌ. ์—”์ง„ ์ƒ์„ฑ ๋ฐ ์กฐ์ž‘์„ ์œ„ํ•œ ๋ฉ”์†Œ๋“œ๋“ค์„ ํฌํ•จ.
์ฐธ๊ณ  :Runner
Render Engine์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์‹œ๊ฐํ™”ํ•˜๊ธฐ ์œ„ํ•œ ๊ฐ„๋‹จํ•œ ์บ”๋ฒ„์Šค ๊ธฐ๋ฐ˜ ๋ Œ๋”๋Ÿฌ.
๊ฐœ๋ฐœ ๋ฐ ๋””๋ฒ„๊น… ๋ชฉ์ ์œผ๋กœ ์‚ฌ์šฉ๋˜์ง€๋งŒ ๊ฐ„๋‹จํ•œ ๊ฒŒ์ž„์—๋„ ์ ํ•ฉ.
์™€์ด์–ดํ”„๋ ˆ์ž„, ์Šคํ”„๋ผ์ดํŠธ ๋ฐ ๋ทฐํฌํŠธ ์ง€์›์„ ํฌํ•จํ•œ ๋‹ค์–‘ํ•œ ๊ทธ๋ฆฌ๊ธฐ ์˜ต์…˜์ด ํฌํ•จ.
Runner ๋ธŒ๋ผ์šฐ์ € ๋‚ด์—์„œ Engine์„ ์ง€์†์ ์œผ๋กœ ์—…๋ฐ์ดํŠธํ•˜๋Š” ๊ฒŒ์ž„ ๋ฃจํ”„๋ฅผ ์ œ๊ณตํ•˜๋Š” ์„ ํƒ์  ์œ ํ‹ธ๋ฆฌํ‹ฐ.
๊ฐœ๋ฐœ ๋ฐ ๋””๋ฒ„๊น… ๋ชฉ์ ์œผ๋กœ ๊ณ ์•ˆ๋˜์—ˆ์ง€๋งŒ ๊ฐ„๋‹จํ•œ ๊ฒŒ์ž„์—๋„ ์ ํ•ฉ.
์ž์ฒด ๊ฒŒ์ž„ ๋ฃจํ”„๋ฅผ ์‚ฌ์šฉ ์ค‘์ด๋ผ๋ฉด Runner ๋Œ€์‹ ์— Engine.update(engine, delta)๋ฅผ ์ž์ฒด ๋ฃจํ”„์—์„œ ํ˜ธ์ถœ.
Bodies ์ง์‚ฌ๊ฐํ˜•, ์› ๋ฐ ๋‹ค๋ฅธ ๋‹ค๊ฐํ˜•๊ณผ ๊ฐ™์€ ์ผ๋ฐ˜์ ์œผ๋กœ ์‚ฌ์šฉ๋˜๋Š” ๋ฐ”๋”” ๊ตฌ์„ฑ์„ ๊ฐ–๋Š” ๊ฐ•์ฒด ๋ฐ”๋”” ๋ชจ๋ธ์„ ๋งŒ๋“œ๋Š” ํŒฉํ† ๋ฆฌ ๋ฉ”์„œ๋“œ
Body ๊ฐ•์ฒด ๋ฐ”๋””๋ฅผ ๋งŒ๋“ค๊ณ  ์กฐ์ž‘ํ•˜๋Š” ๋ฉ”์„œ๋“œ๊ฐ€ ํฌํ•จ
Composite Body, Constraint ๋ฐ ๋‹ค๋ฅธ Composite ๊ฐ์ฒด์˜ ๋ชจ์Œ.
๋ฌผ๋ฆฌ์ ์œผ๋กœ ์—ฐ๊ฒฐ๋˜์–ด ์žˆ์ง€ ์•Š๋”๋ผ๋„ ์—ฌ๋Ÿฌ ๋ถ€๋ถ„์œผ๋กœ ๊ตฌ์„ฑ๋œ ๋ณตํ•ฉ ๊ฐ์ฒด๋ฅผ ๋‚˜ํƒ€๋‚ผ ์ˆ˜ ์žˆ๋Š” ์ปจํ…Œ์ด๋„ˆ.
์ปดํฌ์ง€ํŠธ์—๋Š” ํ•˜๋‚˜์˜ ๋ณธ์ฒด์—์„œ๋ถ€ํ„ฐ ์ „์„ธ๊ณ„๊นŒ์ง€ ๋ชจ๋“  ๊ฒƒ์ด ํฌํ•จ.
์ปดํฌ์ง€ํŠธ๋ฅผ ์ˆ˜์ •ํ•  ๋•Œ๋Š” ์†์„ฑ์„ ์ง์ ‘ ์ˆ˜์ •ํ•˜๋Š” ๋Œ€์‹  ํฌํ•จ๋œ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉ
Composites ์Šคํƒ ๋ฐ ์ฒด์ธ๊ณผ ๊ฐ™์€ ์ผ๋ฐ˜์ ์œผ๋กœ ์‚ฌ์šฉ๋˜๋Š” ๊ตฌ์„ฑ์œผ๋กœ ๋ณตํ•ฉ ๋ฐ”๋””๋ฅผ ๋งŒ๋“œ๋Š” ํŒฉํ† ๋ฆฌ ๋ฉ”์„œ๋“œ
Constraint ์ œ์•ฝ ์กฐ๊ฑด์„ ์ƒ์„ฑํ•˜๊ณ  ์กฐ์ž‘ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๋Š” ๋ฉ”์„œ๋“œ๊ฐ€ ํฌํ•จ.
๋‘ ๊ฐœ์ฒด(๋˜๋Š” ๊ฐœ์ฒด์™€ ๊ณ ์ •๋œ ์›”๋“œ ๊ณต๊ฐ„ ์œ„์น˜) ์‚ฌ์ด์— ๊ณ ์ •๋œ ๊ฑฐ๋ฆฌ๋ฅผ ์œ ์ง€ํ•ด์•ผ ํ•จ์„ ์ง€์ •ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ.
๊ฐ•์„ฑ์€ ์Šคํ”„๋ง์ด๋‚˜ ํƒ„์„ฑ์„ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ์ˆ˜์ • ๊ฐ€๋Šฅ.
Mouse ๋งˆ์šฐ์Šค ์ž…๋ ฅ์„ ์ƒ์„ฑํ•˜๊ณ  ์กฐ์ž‘ํ•˜๋Š” ๋ฉ”์„œ๋“œ๊ฐ€ ํฌํ•จ
MouseConstraint ์‚ฌ์šฉ์ž ์ƒํ˜ธ ์ž‘์šฉ์„ ํ—ˆ์šฉํ•˜๊ณ  ๋งˆ์šฐ์Šค ๋˜๋Š” ํ„ฐ์น˜๋ฅผ ํ†ตํ•ด ์‹ ์ฒด๋ฅผ ์ด๋™์‹œํ‚ค๋Š” ๊ธฐ๋Šฅ์„ ์ œ๊ณต
Events ๋‹ค๋ฅธ ๊ฐ์ฒด์—์„œ ์ด๋ฒคํŠธ๋ฅผ ๋ฐœ์ƒ ๋ฐ ๋ฆฌ์Šค๋‹
Common ๋ชจ๋“  ๋ชจ๋“ˆ์— ๊ณตํ†ต์ ์œผ๋กœ ์‚ฌ์šฉ๋˜๋Š” ์œ ํ‹ธ๋ฆฌํ‹ฐ ํ•จ์ˆ˜๊ฐ€ ํฌํ•จ
Plugin ๋ชจ๋“ˆ์— ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ๋“ฑ๋กํ•˜๊ณ  ์„ค์น˜ํ•˜๋Š” ๊ธฐ๋Šฅ์ด ํฌํ•จ
Bounds ์ถ•์ธ ์ถ•์— ๋งž์ถ˜ ๋ฐ”์šด๋”ฉ ๋ฐ•์Šค(AABB)๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์กฐ์ž‘ํ•˜๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ํฌํ•จ
Collision ์ฃผ์–ด์ง„ ๋‘ ๋ฐ”๋”” ์Œ ์‚ฌ์ด์˜ ์ถฉ๋Œ์„ ๊ฐ์ง€ํ•˜๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ํฌํ•จ. ์ฐธ๊ณ : Detecto, Query
Contact ์ถฉ๋Œ ์ ‘์ด‰์„ ๋งŒ๋“ค๊ณ  ์กฐ์ž‘ํ•˜๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ํฌํ•จ
Detector ๋„“์€ ๋ฒ”์œ„ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ชธ์ฒด ๋ชฉ๋ก ๊ฐ„์˜ ์ถฉ๋Œ์„ ํšจ์œจ์ ์œผ๋กœ ๊ฐ์ง€ํ•˜๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ํฌํ•จ
Matter ์ตœ์ƒ์œ„ ๋„ค์ž„์ŠคํŽ˜์ด์Šค. ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์œ„์— ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์„ค์น˜ํ•˜๋Š” ํ•จ์ˆ˜๋„ ํฌํ•จ
Pair ์ถฉ๋Œ ์Œ์„ ๋งŒ๋“ค๊ณ  ์กฐ์ž‘ํ•˜๋Š” ๋ฉ”์„œ๋“œ๊ฐ€ ํฌํ•จ
Pairs ์ถฉ๋Œ ํŽ˜์–ด ์„ธํŠธ๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์กฐ์ž‘ํ•˜๋Š” ๋ฉ”์†Œ๋“œ๊ฐ€ ํฌํ•จ
Query ์ถฉ๋Œ ์ฟผ๋ฆฌ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐฉ๋ฒ•
Resolver ์ถฉ๋Œ ์Œ์„ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ํฌํ•จ
Sleeping ๊ฐœ์ฒด์˜ ํœด๋ฉด ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ๋ฉ”์†Œ๋“œ๊ฐ€ ํฌํ•จ
Svg SVG ์ด๋ฏธ์ง€๋ฅผ ๋ฒกํ„ฐ ํฌ์ธํŠธ ๋ฐฐ์—ด๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ๋ฉ”์†Œ๋“œ๊ฐ€ ํฌํ•จ. SVGPathSeg ํด๋ฆฌํ•„๋„ ํ•„์š”
Vector ๋ฒกํ„ฐ๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์กฐ์ž‘ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ํฌํ•จ.
๋ฒกํ„ฐ๋Š” ์—”์ง„์˜ ๋ชจ๋“  ํ˜•์ƒ ๊ด€๋ จ ์ž‘์—…์˜ ๊ธฐ์ดˆ๋กœ ๊ฐœ์ฒด Matter.Vector์˜ ํ˜•์‹์€ { x: 0, y: 0 }.
Vertices Matter.Vector์—์„œ ์‚ฝ์ž…ํ•œ ์ถ”๊ฐ€ ์ธ๋ฑ์‹ฑ ์†์„ฑ์ด ์žˆ๋Š” ๋ฐฐ์—ด.
์ •์  ์„ธํŠธ๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์กฐ์ž‘ํ•˜๊ธฐ ์œ„ํ•œ ๋ฉ”์„œ๋“œ๊ฐ€ ํฌํ•จ.

์ œ๊ฐ€ ์ดํ•ดํ•œ ๋ฐ”๋ก ,

Engine์ด ๊ธฐ๋ณธ ๋ฒ ์ด์Šค๋กœ Render์™€ Runner๊ฐ€ ๋„์™€์ฃผ๋Š” ์—ญํ• ์„ ํ•˜๋ฉฐ, Engine์— Composite๋ฅผ ์ƒ์„ฑํ•˜๊ณ , Composite๋Š” Bodies๋กœ ์ƒ์„ฑํ•œ ๋ชจ๋ธ๋“ค, Constraint ๋“ฑ์ด ๋“ค์–ด์žˆ์œผ๋ฉฐ, Events๋กœ ์ด๋ฒคํŠธ๋ฅผ ๋ฐœ์ƒํ•˜๊ณ , Mouse์™€ MouseConstraint๋กœ ๋งˆ์šฐ์Šค ์ž…๋ ฅ์„ ์กฐ์ ˆํ•œ๋‹ค

์ž…๋‹ˆ๋‹ค.

์•„์ง ์ฝ”๋“œ๋งŒ ๋ณด๊ณ ๋Š” ์ •ํ™•ํžˆ ์–ด๋–ค ์›๋ฆฌ๋กœ ๋™์ž‘ํ•˜๋Š”์ง€ ์ž˜ ๋ชจ๋ฅด๊ธฐ ๋•Œ๋ฌธ์— ๋Œ€๋žต ์ ๋Š” ๊ฒƒ์ด ์•„์‰ฝ์Šต๋‹ˆ๋‹ค...

โœ…์ง์ ‘ ๋งŒ๋“ค์–ด๋ณผ๊นŒ?

๊ฐ„๋‹จํ•˜๊ฒŒ Constraint๋ฅผ ์‚ฌ์šฉํ•ด ์—ฐ๊ฒฐํ•˜์—ฌ ์ธํ˜•๋ฝ‘๊ธฐ ์ง‘๊ฒŒ๋ฅผ ๋งŒ๋“ค์–ด๋ณด์•˜์Šต๋‹ˆ๋‹ค. 

๊ฐ„๋‹จํ•œ ์ธํ˜•๋ฝ‘๊ธฐ ์ง‘๊ฒŒ

์‚ฌ์‹ค ์ด๊ฑธ ๋งŒ๋“ ๋‹ค๊ณ  ์ง€ํ”ผํ‹ฐ์™€ 3์‹œ๊ฐ„์”ฉ 5์ผ ๋™์•ˆ ๊ณ ์ƒ์„ ํ–ˆ์ง€๋งŒ,,, ๊ฒฐ๊ตญ ์—Ž๊ณ  ํ•˜๋ฃจ๋งŒ์— ๋‹ค์‹œ ๋งŒ๋“ค์—ˆ๋˜ ์ถ”์–ต์ดใ…Žใ…Ž

์šฐ์„  ๊ธฐ๋ณธ์ ์œผ๋กœ HTML์— CDN์„ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค. canvas๋„ ์žŠ์ง€ ์•Š๊ณ  ์ ์–ด์ค์‹œ๋‹ค.

<!DOCTYPE html>
<html lang="ko">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <script
      src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.19.0/matter.js"
      integrity="sha512-rsntMCBgWYEWKl4HtqWmQ3vdHgvSq8CTtJd19YL7lCtKokLPWt7UEoHVabK1uiNfUdaLit8O090no5BZjcz+bw=="
      crossorigin="anonymous"
      referrerpolicy="no-referrer"
    ></script>
    <title>matterJs</title>
  </head>
  <body>
    <canvas></canvas>
    <script type="module" src="./index.js"></script>
  </body>
 </html>

index.js ํŒŒ์ผ์—์„œ ์œ„์—์„œ ์–ธ๊ธ‰ํ•œ ๊ธฐ๋ณธ ์ฝ”๋“œ๋ฅผ ๋จผ์ € ์„ธํŒ…ํ•ด์ค๋‹ˆ๋‹ค.

- ์‚ฌ๊ฐํ˜•(๋ชจ๋ธ) ๋งŒ๋“ค๊ธฐ

๊ธฐ๋ณธ์ ์œผ๋กœ ์‚ฌ๊ฐํ˜•์„ ์ถ”๊ฐ€ํ•˜๋Š” ์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

const rectangle = Bodies.rectangle(x, y, width, length, {
    ...option,
  });

์—ฌ๋‹ด) option์—๋Š” ์—ฌ๋Ÿฌ๊ฐ€์ง€๊ฐ€ ๋“ค์–ด๊ฐˆ ์ˆ˜ ์žˆ๊ณ  ์•ž์—์„œ ๋ง์”€๋“œ๋ ธ๋“ฏ github์—์„œ ์ฐพ์•„๋ณด๋Š” ๊ฒŒ ์ข‹์Šต๋‹ˆ๋‹ค.

์ด๋ ‡๊ฒŒ ์‚ฌ๊ฐํ˜•์„ ๊ทธ๋ƒฅ ๋งŒ๋“ค๋ฉด ์ˆœ์‹๊ฐ„์— ํ™”๋ฉด์˜ ๊ฐ€์žฅ ์•„๋ž˜๋กœ ์‚ฌ๋ผ์ ธ ๋ฒ„๋ฆฝ๋‹ˆ๋‹ค. ์ค‘๋ ฅ์ด ์ž‘์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฏ€๋กœ ์ค‘๋ ฅ์ด ์ž‘์šฉํ•ด๋„ canvas ์™ธ๋ถ€๋กœ ๋‚˜๊ฐ€์ง€ ์•Š๊ฒŒ ์‚ฌ๋ฐฉ์— ๋ฒฝ์„ ์„ธ์›Œ์ค„ ๊ฒ๋‹ˆ๋‹ค.

const groundHeight = 20;
const ground = Bodies.rectangle(
  canvasWidth / 2,
  canvasHeight - groundHeight / 2,
  canvasWidth,
  groundHeight,
  {
    isStatic: true,
  }
);

์˜ต์…˜์œผ๋กœ isStatic: true๋ฅผ ์ฃผ์—ˆ๋Š”๋ฐ, ์ค‘๋ ฅ์„ ๋ฌด์‹œํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋˜ ๋‹ค๋ฅธ ํŠน์ดํ•œ ์ ์ด ๋ˆˆ์— ๋•๋‹ˆ๋‹ค. x์™€ y ์ขŒํ‘œ๊ฐ€ ๊ฐ๊ฐ canvasWidth / 2, canvasHeight - groundHeight / 2๋กœ ๋˜์–ด์žˆ์Šต๋‹ˆ๋‹ค. canvas์™€๋Š” ๋‹ค๋ฅด๊ฒŒ ์‚ฌ๊ฐํ˜•์„ ๋งŒ๋“ค ๋•Œ ์ค‘์‹ฌ์ขŒํ‘œ๋ฅผ ์ฃผ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

์™ผ์ชฝ ์ƒ๋‹จ์„ (0,0)์œผ๋กœ ๋ดค์„ ๋•Œ, ์˜ค๋ฅธ์ชฝ์œผ๋กœ ๊ฐˆ์ˆ˜๋ก x ์ขŒํ‘œ๊ฐ€ ์•„๋ž˜๋กœ ๊ฐˆ์ˆ˜๋ก y์ขŒํ‘œ๊ฐ€ ์ฆ๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰, (0,0)์˜ ๋ฐ˜๋Œ€ ์ขŒํ‘œ๋Š” (canvasWidth, canvasHeight)์ž…๋‹ˆ๋‹ค.

canvas๋Š” ์ฒ˜์Œ ์‹œ์ž‘์ ๊ณผ ๋์ ์„ ์žก๊ณ  ๊ทธ๋ฆฌ๊ธฐ ๋•Œ๋ฌธ์— ์ดˆ๊ธฐ์—๋Š” ํ—ท๊ฐˆ๋ฆฌ์ง€๋งŒ ๊ธˆ๋ฐฉ ์ต์ˆ™ํ•ด์ง‘๋‹ˆ๋‹ค.

์œ„์˜ ์ฝ”๋“œ๋ฅผ ์ด์šฉํ•ด ์‚ฌ๋ฐฉ์„ ๋ง‰์•„์ค๋‹ˆ๋‹ค. ๋ฒฝ์ด ํŠ€์–ด๋‚˜์™€์„œ ๋ณด๋Š” ๊ฒŒ ์‹ซ๋‹ค๋ฉด ์บ”๋ฒ„์Šค์—์„œ ๋ณด์ด์ง„ ์•Š๊ฒŒ ์ขŒํ‘œ์— ์‚ฌ๊ฐํ˜•์˜ ๊ธธ์ด / 2๋ฅผ ํ•œ ๊ฐ’์„ ์ ์ ˆํžˆ ๋”ํ•ด์ค๋‹ˆ๋‹ค.

๋˜ํ•œ ๋ฒฝ์„ ๋งŒ๋“ค๊ธฐ ์ „์— ํ™”๋ฉด ๋ฐ–์œผ๋กœ ๋‚˜๊ฐ”๋˜ ์‚ฌ๊ฐํ˜•์€ ๊ณ„์† ์กด์žฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์„ฑ๋Šฅ ์ด์Šˆ๊ฐ€ ์ƒ๊ธธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‹ˆ ํ™”๋ฉด ์™ธ๋ถ€๋กœ ๋‚˜๊ฐ„ ๋ชจ๋ธ๋“ค์€ ๋‹ค ์‚ญ์ œํ•ด์ค๋‹ˆ๋‹ค.

- ๋ชจ๋ธ ์ถ”๊ฐ€ ๋ฐ ์‚ญ์ œํ•˜๊ธฐ

Composite.add(engine.world, [ground, leftWall, rightWall]); //์ถ”๊ฐ€
Composite.clear(engine.world, rectangle); //์—ฐ๊ด€๋œ ๊ฐ์ฒด ๋ชจ๋‘ ์‚ญ์ œ
Composite.remove(engine.world, rectangle);//rectangle ์‚ญ์ œ

๊ทธ๋ ‡๋‹ค๋ฉด ๋ชจ๋ธ๋“ค์ด ์–ด๋–ป๊ฒŒ ๋ฐ–์œผ๋กœ ๋‚˜๊ฐ”๋Š”์ง€ ์•Œ ์ˆ˜ ์žˆ์„๊นŒ์š”?

๋ฐ”๋กœ, ํ•ด๋‹น ๊ฐ์ฒด์˜ ์ •๋ณด๋ฅผ ์ฝ˜์†”์— ์ฐ์–ด๋ด…์‹œ๋‹ค.

๊ฐ์ฒด์—๋Š” ์˜ต์…˜๋“ค์— ๋„ฃ์–ด์คฌ๋˜ ์ •๋ณด๋“ค๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚˜์ค‘์— ์–ด๋–ค ์˜ต์…˜์ด ๊ถ๊ธˆํ•œ ์ง€ ๋น ๋ฅด๊ฒŒ ํ™•์ธํ•  ๋• ์ด๋ ‡๊ฒŒ ์ฝ˜์†”์— ์ฐ์–ด๋„ ๊ดœ์ฐฎ์„ ๋“ฏ ํ•ฉ๋‹ˆ๋‹คใ…Žใ…Ž

์ €๊ธฐ์—์„œ position์˜ ๊ฐ’์ด canvas ๋ฒ”์œ„ ๋ฐ–์— ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. ์ด ๋ถ€๋ถ„์€ ์กฐ๊ฑด๋ฌธ์œผ๋กœ ์ฒ˜๋ฆฌํ•ด์„œ ์‰ฌ์šฐ๋‚˜, ํ™”๋ฉด์ด ์—…๋ฐ์ดํŠธํ•  ๋•Œ๋งˆ๋‹ค ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜์ง„ ์•Š์Šต๋‹ˆ๋‹ค. ์ฒ˜์Œ ํ•œ ๋ฒˆ๋งŒ ์‹คํ–‰ํ•  ๋ฟ์ด์ฃ .

๊ทธ๋ ‡๋‹ค๋ฉด! ์—ฌ๊ธฐ์—์„œ ๋“ฑ์žฅํ•˜๋Š” ๊ฒƒ์ด ๋ฐ”๋กœ ์ด๋ฒคํŠธ์ž…๋‹ˆ๋‹ค.

- ์ด๋ฒคํŠธ ๋ชจ๋“ˆ ์‚ฌ์šฉํ•˜๊ธฐ

Events.on(mouseConstraint, "mousedown", () => {
 //code ...
});

์ดˆ๊ธฐ์— mouseConstraint๋ฅผ ์„ ์–ธํ•œ ๊ฒƒ์„ ์ด๋ฒคํŠธ์˜ ์ฒซ๋ฒˆ์งธ ์ธ์ž๋กœ, ๋‘๋ฒˆ์งธ ์ธ์ž๋Š” ์ด๋ฒคํŠธ์˜ ์ด๋ฆ„์„, ์„ธ๋ฒˆ์งธ๋Š” ์‹คํ–‰ํ•  ์ฝœ๋ฐฑํ•จ์ˆ˜๋ฅผ ๋„ฃ์–ด์ค๋‹ˆ๋‹ค. ์ฒซ๋ฒˆ์งธ ์ธ์ž๋งŒ ์ถ”๊ฐ€๋œ ๊ฒƒ์„ ๋นผ๋ฉด ๊ธฐ๋ณธ ์ด๋ฒคํŠธ์™€ ์ƒ๊น€์ƒˆ๊ฐ€ ๋น„์Šทํ•ด์„œ ์‰ฝ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ mouse ์ด๋ฒคํŠธ๊ฐ€ ์ข€ ์ ์„ ๋ฟ์ž…๋‹ˆ๋‹ค. mouseup, mousedown, mousemove ์ •๋„..? ๊ทธ๋ž˜์„œ mouseover๋‚˜ mouseleave ๋“ฑ์€ canvas ์ž์ฒด์— addEventListener๋ฅผ ์ด์šฉํ•ด ๊ฑธ์–ด์ฃผ๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค.

๋งˆ์šฐ์Šค ์ด๋ฒคํŠธ ๋ฟ ์•„๋‹ˆ๋ผ, runner๋„ ์ด๋ฒคํŠธ์˜ ์ฒซ๋ฒˆ์งธ ์ธ์ž๋กœ ๋„ฃ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. runner์˜ ์ด๋ฒคํŠธ๋“ค์—๋Š” ํ™”๋ฉด ๋ Œ๋”๋ง์˜ ์ƒ๋ช…์ฃผ๊ธฐ๊ฐ™์€ ์นœ๊ตฌ์ž…๋‹ˆ๋‹ค.

  • on afterTick
  • on afterUpdate
  • on beforeTick
  • on beforeUpdate
  • on tick

์ด๋ ‡๊ฒŒ 5๊ฐ€์ง€์˜ ์ด๋ฒคํŠธ๊ฐ€ ์žˆ์œผ๋ฉฐ, ์ด๋ฒคํŠธ์˜ ์ธ์ž๋กœ ์ „๋‹ฌํ•  ๋•Œ๋Š” ์•ž์˜ on์„ ๋นผ์•ผ ํ•ฉ๋‹ˆ๋‹ค! ์ด ์ด๋ฒคํŠธ๋“ค์€ requestAnimationFrame์œผ๋กœ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. << ์ฝ”๋“œ: https://github.com/liabru/matter-js/blob/master/src/core/Runner.js

๊ทธ๋Ÿฌ๋‹ˆ runner ์ด๋ฒคํŠธ ์ค‘ tick(์‚ฌ์‹ค ์•„๋ฌด๊ฑฐ๋‚˜ ์ƒ๊ด€์—†์„ ๋“ฏ)์„ ์ด์šฉํ•ด์„œ ์™ธ๋ถ€๋กœ ๋‚˜๊ฐ„ ์‚ฌ๊ฐํ˜•๋“ค์„ ๋ชจ์กฐ๋ฆฌ ์‚ญ์ œํ•ด์ค์‹œ๋‹ค.

Events.on(runner, "tick", () => {
    engine.world.bodies.forEach((body) => {
      const isOutside = body.position.y > canvasHeight;
      if (isOutside) Composite.remove(engine.world, body);
    });
});

์™€ ์•„์ง ๊ฐˆ๊ธธ์ด ๋ฉ‰๋‹ˆ๋‹ค! ์ด์ œ ์‚ฌ๊ฐํ˜•๋„ ๋งŒ๋“ค์—ˆ๊ณ  ์„ฑ๋Šฅ ๋Œ€๋น„๋„ ํ–ˆ์œผ๋‹ˆ ์ง„์งœ์ง„์งœ์ง„์งœ ์ง‘๊ฒŒ๋ฅผ ๋งŒ๋“ค ์ฐจ๋ก€์ž…๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๊ทธ์ „์— ํ•˜๋‚˜ ๋”..ใ…Žใ…Ž Constraint๋ฅผ ์•Œ์•„๋ด…์‹œ๋‹ค.

(์—ฌ๊ธฐ๊นŒ์ง€ ์ธ๊ฐ•์„ ํ†ตํ•ด ๋ฐฐ์› ๋˜ ๋‚ด์šฉ์ž…๋‹ˆ๋‹ค. ์ดํ›„๋ถ€ํ„ฐ๋Š” ๋…ํ•™ ์ค‘! - ํ˜น์‹œ ๋ˆˆ์— ๊ฑฐ์Šฌ๋ฆฌ๋Š” ๋ถ€๋ถ„ ์žˆ๋‹ค๋ฉด ๋Œ“๊ธ€๋กœ ์•Œ๋ ค์ฃผ์„ธ์š”~!)

- Constraint ์•Œ์•„๋ณด๊ธฐ

Constraint๋Š” ๋ชจ๋ธ๋“ค์„ ์—ฐ๊ฒฐํ•ด์ค๋‹ˆ๋‹ค. ๋ณ„๋„๋กœ ์„ ์–ธํ•˜์ง€ ์•Š์œผ๋ฉด ๋ชจ๋ธ๋“ค์˜ ์ค‘์ ์„ ๊ธฐ์ค€์œผ๋กœ ์—ฐ๊ฒฐํ•ด์ค๋‹ˆ๋‹ค. ์ค‘๋ ฅ๊ณผ ๊ณต๊ธฐ์ €ํ•ญ, ๋งˆ์ฐฐ๋ ฅ์— ์˜ํ–ฅ์„ ๋ฐ›์ง€๋งŒ ์ผ๋‹จ ๋‚˜์‚ฌ์ฒ˜๋Ÿผ ๊ณ ์ •๋ฉ๋‹ˆ๋‹ค.

  const constraint = Constraint.create({
    bodyA: rectA,
     //rectA์˜ ๋กœ์ปฌ์ขŒํ‘œ๋กœ rectA์—๊ฒŒ ๋งค๋‹ฌ๋ฆด ์ขŒํ‘œ
     //์ฆ‰, rectB๊ฐ€ ๋งค๋‹ฌ๋ฆฌ๊ฒŒ ํ•  ์ขŒํ‘œ
    pointA: {x : 0, y: 0},
    bodyB: rectB
    //rectB์˜ ๋กœ์ปฌ์ขŒํ‘œ๋กœ rectB๊ฐ€ ๋งค๋‹ฌ๋ฆฐ ์ขŒํ‘œ
    pointB: { x: 0, y: 0 }, 
    length: 0,
  });

์ด๋ ‡๊ฒŒ ์˜ต์…˜์„ ๋‹ค ์ฑ„์›Œ์„œ ์จ๋„ ๋˜๋ฉฐ, ๋ช‡๊ฐ€์ง€๋Š” ๋น ์ ธ๋„ ๋ฉ๋‹ˆ๋‹ค. << ์ด ๋ถ€๋ถ„์€ ์•„์ง ์—ฐ๊ตฌ์ค‘

์—ฌ๊ธฐ์—์„œ๋„ ์ขŒํ‘œ(์‚ฌ์‹ค ๋ฒกํ„ฐ๋ผ๋Š” ๋ง์ด ๋งž๋‹ค - ๊ณต์‹๋ฌธ์„œ)๊ฐ€ ๋‚˜์˜ค๋Š”๋ฐ, ์ฃผ์„์—์„œ๋„ ์จ๋†จ์ง€๋งŒ ๋กœ์ปฌ ์ขŒํ‘œ๋ฅผ ๊ธฐ์ค€์œผ๋กœ ํ•ฉ๋‹ˆ๋‹ค. ์ด ๋กœ์ปฌ ์ขŒํ‘œ๋Š” ๋ชจ๋ธ์„ ๋งŒ๋“ค ๋•Œ ์“ด ์ค‘์ ์„ (0,0)์œผ๋กœ ๋ด์„œ ์กฐ๊ธˆ์ด๋ผ๋„ ๋ณต์žกํ•œ ๋„ํ˜•๋ผ๋ฆฌ ์—ฐ๊ฒฐํ•  ๋• ๋งค์šฐ ์–ด๋ ต์Šต๋‹ˆ๋‹ค. ํŠนํžˆ ํšŒ์ „ํ•˜๋Š” ๊ฒŒ ๋“ค์–ด๊ฐ€๋ฉด sin, cos... ์‚ผ๊ฐํ•จ์ˆ˜๋ฅผ ๊ธฐ๋ณธ์œผ๋กœ ๊น”์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค. (์•Œ๊ณ  ์‹ถ์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค)

โœ…์ธํ˜•๋ฝ‘๊ธฐ ์ง‘๊ฒŒ ๋งŒ๋“ค๊ธฐ!

์ด์ œ ์ง„์งœ์ง„์งœ์ง„์งœ์ง„์งœ ์‹œ์ž‘ํ•  ๊ฑด๋ฐ์š”, ์ค‘๊ฐ„์— ํ•„์š”ํ•œ ๊ฐœ๋…๋“ค์„ ๋จผ์ € ์„ค๋ช…ํ•˜๊ณ  ๊ฐ‘๋‹ˆ๋‹ค. (..์•„์ง๋„..?)

์•ž์„œ gif์—์„œ๋„ ๋‚˜์˜ค์ง€๋งŒ, Constraint๋ฅผ ๊ธฐ์ค€์œผ๋กœ ํšŒ์ „ํ•ฉ๋‹ˆ๋‹ค. ์‚ฌ๊ฐํ˜•์˜ ๊ฐ๋„๋งŒ ๋ฐ”๊พธ๊ฒŒ ๋œ๋‹ค๋ฉด, ์ค‘์ ์„ ๊ธฐ์ค€์œผ๋กœ๋งŒ ๋Œ ๋ฟ, Constraint๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๋Œ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ ํ•„์š”ํ•œ ๊ณ„์‚ฐ์€ ๋ฐ”๋กœ ์› ์œ„์˜ ์ ์˜ ์ขŒํ‘œ์ž…๋‹ˆ๋‹ค. ์ค‘์ ์ด (x, y), ๋ฐ˜์ง€๋ฆ„์ด r, ํšŒ์ „๊ฐ์ด theta๋ผ๊ณ  ํ•  ๋•Œ ์› ์œ„์˜ ์ ์˜ ์ขŒํ‘œ๋Š” ( x + r * cos(theta), y + r * sin(theta) ) ์ž…๋‹ˆ๋‹ค. ์ค‘์ ์„ ๊ธฐ์ค€์œผ๋กœ ์–ด๋Š ์œ„์น˜์— ์žˆ๋Š” ๊ฐ€์— ๋”ฐ๋ผ์„œ ์ค‘์ ์— ๋”ํ• ์ง€, ๋บ„์ง€๋ฅผ ๊ฒฐ์ •ํ•˜๋Š” ๊ฒƒ๋„ ์ข‹์ง€๋งŒ, ์™„์ „ํžˆ ์ค‘์ ์„ ๊ธฐ์ค€์œผ๋กœ ํšŒ์ „ํ•˜๋Š” ์ขŒํ‘œ๋ฅผ ๊ตฌํ•˜๊ธฐ ์œ„ํ•ด์„  theta์˜ ๊ฐ’๋งŒ์œผ๋กœ ์กฐ์ ˆํ•˜๋Š” ๊ฒƒ์ด ํŽธํ•ฉ๋‹ˆ๋‹ค.

์ฒ˜์Œ์— ์ฒœ์žฅ์— ๋งค๋‹ฌ๋ ค ์žˆ๋Š” ์‚ฌ๊ฐํ˜•์„ ๋งŒ๋“ค์–ด์ค๋‹ˆ๋‹ค. ๋”๋ถˆ์–ด ์•ž์œผ๋กœ ์ž์ฃผ ์“ธ ์ˆซ์ž๋“ค๋„ ์ƒ์ˆ˜๋กœ ๋งŒ๋“ค์–ด์ค๋‹ˆ๋‹ค.

const DEG_TO_RAD = Math.PI / 180;
const BAR_INIT_LENGTH = 80;
const BAR_INIT_WIDTH = 5;
const BAR_INIT_ANGLE = 60; //์ฒซ๋ฒˆ์งธ ํšŒ์ „๊ฐ
const BAR_SECOND_ANGLE = -90; //๋‘๋ฒˆ์งธ ํšŒ์ „ ๊ฐ. ์Œ์ˆ˜๊ฐ’์œผ๋กœ ๊ณ ์ •
const currentMousePosition = mouse.position.x; //๋งˆ์šฐ์Šค์˜ ํ˜„์žฌ ์œ„์น˜์˜ x ์ขŒํ‘œ

const bar = Bodies.rectangle(
    currentMousePosition,
    BAR_INIT_LENGTH,
    BAR_INIT_WIDTH,
    BAR_INIT_LENGTH,
    {
      render: {
        fillStyle: "#fff",
      },
      inertia: Infinity,
    }
);

์ฐธ๊ณ ๋กœ ์ง‘๊ฒŒ์˜ ๋ชจ๋“  ์˜ต์…˜์€ bar์˜ ์˜ต์…˜๊ณผ ๋™์ผํ•ฉ๋‹ˆ๋‹ค!

๋‹ค์Œ์œผ๋กœ ์ฒœ์žฅ์— ๊พธ์ค€ํžˆ ๋งค๋‹ฌ๋ ค ์žˆ๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด ์ฒœ์žฅ๊ณผ ์—ฐ๊ฒฐ๋˜๋Š” Constraint๋ฅผ ๋งŒ๋“ค์–ด์ค๋‹ˆ๋‹ค.

  const barConstraint = Constraint.create({
    bodyA: bar,
    pointA: { x: 0, y: -BAR_INIT_LENGTH / 2 },
    pointB: { x: currentMousePosition, y: 0 },
    length: 0,
  });

์ด์ œ ๋‘๋ฒˆ์งธ ์—ฐ๊ฒฐ๋˜๋Š” ์‚ฌ๊ฐํ˜•์„ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

const initialAngleRad = BAR_INIT_ANGLE * DEG_TO_RAD;
const secondAngleRad = BAR_SECOND_ANGLE * DEG_TO_RAD;

const bar_bar1 = Bodies.rectangle(
    currentMousePosition,
    BAR_INIT_LENGTH + BAR_INIT_LENGTH / 2,
    BAR_INIT_WIDTH,
    BAR_INIT_LENGTH / 2,
);
//angle์„ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ค‘์ ์— ์ˆ˜์ง์œผ๋กœ ๋ฐ”๊ฟ”์ค€๋‹ค.
Body.setAngle(bar_bar1, Math.PI / 2)

const bar1_localPosition = {
	x: parseInt(((BAR_INIT_LENGTH / 2) * Math.cos(initialAngleRad)) / 2),
	y: parseInt(((BAR_INIT_LENGTH / 2) * Math.sin(initialAngleRad)) / 2),
}
//๊ธฐ๋ณธ ๊ฐ๋„๋ฅผ ์ค€ ์ƒํƒœ์—์„œ ์ถ”๊ฐ€์ ์œผ๋กœ ๋Œ๋ ค์ค€๋‹ค.
Body.rotate(bar_bar1, initialAngleRad);

//bar์˜ ์ขŒํ‘œ๊ฐ€ ๋Œ€๋ถ€๋ถ„ ๊ณ ์ •์ด๋ผ bar1์€ ํ—ˆ๊ณต์—๋‹ค๊ฐ€ ๊ณ ์ • ๊ฐ€๋Šฅ
const bar1_Constraint = Constraint.create({
    pointA: bar1_localPosition,
    bodyA: bar_bar1,
    pointB: { x: currentMousePosition, y: BAR_INIT_LENGTH },
    length: 0,
});

๋งˆ์ง€๋ง‰ ์‚ฌ๊ฐํ˜•์„ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

const bar_bar1_bar2 = Bodies.rectangle(
    currentMousePosition,
    2 * BAR_INIT_LENGTH + BAR_INIT_LENGTH / 4,
    BAR_INIT_WIDTH,
    BAR_INIT_LENGTH / 4,
    {
      render: {
        fillStyle: "#fff",
      },
    }
  );
  Body.setAngle(bar_bar1_bar2, Math.PI / 2 - secondAngleRad);
  Body.rotate(bar_bar1_bar2, -30);
  
  const bar2_localPosition = {
    x: parseInt(((BAR_INIT_LENGTH / 4) * Math.cos( Math.PI / 2 - secondAngleRad )) / 2),
    y: parseInt(((BAR_INIT_LENGTH / 4) * Math.sin( Math.PI / 2 - secondAngleRad )) / 2),
  }
  
  const bar2_Constraint = Constraint.create({
    bodyA: bar_bar1,
    pointA: { x: -localPosition.x, y: -localPosition.y },
    bodyB: bar_bar1_bar2,
    pointB: bar2_localPosition,
    length: 0,
  });

์—ฌ๊ธฐ์—์„œ bar1์™€ bar2๋Š” ์ขŒ์šฐ๋Œ€์นญ์œผ๋กœ ๋งŒ๋“ค์–ด์•ผ ํ•˜๊ณ , ๊ฐ๋„๋งŒ ๋Œ€์นญ์œผ๋กœ ํ•ด ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‹ˆ, bar1๊ณผ bar2๋ฅผ ์„ ์–ธํ•˜๋Š” ๋ถ€๋ถ„์„ ํ•จ์ˆ˜๋กœ ๋งŒ๋“ค๊ณ , ํ•จ์ˆ˜ ๋‚ด์—์„œ Composite์— add๊นŒ์ง€ ํ•  ์ˆ˜ ์žˆ๋„๋ก ์™ธ๋ถ€์— ๋ฐฐ์—ด์„ ์„ ์–ธํ•˜์—ฌ ์š”์†Œ๋กœ ๋„ฃ์–ด์ค์‹œ๋‹ค.

const composites = [];

function createChain(currentMousePosition, index, rads = []) { /*...code...*/ }

createChain(currentMousePosition, index, [-initialAngleRad, secondAngleRad]);
createChain(currentMousePosition, index, [
Math.PI + initialAngleRad,
-secondAngleRad,
]);

์ด์ œ ์ง‘๊ฒŒ๊ฐ€ ์›€์ง์ผ ์ˆ˜ ์žˆ๋„๋ก ์ด๋ฒคํŠธ๋ฅผ ๋‹ฌ์•„๋ด…๋‹ˆ๋‹ค. ์ผ๋ถ€ ๋ณ€์ˆ˜์˜ ์œ„์น˜๊ฐ€ ๋ณ€๊ฒฝ๋œ๋‹ค๋Š” ์ ์— ์œ ์˜ํ•ด์ฃผ์„ธ์š”!

let isMove = false;
let isMouseOn = false;
let isDown = true;
let isClick = true;
let index = 0;

Events.on(mouseConstraint, "mousedown", () => {
  isClick = !isMove;
  if (isClick) isMove = true;
});

render.canvas.addEventListener("mouseover", (event) => {
  isMouseOn = true;
});
render.canvas.addEventListener("mouseleave", () => {
  isMouseOn = false;
});

Events.on(runner, "tick", () => {
  const currentMousePosition = mouse.position.x;
  const currentMousePositionY = mouse.position.y;
  let ceilingBarLength = BAR_INIT_LENGTH + index;

  const initialAngleRad =
    BAR_INIT_ANGLE * DEG_TO_RAD - index / currentMousePositionY / 2;
  const secondAngleRad =
    BAR_SECOND_ANGLE * DEG_TO_RAD - index / currentMousePositionY; //initialAngle๊ณผ ์ผ์ง์„ ๋ณด๋‹ค ๋„˜์ง€ ์•Š๊ฒŒ ์กฐ์ ˆ

  composites.forEach((comp) => {
    Composite.remove(engine.world, comp);
  });
  composites.length = 0; // ๋ฐฐ์—ด ์ดˆ๊ธฐํ™”

  if (ceilingBarLength >= currentMousePositionY * 2) isDown = false;
  if (ceilingBarLength < BAR_INIT_LENGTH) isDown = true;

  createChain(currentMousePosition, index, [-initialAngleRad, secondAngleRad]);
  createChain(currentMousePosition, index, [
    Math.PI + initialAngleRad,
    -secondAngleRad,
  ]);

  if (isMove) {
    if (ceilingBarLength < BAR_INIT_LENGTH && isDown) {
      index = 0;
      isMove = false;
    }
    index = isDown ? index + 2 : index - 2;
  }

  Composite.add(engine.world, composites);
});

 

์ด๋ ‡๊ฒŒ ํด๋ฆญํ•œ ๊ณณ๊นŒ์ง€ ๋‚ด๋ ค์˜ค๋Š” ์ง‘๊ฒŒ ์™„๋ฃŒ!

โœ”๏ธ๊ฒฐ๋ก 

์‚ฌ์‹ค ์•„์ง ์ •๋ฆฌ๊ฐ€ ์ž˜ ์•ˆ๋œ ์ฝ”๋“œ์ด๊ธฐ๋„ ํ•˜๊ณ , ๊ฐ๋„ ๊ณ„์‚ฐ์—์„œ ์ข€ ๋งŽ์ด ํ—ค๋งธ๋˜ ํ„ฐ๋ผ ์ฝ”๋“œ๊ฐ€ ๊ทธ๋ ‡๊ฒŒ ๊น”๋”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์ด ์ฝ”๋“œ๋“ค์„ ์กฐํ•ฉํ•˜๋ฉด ์ „์ฒด ์ฝ”๋“œ๊ฐ€ ๋˜์ง€๋งŒ, ์ „์ฒด ์ฝ”๋“œ๋Š” ์ข€ ๋” ๋‚˜์ค‘์— ์ธํ˜•๋ฝ‘๊ธฐ๊ฐ€ ์™„๋ฃŒ๋˜๋ฉด ๋ณด์—ฌ๋“œ๋ฆฌ๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

์‚ฌ์ด๋“œ ํ”„๋กœ์ ํŠธ๋ฅผ ์ค€๋น„ํ•˜๋ฉด์„œ ์ตœ๊ทผ์—” ๊ธฐํš๊ณผ ๋””์ž์ธ๋งŒ ํ•˜๋Š๋ผ ๊ฐœ๋ฐœ์— ์†์„ ๋ชป ๋Œ€๋‹ค๋ณด๋‹ˆ ๋„ˆ๋ฌด ์‹ฌ์‹ฌํ•ด์„œ ๋”ด์ง“ํ•œ ๊ฒฐ๊ณผ์ž…๋‹ˆ๋‹ค. ์˜ค๋žœ๋งŒ์— ์‚ผ๊ฐํ•จ์ˆ˜ ๋•Œ๋ฌธ์— ์•„์ดํŒจ๋“œ๋กœ ํ•˜๋‚˜์”ฉ ๊ณ„์‚ฐ๋„ ํ•ด๋ณด๊ณ  ์žฌ๋ฐŒ์—ˆ์Šต๋‹ˆ๋‹ค..........ใ…Ž

728x90