この記事の内容は、CSS-Tricks の記事(「Simulating Mouse Movement」というタイトルのもの)で見かけた、「マウスカーソルの軌跡上でパーティクルを発生させる処理」を、p5.js の処理で置きかえた時の話です。
自分が実装した内容を動作させた時の様子は、以下のとおりです。
元の処理の内容
今回の参照元で用いた、「マウスカーソルの軌跡上でパーティクルを発生させる処理」は、以下の部分に掲載されたものです。
そこで実装されていた JavaScript のプログラムは以下のとおりです。
パーティクルは div要素で作成されていて、それを動かす部分ではアニメーションライブラリの TweenMax によるイージングが用いられていました。
function createParticle (x, y) {
var size = Math.random() * 50 + 10;
x -= (size / 2);
y -= (size / 2);
var particle = document.createElement('div');
document.body.appendChild(particle);
TweenMax.set(particle, {
x: x,
y: y,
width: size,
height: size,
background: function () {
return `hsl(${Math.random() *90+200}, 50%, 50%)`
}
});
TweenMax.to(particle, Math.random() * 2 + 1, {
x: x + (Math.random() - 0.5) * 200,
y: y + (Math.random() - 0.5) * 200,
opacity: 0,
scale:0,
ease: Power2.easeOut,
onComplete: function () {
document.body.removeChild(particle);
}
})
}
window.addEventListener('mousemove', function (e) {
var x = e.clientX;
var y = e.clientY;
createParticle(x, y);
});
document.body.addEventListener('touchmove', function (e) {
var x = e.touches[0].clientX;
var y = e.touches[0].clientY;
e.preventDefault();
createParticle(x, y);
});
この内容を元に、p5.js で実装し直してみます。
なお、今回は簡単のため、一部の処理を簡略化しています。
書きかえた後の内容
p5.js で実装した内容は以下のとおりです。
※ このプログラムは、p5.js Web Editor や OpenProcessing で動作させるのが簡単です(それらのページの JavaScript を書く部分の内容を、以下の内容に置きかえるだけで OK)
div要素で作られていたパーティクルは、p5.js の円の描画に置きかえています。
また、パーティクルを管理する部分は、元と同様にオブジェクトでのパラメータ管理を行うやり方にしてみました(※ もちろんクラス構文で実装しても良いです)。
そして簡単のため、以下のような簡略化・省略をしています。
- イージングが用いられていた部分は、線形の変化となるように実装
- タッチイベントに関する処理は未実装
let particleList = [];
function setup() {
createCanvas(windowWidth, windowHeight);
noStroke();
colorMode(HSB, 360, 100, 100, 100);
}
function draw() {
background(80);
for (const particle of particleList) {
fill(particle.color);
circle(particle.x, particle.y, particle.size);
particle.x -= particle.dx;
particle.y -= particle.dy;
particle.size -= particle.ds;
particle.color[3] -= particle.da;
particle.lifetime -= 1;
}
particleList = particleList.filter((particle) => {
return particle.lifetime > 0;
});
}
function mouseMoved() {
createParticle(mouseX, mouseY);
}
function createParticle(x0, y0) {
const size = random(10, 60);
const [x, y, color] = [
x0 + random(-size / 4, size / 4),
y0 + random(-size / 4, size / 4),
[random(90, 290), 50, 50, 100],
];
const lifetime = random(1, 3) * 60;
const [dx, dy, ds, da] = [
random(-100, 100) / lifetime,
random(-100, 100) / lifetime,
size / lifetime,
100 / lifetime,
];
const particle = { x, y, size, dx, dy, ds, color, da, lifetime };
particleList.push(particle);
}
移動、大きさ・透明度を変化させる部分は、初期値と変化量/減少量をパラメータとして持たせて、それを draw() の中で利用する形にしています。なお、この部分は lerp() を使った実装でも OK です。
↓こちらから試せます
今回の内容は、以下で試すことができます。
余談
実装ミスの話
今回の内容を実装する際、その途中でパーティクルを消失させる部分の実装をミスしたことがありました。しかし、意図しない実装ではあるものの、面白い見た目になったので動画に残してみました。
この後にやってみたこと
今回の実装を行った後、最終的にはこのようなものを作りました。
具体的には、以下の追加実装・変更をしました。その内容については、また別の記事にて。
- イージングを p5.func と lerp() で実装
- 元の記事の続きで書かれていたマウスの軌跡のエミュレーションを実装
- パーティクルの発生源の動きに用いられているシンプレックスノイズの実装に、perlin.js ではなく simplex-noise.jsを利用
- パーティクルの発生源となる動く軌跡を 3つ作成