[JavaScript] メテオストライクの実装とエフェクト追加

はじめに

ブロック崩しゲームで実装した「メテオストライク」を、Three.jsで3Dエフェクトでざっくりとですが移植してみました。

JavaScript + canvas(2d)で実装した ブロック崩しゲームの方のエフェクト動画。

ここまで、作りこんで実装はしてないですが、取り合えず、現状スキルでどこまでやれるか?という事で、数時間で実装してます。

今後は、もう少し作りこむ予定ですが、2Dの開発経験を生かし3Dで実装した内容を簡単に備忘録メモで残しておきます。

1. 概要

メテオストライクの実装概要

メテオストライクは、ゲームやシミュレーションでしばしば使用される迫力のあるエフェクトです。この実装では、Three.jsを用いて、隕石が空から落下して地面に衝突するまでの過程をシミュレーションします。隕石のテクスチャ、落下時のエフェクト、衝突時の爆発や煙、発光効果などを組み合わせて、リアルで迫力あるメテオストライクを作り出します。

まずは、メテオの基本的なジオメトリとマテリアルを作成し、シーンに追加。その後、メテオが落下するアニメーションを設定し、エフェクトを加えて、メテオの衝突時に爆発や煙、光の演出を加えることで、視覚的なインパクトを強化します。最後に、キャラクターの歩行アニメーションや周囲のエフェクトとの連動も視野に入れています。

目標や目的

このプロジェクトの目的は、Three.jsを用いたシンプルかつ効果的なメテオストライクの実装を学ぶことです。具体的な目標は以下の通りです:

  • リアルな隕石の描画:テクスチャと発光効果を使って、隕石が落下するリアルな視覚的表現を作成する。
  • エフェクトの追加:メテオの衝突時に爆発や煙、光などのエフェクトを加えて、迫力のあるシーンを作り出す。
  • アニメーションの作成:隕石の落下をスムーズにアニメーション化し、視覚的なインパクトを強化する。
  • パフォーマンスの最適化:シーン全体のパフォーマンスを維持しつつ、効果的なエフェクトを追加する。

これらを達成することで、ゲームやシミュレーション内で使用できるメテオストライクのエフェクトを完成させます。

2. 準備

使用するツールやライブラリ

今回のメテオストライクの実装では、主に以下のツールとライブラリを使用しています:

  • Three.js 3Dグラフィックスをブラウザで表示するためのライブラリです。Three.jsは、メテオのジオメトリ、テクスチャ、ライティング、エフェクトなど、3Dシーンを作成するために必要な機能を豊富に提供してくれます。今回はThree.jsを使用して、隕石(メテオ)のシェイプ作成、落下アニメーション、エフェクトの追加を行います。

  • JavaScript Three.jsを操作するために、JavaScriptを使用します。特に、メテオの落下アニメーションやエフェクトの制御を行います。

  • HTML5 Three.jsの3Dコンテンツを表示するために、HTML5の<canvas>タグを使用します。このタグ内に3Dシーンを描画します。

  • CSS Webページのスタイルを整えるために使用します。特に、画面のレイアウトや3D表示部分の配置を整えます。

  • その他のツール(オプション)

    • Node.js:プロジェクトのビルドやパッケージ管理に使用する場合、Node.jsを導入することがあります。npmを使って依存ライブラリを管理したり、ローカルサーバーを立てて開発を進めます。
    • Webpack:モジュールのバンドルやファイルの圧縮などを行うビルドツールとして使用することもあります。

開発環境の設定

  1. Three.jsの導入 Three.jsを使用するために、まずは公式サイトからライブラリをダウンロードするか、CDN経由で読み込みます。以下のようにHTMLファイルに追加します:

    <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
    

    また、Node.js環境でプロジェクトを進める場合は、npmでThree.jsをインストールすることもできます:

    npm install three
    
  2. 基本的なHTML構成 3Dシーンを表示するための<canvas>タグをHTMLに追加します。Three.jsはこのキャンバスに描画するため、キャンバスのサイズや位置をCSSで調整します。

    <html>
      <head>
        <title>メテオストライク</title>
        <style>
          body { margin: 0; }
          canvas { display: block; }
        </style>
      </head>
      <body>
        <canvas id="myCanvas"></canvas>
        <script src="app.js"></script>
      </body>
    </html>
    
  3. 開発サーバーの設定(オプション) 開発時にローカルサーバーを使うと、ファイルの変更がすぐに反映されて便利です。Node.jsを使ってローカルサーバーを立ち上げるには、以下のコマンドを使用します:

    npm install -g http-server
    http-server
    

    このコマンドで、ローカル環境にサーバーが立ち上がり、ブラウザでリアルタイムに変更を確認できます。

  4. プロジェクトの構成 プロジェクト内でindex.htmlapp.jsstyle.cssなどのファイルを作成し、これらを基に開発を進めます。適宜、Three.jsのモジュールやサードパーティライブラリをインポートして、必要な機能を追加していきます。

3. メテオの基本的なセットアップ

メテオのジオメトリとマテリアル作成

まず、メテオの基本となる形状(ジオメトリ)とその外観(マテリアル)を作成します。ここでは、Three.jsのSphereGeometryを使用して、メテオの球体を作成し、テクスチャを適用する方法を紹介します。

// メテオのジオメトリを作成
const meteorGeometry = new THREE.SphereGeometry(1, 32, 32);

// メテオのテクスチャを読み込む
const texture = config.imgageList.find((item) => item.name === 'meteor')?.texture;

// メテオのマテリアルを作成
const meteorMaterial = new THREE.MeshStandardMaterial({
  map: texture,            // テクスチャをマテリアルに設定
  transparent: true,       // 透明にする設定
  opacity: 0.9,            // 透明度を調整
  side: THREE.DoubleSide,  // 両面を描画
  emissive: new THREE.Color(0xff6347), // 発光色(オレンジ色)
  emissiveIntensity: 0.5   // 発光強度
});
  • ジオメトリ: SphereGeometryを使用して、隕石の形状を作成します。引数の1は半径、32は水平および垂直のセグメント数で、より高い値にするほど滑らかな球体になります。
  • マテリアル: MeshStandardMaterialを使用して、テクスチャを適用します。透明度や発光効果などの設定も行います。

メテオの初期位置設定

次に、メテオがシーン内でどの位置から落ち始めるかを設定します。通常、メテオは画面外上部から落ちてくるので、適切な位置に設定します。

// メテオの初期位置設定(上から落ちてくる位置)
config.meteorStrike.meteor.position.set(20, 20, 0); // x, y, z の座標
  • set(x, y, z)を使ってメテオの初期位置を設定します。ここでは、メテオが画面の上部(y = 20)から落ちるように設定しています。

シーンにメテオを追加する方法

最後に、作成したメテオをシーンに追加します。Three.jsでは、scene.add()を使って、3Dオブジェクトをシーンに追加します。

// メテオのメッシュをシーンに追加
config.meteorStrike.meteor = new THREE.Mesh(meteorGeometry, meteorMaterial);
config.scene.add(config.meteorStrike.meteor);
  • THREE.Mesh()を使って、ジオメトリ(meteorGeometry)とマテリアル(meteorMaterial)を結びつけ、メテオのメッシュを作成します。
  • scene.add()でメテオをシーンに追加し、画面上に表示します。

これで、メテオがシーン内に登場し、指定された初期位置に配置されました。次は、メテオが落下するアニメーションやエフェクトの追加に進みます。

4. テクスチャとエフェクト

メテオのテクスチャの作成

メテオのテクスチャは、隕石の外観にリアルな質感を与えるための重要な要素です。テクスチャには、隕石の岩肌の模様や傷、クレーター、発光部分などを反映させます。前述のように、THREE.TextureLoaderを使ってテクスチャを読み込んで、メテオの表面に適用します。

// メテオのテクスチャを読み込む
const textureLoader = new THREE.TextureLoader();
const meteorTexture = textureLoader.load('path_to_your_texture.jpg');  // 実際のテクスチャパスに変更

// メテオのマテリアルにテクスチャを適用
const meteorMaterial = new THREE.MeshStandardMaterial({
  map: meteorTexture,       // テクスチャを設定
  transparent: true,        // 透明にする
  opacity: 0.9,             // 透明度
  side: THREE.DoubleSide,   // 両面描画
  emissive: new THREE.Color(0xff6347), // 発光色
  emissiveIntensity: 0.5    // 発光強度
});

ここでは、THREE.TextureLoaderを使ってテクスチャを読み込み、MeshStandardMaterialに適用しています。テクスチャのファイルパス('path_to_your_texture.jpg')は、実際のテクスチャ画像に置き換えてください。


落下エフェクト(アニメーション)

メテオが空から落ちる動きを表現するためには、アニメーションを使います。Three.jsでは、requestAnimationFrame()を利用してアニメーションループを作成し、メテオの位置を更新することができます。

function animateMeteor() {
  // メテオの位置を下に移動
  config.meteorStrike.meteor.position.y -= 0.2;  // 速さを調整(0.2は適切な速度)

  // メテオが地面に着地した場合の処理
  if (config.meteorStrike.meteor.position.y <= 0) {
    config.meteorStrike.meteor.position.y = 0;  // 地面に着地
    // 衝突エフェクトやアニメーションの追加など
  }

  // レンダリングの更新
  renderer.render(config.scene, camera);
  requestAnimationFrame(animateMeteor);  // 次のフレームをリクエスト
}

// アニメーションの開始
animateMeteor();
  • position.yを更新して、メテオを下に落下させます。requestAnimationFrame()を使って、毎フレーム処理を繰り返し、アニメーションを作成します。
  • メテオが地面に到達した時の処理(例えば、衝突エフェクトの追加)もここで設定できます。

発光効果の追加(emissiveの利用)

メテオが落下する過程で発光を加えると、より迫力のある演出ができます。emissiveプロパティを使うと、オブジェクトが光っているように見せることができます。これを使って、隕石が発光する効果を追加します。

// メテオの発光効果(`emissive`)
const meteorMaterial = new THREE.MeshStandardMaterial({
  map: meteorTexture,            // テクスチャを設定
  transparent: true,             // 透明にする
  opacity: 0.9,                  // 透明度
  side: THREE.DoubleSide,        // 両面描画
  emissive: new THREE.Color(0xff6347), // 発光色(オレンジ色)
  emissiveIntensity: 0.7,        // 発光強度を調整
});
  • emissive: これを使うことで、隕石が発光しているように見せることができます。ここではオレンジ色(0xff6347)の発光を設定していますが、他の色にも変更できます。
  • emissiveIntensity: 発光の強度を調整します。値が大きいほど、発光が強くなります。

発光効果は、隕石が落ちるアニメーションと組み合わせることで、よりドラマチックなビジュアルを作り出すことができます。

5. 追加エフェクトと迫力

衝突時のエフェクト(爆発や煙、光の追加)

メテオが地面に衝突した瞬間、爆発や煙、光のエフェクトを追加することで、インパクトを強化できます。Three.jsを使って、衝突時のエフェクトをシーンに追加する方法を紹介します。

function handleCollision() {
  // メテオが地面に衝突したときの処理
  const explosionColor = new THREE.Color(0xff4500);  // 爆発のオレンジ色
  const explosionLight = new THREE.PointLight(explosionColor, 5, 10);  // 爆発の光
  explosionLight.position.set(config.meteorStrike.meteor.position.x, 0, config.meteorStrike.meteor.position.z);
  config.scene.add(explosionLight);  // シーンに追加

  // 爆発の後に光がフェードアウトするように
  setTimeout(() => {
    config.scene.remove(explosionLight);  // 光を削除
  }, 500);  // 0.5秒後に光を消す

  // 煙や火花を追加
  createExplosionParticles(config.meteorStrike.meteor.position);
}

function createExplosionParticles(position) {
  const particleCount = 100;
  const particles = new THREE.BufferGeometry();
  const positions = new Float32Array(particleCount * 3);

  for (let i = 0; i < particleCount; i++) {
    const pX = Math.random() * 2 - 1;
    const pY = Math.random() * 2 - 1;
    const pZ = Math.random() * 2 - 1;
    positions[i * 3] = pX;
    positions[i * 3 + 1] = pY;
    positions[i * 3 + 2] = pZ;
  }

  particles.setAttribute('position', new THREE.BufferAttribute(positions, 3));

  const particleMaterial = new THREE.PointsMaterial({ color: 0xff6347, size: 1 });
  const particleSystem = new THREE.Points(particles, particleMaterial);

  // 衝突位置にパーティクルを追加
  particleSystem.position.set(position.x, position.y, position.z);
  config.scene.add(particleSystem);

  // パーティクルのアニメーション
  setTimeout(() => {
    config.scene.remove(particleSystem);  // 1秒後にパーティクルを削除
  }, 1000);
}
  • 爆発の光: THREE.PointLightを使用して、爆発の瞬間に光を放つ効果を追加します。
  • 煙や火花: パーティクルシステムを利用して、衝突時の煙や火花を表現します。BufferGeometryで位置をランダムに設定し、THREE.PointsMaterialで色をつけています。

パーティクルシステムの活用(煙や火花)

パーティクルシステムは、爆発や煙、火花などのエフェクトに非常に有効です。Three.jsのTHREE.Pointsを使用して、粒子(パーティクル)を表示します。

function createSmokeEffect(position) {
  const particleCount = 300;
  const particles = new THREE.BufferGeometry();
  const positions = new Float32Array(particleCount * 3);

  for (let i = 0; i < particleCount; i++) {
    const pX = Math.random() * 2 - 1;
    const pY = Math.random() * 3 - 1;  // 煙は上に向かう
    const pZ = Math.random() * 2 - 1;
    positions[i * 3] = pX;
    positions[i * 3 + 1] = pY;
    positions[i * 3 + 2] = pZ;
  }

  particles.setAttribute('position', new THREE.BufferAttribute(positions, 3));

  const smokeMaterial = new THREE.PointsMaterial({
    color: 0x808080,  // 煙の色
    size: 2,
    transparent: true,
    opacity: 0.5,  // 煙の透明度
    blending: THREE.AdditiveBlending
  });

  const smokeSystem = new THREE.Points(particles, smokeMaterial);
  smokeSystem.position.set(position.x, position.y, position.z);
  config.scene.add(smokeSystem);

  // 煙のアニメーション
  setTimeout(() => {
    config.scene.remove(smokeSystem);  // 煙が消える
  }, 3000);
}
  • 煙の粒子: positionをランダムに設定し、煙が上昇するようにpYの範囲を広めに設定しています。sizeopacityで煙の見た目を調整しています。

エフェクトを強化するための工夫(emissive強化、発光色の調整)

発光効果(emissive)を強化することで、衝突時により目立つ演出を作り出せます。メテオが衝突した際に発光色を変更し、より強い光を発するように調整します。

// メテオの発光を強化
function enhanceEmissiveEffect() {
  const meteorMaterial = config.meteorStrike.meteor.material;
  meteorMaterial.emissive = new THREE.Color(0xff4500); // 衝突時の強いオレンジ色
  meteorMaterial.emissiveIntensity = 2.0;  // 発光強度を増加
}

// 衝突時に発光を強化する
handleCollision();
enhanceEmissiveEffect();
  • emissiveを強化し、メテオが衝突時により強く光るようにします。発光色はオレンジや赤にして、火のような印象を与えます。
  • emissiveIntensityを高く設定することで、発光の強度を増し、衝突時のインパクトを強化できます。

6. まとめ

メテオストライクは、出発点の座標と、終点の座標を、予め設定して画面内にランダムに落下させるというシンプルなエフェクトですが、シンプル故に如何に迫力のあるアニメーション処理にするかというのが、技量が問われるところだと思います。

今回は、ほんとにざっくりとした実装だったので、味気ないですが、今後エフェクトを勉強して印象的なアニメーション処理を作りたいと思います。