プログラム書いて生物を作ってみたくなりました。作るのが比較的簡単で、手を加えやすいものを目指して作ってみます。
既に存在するプログラムで作られた生物たち
既にあるものと被ってしまうとちょっとつまらないので、人工生物を事前にさらっと調べます。その中から印象的だったものを2つ紹介します。
単純なルールに従って模様が変化していく様子を見ることができる生命のシミュレーションゲームです。中学生のときに見た記憶があります。簡単なルールに従っているだけなのに生きているように見えることに衝撃を受けました。
ソフトボディや流体表現を使った人工生命シミュレーションです。視覚的に工夫されていてとても綺麗な人口生命です。
作成のために使うもの
いくつかの人工生物のシミュレーションを見ていて、次のようなものが多いことに気がつきました。
そこで、横から見た2次元のものを作ることに決めました。
UnityやUnreal Engineなどを使うことを考えたのですが、共有することが比較的簡単で他の人が手を加えやすいというためJavaScriptで使える物理演算エンジンを使います。
物理エンジンは、matter.jsというものを使います。
Matter.js
Matter.js is 2D rigid body physics engine for the web, using JavaScript and HTML5
長方形を配置してみる
どうやったら生き物っぽくなるのかわからないので、とりあえず細長い長方形を置いてみます。
// aliases
const Engine = Matter.Engine,
Render = Matter.Render,
World = Matter.World,
Constraint = Matter.Constraint,
Body = Matter.Body,
Bodies = Matter.Bodies;
const engine = Engine.create();
const render = Render.create({
element: document.body,
engine: engine
})
engine.world.gravity.y = 1.5
const ground = Bodies.rectangle(400, 575, 800, 50, { isStatic: true });
World.add(engine.world, ground);
const bar = Bodies.rectangle(300, 100, 50, 5);
World.add(engine.world, bar);
Engine.run(engine);
Render.run(render);
地味すぎて笑いました。
もうちょっと動きがほしいので、右に回転させてみます。
// aliases
const Engine = Matter.Engine,
Render = Matter.Render,
World = Matter.World,
Constraint = Matter.Constraint,
Body = Matter.Body,
Bodies = Matter.Bodies;
const engine = Engine.create();
const render = Render.create({
element: document.body,
engine: engine
})
engine.world.gravity.y = 1.5
const ground = Bodies.rectangle(400, 575, 800, 50, { isStatic: true });
World.add(engine.world, ground);
const bar = Bodies.rectangle(300, 100, 50, 5);
World.add(engine.world, bar);
// 右に回転させてみる
setInterval(() => {
Body.setAngularVelocity(bar, 0.05);
}, 100);
Engine.run(engine);
Render.run(render);
一気に生き物らしくなった気がします。障害物を置いてみたらどうなるんでしょうか。
// aliases
const Engine = Matter.Engine,
Render = Matter.Render,
World = Matter.World,
Constraint = Matter.Constraint,
Body = Matter.Body,
Bodies = Matter.Bodies;
const engine = Engine.create();
const render = Render.create({
element: document.body,
engine: engine
})
engine.world.gravity.y = 1.5
const ground = Bodies.rectangle(400, 575, 800, 50, { isStatic: true });
World.add(engine.world, ground);
const bar = Bodies.rectangle(300, 100, 50, 5);
World.add(engine.world, bar);
// 障害物を追加
const circleX = 400, circleY = 400;
const ball = Body.create({
parts: [
Bodies.circle(circleX, circleY, 50),
Bodies.rectangle(circleX, circleY, 100, 10)
]
});
World.add(engine.world, ball);
// 右に回転させてみる
setInterval(() => {
Body.setAngularVelocity(bar, 0.05);
}, 100);
Engine.run(engine);
Render.run(render);
障害物のボールを一生懸命押してます。かわいいです。
ただ、一方的に進んでいるところに、ちょっとだけ機械的な印象を受けます。ボールに触れたら一定の確率で方向転換するようにしてみます。
// aliases
const Engine = Matter.Engine,
Render = Matter.Render,
World = Matter.World,
Constraint = Matter.Constraint,
Body = Matter.Body,
Bodies = Matter.Bodies,
SAT = Matter.SAT;
const engine = Engine.create();
const render = Render.create({
element: document.body,
engine: engine
})
engine.world.gravity.y = 1.5
const ground = Bodies.rectangle(400, 575, 800, 50, { isStatic: true });
World.add(engine.world, ground);
const bar = Bodies.rectangle(300, 100, 50, 5);
World.add(engine.world, bar);
// 障害物を追加
const circleX = 500, circleY = 400;
const ball = Body.create({
parts: [
Bodies.circle(circleX, circleY, 50),
Bodies.rectangle(circleX, circleY, 100, 10)
]
});
World.add(engine.world, ball);
var angulerVelocity = 0.05;
// 右に回転させてみる
setInterval(() => {
// ボールにぶつかったら一定の確率で方向転換する
if (SAT.collides(bar, ball).collided) {
console.log(Math.random());
if(Math.random()<0.05) {
angulerVelocity = -angulerVelocity;
}
}
Body.setAngularVelocity(bar, angulerVelocity);
}, 100);
Engine.run(engine);
Render.run(render);
諦めるようになりました。
80体の生物を同時に動かしてみた
おまけとして、同じ生物を80体発生させてみました。心なしか気持ち悪くなりました。
コメント