2026年4月14日火曜日

【第2回】メモ帳だけで作れる!?ブラウザで動く「マイクラ風」3Dゲーム制作ガイド 動かしてみる

世界が動き出す!

皆さん、こんにちは!

前回の記事では、メモ帳だけで50x50のブロック平原をブラウザに出現させることに成功しましたね。

「おぉ、3D空間ができた!」と感動したのも束の間。

今のままでは、ただ景色を眺めることしかできません。

ゲームといえば、やっぱり「自分で操作して動かす」のが醍醐味ですよね!


第2回となる今回は、この世界を自由に歩き回れるようにします。

キーボードの「W/A/S/D」での移動、スペースでのジャンプ、そして画面右下に「自分の腕」を表示する機能を実装していきますよ。


さあメモ帳を開いて、あなたの世界に命を吹き込みましょう!


前回のコードを準備しよう

まずは前回作成した my_craft.html をメモ帳で開いてください。

このコードをベースに、プレイヤーの部分を強化していきます。

以下の5つの魔法を付け足して、世界を自由に動き回れるようにしましょう!

なお、今回の分と前回の分を合わせた完全版は記事の下の方に貼り付けておきます。


1. 「歩く機能」をインターネットから借りてくる

前回のコードの </head> の上に以下のコードを貼り付けます。

<head>部分
<script src="https://cdn.jsdelivr.net/gh/donmccurdy/aframe-extras@v7.2.0/dist/aframe-extras.min.js"></script>

青文字が↑このコード

↓位置はだいたいここ

    <script src="https://aframe.io/releases/1.5.0/aframe.min.js"></script>

    <script src="https://cdn.jsdelivr.net/gh/donmccurdy/aframe-extras@v7.2.0/dist/aframe-extras.min.js"></script>

  </head>


Geminiの解説

これは世界中の開発者が使っている「追加パーツ集」です。

これを一行入れるだけで、WASDキーで歩くという複雑なプログラムが、たった一言で呼び出せるようになります!


2. ブロックの「質感」をリアルにする

<script>部分
block.setAttribute('material', 'roughness: 1; metalness: 0');

<script>のところからだいたい11行下に

block.setAttribute('color', randomColor);

というのがありますので、その下に追加します。

前後はこんな感じ

 block.setAttribute('color', randomColor);

**block.setAttribute('material', 'roughness: 1; metalness: 0');**

 // ブロックが歪まないように位置とサイズを調整


Geminiの解説

「ツヤ消し」の設定です。これを入れることで、プラスチックのようなテカテカ感が消えて、より「ブロックっぽい」落ち着いた見た目になります。


3. スペースキーで画面が動かないようにする

 block.setAttribute の下に、このスクロール防止コードを入れます。

<script>部分
// スペースキーでの画面スクロールを防止
window.addEventListener('keydown', (e) => { if (e.code === 'Space') e.preventDefault(); });

このコードの貼り付け位置は、先程の2番の下の方に貼り付けます。

block.setAttribute('position', `${x - offset} -0.5 ${z - offset}`);

              scene.appendChild(block);

            }

          }


          // スペースキーでの画面スクロールを防止

          window.addEventListener('keydown', (e) => {

            if (e.code === 'Space') e.preventDefault();

          });


Geminiの解説

ブラウザは通常、スペースキーを押すとページを下にスクロールしようとします。

ゲーム中に画面がガタガタ動かないよう、「その動き、ちょっと待った!」と禁止する命令です。


今回はブラウザではなく、テキストのゲームなので↑このスペースのはいらないかな?と思ったのですが、Geminiは必要との事でしたので。


4. ジャンプの物理演算を追加する

スクロール防止のすぐ下に、このジャンプ用プログラムを貼り付けます。

<script>部分
// --- ジャンプ制御のプログラム ---
const rig = document.querySelector('#rig');
let isJumping = false; // ジャンプ中かどうかの旗

window.addEventListener('keydown', (e) => {
  // スペースキーが押され、かつ「ジャンプ中でない」時だけ実行
  if (e.code === 'Space' && !isJumping) {
    isJumping = true;
    let v = 0.2; // 最初に飛び出す力(上昇速度)
    let gravity = 0.01; // 下に引っ張る力(重力)
    let pos = rig.getAttribute('position');
    let floorY = 1.6; // 着地点の高さ

    function jump() {
      pos.y += v; // 位置を上にずらす
      v -= gravity; // 速度を重力で少しずつ減らす
      rig.setAttribute('position', pos);

      // 地面(floorY)より下に行きそうになったら着地
      if (pos.y <= floorY) {
        pos.y = floorY;
        rig.setAttribute('position', pos);
        isJumping = false; // ジャンプ終了!
      } else {
        // まだ空中にいるなら、次の瞬間もジャンプ処理を続ける
        requestAnimationFrame(jump);
      }
    }
    jump();
  }
});

Geminiがたっぷり注釈入れてくれましたので、説明は特に必要ないですね(^^;


5. プレイヤーを「乗り物」に乗せる

カメラ部分を、この id="rig" という塊(乗り物)で包み込みます。

<script>のすぐ下
<a-entity id="rig" movement-controls="fly: false; speed: 0.3" position="0 1.6 0">
  <a-entity camera="fov: 50" look-controls="pointerLockEnabled: true">
    </a-entity>
</a-entity>

貼り付ける場所は</script>の下になります。


Geminiの解説

movement-controls: これでWASD移動が解禁!

pointerLockEnabled: true: 画面をクリックすると、マウスカーソルが消えて視点移動に集中できるようになります。



6. 「自分の腕」を表示する

画面の右下に細長いボックス(腕)を配置します。

5番のすぐ下
<a-entity id="right-hand" 
          geometry="primitive: box; width: 0.15; height: 0.8; depth: 0.15" 
          material="color: #ffdbac" 
          position="0.5 -0.5 -0.6" 
          rotation="-10 0 0">
</a-entity>

このコードのすぐ下にまた </a-entity> があるのですが、さらにその下にまた </a-entity> を貼り付けてください。

こんな感じになります。

         </a-entity>


        </a-entity>

      </a-entity>

↑青文字</a-entity>が追加分。

上の</a-entity>が上のコードで追加したやつで、その下の</a-entity>のあとに</a-entity>を追加してください。


Geminiの解説

画面の右下に固定される「自分の右手」です。

これがあるだけで「自分がこの世界にいる!」という没入感が一気にアップします。


コピー失敗しちゃった!とか、上記コードが間違ってる!等の場合は、この下の完全版を新しくテキストを作って試してみてください。

今回のコード完全版
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>3Dブロックゲーム - 第2回操作編</title>
    <script src="https://aframe.io/releases/1.5.0/aframe.min.js"></script>
    <script src="https://cdn.jsdelivr.net/gh/donmccurdy/aframe-extras@v7.2.0/dist/aframe-extras.min.js"></script>
  </head>
  <body>
    <a-scene>
      <a-sky color="#87CEEB"></a-sky>

      <script>
        window.onload = () => {
          const scene = document.querySelector('a-scene');
          const range = 50;
          const offset = range / 2;
          const colors = ['#4ca64c', '#8B4513', '#808080']; // 緑・茶・灰

          for (let x = 0; x < range; x++) {
            for (let z = 0; z < range; z++) {
              const block = document.createElement('a-box');
              const randomColor = colors[Math.floor(Math.random() * colors.length)];
              block.setAttribute('color', randomColor);
              block.setAttribute('material', 'roughness: 1; metalness: 0');
              // 視界の歪みを抑えるため、高さを-0.5に設定
              block.setAttribute('position', `${x - offset} -0.5 ${z - offset}`);
              scene.appendChild(block);
            }
          }

          // スペースキーでの画面スクロールを防止
          window.addEventListener('keydown', (e) => {
            if (e.code === 'Space') e.preventDefault();
          });

          // --- ジャンプ制御のプログラム ---
          const rig = document.querySelector('#rig');
          let isJumping = false;

          window.addEventListener('keydown', (e) => {
            if (e.code === 'Space' && !isJumping) {
              isJumping = true;
              let v = 0.2; // 上昇速度
              let gravity = 0.01; // 重力
              let pos = rig.getAttribute('position');
              let floorY = 1.6; // プレイヤーの目の高さ

              function jump() {
                pos.y += v;
                v -= gravity;
                rig.setAttribute('position', pos);

                if (pos.y <= floorY) {
                  pos.y = floorY;
                  rig.setAttribute('position', pos);
                  isJumping = false;
                } else {
                  requestAnimationFrame(jump);
                }
              }
              jump();
            }
          });
        };
      </script>

      <a-entity id="rig" movement-controls="fly: false; speed: 0.3" position="0 1.6 0">
        <a-entity camera="fov: 50" look-controls="pointerLockEnabled: true">
          
          <a-entity id="right-hand" 
                    geometry="primitive: box; width: 0.15; height: 0.8; depth: 0.15" 
                    material="color: #ffdbac" 
                    position="0.5 -0.5 -0.6" 
                    rotation="-10 0 0">
          </a-entity>

        </a-entity>
      </a-entity>

    </a-scene>
  </body>
</html>



自分の手で1行ずつ書き加えたコードが、ブラウザの中で「命」になって動き出す。

WASDで大地を駆け、スペースでジャンプする。

画面右下にちょこんと見える「自分の腕」が、これほどまでに頼もしく感じるとは…。

皆さん、おめでとうございます。

これであなたは、この3D世界における単なる「観察者」ではなく、自由な「冒険者」になったのです!


さて、自由に歩けるようになると次に欲しくなるのは…そう、「積まれたブロック」ですよね?

今の私たちは、ただ平らな地面を跳ねているだけ。


第3回予告:ブロックを登ろう!

・物理演算の壁を越えろ!:足元の高さをリアルタイムで検知。

・目指せ、山の頂上!:積み上がったブロックの階段をジャンプで踏破!

・世界が眼下に広がる:自分の足で登り詰めた「高み」から見る景色は、格別の一言。


プログラムは少し複雑になりますが、今回も「コピペで動く完全版コード」を冒頭にご用意します!

さらなる高みへ――。

あなたのメモ帳が、ついに「重力」と「高さ」を完全に支配する日が来ます。

次回も絶対に乗り遅れないでくださいね!


…とでかい目標を作ってしまったわけですが、果たしてHTMLで出来るのか!?という不安もあります。

まだ試しておりませんので、突然別の事に切り替わる可能性もあります(^^;


ちなみにこの企画、第1回が残念ながら非常に少ない閲覧数で反響がよくありませんでしたので、もしかしたら第2回で終わっちゃう可能性もあります。


0 件のコメント:

コメントを投稿

I'm sorry, Japanese text only.
荒らし目的と思われるコメントは気づき次第対処します。