<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>スモークパーティクルシミュレーション</title>
<!-- p5.js ライブラリを含める -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
<style>
body {
margin: 0;
overflow: hidden;
}
canvas {
display: block;
}
</style>
</head>
<body>
<script>
let particleSystem;
function setup() {
createCanvas(windowWidth, windowHeight); // 全画面のキャンバスを作成
colorMode(HSB); // カラーモードをHSBに設定
particleSystem = new ParticleSystem(createVector(width / 2, height - 50)); // パーティクルシステムを初期化
}
function draw() {
background(0, 0, 0, 25); // 背景を徐々に消えるように設定(スモークの効果)
// マウスの位置に基づいて風力を計算
let wind = createVector(mouseX - width / 2, mouseY - height / 2);
wind.normalize(); // 風力の方向を正規化
wind.mult(0.1); // 風力の強さを調整
// パーティクルシステムに風力を適用
particleSystem.applyForce(wind);
particleSystem.addParticle(); // 新しいパーティクルを追加
particleSystem.run(); // パーティクルシステムを更新し、表示する
}
class ParticleSystem {
constructor(origin) {
this.particles = []; // パーティクルの配列
this.origin = origin.copy(); // 発生源の位置をコピー
}
run() {
// 各パーティクルを更新し、表示する
for (let i = this.particles.length - 1; i >= 0; i--) {
let p = this.particles[i];
p.run();
if (p.isDead()) {
this.particles.splice(i, 1); // 死亡したパーティクルを削除
}
}
}
addParticle() {
this.particles.push(new Particle(this.origin)); // 新しいパーティクルを追加
}
applyForce(force) {
for (let p of this.particles) {
p.applyForce(force); // すべてのパーティクルに風力を適用
}
}
}
class Particle {
constructor(origin) {
this.position = origin.copy(); // パーティクルの位置を初期化
this.velocity = createVector(random(-1, 1), random(-2, 0)); // ランダムな速度を設定
this.acceleration = createVector(); // 加速度を初期化
this.lifespan = 255; // 寿命を設定
this.color = color(random(0, 360), 80, 80); // 色を設定(HSB)
}
run() {
this.update(); // パーティクルの更新
this.display(); // パーティクルの表示
}
update() {
this.velocity.add(this.acceleration); // 加速度を速度に加算
this.position.add(this.velocity); // 速度を位置に加算
this.acceleration.mult(0); // 加速度をリセット
this.lifespan -= 2; // 寿命を減少
}
display() {
noStroke(); // パーティクルの枠線なし
fill(this.color.levels[0], this.color.levels[1], this.color.levels[2], this.lifespan); // 色と透明度を設定
ellipse(this.position.x, this.position.y, 12); // パーティクルを描画
}
applyForce(force) {
this.acceleration.add(force); // 加速度に風力を追加
}
isDead() {
return this.lifespan <= 0; // 寿命が終了したかチェック
}
}
</script>
</body>
</html>