p5.jsと Matter.jsを 組み合わせる資料が意外と少なかったのでメモ。
シンプルなやつ
シンプルに、staticな壁で囲んで、中にボールをいくつか入れるやつ。
<!DOCTYPE html>
<html lang="en">
<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">
<title>circle</title>
<script src="https://cdn.jsdelivr.net/npm/p5@1.5.0/lib/p5.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.18.0/matter.min.js" integrity="sha512-5T245ZTH0m0RfONiFm2NF0zcYcmAuNzcGyPSQ18j8Bs5Pbfhp5HP1hosrR8XRt5M3kSRqzjNMYpm2+it/AUX/g==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="./sketch.js"></script>
</head>
<body style="background-color: #222222">
</body>
</html>
let engine;
const bodies = [];
let Engine, Runner, Bodies, Composite;
function setup() {
createCanvas(600, 600);
Engine = Matter.Engine;
Runner = Matter.Runner;
Bodies = Matter.Bodies;
Composite = Matter.Composite;
engine = Engine.create();
for (let i = 0; i < 30; i++) {
const circle = Bodies.circle(
width / 2 + random(-100, 100),
height / 2 + random(-100, 100),
random(20, 50),
);
bodies.push(circle);
}
bodies.push(Bodies.rectangle(width / 2, 10, width - 10, 10, { isStatic: true }));
bodies.push(Bodies.rectangle(width / 2, height - 10, width - 10, 10, { isStatic: true }));
bodies.push(Bodies.rectangle(width - 10, height / 2, 10, height - 10, { isStatic: true }));
bodies.push(Bodies.rectangle(10, height / 2, 10, height - 10, { isStatic: true }));
Composite.add(engine.world, bodies);
const runner = Runner.create();
Runner.run(runner, engine);
}
function draw() {
background(50);
bodies.forEach(body => {
push();
fill(100, 200, 250);
stroke(255);
beginShape();
body.vertices.forEach(v => {
vertex(v.x, v.y);
});
endShape(CLOSE);
pop();
});
}
レンダリングは少し変えたやつ
物理演算でレイアウトする必要があったので、その際のコードも置いておく。 シンプルなやつの、ボールに内接する正方形をレンダリングするやつ。
<!DOCTYPE html>
<html lang="en">
<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">
<title>circle</title>
<script src="https://cdn.jsdelivr.net/npm/p5@1.5.0/lib/p5.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.18.0/matter.min.js" integrity="sha512-5T245ZTH0m0RfONiFm2NF0zcYcmAuNzcGyPSQ18j8Bs5Pbfhp5HP1hosrR8XRt5M3kSRqzjNMYpm2+it/AUX/g==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="./sketch.js"></script>
</head>
<body style="background-color: #222222">
</body>
</html>
let engine;
const bodies = [];
let Engine, Runner, Bodies, Composite;
let displayBody = true;
function setup() {
createCanvas(600, 600);
rectMode(CENTER);
Engine = Matter.Engine;
Runner = Matter.Runner;
Bodies = Matter.Bodies;
Composite = Matter.Composite;
engine = Engine.create();
for (let i = 0; i < 30; i++) {
const circle = Bodies.circle(
width / 2 + random(-100, 100),
height / 2 + random(-100, 100),
random(20, 50),
{ visible: true, angle: random(PI * 2) }
);
bodies.push(circle);
}
bodies.push(Bodies.rectangle(width / 2, 10, width - 10, 10, { isStatic: true, visible: false }));
bodies.push(Bodies.rectangle(width / 2, height - 10, width - 10, 10, { isStatic: true, visible: false }));
bodies.push(Bodies.rectangle(width - 10, height / 2, 10, height - 10, { isStatic: true, visible: false }));
bodies.push(Bodies.rectangle(10, height / 2, 10, height - 10, { isStatic: true, visible: false }));
Composite.add(engine.world, bodies);
const runner = Runner.create();
Runner.run(runner, engine);
}
function draw() {
background(255);
bodies.forEach(body => {
if (displayBody) {
push();
noFill();
stroke(255, 50, 50);
beginShape();
body.vertices.forEach(v => {
vertex(v.x, v.y);
});
endShape(CLOSE);
pop();
}
if (!body.visible) {
return;
}
const x = body.position.x;
const y = body.position.y;
const circleWidth = body.bounds.max.x - body.bounds.min.x;
const w = (circleWidth / 2) * Math.sqrt(2);
push();
noFill();
stroke(0);
translate(x, y);
rotate(body.angle);
square(0, 0, w, w / 10);
pop();
// textAlign(CENTER, CENTER);
// text(degrees(body.angle).toFixed(2), x, y);
});
}