レーザービームでターゲットドローンを打ち落とすゲーム。
上空に侵入した敵ドローン1000機に対して、可及的速やかにこれを排除してください。
スペースキーを押すと自動迎撃開始です。
(敵にレーザが命中すると10個の破片となり爆散します。)
レーザーで迎撃する設定なのでミサイルのような弾道計算が不要です。
コードがシンプルになります。
コードをメモ帳などのテキストエディタに貼り付け、ファイル名を「index.html」として保存します。その後、保存したファイルをブラウザで開けば、コードが実行されます。
実行結果。
迎撃しないほうが良かった。!
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>3D Particle Explosion Simulation</title>
<style>
body { margin: 0; }
canvas { display: block; }
</style>
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<script>
// シーン、カメラ、レンダラーをセットアップ
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// 地面と空を設定
const groundGeometry = new THREE.PlaneGeometry(1000, 1000);
const groundMaterial = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
const ground = new THREE.Mesh(groundGeometry, groundMaterial);
ground.rotation.x = -Math.PI / 2; // 横に倒して地面として使う
ground.position.y = -100; // 地面の高さを設定
scene.add(ground);
scene.background = new THREE.Color(0x87ceeb); // 空の色を青に設定
// パーティクルの配列を保持
const particles = [];
const explosions = []; // 爆発用の小さなパーティクル
const particleCount = 1000; // パーティクルの数
let shooting = false; // レーザー発射中かどうか
let targetIndex = 0; // 次に打ち落とすパーティクルのインデックス
// カメラの位置を設定
camera.position.z = 200;
// パーティクル用のジオメトリとマテリアルを定義
const particleGeometry = new THREE.SphereGeometry(1, 8, 8);
// パーティクルクラス
class Particle {
constructor(x, y, z, color) {
this.mesh = new THREE.Mesh(particleGeometry, new THREE.MeshBasicMaterial({ color: color }));
this.mesh.position.set(x, y, z); // 初期位置
this.vx = (Math.random() - 0.5) * 2; // X方向の速度
this.vy = (Math.random() - 0.5) * 2; // Y方向の速度
this.vz = (Math.random() - 0.5) * 2; // Z方向の速度
this.alive = true; // パーティクルが生存しているかどうか
scene.add(this.mesh); // シーンに追加
}
// パーティクルの位置を更新
update() {
if (this.alive) {
this.mesh.position.x += this.vx;
this.mesh.position.y += this.vy;
this.mesh.position.z += this.vz;
// 画面の範囲内で動き続けるように反射させる
if (this.mesh.position.x > 100 || this.mesh.position.x < -100) this.vx *= -1;
if (this.mesh.position.y > 100 || this.mesh.position.y < -100) this.vy *= -1;
if (this.mesh.position.z > 100 || this.mesh.position.z < -100) this.vz *= -1;
}
}
// パーティクルを打ち落とす
shoot() {
this.alive = false;
scene.remove(this.mesh); // シーンから削除
// 爆発(10個の小さなパーティクルを生成)
for (let i = 0; i < 10; i++) {
const explosionParticle = new Particle(
this.mesh.position.x,
this.mesh.position.y,
this.mesh.position.z,
new THREE.Color(Math.random(), Math.random(), Math.random()) // ランダムな色
);
explosionParticle.vx = (Math.random() - 0.5) * 5; // 爆発の速度を大きめに
explosionParticle.vy = (Math.random() - 0.5) * 5;
explosionParticle.vz = (Math.random() - 0.5) * 5;
explosions.push(explosionParticle);
}
}
}
// パーティクルを作成
function createParticles() {
for (let i = 0; i < particleCount; i++) {
const x = (Math.random() - 0.5) * 200;
const y = (Math.random() - 0.5) * 200;
const z = (Math.random() - 0.5) * 200;
const color = new THREE.Color(Math.random(), Math.random(), Math.random()); // カラフルな色をランダム生成
particles.push(new Particle(x, y, z, color));
}
}
// レーザーを発射してパーティクルを打ち落とす
function shootParticle() {
if (targetIndex < particles.length) {
const target = particles[targetIndex];
if (target.alive) {
// レーザービームを描画(カメラの中心からターゲットへ)
const laserGeometry = new THREE.BufferGeometry();
const vertices = new Float32Array([
0, 0, 0, // カメラの位置(レーザー発射点)
target.mesh.position.x, target.mesh.position.y, target.mesh.position.z // パーティクルの位置(ターゲット)
]);
laserGeometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3));
const laserMaterial = new THREE.LineBasicMaterial({ color: 0xff0000 });
const laser = new THREE.Line(laserGeometry, laserMaterial);
scene.add(laser);
// パーティクルを打ち落とす
setTimeout(() => {
scene.remove(laser); // レーザーを消す
target.shoot(); // パーティクルを打ち落とす(爆発を含む)
targetIndex++; // 次のターゲットへ
}, 100); // 0.1秒後にパーティクルを消去
} else {
targetIndex++;
}
} else {
shooting = false; // 全てのパーティクルを打ち落としたら終了
targetIndex = 0; // インデックスをリセット
}
}
// アニメーションループ
function animate() {
requestAnimationFrame(animate);
// 全パーティクルを更新
particles.forEach(particle => {
particle.update();
});
// 爆発パーティクルを更新
explosions.forEach(particle => {
particle.update();
});
// レーザー発射中であれば、パーティクルを順に打ち落とす
if (shooting) {
shootParticle();
}
// シーンをレンダリング
renderer.render(scene, camera);
}
// ユーザーがスペースキーを押したときの処理
document.addEventListener('keydown', (e) => {
if (e.code === 'Space') {
shooting = true; // レーザー発射を開始
}
});
// パーティクルを作成してアニメーション開始
createParticles();
animate();
// ウィンドウサイズ変更時の対応
window.addEventListener('resize', () => {
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
});
</script>
</body>
</html>