キャンバスを作ってその上に描画する - ゲーム開発

キャンバスを作ってその上に描画する
=================

* « 前のページ
* 次のページ »

これは、ゲーム開発キャンバスチュートリアル の 10 ステップ中 **1 ステップ目**になります。このレッスンを終えた後のソースコードは、Gamedev-Canvas-workshop/lesson1.htmlで見ることができます。

ゲームの機能を書き始める前に、ゲームを内部でレンダリングするための基本的な構造を作成する必要があります。これは、HTML と `<canvas>` 要素を使用して行うことができます。

ゲームの HTML
---------

ゲームはすべて `<canvas>` 要素に描画されるため、 HTML 文書構造は極めて簡潔です。好きなテキストエディターを使って新しい HTML 文書を作成し、適当な場所に `index.html` として保存してください。そして、その HTML 文書に次のコードを追加してください。

```html
<!doctype html>
<html lang="en-US">
  <head>
    <meta charset="utf-8" />
    <title>Gamedev Canvas Workshop</title>
    <style>
 \* {
 padding: 0;
 margin: 0;
 }
 canvas {
 background: #eee;
 display: block;
 margin: 0 auto;
 }
 </style>
  </head>
  <body>
    <canvas id="myCanvas" width="480" height="320"></canvas>

    <script>
 // JavaScript のコードはここ
 </script>
  </body>
</html>
```

`charset` を定義し、 `<title>` と簡単なな CSS をヘッダーに記述しました。本体には `<canvas>` と `<script>` 要素があり、前者にはゲームを描画し、後者にはそれを制御する JavaScript のコードを記述します。 `<canvas>` 要素は簡単に参照を取得できるように `id` を `myCanvas` とし、幅は 480 ピクセル、高さは 320 ピクセルとしています。このチュートリアルで書くすべての JavaScript のコードは開始の `<script>` と終了の `</script>` タグの間に配置されます。

キャンバスの基本
--------

実際に `<canvas>` 要素に映像を描画するために、まずは JavaScript から要素への参照を取得しなければなりません。次のコードを開始の `<script>` タグのあとに追記してください。

```js
const canvas = document.getElementById("myCanvas");
const ctx = canvas.getContext("2d");
```

ここでは `<canvas>` 要素への参照を `canvas` に保存しています。それから 2D 描画コンテキストを保存するために `ctx` 変数を作成しています。 2D 描画コンテキストは実際にキャンバスに描画するために使うツールとなります。

赤い四角形をキャンバスの上に表示するコード例を見てみましょう。下記のコードを先程記述した JavaScript のあとに追記して、 `index.html` をブラウザーで読み込んでみてください。

```js
ctx.beginPath();
ctx.rect(20, 40, 50, 50);
ctx.fillStyle = "#FF0000";
ctx.fill();
ctx.closePath();
```

すべての命令は `beginPath()` メソッドと `closePath()` メソッドの間に記述されています。四角形を `rect()` を用いて定義しています。最初の 2 つの値は左上の角のキャンバス上での座標を指定し、あとの 2 つの値は幅と高さを指定しています。今回描画された四角形は画面の左端から 20 ピクセル、上端から 40 ピクセルの位置に幅 50 ピクセル、高さ 50 ピクセルの大きさで、正方形になっています。 `fillStyle` プロパティは `fill()` (en-US) メソッドで用いられる色 (今回は赤) を保存します。

もちろん四角形だけではありません。ここでは緑の円を描画するコードを紹介します。次のコードを自分の JavaScript の最後に追記し、保存して再読込してみてください。

```js
ctx.beginPath();
ctx.arc(240, 160, 20, 0, Math.PI \* 2, false);
ctx.fillStyle = "green";
ctx.fill();
ctx.closePath();
```

見て分かるとおり、 `beginPath()` メソッドと `closePath()` メソッドが再び用いられています。その間にこのコードで最も重要な部分、 `arc()` メソッドが呼び出されています。このメソッドは 6 つの引数を持ちます。

* 円の中心の `x`、`y` 座標
* 円の半径
* 開始角度と終了角度 (円を描く始める時点の角度と描き終えたあとの角度をラジアンで)
* 描く方向 (時計回りは `false` で、既定値。反時計回りは `true`。) この最後の引数は省略可能です。

`fillStyle` プロパティは先程とは違う形になっています。これは CSS でそうであるように、色は 16 進値、色キーワード、 `rgba()` 関数、その他利用可能な色メソッドなら何でも指定することができるからです。

図形を `fill()` (en-US) で塗りつぶすかわりに `stroke()` で縁だけ色を付けることも出来ます。次のコードも自分の JavaScript に追記してみてください。

```js
ctx.beginPath();
ctx.rect(160, 10, 100, 40);
ctx.strokeStyle = "rgba(0, 0, 255, 0.5)";
ctx.stroke();
ctx.closePath();
```

上記のコードは青く縁取られたからの四角形を描画します。 `rgba()` 関数内のアルファチャネルにより青色は半透明になっています。

自分のコードと比べる
----------

以下が JSFiddle で即実行可能な最初のレッスンのソースコード全てです。

**メモ:** 与えられた図形の大きさや色を変えてみましょう。

次のステップ
------

ここまでで基本的な HTML を組み上げキャンバスについて少し学習しました。それでは、第 2 章に進み、どうやってゲーム内のボールを動かすかを学びましょう。

* « 前のページ
* 次のページ »


パドルとキーボード操作 - ゲーム開発

パドルとキーボード操作
===========

* « 前のページ
* 次のページ »

これは、ゲーム開発キャンバスチュートリアル の 10 ステップ中 **4 ステップ目**になります。このレッスンを終えた後のソースコードは、Gamedev-Canvas-workshop/lesson4.htmlで見ることができます。

ボールが自由に壁に跳ね返っていて、それを無限に眺めることができるのですが、現状では対話することができないのです。操作できないのでは、ゲームとは言えません! そこで、ユーザーが操作できるパドルという対話を追加してみましょう。

ボールにぶつかるパドルの定義
--------------

そういうわけで、ボールに当てるパドルが必要になりました。パドルに用いるいくつかの変数を定義しましょう。次の変数を、他の変数と一緒にコードの一番上に追加してください。

```js
const paddleHeight = 10;
const paddleWidth = 75;
let paddleX = (canvas.width - paddleWidth) / 2;
```

ここではパドルの高さと幅、 `x` 軸上の開始地点を定義しています。続くコードではこれらを用いてさらなる計算が行われます。パドルを画面上に表示する関数を作成しましょう。 `drawBall()` のすぐ下に次の関数を追加してください。

```js
function drawPaddle() {
  ctx.beginPath();
  ctx.rect(paddleX, canvas.height - paddleHeight, paddleWidth, paddleHeight);
  ctx.fillStyle = "#0095DD";
  ctx.fill();
  ctx.closePath();
}
```

パドルを操作できるようにする
--------------

こにパドルを描画しても良いですが、ユーザーの行動に応答する必要があります。キーボード操作を実装するのです。必要なものは次のとおりです。

* 左の操作ボタンが押されているか、右の操作ボタンが押されているかという情報を保存する 2 つの変数。
* `keydown` イベントと `keyup` イベントの 2 つのイベントリスナー。ボタンが押されたときにパドルの動きを扱うコードを走らせたいのです。
* `keydown` イベントと `keyup` イベントを扱い、ボタンが押されたときに実行されるコード。
* パドルを左や右に動かす機能

押されているボタンはこのとおり、論理値として定義、初期化できます。このコードをどこか他の変数の近くに追記してください。

```js
let rightPressed = false;
let leftPressed = false;
```

最初は制御ボタンは押されていないため、どちらにおいても既定値は `false` です。ボタンが押されたのを検知するため、 2 つのイベントリスナーを設定します。 JavaScript の最後にある `setInterval()` の行のちょうど上に次のコードを追記してください。

```js
document.addEventListener("keydown", keyDownHandler, false);
document.addEventListener("keyup", keyUpHandler, false);
```

キーボードのキーのどれかに対して `keydown` イベントが発生したとき（どれかが押されたとき）、 `keyDownHandler()` 関数が実行されます。 2 つ目のリスナーについても同様で、（そのキーが押されなくなったき） `keyup` イベントは `keyUpHandler()` 関数を呼び出します。自分の `addEventListener()` の行の下に次のコードを追記してください。

```js
function keyDownHandler(e) {
  if (e.key === "Right" || e.key === "ArrowRight") {
    rightPressed = true;
  } else if (e.key === "Left" || e.key === "ArrowLeft") {
    leftPressed = true;
  }
}

function keyUpHandler(e) {
  if (e.key === "Right" || e.key === "ArrowRight") {
    rightPressed = false;
  } else if (e.key === "Left" || e.key === "ArrowLeft") {
    leftPressed = false;
  }
}
```

キーが押されたとき、その情報は変数に保存されます。それぞれの場合で関連する変数が `true` に設定されます。キーが離されたときに変数は `false` に戻されます。

どちらの関数も変数 `e` で表されるイベントを引数としてとります。これから有用な情報が手に入ります。 `key` は押されたキーについての情報を持っています。大抵のブラウザーでは左右の矢印キーにそれぞれ `ArrowLeft` と `ArrowRight` が対応します。ただし IE/Edge に対応するために、 `Left` と `Right`も確認する必要があります。 もし左カーソルが押されたら、変数 `leftPressed` は `true` に、離されたら変数 `leftPressed` は `false` に設定されます。右カーソルと変数 `rightPressed` についても同様です。

### パドルの移動ロジック

押されているキーについての情報を保存している変数、そして関連する関数が設定されました。ではそれらを使う実際のコードに手を入れて画面上のパドルを動かしてみましょう。 `draw()` 関数の中で、各々のフレームを描画するときに左カーソルキーが押されているか、右カーソルが押されているか確認しましょう。次のようなコードになっているでしょう。

```js
if (rightPressed) {
  paddleX += 7;
} else if (leftPressed) {
  paddleX -= 7;
}
```

左カーソルを押すとパドルは左に 7 ピクセル移動し、右カーソルを押すとパドルは右に 7 ピクセル移動する。これは今のところうまく動作しているが、どちらかのキーを長く押しているとパドルがキャンバスの端から消えてしまいます。これを改善し、パドルをキャンバスの枠内だけ移動させるには、次のようなコードに変更します。

```js
if (rightPressed) {
  paddleX = Math.min(paddleX + 7, canvas.width - paddleWidth);
} else if (leftPressed) {
  paddleX = Math.max(paddleX - 7, 0);
}
```

ここで用いられている位置 `paddleX` は期待されているように左端の `0` と右端の `canvas.width-paddleWidth` 間で動きます。

上記のコード片を `draw()` 関数の最後、閉じ波括弧のちょうど前に追記してください。

あとは `drawPaddle()` 関数を `draw()` 関数から呼び出し、実際に画面に表示するようにすれば完了です。次の行を `draw()` 関数の、ちょうど `drawBall()` を呼ぶ行の下に追記してください。

```js
drawPaddle();
```

自分のコードと比べる
----------

自分のコードと比べられる、実際に動くコードがこちらになります。

**メモ:** パドルを速く、または遅く動くようにしたり、大きさを変えたりしてみましょう。

次のステップ
------

ゲームっぽい要素を追加しましょう。今問題なのはただパドルでボールを永遠に打ち続けることしか出来ないという点です。これは第5章、ゲームオーバーでゲームの終了状態を追加することで完全に変わることになります。

* « 前のページ
* 次のページ »


ボールを動かす - ゲーム開発

ボールを動かす
=======

* « 前のページ
* 次のページ »

これは、ゲーム開発キャンバスチュートリアル の 10 ステップ中 **2 ステップ目**になります。このレッスンを終えた後のソースコードは、Gamedev-Canvas-workshop/lesson2.htmlで見ることができます。

前回のレッスンを一通りこなしてみてボールの描き方が分かりました。では今回はそれを動かしましょう。技術的には、ボールを描画し、またそれを消してからほんの少し違う位置に描画し直すという処理を毎フレームずつ行うことで動いているような印象を生み出します。ちょうど映画がどのように動くのかと同じです。

描画ループを定義する
----------

キャンバスを毎フレーム、定期的に更新し続けるためには、何度も実行されるような関数を定義する必要があります。この関数には画像の位置を変えたりするために毎回違う値が与えらます。 JavaScript のタイミング関数、例えば `setInterval()` や `requestAnimationFrame()` を用いれば同じ関数を何度も実行できます。

現在 HTML ファイル内にある JavaScript を、最初の 2 行を除いてすべて削除し、その下に以下のように追加してください。`draw()` 関数は `setInterval` 内で 10 ミリ秒ごとに実行されます。

```js
function draw() {
  // 描画コード
}
setInterval(draw, 10);
```

無限に続く `setInterval` の性質のため、`draw()`は 10 ミリ秒おきにずっと、あるいは私たちが止めるまで呼ばれ続けます。では、ボールを描画してみましょう。 `draw()` 関数の中に下記のコードを追記してください。

```js
ctx.beginPath();
ctx.arc(50, 50, 10, 0, Math.PI \* 2);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
```

では、書き換えたコードを試してみましょう。ボールが毎フレーム再描画されるはずです。

ボール動かす
------

動きがないのでボールが再描画され続けていることに気づかないはずです。動きを加えてみましょう。まず、直書きされた位置 (50,50) のかわりに `x`、`y`という名の変数に開始位置を中央下端として定義し、それらを用いて円が描画される位置を定義します。

まず、 `x` と `y` を定義するために自分の `draw()` 関数の上に次の 2 行を追加しましょう。

```js
let x = canvas.width / 2;
let y = canvas.height - 30;
```

次に `draw()` 関数を更新して、変数 x と変数 y を `arc()` メソッド内で使うように書き換えましょう。次のハイライトされている行のとおりです。

```js
function draw() {
  ctx.beginPath();
  ctx.arc(x, y, 10, 0, Math.PI \* 2);
  ctx.fillStyle = "#0095DD";
  ctx.fill();
  ctx.closePath();
}
```

ここからが大事な部分です。 `x` と `y` に毎フレーム描画した後に小さな値を加え、ボールが動いているように見せるのです。その小さな値を `dx`、`dy` として 2、-2 をそれぞれ設定しましょう。変数 x、y の定義のあとに次のコードを追記してください。

```js
let dx = 2;
let dy = -2;
```

最後に残っていることがあります。フレームごとに `x` と `y` を変数 `dx`、`dy` で更新して、更新されるたびにボールが新しい位置に描画されるようにするのです。次に示されている新しい 2 行を `draw()` 関数の最後に追記してください。

```js
function draw() {
  ctx.beginPath();
  ctx.arc(x, y, 10, 0, Math.PI \* 2);
  ctx.fillStyle = "#0095DD";
  ctx.fill();
  ctx.closePath();
  x += dx;
  y += dy;
}
```

コードを保存してください。問題なく動作しますが、ボールの軌跡が残ります。

![](/ja/docs/Games/Tutorials/2D_Breakout_game_pure_JavaScript/Move_the_ball/ball-trail.png)

各フレームの前にキャンバスを消去
----------------

前のフレームを削除せずに毎フレーム描画しているために軌跡が残ってしまいます。でも心配する必要はありません。キャンバスの内容を消去するメソッド、 `clearRect()` があります。このメソッドは 4 つの引数をとります。四角形の左上端の x、y 座標と四角形の右下端の x、y 座標です。この四角形で囲われた領域にある内容全てが消去されます。

次のハイライトされている新しい行を `draw()` 関数に追記してください。

```js
function draw() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  ctx.beginPath();
  ctx.arc(x, y, 10, 0, Math.PI \* 2);
  ctx.fillStyle = "#0095DD";
  ctx.fill();
  ctx.closePath();
  x += dx;
  y += dy;
}
```

コードを保存してもう一度試してみてください。今度は軌跡のないボールがみえるはずです。 10 ミリ秒おきにキャンバスは消去され、青い円 (ボール) が指定された位置に描画され、 `x`と`y`の値は次のフレームに備えて更新されます。

コードを整える
-------

これからいくつかの記事で `draw()` 関数にどんどんコマンドを追加していくので、可能な限りシンプルでクリーンにしておくと良いでしょう。まずは、ボールを描くコードを別個の関数に移動させることから始めましょう。

既存の draw() 関数を以下の 2 つの関数に置き換える。

```js
function drawBall() {
  ctx.beginPath();
  ctx.arc(x, y, 10, 0, Math.PI \* 2);
  ctx.fillStyle = "#0095DD";
  ctx.fill();
  ctx.closePath();
}

function draw() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  drawBall();
  x += dx;
  y += dy;
}
```

自分のコードと比べる
----------

この記事で組み上げた自分のコードを下のライブデモで確認したり、書き換えたりしてどのように動いているかしっかり理解しましょう。

**メモ:** 動くボールの速さや向きを変えてみましょう。

次のステップ
------

ボールを描画して動くようにしましたが、そのままキャンバスの縁から消えていってしまいます。第 3 章ではどのようにボールを壁で弾ませるか探っていきます。

* « 前のページ
* 次のページ »


ブロックのかたまりを作る - ゲーム開発

ブロックのかたまりを作る
============

* « 前のページ
* 次のページ »

これは、ゲーム開発キャンバスチュートリアル の 10 ステップ中 **6 ステップ目**になります。このレッスンを終えた後のソースコードは、Gamedev-Canvas-workshop/lesson6.htmlで見ることができます。

ゲームプレイの仕組みを修正した結果、負けることができるようになりました。これは、ゲームがようやくゲームらしくなってきたという意味で、とてもいいことです。しかし、壁やパドルでボールを跳ね返すだけでは、すぐに飽きられてしまいます。ブロック崩しに必要なのは、ボールでレンガを破壊すること。

ブロック変数を設定する
-----------

このレッスンの全体的な目的は、二次元配列で動作する入れ子ループを使用して、レンガのコードをいくつかレンダリングすることです。しかし、最初の段階では、レンガの幅や高さ、行や列などの情報を定義するために、いくつかの変数を設定する必要があります。次の行を、あらかじめプログラムで宣言しておいた変数の下に追加してください。

```js
const brickRowCount = 3;
const brickColumnCount = 5;
const brickWidth = 75;
const brickHeight = 20;
const brickPadding = 10;
const brickOffsetTop = 30;
const brickOffsetLeft = 30;
```

ここではブロックの行と列の数、幅と高さ、ブロックがくっつかないようにするブロック間の隙間、そしてキャンバスの端に描画されないようにするための上端、左端からの相対位置を定義しました。

1 つの二次元配列で全てのブロックを記録します。二次元配列はブロックの列 (c) を含んでおり、列は行 (r) を含み、行はそれぞれのブロックが描画される画面上の `x` 座標と `y` 座標をもつオブジェクトを含んでいます。

```js
const bricks = [];
for (let c = 0; c < brickColumnCount; c++) {
  bricks[c] = [];
  for (let r = 0; r < brickRowCount; r++) {
    bricks[c][r] = { x: 0, y: 0 };
  }
}
```

上記のコードは行と列を通してループし、新しいブロックを作ります。このブロックオブジェクトは後に衝突検出のためにも使われることを覚えておいてください。

ブロック描画ロジック
----------

配列に含まれる全てのブロックを通してループする関数を作成し、画面上に描画しましょう。コードは次のようになります。

```js
function drawBricks() {
  for (let c = 0; c < brickColumnCount; c++) {
    for (let r = 0; r < brickRowCount; r++) {
      bricks[c][r].x = 0;
      bricks[c][r].y = 0;
      ctx.beginPath();
      ctx.rect(0, 0, brickWidth, brickHeight);
      ctx.fillStyle = "#0095DD";
      ctx.fill();
      ctx.closePath();
    }
  }
}
```

もう一度、行と列を通してループし、それぞれのブロックの `x` 座標と `y` 座標を設定するとともに、 1 回ループを回るごとに大きさ `brickWidth` x `brickHeight` のブロックをキャンバス上に描画しています。問題はそれら全てを 1 箇所、座標 `(0,0)` に描画していることです。それぞれのブロックの `x` 座標と `y` 座標を導出する計算を一回一回のループに含める必要があります。

```js
const brickX = c \* (brickWidth + brickPadding) + brickOffsetLeft;
const brickY = r \* (brickHeight + brickPadding) + brickOffsetTop;
```

それぞれの座標 `brickX` は `brickWidth` + `brickPadding` に列番号 `c` をかけ、 `brickOffsetLeft` を足したものとして導出されます。 brickY のロジックも同様ですが、行番号 `r`、`brickHeight`、そして `brickOffsetTop` が用いられます。これで、それぞれのブロックは正しい行、列に間隔を空けて置かれ、左上端から一定の位置に描画されるようになりました。

`drawBricks()` の最終版は、次のように `brickX` と `brickY` の値を `(0,0)` の代わりに座標として代入するようにしたものとなります。これを `drawPaddle()` 関数の下に追加してください。

```js
function drawBricks() {
  for (let c = 0; c < brickColumnCount; c++) {
    for (let r = 0; r < brickRowCount; r++) {
      const brickX = c \* (brickWidth + brickPadding) + brickOffsetLeft;
      const brickY = r \* (brickHeight + brickPadding) + brickOffsetTop;
      bricks[c][r].x = brickX;
      bricks[c][r].y = brickY;
      ctx.beginPath();
      ctx.rect(brickX, brickY, brickWidth, brickHeight);
      ctx.fillStyle = "#0095DD";
      ctx.fill();
      ctx.closePath();
    }
  }
}
```

実際のブロックの描画
----------

`drawBricks()` へ呼び出しを `draw()` 関数のどこかに追加して、このレッスンの仕上げとしましょう。最初のあたりの、キャンバスを消去する部分とボールを描画する部分の間あたりが良いでしょう。 `drawBall()` の呼び出しのすぐ前に次の行を追加してください。

```js
drawBricks();
```

自分のコードと比べる
----------

ここまででゲームは更にもう少し面白くなりました。

**メモ:** 行や列にあるブロックの数や位置を替えてみましょう。

次のステップ
------

というわけでついにブロックができました。でもボールはブロックに全く反応しません。第 7 章、衝突検知ではこれを変えます。

* « 前のページ
* 次のページ »


asm.js - ゲーム開発

asm.js
======

**非推奨:** この機能は非推奨になりました。まだ対応しているブラウザーがあるかもしれませんが、すでに関連するウェブ標準から削除されているか、削除の手続き中であるか、互換性のためだけに残されている可能性があります。使用を避け、できれば既存のコードは更新してください。このページの下部にある互換性一覧表を見て判断してください。この機能は突然動作しなくなる可能性があることに注意してください。

asm.js は 高度に最適化可能な JavaScript のサブセットを規定する仕様です。この文書では、asm.js で可能なこと、利点、利用方法、そして関連する情報と使用例を解説します。

asm.js とは
---------

極めて小さく、厳密な JavaScript のサブセットです。while や if、数値型、トップレベルの名前付き関数といくつかの単純な生成物のみ利用可能です。オブジェクト、文字列、クロージャや、ヒープを必要とするものは利用できません。asm.js のコードは多くの点で C のそれと類似していますが、全ての JavaScript エンジンで動作します。JavaScript エンジンの最適化を助ける一方、Emscripten のようなコンパイラーが出力するべきコードを明確に規定しています。asm.js のコードと、それがどのように動作するのか、そしてどのように利用できるかを解説します。

JavaScript のサブセットは Just-In-Time (JIT) コンパイラーを持つ多くのエンジンで高度に最適化されています。しかし、明確な標準を定めることによって、この種のコードの最適化により取り組むことができ、また驚くほどの高速化が可能となります。議論と測定が容易になるため、複数の JS エンジンの間での協力がより簡単になります。この種のコードは全てのエンジンで高速に動作するべきで、そうでないのはバグであるべきです。そのためのエンジンが最適化するべき仕様となっています。

標準は Web 向けにハイパフォーマンスなコードを出力したいと考えるコンパイラー製作者たちも助けます。asm.js の仕様を参考にでき、asm.js に忠実であれば高速に動作するということがわかるからです。C/C++ を JavaScript へコンパイルする Emscripten は asm.js を出力し、そのコードはいくつかのブラウザでネイティブと同等の速度で動作します。

またエンジンが asm.js のコードを識別べきする場合、さらなる最適化を行えます。現在のところ、それが可能なブラウザは Firefox のみとなっています。

asm.js 言語のまとめ
-------------

asm.js は中間言語です。厳密に型づけされた整数および浮動小数点演算、関数呼び出しとヒープ領域へのアクセスのみが許されるため、パフォーマンスレートの予測が極めて容易です。通常の JavaScript と比べ、そのパフォーマンス特性はネイティブコードに近くなっています。主要なブラウザは既に asm.js をサポートしています。asm.js はブラウザ内で動作するため、ブラウザとハードウェアに大きく依存します。


WebRTC データチャネル - ゲーム開発

WebRTC データチャネル
==============

WebRTC (Web Real-Time Communications、ウェブリアルタイム通信) API は、主に音声や動画の通信に対応していることで知られていますが、ピアツーピアのデータチャネルも提供されています。この記事では、このことについて詳しく説明し、ゲームにデータチャンネルを搭載するためにライブラリーを使用する方法を紹介します。

データチャネルとは?
----------

WebRTC データチャネルを使用すると、ピアとのアクティブな接続を介してテキストまたはバイナリーデータを送信することができます。ゲームのコンテキストでは、プレイヤーはテキストチャットやゲームのステータス情報など、互いにデータを送信できます。データチャネルには 2 種類のタイプがあります。

**信頼性の高いチャンネル (Reliable channels)** は、送信したメッセージが相手ピアに、送信したのと同じ順序で到着することを保証します。これは TCP ソケットに類似しています。

**信頼性のないチャンネル (Unreliable channels)** は、そのような保証はありません。これは UDP ソケットに類似しています。

私たちの文書化には WebRTC を使用するためのドキュメントがあります。しかし、この記事では、この作業を些細なものにするのに役立ついくつかのライブラリーを利用し、ブラウザ間の実装の違いを回避するために抽象化を使用する方法を説明します。もちろん、このような差異が時間の経過とともに消えていくことを期待しています。

p2p ライブラリーを使用する
---------------

使用できるライブラリーの一つにp2pライブラリーがあります。このライブラリーは、ピア接続を作成し、ストリームとデータチャネルを設定するための簡単なAPIを提供しています。また、ブローカーサーバーコンポーネントとホスティングブローカーもあり、自分で設定する代わりに使用することができます。

**メモ:** 近々、ここにコンテンツを追加していく予定です。

原典情報
----

* 著者: Alan Kligman
* 原典: WebRTC Data Channels for Great Multiplayer
* その他の貢献者: Robert Nyman
* 著作権情報: Alan Kligman, 2013


asm.js の非同期スクリプト - ゲーム開発

asm.js の非同期スクリプト
================

全ての中～大規模ゲームでは、コンパイル処理を最適化してブラウザーを最大限柔軟にする、非同期スクリプトとして asm.js コードをコンパイルします。 Gecko では、非同期コンパイルによって、ゲームの読み込み時に JavaScript エンジンがメインスレッド外で asm.js をコンパイルし、生成した機械語コードをキャッシュして、それ以降の読み込み時にコンパイル不要となります（Firefox 28から）。違いを見るには、`about:config` で `javascript.options.parallel_parsing` を反転させてください。

非同期を動作させる
---------

非同期のコンパイルは簡単です。 JavaScript を書く時に、単に `async` 属性を使います。

```html
<script async src="file.js"></script>
```

あるいは、スクリプトで同じことを行います。

```js
const script = document.createElement("script");
script.src = "file.js";
document.body.appendChild(script);
```

（スクリプトによって生成されるスクリプトは既定で非同期です。）既定の HTML シェル Emscripten は、後者を生成します。

非同期とそうでない時?
-----------

スクリプトが非同期で *ない* 、よく似た状況 (仕様に定義されている通り) では次の通りです。

```html
<script async>
 code;
</script>
```

および

```js
const script = document.createElement("script");
script.textContent = "code";
document.body.appendChild(script);
```

両方とも「インライン」スクリプトと考えられ、コンパイルされて、すぐに実行されます。

コードが JS 文字列内にあった場合はどうでしょう? `eval` や `innerHTML`（両方とも同期コンパイルを起動します）を使う代わりに、 オブジェクトURLと一緒の Blob を使います。

```js
const blob = new Blob([codeString]);
const script = document.createElement("script");
const url = URL.createObjectURL(blob);
script.onload = script.onerror = () => URL.revokeObjectURL(url);
script.src = url;
document.body.appendChild(script);
```

`innerHTML` ではなく `src`　をセットすると、スクリプトが非同期になります。


三次元の衝突検出 - ゲーム開発

三次元の衝突検出
========

この記事では、三次元環境で衝突検出を実装するために使用されるさまざまなバウンディングボリューム手法の概要を説明します。後続の記事では、特定の 3D ライブラリーに搭載されたものを取り上げる予定です。

座標軸に沿ったバウンディングボックス
------------------

二次元の衝突検出と同様に、**座標軸に沿ったバウンディングボックス**（axis-aligned bounding boxes、AABB）は、2つのゲームエンティティが重複しているかどうかを判断するための最も速いアルゴリズムです。 これは、ゲームエンティティを回転しない（つまり座標軸に沿った）ボックスで包み、三次元座標空間でこれらのボックスの位置をチェックして、それらが重なっているかどうかを確認することで構成されます。

![Two 3-D non-square objects floating in space encompassed by virtual rectangular boxes.](/ja/docs/Games/Techniques/3D_collision_detection/screen_shot_2015-10-16_at_15.11.21.png)

**軸配置の制約**があるのは、パフォーマンス上の理由からです。回転していない2つのボックスの間の重複領域は論理比較だけでチェックできますが、回転したボックスではさらに三角関数の演算を運営する必要があり、計算にかかる時間が長くなってしまいます。回転するエンティティがある場合、外接ボックスの寸法を変更してオブジェクトを包むようにするか、球などの別の外接ジオメトリ タイプ（回転に対して不変）を使用できます。以下のアニメーション GIF は、回転するエンティティにサイズを合わせる AABB のグラフィック例です。ボックスは常に寸法を変化させ、中に含まれるコンテナーの中にぴったりとフィットします。

![Animated rotating knot showing the virtual rectangular box shrink and grow as the knots rotates within it. The box does not rotate.](/ja/docs/Games/Techniques/3D_collision_detection/rotating_knot.gif)

**メモ:** この手法の実際の実装については、Three.js を使用したバウンディングボリュームの記事を確認してください。

### 点 対 AABB

点が AABB 内にあるかどうかを確認するのは非常に簡単です。 点の座標が、AABB 内にあるかどうかを確認する必要があります。 各座標軸を個別に検討します。 *Px*、*Py*、*Pz* を点の座標、*BminX*–*BmaxX*、*BminY*–*BmaxY*、*BminZ*–*BmaxZ* を AABB の各座標軸の範囲とすると、次の式を使用して、 2 つの間で衝突が発生したかどうかを計算できます。

f
(
P
,
B
)
=
(

P
x

≥

B

m
i
n
X

∧

P
x

≤

B

m
a
x
X

)
∧
(

P
y

≥

B

m
i
n
Y

∧

P
y

≤

B

m
a
x
Y

)
∧
(

P
z

≥

B

m
i
n
Z

∧

P
z

≤

B

m
a
x
Z

)

f(P, B)= (P\_x \ge B\_{minX} \wedge P\_x \le B\_{maxX}) \wedge (P\_y \ge B\_{minY} \wedge P\_y \le B\_{maxY}) \wedge (P\_z \ge B\_{minZ} \wedge P\_z \le B\_{maxZ})

あるいは、JavaScript では、次のようになります。

```js
function isPointInsideAABB(point, box) {
  return (
    point.x >= box.minX &&
    point.x <= box.maxX &&
    point.y >= box.minY &&
    point.y <= box.maxY &&
    point.z >= box.minZ &&
    point.z <= box.maxZ
  );
}
```

### AABB 対 AABB

AABB が別の AABB と交差するかどうかのチェックは、点のテストと同様です。 ボックスの境界を使用して、座標軸ごとに1つのテストを実行する必要があります。 次の図は、X 軸上で実行するテストを示しています。 基本的には、*AminX*–*AmaxX* と *BminX*–*BmaxX* の範囲は重複しているかです。

![Hand drawing of two rectangles showing the upper right corner of A overlapping the bottom left corner of B, as A's largest x coordinate is greater than B's smallest x coordinate.](/ja/docs/Games/Techniques/3D_collision_detection/aabb_test.png)

数学的には、これは次のようになります。

f
(
A
,
B
)
=
(

A

m
i
n
X

≤

B

m
a
x
X

∧

A

m
a
x
X

≥

B

m
i
n
X

)
∧
(

A

m
i
n
Y

≤

B

m
a
x
Y

∧

A

m
a
x
Y

≥

B

m
i
n
Y

)
∧
(

A

m
i
n
Z

≤

B

m
a
x
Z

∧

A

m
a
x
Z

≥

B

m
i
n
Z

)

f(A, B) = (A\_{minX} \le B\_{maxX} \wedge A\_{maxX} \ge B\_{minX}) \wedge ( A\_{minY} \le B\_{maxY} \wedge A\_{maxY} \ge B\_{minY}) \wedge (A\_{minZ} \le B\_{maxZ} \wedge A\_{maxZ} \ge B\_{minZ})

そして、JavaScript では、これを使用します。

```js
function intersect(a, b) {
  return (
    a.minX <= b.maxX &&
    a.maxX >= b.minX &&
    a.minY <= b.maxY &&
    a.maxY >= b.minY &&
    a.minZ <= b.maxZ &&
    a.maxZ >= b.minZ
  );
}
```

バウンディングスフィア
-----------

バウンディングスフィア（bounding spheres）を使用して衝突を検出することは、AABB よりも少し複雑ですが、それでもテストはかなり迅速です。 球の主な利点は、回転に対して不変であるため、包まれたエンティティが回転しても、バウンディングスフィアは同じままであるということです。 主な欠点は、包んでいるエンティティが実際に球形でない限り、包むのは通常適切ではないことです（つまり、バウンディングスフィアで人を包むと、多くの誤検知が発生しますので、AABB の方が適しています）。

### 点 対 球

球に点が含まれているかどうかを確認するには、点と球の中心との間の距離を計算する必要があります。 この距離が球の半径以下の場合、点は球の内側にあります。

![Hand drawing of a 2D projection of a sphere and a point in a Cartesian coordinate system. The point is outside of the circle, to the lower right of it. The distance is denoted by a dashed line, labeled D, from the circle's center to the point. A lighter line shows the radius, labeled R, going from the center of the circle to the border of the circle.](/ja/docs/Games/Techniques/3D_collision_detection/point_vs_sphere.png)

2つの点 *A* と *B* の間のユークリッド距離が

(

A
x

-

B
x

)
2

)
+
(

A
y

-

B
y

)
2

+
(

A
z

-

B
z

)

\sqrt{(A\_x - B\_x) ^ 2) + (A\_y - B\_y)^2 + (A\_z - B\_z)}

 であることを考慮すると、点対球の衝突検出の式は次のようになります。

f
(
P
,
S
)
=

S

r
a
d
i
u
s

≥

(

P
x

−

S
x

)
2

+
(

P
y

−

S
y

)
2

+
(

P
z

−

S
z

)
2

f(P,S) = S\_{radius} \ge \sqrt{(P\_x - S\_x)^2 + (P\_y - S\_y)^2 + (P\_z - S\_z)^2}

あるいは、JavaScript では、次のようになります。

```js
function isPointInsideSphere(point, sphere) {
  // Math.pow を呼び出すよりも高速であるため、乗算を使用しています
  const distance = Math.sqrt(
    (point.x - sphere.x) \* (point.x - sphere.x) +
      (point.y - sphere.y) \* (point.y - sphere.y) +
      (point.z - sphere.z) \* (point.z - sphere.z),
  );
  return distance < sphere.radius;
}
```

**メモ:** 上記のコードは平方根を特徴としており、計算にコストがかかる可能性があります。 これを回避する簡単な最適化は、距離の2乗と半径の2乗を比較することで構成されているため、最適化された方程式には、代わりに `distanceSqr < sphere.radius * sphere.radius` が含まれます。

### 球 対 球

球対球のテストは、点対球のテストに似ています。 ここでテストする必要があるのは、球の中心間の距離がそれらの半径の合計以下であることです。

![Hand drawing of two partially overlapping circles. Each circle (of different sizes) has a light radius line going from its center to its border, labeled R. The distance is denoted by a dotted line, labeled D, connecting the center points of both circles.](/ja/docs/Games/Techniques/3D_collision_detection/sphere_vs_sphere.png)

数学的には、これは次のようになります。

f
(
A
,
B
)
=

(

A
x

−

B
x

)
2

+
(

A
y

−

B
y

)
2

+
(

A
z

−

B
z

)
2

≤

A

r
a
d
i
u
s

+

B

r
a
d
i
u
s

f(A,B) = \sqrt{(A\_x - B\_x)^2 + (A\_y - B\_y)^2 + (A\_z - B\_z)^2} \le A\_{radius} + B\_{radius}

あるいは、JavaScript では、次のようになります。

```js
function intersect(sphere, other) {
  // Math.pow を呼び出すよりも高速であるため、乗算を使用しています
  const distance = Math.sqrt(
    (sphere.x - other.x) \* (sphere.x - other.x) +
      (sphere.y - other.y) \* (sphere.y - other.y) +
      (sphere.z - other.z) \* (sphere.z - other.z),
  );
  return distance < sphere.radius + other.radius;
}
```

### 球 対 AABB

球と AABB が衝突しているかどうかのテストは少し複雑ですが、それでも単純で高速です。 論理的なアプローチは、AABB のすべての頂点をチェックし、それぞれに対して点対球のテストを実行することです。 ただし、これはやり過ぎです。 AABB の*最も近い点*（必ずしも頂点である必要はありません）と球の中心との間の距離を計算して、球の半径以下であるかどうかを確認するだけで済むため、すべての頂点をテストする必要はありません。 この値は、球の中心を AABB の限界にクランプすることで取得できます。

![Hand drawing of a square partially overlapping the top of a circle. The radius is denoted by a light line labeled R. The distance line goes from the circle's center to the closest point of the square.](/ja/docs/Games/Techniques/3D_collision_detection/sphere_vs_aabb.png)

JavaScript では、次のようにこのテストを行います。

```js
function intersect(sphere, box) {
  // クランプして球の中心からボックスの最も近い点を取得します
  const x = Math.max(box.minX, Math.min(sphere.x, box.maxX));
  const y = Math.max(box.minY, Math.min(sphere.y, box.maxY));
  const z = Math.max(box.minZ, Math.min(sphere.z, box.maxZ));

  // これは isPointInsideSphere と同じです
  const distance = Math.sqrt(
    (x - sphere.x) \* (x - sphere.x) +
      (y - sphere.y) \* (y - sphere.y) +
      (z - sphere.z) \* (z - sphere.z),
  );

  return distance < sphere.radius;
}
```

物理エンジンの使用
---------

**3D 物理エンジン** (3D physics engines) は、衝突検出アルゴリズムを提供していますが、そのほとんどは、バウンディングボリュームにも基づいています。 物理エンジンが機能する方法は、通常はその視覚的表現に付属した**物理的なボディ** (physical body) を作成することです。 このボディには、速度、位置、回転、トルクなどのプロパティと、**物理的な形状** (physical shape) があります。 この形状は、衝突検出の計算で考慮されるものです。

このような手法が実際に動作していることを確認できるライブ衝突検出デモ（ソースコード付き）を用意しました。 これは、オープンソースの 3D 物理エンジン cannon.js を使用しています。

関連情報
----

MDN の関連記事

* Three.js によるバウンディングボリューム衝突検出
* 2D 衝突検出

外部リソース

* Gamasutra のゲームのための簡単な交点テスト（英語）
* ウィキペディアのバウンディングボリューム（英語）


ウェブ上の 3D ゲームの概要 - ゲーム開発

ウェブ上の 3D ゲームの概要
===============

ウェブでのリッチなゲーム体験を実現するためには、HTML の `<canvas>` 上にレンダリングされる WebGL が武器となります。 WebGL は基本的にウェブ用の OpenGL ES 2.0 であり、リッチでインタラクティブなアニメーションや、もちろんゲームを構築するためのツールを提供する JavaScript API です。ハードウェアアクセラレーションによる JavaScript で、動的な 3D グラフィックを生成し、レンダリングすることができます。

ドキュメントとブラウザーの対応
---------------

WebGL プロジェクトのドキュメントと仕様書は、 Khronos Group が管理しており、ほとんどの Web API のように W3C が管理しているわけではありません。最近のブラウザーでの対応は、モバイルでも非常に優れているので、あまり気にする必要はありません。主要なブラウザーはすべて WebGL に対応しており、使用する端末でのパフォーマンスを最適化することに集中すればよいのです。

近い将来、 WebGL 2.0（OpenGL ES 3.0 に基づく）のリリースに向けた継続的な取り組みがあります。これにより、多くの改善がもたらされ、開発者は現在の強力なハードウェアを使用して最新のウェブ用のゲームを構築することができるようになります。

基本的な 3D 理論の説明
-------------

3D 理論の基本は、3D 空間で表される形状を中心としており、座標系を使用してそれらの位置を計算します。必要なすべての情報については、基本的な 3D 理論の説明の記事を参照してください。

高度な概念
-----

WebGL を使用すると、さらに多くのことができます。シェーダー、衝突検出、または最新のホットトピックであるウェブ上の仮想現実など、詳細に掘り下げて学ぶ必要のある高度な概念がいくつかあります。

### シェーダー

それ自体は別の話であるシェーダーについて言及する価値があります。 シェーダーは、グラフィックパイプラインによって直接実行される C と同様の構文を持つ特別な OpenGL シェーディング言語である GLSL を使用します。 これらは、頂点シェーダーとフラグメントシェーダー（またはピクセルシェーダー）に分割できます。 前者は形状の位置を実際の 3D 描画座標に変換し、後者はレンダリングする色やその他の属性を計算します。 それらの詳細については、GLSL シェーダーの記事を必ず確認してください。

### 衝突検出

衝突検出のないゲームを想像するのは難しいです — 何かが何かにぶつかっているときには、常にそれを解決する必要があります。 以下に学ぶことができる情報があります。

* 2D の衝突検出
* 3D の衝突検出
### WebVR

仮想現実の概念は新しいものではありませんが、Oculus Rift などのハードウェアの進歩と VR ハードウェアから情報をキャプチャして JavaScript アプリケーションで使用できるようにするための (現在実験的な) WebVR API のおかげで、ウェブに押し寄せています。 詳細については、WebVR — ウェブによる仮想現実をご覧ください。

また、A-Frame を使った基本的なデモの構築の記事では、 A-Frame フレームワークを使用して仮想現実の 3D 環境を構築することがいかに簡単であるかを示しています。

ライブラリーとフレームワークの台頭
-----------------

生の WebGL のコーディングはかなり複雑ですが、プロジェクトがより高度になるにつれて、長期的にはそれを理解する必要があります（始めるには、WebGL ドキュメントを参照してください）。 実際のプロジェクトでは、開発をスピードアップし、作業中のプロジェクトを管理するのに役立つフレームワークをたぶん使うことになるでしょう。 3D ゲームのフレームワークを使用すると、使用するツールによって多くの処理が行われるため、パフォーマンスを最適化するのにも役立ちます。 これにより、ゲーム自体の構築に集中できます。

最も人気のある JavaScript の 3D ライブラリーは Three.js で、一般的な 3D 技術をより簡単に実装できる多目的ツールです。 他にもチェックする価値のある人気のあるゲーム開発ライブラリーやフレームワークとして、 A-Frame、PlayCanvas、Babylon.js などは、豊富なドキュメント、オンラインエディター、活発なコミュニティを備えた、最もよく知られたものです。

### A-Frame を使った基本的なデモの構築

A-Frame は、3D および VR エクスペリエンスを構築するためのウェブフレームワークです。 内部的には、宣言型のエンティティコンポーネントパターンを備えた Three.js フレームワークなので、 HTML だけでシーンを構築できます。 デモを作成するステップバイステップのプロセスについては、A-Frame を使った基本的なデモの構築のサブページを参照してください。

### Babylon.js を使った基本的なデモの構築

Babylon.js は、開発者が使用する最も人気のある 3D ゲームエンジンの 1 つです。 他の 3D ライブラリーと同様に、一般的な 3D 機能をより迅速に実装するのに役立つ組み込み関数を提供します。 開発環境のセットアップ、必要な HTML の構造化、JavaScript コードの記述など、Babylon.jsの 基本的な使い方については、Babylon.js を使った基本的なデモの構築のサブページを参照してください。

### PlayCanvas を使った基本的なデモの構築

PlayCanvas は、GitHub でオープンソース化された人気の 3D WebGL ゲームエンジンであり、オンラインで利用可能なエディターと優れたドキュメントを備えています。 より高度な詳細については、PlayCanvas を使った基本的なデモの構築のサブページを参照してください。 また、PlayCanvas ライブラリーとオンラインエディターを使ったデモの作成方法については、さらに詳しい記事を参照してください。

### Three.js を使った基本的なデモの構築

Three.js は、他のライブラリーと同様に、巨大なアドバンテージを提供します。 何百行もの WebGL コードを記述して興味深いものを構築する代わりに、組み込みのヘルパー関数を使用して、はるかに簡単かつ迅速に構築できます。 デモを作成するステップバイステップのプロセスについては、Three.js を使った基本的なデモの構築のサブページを参照してください。

### その他のツール

Unity と Unreal はどちらも asm.js を使用してゲームを WebGL にエクスポートできるため、それらのツールとテクニックを自由に使用して、ウェブにエクスポートするゲームを構築できます。

![](/ja/docs/Games/Techniques/3D_on_the_web/shapes.png)

次に行くべきところ
---------

この記事では、現在利用可能な技術で可能なことの表面に触れただけです。WebGL とその上に構築されたライブラリーやフレームワークを使用すれば、ウェブ上で没入感のある、美しく、高速な 3D ゲームを構築することができます。

### ソースコード

このシリーズのデモのすべてのソースコードは GitHub にあります。

### API

* Canvas API
* WebGL API
* WebVR API
### フレームワーク

* Three.js
* PlayCanvas
* Babylon.js
* A-Frame
### チュートリアル

* Three.js を使った基本的なデモの構築
* PlayCanvas を使った基本的なデモの構築
* Babylon.js を使った基本的なデモの構築
* A-Frame を使った基本的なデモの構築


ゲームパッド API を使用したコントロールの実装 - ゲーム開発

ゲームパッド API を使用したコントロールの実装
=========================

この記事では、ゲームパッド API を使用してウェブゲーム用の効果的なクロスブラウザー制御システムを実装し、ゲーム機のゲームコントローラーを使用してウェブゲームを制御できるようにします。 Enclave Games によって作成されたケーススタディゲーム Hungry Fridge を掲載しています。

ウェブゲームのコントロール
-------------

歴史的には、テレビに接続されたゲーム機でゲームをすることと、 PC 上でのゲームとはまったく異なる体験でした。最終的にはドライバーとプラグインにより、ゲーム機のゲームパッドをデスクトップゲーム――ネイティブかブラウザーで実行されるゲーム――で使用できるようになりました。ゲームパッド API が登場し、プラグインなしでゲームパッドコントローラを使用してブラウザーベースのゲームをプレイできるようになりました。ゲームパッド API は、入力を処理するために JavaScript コード内で使用できるボタンの押下と軸の変更を公開するインターフェイスを提供することで、これを実現します。 これらは、ブラウザーゲームにとって良いことです。

API ステータスとブラウザーサポート
-------------------

ゲームパッド API は W3C のプロセスではまだ草案の状態であり、まだ実装が変わることがありますが、ブラウザーの対応はかなり良い状態です。 Firefox 29 以降はそのまま使用できます。 Opera はバージョン 22 以降で API に対応しています（Chrome の Blink エンジンを使用していることを考えると驚くことではありません）。 Microsoft は Edge にて API をサポートしており、ゲームパッド API は 4 つの主要なブラウザーが現在対応しています。

どのゲームパッドが良いか？
-------------

現在最も人気のあるゲームパッドは XBox 360、XBox One、PS3 や PS4 であり、これらは かなりテストが行われており、Windows や Mac OS X のブラウザーでゲームパッド API がうまく動いています。

さまざまなボタンレイアウトを備えたデバイスも多数あり、ブラウザーの実装によって多かれ少なかれ動作します。 この記事で取り上げたコードはいくつかのゲームパッドでテストしましたが、著者の好みはワイヤレス XBox 360 コントローラと Mac OS X 上の Firefox ブラウザーの組み合わせです。

ケーススタディ: Hungry Fridge
----------------------

GitHub Game Off II のコンペが 2013 年 11 月に実施され、 Enclave Games が参加することに決めました。コンペのテーマは「変化」で、 Hungry Fridge に健康な食べ物（リンゴ、ニンジン、レタス）をタップして与え、「悪しき」食べ物（ビール、ハンバーガー、ピザ）を避けるゲームを提出しました。カウントダウンで、Fridgeが食べたいものの種類が数秒ごとに変わるので、注意してすばやく行動する必要があります。

2 番目の、隠された「変化」の実装は、静的な Fridge を本格的な移動式射撃食堂に変えることです。 コントローラーを接続すると、ゲームが大きく変わります（Hungry Fridge が Super Turbo Hungry Fridge に変わります）、ゲームパッド API を使用して装甲冷蔵庫を制御できます。 あなたは食べ物を撃たなければなりませんが、もう一度、冷蔵庫が各所で食べたい食べ物の種類を見つけなければなりません。そうしないとエネルギーが失われます。

このゲームは、 2 つの全く異なるタイプの「変化」をカプセル化しています。

デモ
--

Hungry Fridge ゲームのフルバージョンが最初に構築され、次にゲームパッド API が実際に表示され、JavaScript のソースコードが表示され、簡単なデモが作成されました。 これは GitHub で利用可能な Gamepad API Content Kit の一部であり、コードを深く掘り下げてどのように動作するかを正確に調べることができます。

以下に説明するコードは、Hungry Fridge ゲームのフルバージョンからのものですが、デモのものとほぼ同じです。唯一の違いは、フルバージョンでは、スーパーターボモードを使用してゲームを起動するかどうかを決定する`ターボ`変数。 これは独立して機能するので、ゲームパッドが接続されていなくてもオンにすることができます。

**メモ:** イースターエッグの時間: ゲームパッドを接続せずにデスクトップで Super Turbo Hungry Fridge を起動する隠しオプションがあります。スクリーンの右上にあるゲームパッドアイコンをクリックします。 それはスーパーターボモードでゲームを起動し、あなたはキーボードで冷蔵庫を制御することができます。タレットを左右に回すたには A と D、撃つためには W、移動の多面実は矢印キーを使います。

実装
--

ゲームパッド API で使用する重要なイベントは、`gamepadconnected` と `gamepaddisconnected` の2つです。最初のイベントは、ブラウザが新しいゲームパッドの接続を検出したときに発行され、 2 つ目はゲームパッドが切断されたときに発行されます（ユーザーによる物理的な切断、または操作不能による切断）。このデモでは、`gamepadAPI` オブジェクトを使用して API に関するすべての情報を格納しています。

```js
const gamepadAPI = {
  controller: {},
  turbo: false,
  connect() {},
  disconnect() {},
  update() {},
  buttonPressed() {},
  buttons: [],
  buttonsCache: [],
  buttonsStatus: [],
  axesStatus: [],
};
```

`buttons` の配列は XBox 360 ボタンレイアウトを格納します。

```js
buttons: [
  'DPad-Up','DPad-Down','DPad-Left','DPad-Right',
  'Start','Back','Axis-Left','Axis-Right',
  'LB','RB','Power','A','B','X','Y',
],
```

これは、 PS3 コントローラ（または名前のない、一般的なもの）のような他のタイプのゲームパッドでは異なる場合があり、期待しているボタンが実際に得るのと同じボタンになるか注意する必要があり、また仮定してはいけません。

```js
window.addEventListener("gamepadconnected", gamepadAPI.connect);
window.addEventListener("gamepaddisconnected", gamepadAPI.disconnect);
```

セキュリティポリシーのため、イベントが発生するとページが表示されている間にコントローラーと最初にやりとりする必要があります。 API がユーザーとのやりとりなしで動作した場合、 API を認識することなくフィンガープリントに使用できます。

どちらの関数もかなりシンプルです。

```js
connect(evt) {
  gamepadAPI.controller = evt.gamepad;
  gamepadAPI.turbo = true;
  console.log('Gamepad connected.');
},
```

`connect()` 関数はイベントを引数として受け取り、 `gamepad` オブジェクトを `gamepadAPI.controller` 変数に代入します。このゲームでは 1 つのゲームパッドしか使用しないため、ゲームパッドの配列ではなく単一のオブジェクトです。次に、 `turbo` プロパティを `true` に設定します。（この目的のために `gamepad.connected` という論理値を使用することができましたが、上で説明した理由から、ゲームパッドを接続しなくてもターボモードを有効にするための別の変数が必要でした）。

```js
disconnect(evt) {
  gamepadAPI.turbo = false;
  delete gamepadAPI.controller;
  console.log('Gamepad disconnected.');
},
```

`disconnect` 関数は `gamepad.turbo` プロパティを `false` に設定し、gamepad オブジェクトを含む変数を削除します。

### Gamepad オブジェクト

`gamepad` オブジェクトには、ボタンや軸の状態が最も重要な情報がたくさんあります。

* `id`: コントローラーに関する情報を含む文字列。
* `index`: 接続したデバイスを定義するユニークな識別子。
* `connected`: 接続時に `true` になる真偽値の変数。
* `mapping`: ボタンのレイアウトタイプ。 標準は現在利用可能な唯一のオプション。
* `axes`: 各軸の状態。浮動小数点値の配列で表される。
* `buttons` : `pressed` プロパティと `value` のプロパティを含む `GamepadButton` オブジェクトの配列で表される各ボタンの状態。

`index` 変数は、 2 つ以上のコントローラを接続しており、2つのデバイスが接続されている2人のゲームがある場合など、それらを識別する必要がある場合に便利です。

### gamepad オブジェクトのクエリー

`connect()` と `disconnect()` のほかに、`gamepadAPI` オブジェクトには `update()` と `buttonPressed()` の 2 つのメソッドがあります。 `update()`は、ゲームループ内のすべてのフレームで実行され、ゲームパッドオブジェクトの実際のステータスを定期的に更新します：

```js
update() {
  // Clear the buttons cache
  gamepadAPI.buttonsCache = [];

  // Move the buttons status from the previous frame to the cache
  for (let k = 0; k < gamepadAPI.buttonsStatus.length; k++) {
    gamepadAPI.buttonsCache[k] = gamepadAPI.buttonsStatus[k];
  }

  // Clear the buttons status
  gamepadAPI.buttonsStatus = [];

  // Get the gamepad object
  const c = gamepadAPI.controller || {};

  // Loop through buttons and push the pressed ones to the array
  const pressed = [];
  if (c.buttons) {
    for (let b = 0; b < c.buttons.length; b++) {
      if (c.buttons[b].pressed) {
        pressed.push(gamepadAPI.buttons[b]);
      }
    }
  }

  // Loop through axes and push their values to the array
  const axes = [];
  if (c.axes) {
    for (let a = 0; a < c.axes.length; a++) {
      axes.push(c.axes[a].toFixed(2));
    }
  }

  // Assign received values
  gamepadAPI.axesStatus = axes;
  gamepadAPI.buttonsStatus = pressed;

  // Return buttons for debugging purposes
  return pressed;
},
```

すべてのフレームで、 `update()` は前のフレームで押されたボタンを `buttonsCache` 配列に保存し、新しいものを `gamepadAPI.controller` オブジェクトから取得します。 次に、実際の状態と値を取得するためにボタンと軸をループします。

### ボタンプレスの検出

`buttonPressed()` メソッドはメインのゲームループに配置され、ボタンの押下を待機します。 2 つの引数、つまり待ち受けするボタンと、ボタンを押したままにすることをゲームに伝える（オプション）方法があります。 それがなければ、ボタンを放してもう一度押して、希望する効果を持たなければなりません。

```js
buttonPressed(button, hold) {
  let newPress = false;

  // Loop through pressed buttons
  for (let i = 0; i < gamepadAPI.buttonsStatus.length; i++) {
    // If we found the button we're looking for
    if (gamepadAPI.buttonsStatus[i] === button) {
      // Set the boolean variable to true
      newPress = true;

      // If we want to check the single press
      if (!hold) {
        // Loop through the cached states from the previous frame
        for (let j = 0; j < gamepadAPI.buttonsCache.length; j++) {
          // If the button was already pressed, ignore new press
          newPress = (gamepadAPI.buttonsCache[j] !== button);
        }
      }
    }
  }
  return newPress;
},
```

ボタンには、 1 回の押下と長押しの2種類のアクションがあります。論理型の `newPress` 変数は、ボタンの新規押下があるかどうかを示します。 次に、押されたボタンの配列をループします。指定されたボタンが探しているボタンと同じ場合、`newPress` 変数は `true` に設定されます。 プレスが新しいものかどうかを確認するために、プレイヤーがキーを保持していないので、ゲームループの前のフレームからのボタンのキャッシュ状態をループします。 ボタンが見つかった場合、ボタンが押されていることを意味するので、新しいプレスはありません。 最後に、`newPress` 変数が返されます。 `buttonPressed` 関数は、このようなゲームの更新ループで使用されます：

```js
if (gamepadAPI.turbo) {
  if (gamepadAPI.buttonPressed("A", "hold")) {
    this.turbo\_fire();
  }
  if (gamepadAPI.buttonPressed("B")) {
    this.managePause();
  }
}
```

`gamepadAPI.turbo` が `true` で、指定されたボタンが押された (または保持されている) 場合、それらに割り当てられた適切な関数を実行します。 この場合、 `A` を押すと、弾丸が発射され、 `B` を押すとゲームが一時停止します。

### 軸のしきい値

ボタンには `0` または `1` の 2 つの状態しかありませんが、アナログスティックは `X` 軸と `Y` 軸の両方に沿って `-1` と `1` の間の浮動小数点範囲を持っています。

ゲームパッドは使用しないまま放置しておくと、ホコリで汚れてしまうことがあり、-1 や 1 の値を正確にチェックすることが難しくなります。このため、軸の値が有効になるための閾値を設定するとよいでしょう。例えば、Fridge のタンクは、 `X` の値が `0.5` より大きいときだけ右に曲がります。

```js
if (gamepadAPI.axesStatus[0].x > 0.5) {
  this.player.angle += 3;
  this.turret.angle += 3;
}
```

たとえ誤って少し動かしても、スティックが元の位置に戻らない場合でも、タンクが予期せず回転することはありません。

仕様書の更新
------

1 年以上の安定の後、 2015 年 4 月に W3C Gamepad API 仕様書が更新されました (最新の仕様を参照) 。あまり変わっていませんが、何が起こっているのかを知ることは良いことです。

### ゲームパッドの取得

`Navigator.getGamepads()` メソッドが長い説明とコードの例と共に更新されました。ゲームパッドの配列の長さは `n+1` でなければなりません。ここで `n` は接続されている機器の数です。`[null, [object Gamepad]]` となります。機器が切断されていたり、利用できない場合は、その機器に対応する値が `null` に設定されます。

### マッピング標準

マッピング型は、文字列ではなく列挙型のオブジェクトになりました。

```ts
enum GamepadMappingType {
  "",
  "standard",
}
```

この列挙型は、ゲームパッドの既知のマッピングのセットを定義します。 今のところ `standard` のレイアウトしかありませんが、将来は新しいレイアウトが登場する可能性があります。 レイアウトが不明な場合は、空の文字列に設定されます。

### イベント

仕様書には `gamepadconnected` と `gamepaddisconnected` 以外にも使用できるイベントがあったが、とても特殊なものではないと判断され、仕様書から削除された。それらを戻すべきかどうか、またどのような形で戻すべきかについては、現在も議論が続いています。

概要
--

ゲームパッド API は、とても簡単に開発することができます。プラグインを一切使わずに、ゲーム機のような体験をブラウザで実現することが、これまで以上に簡単にできるようになりました。ブラウザーで直接、 Hungry Fridge のフルバージョンをプレイすることができます。 Gamepad API Content Kit の他のリソースもチェックしてみてください。


ウェブゲーム用の音声 - ゲーム開発

ウェブゲーム用の音声
==========

音声はゲームの重要部分です。つまりこれはフィードバックと雰囲気を与えます。ウェブベースの音声は早くから成熟していますが、まだ多くのブラウザーに案内すべき違いがあります。ゲームエクスペリエンスにとってどの音声パーツが重要で、どれがあっても良いけど不要なものかを決めて、それに従って戦略を決めるのが必要となる事がよくあります。この記事ではウェブゲーム用の音声を実装するための詳細なガイドを提供し、現在なるべく広い範囲のプラットフォームで動作するものを観察します。

モバイル音声の注意点
----------

これまでウェブオーディオのサポートを提供するのに最も難しいプラットフォームはモバイルプラットフォームでした。不幸にもこれはゲームで遊ぶ人が良くいるプラットフォームです。デスクトップとモバイルのブラウザーにはいくつかの違いがあり、それがブラウザーベンダーに、ゲーム開発者が作業するのが難しくなるウェブオーディオの選択を起こすことがありました。これを見ていきましょう。

### 自動再生

ブラウザー自動再生ポリシーは、デスクトップ*および*モバイルブラウザーに影響を与えるようになりました。それについての詳細な情報があります Google Developers サイトからこちら。

音声付きの自動再生が許可されるのは、次のような場合であることは特筆すべきです。

* ユーザーがドメインと対話したことがあること。
* モバイルでは、ユーザーがサイトを画面の内側へ追加した場合に許可されます。

多くのモバイルブラウザーは、ゲームが音声再生するように要求しても単に無視します。つまり音声の再生にはユーザーが開始するイベントが必要です。これは音声再生の構成を考慮する必要があるということです。これは通常、事前に音声を読み込んでユーザーが開始するイベントに準備しておくことで守られます。

受動的な音声の自動再生、例えばゲームが読み込まれるとすぐに始まる BGM の場合、ユーザーが開始したイベントを検知して再生を開始するのも 1 つの方法です。ゲーム中に使用できるアクティブなサウンドの場合は、"Start" ボタンなどが押された時点で再生させることもできます。

このように音声を再生するには、その一部を再生する必要があります。そのためには、音声サンプルの最後に一瞬の無音を入れるのが効果的です。この無音部分にジャンプして再生し、一時停止することで、JavaScript を使用して任意の時点でそのファイルを再生できるようになります。自動再生ポリシーの最善の手法はこちら (en-US)で詳しく説明されています。

**メモ:** もしブラウザーがあなたに音量を変更することを許可するならば、ファイルを音量ゼロで再生することも可能でしょう（後述）。また、音声を再生後に即時停止することは、音声の小さな断片が再生されないことを保証しない、ということにも注意してください。

**メモ:** モバイルのホーム画面にウェブアプリを追加することで特性が変化してしまうかもしれません。今のところ、 iOS 上の自動再生がこのケースに当てはまるようです。可能であれば、いくつかのデバイスとプラットフォームでコードがどう動くか試すべきです。

### 音量

ボリュームコントロールのプログラムはモバイルブラウザーで無効化されていることがあります。この理由はしばしばユーザーが OS レベルでボリュームをコントロールし、上書きが禁止されているためです。

### バッファリングと先読み

急騰するモバイルネットワークのデータ使用を軽減するための試みとして、再生開始前のバッファリングができなくなることが恐らくあります。バッファリングとは、ブラウザーが前もってメディアのダウンロードをする処理であり、円滑な再生を確実なものにするために度々必要になります。

`HTMLMediaElement` インターフェイスが備える 多くのプロパティ はトラックが再生可能な状態にあるかどうかを決定する助けになります。

**メモ:** 色々な意味でバッファリングの概念は時代遅れです。バイトレンジリクエストが許容される限り（これが既定の振る舞いです）、先行する内容のダウンロードの必要なしに音声の任意の点に飛ぶことができるべきです。しかしながら、先読みは依然として便利です。それなしでは、再生が始められるようになる前に、常にいくらかのクライアント・サーバー間通信が必要になるでしょう。

### 並行した音声再生

多くのゲームでは、複数の音声を同時に再生することが求められます。例えば、ゲーム内で様々なことが起こるために、バックグラウンドミュージックと効果音を一緒に再生することがあります。この状況は近々、 ウェブオーディオ API の採用でもっと上手くいくようになる予定ですが、現状最も広くサポートされている方法 ― 平凡な `<audio>` 要素を使用すること ― は、モバイル端末上では不安定な結果になります。

### テストとサポート

ここでは、どのモバイルプラットフォームが前述した機能をサポートするかを表に示します。

ウェブオーディオ機能のモバイル対応| モバイルブラウザー | バージョン | 同時再生 | 自動再生 | 音量調整 | 先読み |
| --- | --- | --- | --- | --- | --- |
| Chrome (Android) | 69+ | Y | Y | Y | Y |
| Firefox (Android) | 62+ | Y | Y | Y | Y |
| Edge Mobile |  | Y | Y | Y | Y |
| Opera Mobile | 46+ | Y | Y | Y | Y |
| Safari (iOS) | 7+ | Y/N\* | N | N | Y |
| Android Browser | 67+ | Y | Y | Y | Y |

モバイルとデスクトップの HTMLMediaElement に対応している完全な互換性表があります。

**メモ:** 音声の同時再生は私たちの同時音声テストの例を使ってテストされますが、そこでは標準の音声 API を使って 3 つの音声の同時再生を試しています。

**メモ:** 単純な自動再生機能は私たちの自動再生テストの例でテストされます。

**メモ:** 音量の可変性は私たちの音量テストの例でテストされます。

モバイルの回避処理
---------

モバイルブラウザーは問題を抱えていますが、上に詳述した問題については回避する方法があります。

### 音声スプライト

音声スプライトは CSS スプライトから名前をとったもので、 CSS スプライトとは単一グラフィックリソースを連続したスプライトに分解して使う CSS のための視覚的なテクニックです。同じ原理を音声に適用することで、読み込みと再生に時間のかかる小さな音声ファイルの束ではなく、必要とする音声すべてを含む大きな音声ファイル一つを用いることができます。そのファイルから特定の音を再生するには、各音声スプライトの既知の開始・停止時間を指定するだけです。

利点は、一つの音声を前もって提供しておき、スプライトをすぐ使える状態にできることです。こうすることで、大きな一つの音声の再生と即時停止をするだけですみます。また、サーバーリクエスト数を減らすことと、帯域幅を節約することもできます。

```js
const myAudio = document.createElement("audio");
myAudio.src = "mysprite.mp3";
myAudio.play();
myAudio.pause();
```

停止すべき時間を知るために、現在時間のサンプリングをする必要があるでしょう。もし個々の音声について 500ms 以上の間隔をあけるなら、 `timeUpdate` イベント（250ms 毎に発動します）を使うことで事足りるはずです。ファイルは厳密に必要であるよりわずかに長くなりますが、無音部分はよく圧縮されます。

ここに音声スプライトプレイヤーの例があります。 ― まずはHTMLでユーザーインターフェイスを構築しましょう:

```html
<audio id="myAudio" src="http://jPlayer.org/tmp/countdown.mp3"></audio>
<button data-start="18" data-stop="19">0</button>
<button data-start="16" data-stop="17">1</button>
<button data-start="14" data-stop="15">2</button>
<button data-start="12" data-stop="13">3</button>
<button data-start="10" data-stop="11">4</button>
<button data-start="8" data-stop="9">5</button>
<button data-start="6" data-stop="7">6</button>
<button data-start="4" data-stop="5">7</button>
<button data-start="2" data-stop="3">8</button>
<button data-start="0" data-stop="1">9</button>
```

今、開始・停止時間を秒単位で指定したボタンがあります。"countdown.mp3" という MP3 ファイルは 2 秒ごとに声に出された数字から成り、ここで意図していることは、対応するボタンが押された時にその数が再生されるということです。

このように動作する JavaScript を追加しましょう。

```js
const myAudio = document.getElementById("myAudio");
const buttons = document.getElementsByTagName("button");
let stopTime = 0;

for (const button of buttons) {
  button.addEventListener(
    "click",
    () => {
      myAudio.currentTime = button.getAttribute("data-start");
      stopTime = button.getAttribute("data-stop");
      myAudio.play();
    },
    false,
  );
}

myAudio.addEventListener(
  "timeupdate",
  () => {
    if (myAudio.currentTime > stopTime) {
      myAudio.pause();
    }
  },
  false,
);
```

**メモ:** JSFiddle　上で私たちの音声スプライトプレイヤーライブを試すことができます。

**メモ:** 上に詳述したように、モバイルでは、スタートボタンが押されるといったようなユーザー開始イベントからコードを発動させる必要があるかもしれません。

**メモ:** ビットレートに気をつけてください。低ビットレートのエンコードではファイルサイズは小さくなりますが、シーク精度も低くなります。

### バックグラウンドミュージック (BGM)

ゲーム内の音楽は感情に訴える強力な効果があります。あなたは様々な楽曲サンプルを組み合わせることができ、さらに、音声要素のボリュームをコントロールすることができることを想定すれば、異なる楽曲をクロスフェードさせることができます。 `playbackRate()` を使うことで、動きにより良く同期させるために、ピッチに影響なく音楽のスピードの調節もできます。

これは標準の `<audio>` 要素を使って `HTMLMediaElement` と連携しさえすれば可能となりますが、より発展した ウェブオーディオ API を使えばもっと簡単で柔軟になります。次にこれについて見ていきましょう。

### ゲーム向けのウェブオーディオ API

ウェブオーディオ APIは、 Opera Mini を除く、最近のすべてのデスクトップおよびモバイルブラウザーで対応しています。このことを考慮すれば、多くの場面でウェブオーディオ API を使用することは受け入れられるアプローチです（ブラウザーの互換性については Can I use Web Audio API ページ を参照してください）。ウェブオーディオ API は、ゲーム音声に最適な、高度な音声 JavaScript API です。開発者は、音声の生成や音声サンプルの操作だけでなく、三次元のゲーム空間での音声の位置決めも可能です。

実現可能なクロスブラウザー戦略は、標準の `<audio>` 要素を使用して基本的な音声を提供し、対応している場合はウェブオーディオ API を使用して体験を拡張することでしょう。

**メモ:** 重要なのは、 iOS Safari がウェブオーディオ API に対応していることです。つまり、iOS 向けのネイティブ品質の音声で、ウェブベースのゲームを書くことが可能になりました。

ウェブオーディオ API は音声再生の正確な時刻と制御を可能にするので、ゲームの没入感を高める重要な要素である、特定の瞬間にサンプルを再生するために使用することができます。ゲームの没入感を高めるには、爆発の後に轟音が続くのではなく、轟音と一緒に爆発してほしいものです。

### ウェブオーディオ API での BGM

`<audio>` 要素を使用して、ゲーム環境に反応して変化しない直線的な BGM を流すこともできますが、ウェブオーディオ API はよりダイナミックな音楽体験を搭載するのに理想的です。サスペンスを盛り上げるのか、プレイヤーを何らかの形で勇気づけるのかによって、音楽を変化させたい場合があります。音楽はゲーム体験の重要な要素であり、入力するゲームの型によっては、正しい音楽 を提供するために多大な労力を費やすことになるかもしれません。

音楽サウンドトラックをよりダイナミックにする方法の1つとして、ループやトラックに分割する方法があります。ウェブオーディオ API は、これらのパーツを同期させるのに非常に優れています。楽曲を構成する様々なトラックを保有したら、必要に応じてトラックを出し入れすることができます。

また、音楽にフィルターや エフェクトをかけることもできます。キャラクターは洞窟の中にいるのでしょうか？エコーを強くしましょう。水中のシーンがある場合は、音を消すフィルターを適用することもできます。

ここでは、ウェブオーディオ API のテクニックを使って、ベースとなるトラックから動的に音楽を調整する方法を見ていきましょう。

### トラックを読み込む

ウェブオーディオ API では、 `XMLHttpRequest` または Fetch API を使用して別個のトラックやループを個別に読み込むことができ、これは同期的にまたは並行してそれらを読み込むことができることを意味します。同期的に読み込むと、音楽の一部が早く準備でき、他のものが読み込まれている間に再生を開始することができます。

いずれにせよ、トラックやループを同期させたいと思うかもしれません。ウェブオーディオ API には、音声コンテキストを作成した瞬間に動き出す内部時計という概念があります。音声コンテキストを作成してから、最初の音声トラックが再生されるまでの時間を考慮する必要があります。このオフセットを記録し、再生中のトラックの現在時刻を問い合わせることで、別個の音声を同期させるのに十分な情報が得られます。

これを実際に見るために、別個のトラックをいくつか並べてみましょう。

```html
<section id="tracks">
  <ul>
    <li data-loading="true">
      <a href="leadguitar.mp3" class="track">Lead Guitar</a>
      <p class="loading-text">Loading…</p>
      <button data-playing="false" aria-describedby="guitar-play-label">
        <span id="guitar-play-label">Play</span>
      </button>
    </li>
    <li data-loading="true">
      <a href="bassguitar.mp3" class="track">Bass Guitar</a>
      <p class="loading-text">Loading…</p>
      <button data-playing="false" aria-describedby="bass-play-label">
        <span id="bass-play-label">Play</span>
      </button>
    </li>
    <li data-loading="true">
      <a href="drums.mp3" class="track">Drums</a>
      <p class="loading-text">Loading…</p>
      <button data-playing="false" aria-describedby="drums-play-label">
        <span id="drums-play-label">Play</span>
      </button>
    </li>
    <li data-loading="true">
      <a href="horns.mp3" class="track">Horns</a>
      <p class="loading-text">Loading…</p>
      <button data-playing="false" aria-describedby="horns-play-label">
        <span id="horns-play-label">Play</span>
      </button>
    </li>
    <li data-loading="true">
      <a href="clav.mp3" class="track">Clavi</a>
      <p class="loading-text">Loading…</p>
      <button data-playing="false" aria-describedby="clavi-play-label">
        <span id="clavi-play-label">Play</span>
      </button>
    </li>
  </ul>
  <p class="sourced">
    All tracks sourced from <a href="https://jplayer.org/">jplayer.org</a>
  </p>
</section>
```

これらのトラックはすべて同じテンポで、互いに同期するように設計されているので、それらを再生できるようにする*前に*、それらが読み込まれて API が利用可能であることを確認する必要があります。これは、 JavaScript の `async`/`await` 機能を使用して行うことができます。

再生が可能になったら、他のトラックが再生しているであろう正しい点から開始するようにし、同期させる必要があります。

それでは、音声コンテキストを作成しましょう。

```js
const audioCtx = new AudioContext();
```

ここで、`<li>`要素をすべて選択してみましょう。後で、これらの要素を利用して、トラックのファイルパスや個々の再生ボタンにアクセスすることができます。

```js
const trackEls = document.querySelectorAll("li");
```

使用する前に、各ファイルが読み込まれてバッファーにデコードされたことを確認したいので、これを可能にする `async` 関数を作成しましょう。

```js
async function getFile(filepath) {
  const response = await fetch(filepath);
  const arrayBuffer = await response.arrayBuffer();
  const audioBuffer = await audioCtx.decodeAudioData(arrayBuffer);
  return audioBuffer;
}
```

そして、この関数を呼び出すときに `await` 演算子を使用することで、実行が完了したときに後続のコードを確実に実行することができます。

サンプルを設定するために、もうひとつ `async` 関数を作成しましょう。2 つの非同期関数をうまくプロミスパターンで組み合わせれば、各ファイルが読み込まれてバッファリングされたときに、さらにアクションを実行することができます。

```js
async function loadFile(filePath) {
  const track = await getFile(filePath);
  return track;
}
```

また、 `playTrack()` 関数も作成しましょう。これは、一度ファイルを取得したときに呼び出すことができます。あるファイルの再生を開始したときに、どの程度先にある別のファイルを開始すればよいかを記録しておくために、ここではオフセットが必要です。

`start()` はオプションで 2 つの引数を見なされます。 1 つ目は再生を開始するタイミング、 2 つ目は再生する場所、つまりオフセットを指定します。

```js
let offset = 0;

function playTrack(audioBuffer) {
  const trackSource = audioCtx.createBufferSource();
  trackSource.buffer = audioBuffer;
  trackSource.connect(audioCtx.destination);

  if (offset === 0) {
    trackSource.start();
    offset = audioCtx.currentTime;
  } else {
    trackSource.start(0, audioCtx.currentTime - offset);
  }

  return trackSource;
}
```

最後に、`<li>` 要素をループして、それぞれ正しいファイルを取得し、"loading" テキストを隠して再生ボタンを表示することで、再生を許可してみましょう。

```js
trackEls.forEach((el, i) => {
  // Get children
  const anchor = el.querySelector("a");
  const loadText = el.querySelector("p");
  const playButton = el.querySelector("button");

  // Load file
  loadFile(anchor.href).then((track) => {
    // Set loading to false
    el.dataset.loading = "false";

    // Hide loading text
    loadText.style.display = "none";

    // Show button
    playButton.style.display = "inline-block";

    // Allow play on click
    playButton.addEventListener("click", () => {
      // Check if context is in suspended state (autoplay policy)
      if (audioCtx.state === "suspended") {
        audioCtx.resume();
      }

      playTrack(track);
      playButton.dataset.playing = true;
    });
  });
});
```

**メモ:** デモの実際の動きを見ることや、ソースコードを見ることができます。

ゲーム世界の文脈では、異なる状況で使用されるループやサンプルがあるかもしれません。よりシームレスな体験のために、他のトラックと同期させることができると便利です。

**メモ:** この例では、次の曲を導入する前にビートが終了するのを待ちません。トラックの BPM (Beats Per Minute) がわかっていれば、このようにすることができます。

新しい曲の導入は、ビート／バー／フレーズなど、 BGM を分割したい単位で行うと、より自然に聞こえることがあります。

これを行うには、同期させたいトラックを再生する前に、次のビート／バーなどの開始までの時間を計算する必要があります。

以下は、テンポ（ビート／バーの秒単位の時間）が与えられたときに、次のパートを再生するまでの時間を計算するコードの一部です。結果の値を最初のパラメータとして `start()` 関数に渡すと、その関数は再生を開始する絶対時刻を受け取ります。2つ目の引数（新しいトラックのどこから再生を開始するか）は、関連のあるものであることに注意してください。

```js
if (offset === 0) {
  source.start();
  offset = context.currentTime;
} else {
  const relativeTime = context.currentTime - offset;
  const beats = relativeTime / tempo;
  const remainder = beats - Math.floor(beats);
  const delay = tempo - remainder \* tempo;
  source.start(context.currentTime + delay, relativeTime + delay);
}
```

**メモ:** こちらの JSFiddle で、私たちの待ち時間計算機のコードを試すことができます（今回はバーに同期しています）。

**メモ:** 最初の引数が 0 またはコンテキスト `currentTime` よりも小さい場合、再生は直ちに開始されます。

### 場所つきの音声

場所つきの音声は、音声を没入感のあるゲーム体験の重要な一部にするための重要なテクニックになります。ウェブオーディオ API は、多くの音声ソースを三次元空間に配置できるだけでなく、その音声をよりリアルに見せるためのフィルターを適用することも可能です。

`pannerNode` はウェブオーディオ API の位置情報を利用し、ゲームの世界に関するさらなる情報をプレイヤーに関連付けることができるようになります。 `pannerNode` をより詳しく理解するためのチュートリアルがこちら (en-US)にあります。

以下のものに関連付けることができます。

* オブジェクトの位置関係
* オブジェクトの方向と動き
* 環境（洞窟、水中など）

これは、WebGL を使用してレンダリングされた三次元環境で特に有効で、ウェブオーディオ API を使用すると、音声をオブジェクトや視点に関連付けることが可能になります。

関連情報
----

* ウェブオーディオ API (MDN)
* `<audio>` (MDN)
* Developing Game Audio with the Web Audio API (HTML5Rocks)
* Mixing Positional Audio and WebGL (HTML5Rocks)
* Songs of Diridum: Pushing the Web Audio API to Its Limits
* Making HTML5 Audio Actually Work on Mobile
* Audio Sprites (and fixes for iOS)


二次元の衝突検出 - ゲーム開発

二次元の衝突検出
========

二次元ゲームでの衝突を判定するアルゴリズムは、衝突する図形の種類に依存します（例：矩形と矩形、矩形と円、円と円など）。一般的には、「ヒットボックス」として知られる実体に応じたシンプルな汎用図形を保有することになるので、たとえ衝突がピクセル単位で完璧でなくても、十分に見栄えが良く、複数の実体にわたってパフォーマンスを発揮することができるのです。この記事では、二次元ゲームで衝突判定を提供するために使用される最も一般的なテクニックのレビューを提供します。

座標軸に沿った囲みボックス
-------------

衝突検出の簡単な形式の一つは、軸が配置されている、つまり回転していない 2 つの矩形間の衝突です。このアルゴリズムは、矩形の 4 つの辺の間に隙間がないことを確認することによって動作します。隙間があれば、衝突が存在しないことを意味します。
```

<div id="cr-stage"></div>
<p>矢印キーで矩形を移動してください。緑は衝突、青は衝突なしを意味します。</p>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crafty/0.5.4/crafty-min.js"></script>
```

```js
Crafty.init(200, 200);

const dim1 = { x: 5, y: 5, w: 50, h: 50 };
const dim2 = { x: 20, y: 10, w: 60, h: 40 };

const rect1 = Crafty.e("2D, Canvas, Color").attr(dim1).color("red");

const rect2 = Crafty.e("2D, Canvas, Color, Keyboard, Fourway")
  .fourway(2)
  .attr(dim2)
  .color("blue");

rect2.bind("EnterFrame", function () {
  if (
    rect1.x < rect2.x + rect2.w &&
    rect1.x + rect1.w > rect2.x &&
    rect1.y < rect2.y + rect2.h &&
    rect1.h + rect1.y > rect2.y
  ) {
    // collision detected!
    this.color("green");
  } else {
    // no collision
    this.color("blue");
  }
});
```

**メモ:** キャンバスや外部ライブラリーを使用しない別の例.

円形衝突
----

衝突検出のためのもう一つの単純な図形は、 2 つの円の間です。このアルゴリズムは、 2 つの円の中心点を取り、その中心点間の距離が 2 つの半径を足したものより小さいことを確認することで動作します。
```

<div id="cr-stage"></div>
<p>
  矢印キーで円を移動させてください。緑は衝突あり、青は衝突なしを意味します。
</p>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crafty/0.5.4/crafty-min.js"></script>
```

```
#cr-stage {
  position: static !important;
  height: 200px !important;
}
```

```js
Crafty.init(200, 200);

const dim1 = { x: 5, y: 5 };
const dim2 = { x: 20, y: 20 };

Crafty.c("Circle", {
  circle(radius, color) {
    this.radius = radius;
    this.w = this.h = radius \* 2;
    this.color = color || "#000000";

    this.bind("Move", Crafty.DrawManager.drawAll);
    return this;
  },

  draw() {
    const ctx = Crafty.canvas.context;
    ctx.save();
    ctx.fillStyle = this.color;
    ctx.beginPath();
    ctx.arc(
      this.x + this.radius,
      this.y + this.radius,
      this.radius,
      0,
      Math.PI \* 2,
    );
    ctx.closePath();
    ctx.fill();
    ctx.restore();
  },
});

const circle1 = Crafty.e("2D, Canvas, Circle").attr(dim1).circle(15, "red");

const circle2 = Crafty.e("2D, Canvas, Circle, Fourway")
  .fourway(2)
  .attr(dim2)
  .circle(20, "blue");

circle2.bind("EnterFrame", () => {
  const dx = circle1.x + circle1.radius - (circle2.x + circle2.radius);
  const dy = circle1.y + circle1.radius - (circle2.y + circle2.radius);
  const distance = Math.sqrt(dx \* dx + dy \* dy);

  if (distance < circle1.radius + circle2.radius) {
    // collision detected!
    this.color = "green";
  } else {
    // no collision
    this.color = "blue";
  }
});
```

**メモ:** キャンバスや 外部ライブラリーを使わない例はこちらです。

分割軸定理
-----

これは衝突アルゴリズムで、任意の2つの \*convex\* ポリゴンの間の衝突を検出することができます。上記のメソッドよりも実装が複雑ですが、より強力です。このようなアルゴリズムの複雑さは、次のコーナーに応じた性能の最適化を検討する必要があることを意味します。

SAT を搭載することは、このページの範囲外なので、以下の推奨チュートリアルを参照してください。

1. 分割軸定理 (SAT) の説明
2. 衝突の検知と応答
3. 分割軸定理を使用した衝突の検知
4. SAT (分割軸定理)
5. 分割軸定理
衝突のパフォーマンス
----------

このような衝突検出のアルゴリズムには、計算が簡単なものもありますが、\*すべての\*エンティティを他のすべてのエンティティとテストすることは、サイクルの無駄 になります。通常、ゲームでは衝突を 2 つのフェーズ（広い範囲と狭い範囲）に分けます。

### 広域フェーズ

広域フェーズでは、衝突する可能性のあるエンティティのリストが得られるはずです。これは、エンティティがどこに存在し、その周囲に何が存在するかを大まかに知ることができる空間的なデータ構造で実装することができます。空間データ構造の例としては、 Quad Trees、R-Trees、Spacial Hashmap などがあります。

### 狭域フェーズ

チェックすべきエンティティの小さなリストがあるときには、（上記のような）狭域位相アルゴリズムを使用して、衝突があるかどうかに関して一定の答えを提供したいと思うでしょう。


ゲーム制御機構の搭載 - ゲーム開発

ゲーム制御機構の搭載
==========

ゲーム開発プラットフォームとしての HTML5 の主な利点の 1 つは、さまざまなプラットフォームおよび端末上で実行できることです。端末間の違いを合理化することは、特に異なるコンテキストに適切なコントロールを提供するときには、複数の課題を生み出します。このシリーズの記事では、タッチ画面のスマートフォン、マウス、キーボード、そしてゲームパッドなどのあまり一般的ではないメカニズムを使用してプレイできるゲームの構築方法について説明します。

事例研究
----

ここでは Captain Rogers: Battle at Andromeda demo を例にします。

![Captain Rogers: Battle at Andromeda - cover of the game containing Enclave Games and Blackmoon Design logos, Roger's space ship and title of the game.](/ja/docs/Games/Techniques/Control_mechanisms/captainrogers2-cover.png)

Captain Rogers は Phaser フレームワークを使用して作成されています。現在、 JavaScript でシンプルな 2D ゲームを開発するための最も人気のあるツールですが、これらの記事に含まれる知識を純粋な JavaScript または他のフレームワークでゲームを構築する際に再利用することはかなり簡単なはずです。 Phaser の入門書をお探しなら、2D breakout game using Phaser チュートリアルをチェックしてみてください。

以下の記事では、モバイルのタッチ操作から、デスクトップのキーボード／マウス／ゲームパッド、そしてテレビのリモコン、ラップトップの前で叫んだり手を振ったり、バナナを握ったりといった型破りなものまで、さまざまなプラットフォームに対応するために、Captain Rogers にさまざまな操作機構を搭載する方法を紹介します。

環境の設定
-----

まず、ゲームのフォルダー構造、JavaScriptファイル、ゲーム内の状態を手短に説明し、どこで何が起きているのかを把握します。ゲームのフォルダーは以下のような感じです。

![Captain Rogers: Battle at Andromeda - folder structure of the games' project containing JavaScript sources, images and fonts.](/ja/docs/Games/Techniques/Control_mechanisms/captainrogers2-folderstructure.png)

ご覧のように、画像、JavaScript ファイル、フォント、効果音用のフォルダーがあります。 `src` フォルダーには、別個の状態として分割された JavaScript ファイル、 `Boot.js`, `Preloader.js`, `MainMenu.js`, `Game.js` があり、これらはこの順番でインデックスファイルに読み込まれます。最初のものは Phaser を初期化し、 2 つ目はすべての資産を先読みさせ、 3 つ目はプレーヤーを歓迎するメインメニューを制御し、 4 つ目は実際のゲームプレイを制御するものです。

状態にはそれぞれ `preload()`, `create()`, `update()` という既定のメソッドがあります。最初のメソッドは必要な資産を先読みするために必要で、`create()` は状態が開始されると実行され、`update()` はフレームごとに実行されます。

例えば、`create()` 関数でボタンを定義することができます。

```js
create() {
  // …
  const buttonEnclave = this.add.button(10, 10, 'logo-enclave', this.clickEnclave, this);
  // …
}
```

ゲーム開始時に一度だけ作成され、クリックされるとそれに割り当てられた `this.clickEnclave()` アクションを実行しますが、 `update()` 関数でマウスのポインタの値を使用してアクションを作成することもできます。

```js
update() {
  // …
  if(this.game.input.mousePointer.isDown) {
      // do something
  }
  // …
}
```

これはマウスボタンが押されるたびに実行され、ゲームの各フレームで入力の `isDown` という論理変数と照合されます。

これで、プロジェクトの構成がある程度理解できたと思います。今回は、主に `MainMenu.js` と `Game.js` ファイルで遊びます。`create()` と `update()` メソッド内のコードについては、後日、より詳しく説明したいと思います。

純粋な JavaScript のデモ
------------------

また、小さなオンラインデモ と GitHub で利用可能な完全なソースコードがあり、記事で記述した制御機構の基本的な対応は、純粋な JavaScript で実装されています。それは以下の与えられた記事自体で説明されますが、あなたはすでにそれで遊ぶことができ、学習の目的のためにコードを好きなように使用することができます。

記事
--

HTML5 が真にマルチプラットフォームであるため、JavaScript はモバイルゲームに最適です。以下の記事はすべて、さまざまな制御機構とインターフェイスするために提供される API に焦点を当てています。

1. モバイルのタッチ制御 (en-US) — 最初の記事は、モバイルファーストの考え方が浸透していることから、タッチでキックオフします。
2. デスクトップ PC のマウスとキーボードによる操作 (en-US) — デスクトップ／ノートパソコンでプレイする場合、ゲームに受け入れられるレベルのアクセシビリティを提供するためには、キーボードとマウスによる操作性を提供することが不可欠です。
3. デスクトップ PC のゲームパッドによる操作 (en-US) — ゲームパッド API は、デスクトップ PC やノート PC のウェブアプリケーションを操作するためにゲームパッドを使用することを可能にし、コンソール感覚を提供します。
4. 非従来型制御 (en-US) — 最後の記事では、実験的なものからちょっとクレイジーなものまで、ゲームを使用するとは思えないような、型破りな操作機構を紹介しています。


THREE.js によるバウンディングボリューム衝突検出 - ゲーム開発

THREE.js によるバウンディングボリューム衝突検出
============================

この記事では、**Three.js ライブラリーを使用してバウンディングボックスとバウンディングスフィアの間の衝突検出**を実装する方法を示します。 これを読む前に、まず三次元の衝突検出の紹介記事を読み、かつ Three.js に関する基本的な知識があることを前提としています。

`Box3` と `Sphere` の使用
---------------------

Three.js には、**数学的なボリューム**（mathematical volumes）と形状を表すオブジェクトがあります。 3D の AABB とバウンディングスフィアには、**`Box3`** オブジェクトと **`Sphere`** オブジェクトを使用できます。 インスタンス化されると、他のボリュームに対して交差テストを実行するために使用できるメソッドがあります。

### ボックスのインスタンス化

**`Box3` インスタンス**を作成するには、ボックスの**下と上の境界**（対角線の 2 つの座標）を指定する必要があります。 通常、この AABB を 3D ワールドのオブジェクト（文字など）に「リンク」する必要があります。 Three.js では、`Geometry` インスタンスにオブジェクトの `min` と `max` の境界を持つ `boundingBox` プロパティがあります。 このプロパティを定義するには、事前に `Geometry.computeBoundingBox` を手動で呼び出す必要があることに注意してください。

```js
const knot = new THREE.Mesh(
  new THREE.TorusKnotGeometry(0.5, 0.1),
  new MeshNormalMaterial({}),
);

knot.geometry.computeBoundingBox();
const knotBBox = new Box3(
  knot.geometry.boundingBox.min,
  knot.geometry.boundingBox.max,
);
```

**メモ:** `boundingBox` プロパティは、`Mesh` ではなく、`Geometry` 自体を参照として使用します。 したがって、`Mesh` に適用された拡大縮小、位置などの変換は、計算するボックスの計算では無視されます。

前の問題を修正するより簡単な代替方法は、後で `Box3.setFromObject` を使用してこれらの境界を設定することです。 これにより、3D エンティティの**変換** *と* **子メッシュ**も考慮して寸法が計算されます。

```js
const knot = new THREE.Mesh(
  new THREE.TorusKnotGeometry(0.5, 0.1),
  new MeshNormalMaterial({}),
);

const knotBBox = new Box3(new THREE.Vector3(), new THREE.Vector3());
knotBBox.setFromObject(knot);
```

### 球のインスタンス化

**`Sphere` オブジェクト**のインスタンス化も同様です。 球の中心と半径を指定する必要があります。 これらは、`Geometry` で使用可能な `boundingSphere` プロパティで追加できます。

```js
const knot = new THREE.Mesh(
  new THREE.TorusKnotGeometry(0.5, 0.1),
  new MeshNormalMaterial({}),
);

const knotBSphere = new Sphere(
  knot.position,
  knot.geometry.boundingSphere.radius,
);
```

残念ながら、`Sphere` インスタンスに `Box3.setFromObject` に相当するものはありません。 したがって、変換を適用したり、`Mesh` の位置を変更したりする場合は、バウンディングスフィアを手動で更新する必要があります。 例えば次のようにです。

```js
knot.scale.set(2, 2, 2);
knotBSphere.radius = knot.geometry.radius \* 2;
```

### 交差テスト

#### 点 対 `Box3` / `Sphere`

`Box3` と `Sphere` の両方に、このテストを実行するための **`containsPoint`** メソッドがあります。

```js
const point = new THREE.Vector3(2, 4, 7);
knotBBox.containsPoint(point);
```

#### `Box3` 対 `Box3`

**`Box3.intersectsBox`** メソッドは、このテストを実行するために使用できます。

```js
knotBbox.intersectsBox(otherBox);
```

**メモ:** これは、`Box3` が別のものを *完全に* 包んでいるかどうかをチェックする `Box3.containsBox` メソッドとは異なります。

#### `Sphere` 対 `Sphere`

前のものと同様の方法で、このテストを実行するための **`Sphere.intersectsSphere`** メソッドがあります。

```js
knotBSphere.intersectsSphere(otherSphere);
```

#### `Sphere` 対 `Box3`

残念ながら、このテストは Three.js には実装されていませんが、`Sphere` にパッチを適用して球対 AABB の交差アルゴリズムを実装できます。

```js
// THREE.js の Sphere を展開して、対 Box3 衝突テストをサポートします。
// チェックのたびに Vector3 の新しいインスタンスが生成されないように、
// メソッドスコープ外でベクターを作成しています。

THREE.Sphere.__closest = new THREE.Vector3();
THREE.Sphere.prototype.intersectsBox = function (box) {
  // get box closest point to sphere center by clamping
  THREE.Sphere.__closest.set(this.center.x, this.center.y, this.center.z);
  THREE.Sphere.__closest.clamp(box.min, box.max);

  const distance = this.center.distanceToSquared(THREE.Sphere.__closest);
  return distance < this.radius \* this.radius;
};
```

### デモ

これらの手法を示すために、いくつかのライブデモと、調べるためのソースコードを用意しました。

* 点 対 ボックスと球
* ボックス 対 ボックスと球
* 球 対 ボックスと球

![](/ja/docs/Games/Techniques/3D_collision_detection/Bounding_volume_collision_detection_with_THREE.js/screen_shot_2015-10-20_at_15.19.16.png)

`BoxHelper` の使用
---------------

生の `Box3` オブジェクトと `Sphere` オブジェクトを使用する代わりに、Three.js には、**バウンディングボックスの処理を容易にする**便利なオブジェクト **`BoxHelper`** があります（以前の `BoundingBoxHelper` は非推奨となりました）。 このヘルパーは `Mesh` を取り、そのバウンディングボックスのボリューム（子メッシュを含む）を計算します。 これにより、バウンディングボックスを表す新しいボックスの `Mesh` が作成されます。 これは、バウンディングボックスの形状を示し、`Mesh` と一致するバウンディングボックスを作成するために、前に見た `setFromObject` メソッドに渡すことができます。

`BoxHelper` は、Three.js のバウンディングボリュームとの 3D 衝突を処理するための**推奨される**方法です。 球のテストをもらすことになりますが、このトレードオフにはそれだけの価値があります。

このヘルパーを使用する利点は次のとおりです。

* リンクした `Mesh` が回転したり、その寸法を変更した場合に、バウンディングボックスの `Mesh` の**サイズを変更**し、その**位置**を更新する `update()` メソッドがあります。
* バウンディングボックスのサイズを計算するときに**子メッシュが考慮される**ため、元のメッシュとそのすべての子が包まれます。
* `BoxHelper` が作成する `Mesh` を**レンダリングする**ことで、衝突を簡単にデバッグできます。 デフォルトでは、`LineBasicMaterial` マテリアル（ワイヤーフレームスタイルのジオメトリーを描画するための three.js マテリアル）を使用して作成されます。

主な欠点は、**ボックスのバウンディングボリュームのみを作成する**ことです。 したがって、球対 AABB のテストが必要な場合は、独自の `Sphere` オブジェクトを作成する必要があります。

これを使用するには、新しい `BoxHelper` インスタンスを作成し、ジオメトリーと、オプションで、ワイヤーフレームマテリアルに使用する色を指定する必要があります。 また、新しく作成したオブジェクトをレンダリングするには、three.js のシーンに追加する必要があります。 シーン変数は単に `scene` と呼ばれると仮定します。

```js
const knot = new THREE.Mesh(
  new THREE.TorusKnotGeometry(0.5, 0.1),
  new THREE.MeshNormalMaterial({}),
);
const knotBoxHelper = new THREE.BoxHelper(knot, 0x00ff00);
scene.add(knotBoxHelper);
```

実際の `Box3` バウンディングボックスも作成するために、新しい `Box3` オブジェクトを作成し、`BoxHelper` の形状と位置を想定します。

```js
const box3 = new THREE.Box3();
box3.setFromObject(knotBoxHelper);
```

`Mesh` の位置、回転、拡大縮小などを変更する場合は、`update()` メソッドを呼び出して、`BoxHelper` インスタンスがリンクした `Mesh` と一致するようにする必要があります。 `Box3` を `Mesh` に従わせるには、`setFromObject` を再度呼び出す必要もあります。

```js
knot.position.set(-3, 2, 1);
knot.rotation.x = -Math.PI / 4;
// update the bounding box so it stills wraps the knot
knotBoxHelper.update();
box3.setFromObject(knotBoxHelper);
```

**衝突テスト**の実行は、上記のセクションで説明したのと同じ方法で実行します。 つまり、Box3 オブジェクトを上記と同じ方法で使用します。

```js
// box vs box
box3.intersectsBox(otherBox3);
// box vs point
box3.containsPoint(point.position);
```

### デモ

ライブデモのページで確認できる **2 つのデモ**があります。 1 つ目は、`BoxHelper` を使用した点対ボックスの衝突を示しています。 2 つ目は、ボックス対ボックスのテストを実行します。

![](/ja/docs/Games/Techniques/3D_collision_detection/Bounding_volume_collision_detection_with_THREE.js/screen_shot_2015-10-19_at_12.10.06.png)


WebVR — ウェブによる仮想現実 - ゲーム開発

WebVR — ウェブによる仮想現実
==================

仮想現実の概念自体は新しいものではありませんが、今ではそれをあるべき姿で機能させるためのテクノロジーと、それをウェブアプリケーションで活用するための JavaScript API があります。 この記事では、ゲームでの使用の観点から WebVR を紹介しています。

**メモ:** WebVR API は WebXR 機器 API に置き換えられました。 WebVR は標準として承認されることはなく、ごく少数のブラウザーが既定で実装および有効化し、少数の機器に対応していました。

VR 機器
-----

Oculus Rift の人気とその他の多くの機器が間もなく市場に登場することで、未来は明るいように見えます。 ゲームをプレイするのに "十分な" VR 体験を実現するのに十分なテクノロジーがすでにあります。 Oculus Rift や HTC Vive などのデスクトップ型のものから、 Playstation VR (現時点では WebVR に対応していないことは確かです) を備えたコンソール、Gear VR や Google Cardboard などのモバイルエクスペリエンスまで、選択できる機器はたくさんあります。

![](/ja/docs/Games/Techniques/3D_on_the_web/WebXR/hmds.jpg)

**メモ:** 詳細については WebVR の概念 をご覧ください。

WebVR API
---------

WebVR API は、コンピューターに接続された VR 機器の情報とヘッドセットの位置/向き/速度/加速度の情報をキャプチャし、それをゲームやその他のアプリケーションで使用できる有用なデータに変換するための中心的な API です。

**メモ:** もちろん、ゲームの作成に役立つ他の API もあります。 例えば、コントロール入力用の ゲームパッド API や、モバイルでのディスプレイの方向を扱うための Device Orientation API などです。

### ブラウザーの対応と仕様書の状態

現在、 WebVR API のブラウザー対応はまだ実験的です — nightly builds of Firefox と experimental builds of Chrome で動作しますが（Mozilla と Google が一丸となって実装に取り組みます）、遅かれ早かれ通常のビルドで見ることができるようになるでしょう。

WebVR 仕様は、編集者草案の状態にあり、これはまだ変更される可能性があることを意味します。 開発は、Mozilla の Vladimir Vukicevic と Google の Brandon Jones が主導しています。 詳細については WebVR.info のウェブサイトにアクセスしてください。

### WebVR API の使用

WebVR API は、ヘッドセットの両方のレンズに立体画像を送信することと、センサーから頭の位置データを受信することの 2 つの概念に基づいており、これら 2 つは `HMDVRDevice` (en-US)（head-mounted display virtual reality device、ヘッドマウントディスプレイ仮想現実機器）と `PositionSensorVRDevice` (en-US) によって処理されます。

### 機器の取得

コンピューターに接続されている機器に関する情報を取得するには、次のように `Navigator/getVRDisplays` メソッドを使用できます。

```js
navigator.getVRDevices().then(function (devices) {
  for (var i = 0; i < devices.length; ++i) {
    if (devices[i] instanceof HMDVRDevice) {
      gHMD = devices[i];
      break;
    }
  }
  if (gHMD) {
    for (var i = 0; i < devices.length; ++i) {
      if (
        devices[i] instanceof PositionSensorVRDevice &&
        devices[i].hardwareUnitId === gHMD.hardwareUnitId
      ) {
        gPositionSensor = devices[i];
        break;
      }
    }
  }
});
```

このコードは、利用可能な機器をループして、適切なセンサーをヘッドセットに割り当てます。最初の `devices` 配列には、接続された機器が含まれており、`HMDVRDevice` (en-US) を見つけるためのチェックが行われ、変数 `gHMD` に割り当てられます。これを使用して、シーンを設定し、目のパラメーターを得て、フィールドオブビュー等を設定することができます。例として

```js
function setCustomFOV(up, right, down, left) {
  var testFOV = new VRFieldOfView(up, right, down, left);

  gHMD.setFieldOfView(testFOV, testFOV, 0.01, 10000.0);
}
```

`gPositionSensor` 変数は `PositionSensorVRDevice` (en-US) を保持します — これを使用して、現在の位置や方向の状態を取得したり（例えば、すべてのフレームでシーンビューを更新したり）、センサーをリセットできます。 例えば、次のコードは画面上の位置情報を出力します。

```js
function setView() {
  var posState = gPositionSensor.getState();

  if (posState.hasPosition) {
    posPara.textContent =
      "Position: x" +
      roundToTwo(posState.position.x) +
      " y" +
      roundToTwo(posState.position.y) +
      " z" +
      roundToTwo(posState.position.z);
    xPos = -posState.position.x \* WIDTH \* 2;
    yPos = posState.position.y \* HEIGHT \* 2;
    if (-posState.position.z > 0.01) {
      zPos = -posState.position.z;
    } else {
      zPos = 0.01;
    }
  }

  // …
}
```

これを取得するデモの完全な説明と詳細については、WebVR API の使い方を参照してください。

ツールとテクニック
---------

最初の WebVR の実験とデモでは、おそらくウェブで最も人気のある 3D エンジンである Three.js を使用しました。 Three.js github で利用可能な VREffect および VRControls 関数を参照して、Three.js で WebVR を実装および処理するのに役立ててください。

![](/ja/docs/Games/Techniques/3D_on_the_web/WebXR/sechelt.jpg)

Boris Smus は、レスポンシブ WebVR の概念について書いています。 このコンセプトでは、 VR ハードウェアのないラップトップ、 Oculus Rift を搭載した PC、Google Cardboard に内蔵したスマートフォンなど、さまざまなデバイスで単一のウェブゲームをプレイしながら、それらすべてにユニークで価値のある体験を提供できます。 レスポンシブデザインに似ていますが、 VR の世界に適用されます — 一度書けば VR ヘッドセットで実行できます ... またはそれなしで。 WebVR ボイラープレートのソースを確認できます。 これは、WebVR の学習を開始する良い例であり、Web ベースの VR 体験の出発点です。

WebVR のシンプルなビルディングブロックを提供する A-Frame と呼ばれるマークアップフレームワークもあるため、VRウェブサイトやゲームをすばやく構築して実験できます。 詳細については、A-Frame を使った基本的なデモの作成というチュートリアルを参照してください。

没入感は、ゲームプレイやグラフィックスよりも重要です — 体験の "内側にいる" と感じる必要があります。 実現するのは簡単ではありませんが、リアルな画像は必要ありません。 それどころか、基本的な形状を高フレームレートで飛び交うだけで、かなりの効果が得られます。 実験が重要なことを覚えておいてください — 特にあなたのゲームに何が有効かを確認してください。

WebVR の未来
---------

それは起こっています — 消費者向けデバイスは現在市場に出回っており、Web 上でそれらをサポートする JavaScript API がすでにあります。 今必要なのは、安定した仕様、優れた UX と UI、より優れたハードウェア、より多くのツールとライブラリーです。 そしてそのすべてが間近に迫っています。 WebVR に飛び込んで実験するのに最適な時期です。

関連項目
----

* WebVR API
* WebVR の概念
* WebVR API の使い方
* A-Frame を使った基本的なデモの作成


GLSL シェーダー - ゲーム開発

GLSL シェーダー
==========

シェーダーは、 C と同様の構文を持つ特別な OpenGL シェーディング言語である GLSL (OpenGL Shading Language) を使用します。 GLSL はグラフィックスパイプラインによって直接実行されます。様々な種類のシェーダーがありますが、ウェブ上のグラフィックを作成するのに良く使用されるのは、頂点 (バーテックス) シェーダーとフラグメント (ピクセル) シェーダーの 2 種類です。 頂点シェーダーは、形状の位置を 3D 描画座標に変換します。 フラグメントシェーダーは、形状の色やその他の属性のレンダリングを計算します。

GLSL は JavaScript ほど直感的ではありません。 GLSL は強く型付けされており、ベクトルと行列を含む多くの数学があります。 それは非常に複雑になる可能性があります — 非常に速くも。 この記事では、立方体をレンダリングする簡単なコード例を作成します。 背景となるコードを高速化するために、Three.js API を使用します。

基本理論の記事から覚えているかもしれませんが、頂点は 3D 座標系の点です。 頂点は追加のプロパティを持つことがあります。 3D 座標系は空間を定義し、頂点はその空間内の形状を定義するのに役立ちます。

シェーダーの種類
--------

シェーダーは基本的に、画面に何かを描画するために必要な機能です。 シェーダーは、このような操作のために最適化された GPU (graphics processing unit) で実行されます。 シェーダーの対処に GPU を使用することで、数値計算の一部を CPU から開放します。 これにより、CPU は、コードの実行などの他のタスクに処理能力を集中することができます。

### 頂点シェーダー

頂点シェーダーは 3D 空間の座標を操作し、頂点ごとに1回呼び出されます。 頂点シェーダーの目的は、`gl_Position` 変数を設定することです。 これは、特別なグローバルな組み込み GLSL 変数です。 `gl_Position` は、現在の頂点の位置を格納するために使用されます。

`void main()` 関数は、`gl_Position` 変数を定義する標準的な方法です。 `void main()` 内のすべては、頂点シェーダーによって実行されます。 頂点シェーダーは、3D 空間での頂点の位置を 2D 画面に投影する方法を含む変数を生成します。

### フラグメントシェーダー

フラグメント（またはテクスチャ）シェーダーは、処理される各ピクセルの RGBA (赤、緑、青、アルファ) 色を定義します。 単一のフラグメントシェーダーは、ピクセルごとに 1 回ずつ呼び出されます。 フラグメントシェーダーの目的は、 `gl_FragColor` 変数を設定することです。 `gl_FragColor` は、 `gl_Position` のような組み込みの GLSL 変数です。

計算の結果、RGBA 色に関する情報を含む変数が得られます。

デモ
--

これらのシェーダーの動作を説明する簡単なデモを作成しましょう。 最初に Three.js のチュートリアルを読んで、シーンの概念、そのオブジェクト、およびマテリアルを把握してください。

**メモ:** シェーダーを作成するために Three.js やその他のライブラリーを使用する必要はなく、純粋な WebGL (Web Graphics Library) で十分です。 ここでは Three.js を使用して、背景となるコードを非常に単純でわかりやすくしているため、シェーダーのコードに集中することができます。 Three.js やその他の 3D ライブラリーは、多くのことを抽象化します。 このような例を生の WebGL で作成する場合は、実際に機能させるために多くの追加コードを作成する必要があります。

### 環境設定

WebGL シェーダーを使うには、それほど多くは必要ありません。 次のことが必要です。

* 最新の Firefox や Chrome など、WebGL を適切にサポートする最新のブラウザーを使用していることを確認してください。
* 実験を保存するディレクトリーを作成します。
* 最小化された最新の Three.js ライブラリーのコピーをディレクトリー内に保存します。
### HTML の構造

使用する HTML の構造は次のとおりです。

```html
<!doctype html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>MDN Games: Shaders demo</title>
    <style>
 body {
 margin: 0;
 padding: 0;
 font-size: 0;
 }
 canvas {
 width: 100%;
 height: 100%;
 }
 </style>
    <script src="three.min.js"></script>
  </head>
  <body>
    <script id="vertexShader" type="x-shader/x-vertex">
 // vertex shader's code goes here
 </script>
    <script id="fragmentShader" type="x-shader/x-fragment">
 // fragment shader's code goes here
 </script>
    <script>
 // scene setup goes here
 </script>
  </body>
</html>
```

文書の `<title>` のような基本情報と、 Three.js がページに挿入する `<canvas>` 要素の `width` と `height` をビューポートのフルサイズに設定するための CSS が含まれています。 `<head>` の `<script>` 要素には、ページの Three.js ライブラリーが含まれています。 `<body>` タグの 3 つのスクリプトタグにコードを記述します。

1. 最初のものには、頂点シェーダーを含みます。
2. 2 つ目は、フラグメントシェーダーを含みます。
3. 3 つ目は、シーンを生成する実際の JavaScript コードを含みます。

先に進む前に、このコードを新しいテキストファイルにコピーして、作業ディレクトリーに `index.html` として保存してください。 このファイルでは、シェーダーがどのように機能するかを説明するために、単純な立方体を特徴とするシーンを作成します。

### 立方体のソースコード

すべてを最初から作成する代わりに、 Three.js を使った基本的なデモの構築のソースコードの立方体を再利用できます。 レンダラー、カメラ、ライトなどのほとんどのコンポーネントは同じままですが、基本的なマテリアルの代わりに、シェーダーを使用して立方体の色と位置を設定します。

GitHub の cube.html ファイルに移動し、 2 番目の `<script>` 要素内からすべての JavaScript コードをコピーして、現在の例の 3 番目の `<script>` 要素に貼り付けます。 `index.html` を保存してブラウザーでロードすると、青い立方体が表示されます。

### 頂点シェーダーのコード

続けて、簡単な頂点シェーダーを作成しましょう。 ボディの最初の `<script>` タグ内に以下のコードを追加します。

```glsl
void main() {
  gl_Position = projectionMatrix \* modelViewMatrix \* vec4(position.x+10.0, position.y, position.z+5.0, 1.0);
}
```

結果の `gl_Position` は、モデルビュー行列と射影行列に各ベクトルを乗算して、いずれの場合も最終的な頂点位置を取得することによって計算されます。

**メモ:** 頂点処理の段落から、*モデル変換*、*ビュー変換*、および*投影変換*について詳しく知ることができます。 また、この記事の最後にあるリンクからも、詳細を学ぶことができます。

`projectionMatrix` と `modelViewMatrix` はどちらも Three.js によって提供され、ベクトルは新しい 3D 位置を渡します。 これにより、元の立方体がシェーダーを介して平行移動され `x` 軸に沿って 10 単位、`z` 軸に沿って 5 単位移動します。 4番目のパラメーターは無視して、デフォルトの `1.0` 値のままにしておくことができます。 これは、3D 空間の頂点位置のクリッピングを操作するために使用されますが、今回のケースでは必要ありません。

### テクスチャーシェーダーのコード

次に、テクスチャーシェーダーをコードに追加します。 以下のコードをボディの 2 番目の `<script>` タグに追加します。

```glsl
void main() {
  gl_FragColor = vec4(0.0, 0.58, 0.86, 1.0);
}
```

これにより、RGBA 色が設定され、現在の水色が再現されます。 最初の3つの浮動小数点値（`0.0` から `1.0` の範囲）は赤、緑、青のチャンネルを表し、4番目の値はアルファ透明度 (`0.0` の完全に透明から `1.0` の完全に不透明の範囲) を表します。

### シェーダーの適用

新しく作成したシェーダーを実際に立方体に適用するには、最初に `basicMaterial` の定義をコメントアウトします。

```js
// var basicMaterial = new THREE.MeshBasicMaterial({color: 0x0095DD});
```

次に、 `shaderMaterial` を作成します。

```js
var shaderMaterial = new THREE.ShaderMaterial({
  vertexShader: document.getElementById("vertexShader").textContent,
  fragmentShader: document.getElementById("fragmentShader").textContent,
});
```

このシェーダーマテリアルは、スクリプトからコードを取り出し、マテリアルが割り当てられているオブジェクトに適用します。

次に、立方体を定義する行で、`basicMaterial` を新しく作成した `shaderMaterial` に置き換える必要があります。

```js
// var cube = new THREE.Mesh(boxGeometry, basicMaterial);
var cube = new THREE.Mesh(boxGeometry, shaderMaterial);
```

Three.js は、このマテリアルが与えられたメッシュにアタッチされたシェーダーをコンパイルして実行します。 この場合、立方体には頂点シェーダーとテクスチャシェーダーの両方が適用されます。 これで完了です。 可能な限り単純なシェーダーを作成しました。 おめでとう! 立方体は次のようになります。

![Three.js blue cube demo](/ja/docs/Games/Techniques/3D_on_the_web/GLSL_Shaders/cube.png)

見た目は Three.js の立方体のデモとまったく同じですが、シェーダーを使用すると、位置がわずかに異なり、青色が同じになります。

最終的なコード
-------

### HTML

```html
<script src="https://end3r.github.io/MDN-Games-3D/Shaders/js/three.min.js"></script>
<script id="vertexShader" type="x-shader/x-vertex">
 void main() {
 gl\_Position = projectionMatrix \* modelViewMatrix \* vec4(position.x+10.0, position.y, position.z+5.0, 1.0);
 }
</script>
<script id="fragmentShader" type="x-shader/x-fragment">
 void main() {
 gl\_FragColor = vec4(0.0, 0.58, 0.86, 1.0);
 }
</script>
```

### JavaScript

```js
var WIDTH = window.innerWidth;
var HEIGHT = window.innerHeight;

var renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(WIDTH, HEIGHT);
renderer.setClearColor(0xdddddd, 1);
document.body.appendChild(renderer.domElement);

var scene = new THREE.Scene();

var camera = new THREE.PerspectiveCamera(70, WIDTH / HEIGHT);
camera.position.z = 50;
scene.add(camera);

var boxGeometry = new THREE.BoxGeometry(10, 10, 10);

var shaderMaterial = new THREE.ShaderMaterial({
  vertexShader: document.getElementById("vertexShader").textContent,
  fragmentShader: document.getElementById("fragmentShader").textContent,
});

var cube = new THREE.Mesh(boxGeometry, shaderMaterial);
scene.add(cube);
cube.rotation.set(0.4, 0.2, 0);

function render() {
  requestAnimationFrame(render);
  renderer.render(scene, camera);
}
render();
```

### CSS

```css
body {
  margin: 0;
  padding: 0;
  font-size: 0;
}
canvas {
  width: 100%;
  height: 100%;
}
```

### 結果

まとめ
---

この記事では、シェーダーの基本について説明しました。 私たちの例ではあまり多くのことをしていませんが、シェーダーでできるクールなことがもっとたくさんあります。 ShaderToy で本当にクールなものをチェックして、インスピレーションを得て、それらのソースから学んでください。

関連情報
----

* WebGL の学習 — 一般的な WebGL の知識について (アーカイブ、英語、和訳あり)
* WebGL の基本での WebGL のシェーダーと GLSL — GLSL 固有の情報について (英語、和訳あり)


基本の 3D 理論の解説 - ゲーム開発

基本の 3D 理論の解説
============

この記事では、これから 3D を始める際に知っておくと便利な基礎理論をすべて解説しています。

座標系
---

3D は本来、三次元空間における図形の表現に関するすべてのものであり、その位置を計算するために座標系が使用されます。

![座標系](/ja/docs/Games/Techniques/3D_on_the_web/Basic_theory/mdn-games-3d-coordinate-system.png)

WebGL は右手系座標系を利用します。上記の図のように `x` 軸は右方向へ、`y` 軸は上方向へ、`z` 軸は画面の外の方向へ向かいます。

オブジェクト
------

さまざまな種類のオブジェクトは頂点を用いて構築されます。**頂点**は空間上の点であり、座標系における 3D の位置を持ち、たいていはいくつか追加で情報が定義されています。すべての頂点は、これらの属性によって記述されます。

* **位置**: 3D 空間での位置 (`x`, `y`, `z`) を特定します。
* **色**: RGBA 値を持ちます (R、G、B は赤、緑、青のチャンネルを、alpha は透過度を - すべての値の範囲は `0.0` から `1.0` までです)。
* **法線**: 頂点が向いている方向を記述する方法です。
* **テクスチャ**: 頂点が、単純な色の代わりに、その一部である表面を装飾するために使用できる 2D 画像です。

この情報を用いて形状を構築することができます - 次は立方体の例です。

![Cube](/ja/docs/Games/Techniques/3D_on_the_web/Basic_theory/mdn-games-3d-cube.png)

形から定義される表面は頂点同士の表面となります。例えば、立方体は 8 つの異なる頂点(空間上の点)と 6 つの異なる表面を持ち、それぞれの表面が 4 つの頂点から構築されています。法線は表面がどの方向に向いているかを定義します。そしてまた、立方体の端で点が接続されています。形状は頂点と法線から構築され、また材質は色や画像のテクスチャになります。形状が材質と接続されている場合、メッシュを得ることができます。

レンダリングパイプライン
------------

レンダリングパイプラインは画面上に画像を準備し、出力するためのプロセスです。画像のレンダリングパイプラインは 3D オブジェクトを **頂点** を用いて作図された **単純なオブジェクト(プリミティブ)** から作り、処理を加え、**断片(フラグメント)** を計算し、そして 2D の画面上に **ピクセル** として出力します。

![Rendering pipeline](/ja/docs/Games/Techniques/3D_on_the_web/Basic_theory/mdn-games-3d-rendering-pipeline.png)

上記の図で使われる専門用語は以下の通りです:

* **プリミティブ (Primitive)**: パイプラインへの入力 - これは頂点から構築され、三角形や点、ラインとなります。
* **断片 (Fragment)**: ピクセルを 3D に投影したもの、すべての属性はピクセルと同じ属性を持つ。
* **ピクセル (Pixel)**: 画面上の 2D のグリッドに配置された点、それぞれ RGBA の色を持ちます。

頂点とフラグメントの処理はプログラミング可能です - 自分自身でシェーダーを書いて出力を操作することができます。

頂点の処理
-----

頂点の処理は個々の座標の情報をつなげることでプリミティブを作成し、それらの座標を 3D 空間のビューアーで見られるように設定します。これは風景の写真を撮る準備に似ています - 最初にオブジェクトを配置し、カメラを設定し、そして撮影します。

![Vertex processing](/ja/docs/Games/Techniques/3D_on_the_web/Basic_theory/mdn-games-3d-vertex-processing.png)

この処理には 4 つの段階があります。最初の処理はオブジェクトを配置するのに必要な処理で、これは**モデル変換** (model transformation) と呼ばれています。そして**視野変換** (view transformation) で 3D 空間上のカメラの位置の設定と向きを設定をします。カメラには位置、方角、角度の 3 つの引数があります。これは新しいシーンを作成したときに定義しなくてはなりません。

![Camera](/ja/docs/Games/Techniques/3D_on_the_web/Basic_theory/mdn-games-3d-camera.png)

**投影変換** (Projection transformation) (または透視変換 (perspective transformation) とも呼ばれます) はカメラの設定を定義します。これはカメラから何が見えるのかを設定します - 設定には *field of view(視野)*、*aspect ratio(アスペクト比)* そして任意の *近く(near)* と *遠くの平面(far planes)* を含みます。これらを学ぶには Three.js の Camera の段落の記事を読んでください。

![Camera settings](/ja/docs/Games/Techniques/3D_on_the_web/Basic_theory/mdn-games-3d-camera-settings.png)

最後の処理は **ビューポート変換** (viewport transformation) で、レンダリングパイプラインの次の処理で出力に使うすべての処理を含みます。

ラスタ化
----

ラスタ化では（頂点で接続された）プリミティブを、断片の集まりに変換します。

![Rasterization](/ja/docs/Games/Techniques/3D_on_the_web/Basic_theory/mdn-games-3d-rasterization.png)

それらの断片 - 3D 投影からなる 2D のピクセル - はピクセルのグリッドに整列されていて、最終的に出力統合の段階の間ピクセルとして 2D の画面上に出力可能になります。

断片処理
----

断片処理はテクスチャと照明に焦点を当てます - これは与えられたパラメータを元に最終的な色を計算します。

![Fragment processing](/ja/docs/Games/Techniques/3D_on_the_web/Basic_theory/mdn-games-3d-fragment-processing.png)

### テクスチャ

テクスチャは 3D 空間上でより見た目がよく、よりリアルなオブジェクトを作成するために使われる 2D 画像です。テクスチャは texels と呼ばれる単一テクスチャ要素から組み合わされており、texels は写真の要素と同様のピクセルの組み合わせです。レンダリングパイプラインの断片処理の段階でテクスチャをオブジェクトに追加することで必要によってオブジェクトを覆うよう調整したり、フィルターリングをすることができます。

テクスチャは 3D オブジェクトの間で繰り返し 2D 画像を覆うことができます。テクスチャのフィルターリングは元の解像度またはテクスチャの画像が表示される断片と異なる場合に適用されます - これは結果的に縮小または拡大となります。

### 照明

私たちが画面上で見る色は光とオブジェクトの素材自体の表面の色との相互作用の結果となります。光は吸収されるか、反射されるでしょう。WebGL で実装されている標準的な **Phong Lighting Model** には４つの光のタイプがあります。

* **Diffuse**: 太陽のような、遠くからの指向性のある光。
* **Specular**: 部屋の中の電球や閃光のような、光のポイント。
* **Ambient**: シーンにあるすべてに絶え間なく当てられる光。
* **Emissive**: オブジェクトから直接発せられる光。
出力統合
----

出力処理の段階の間で、画面ディスプレイ上に出力するために 3D空間上のすべてのプリミティブの断片を 2D グリッドのピクセルに変換する。

![Output merging](/ja/docs/Games/Techniques/3D_on_the_web/Basic_theory/mdn-games-3d-output-merging.png)

出力統合の間はいくつかの処理は必要のないものであれば無視されます - 例えばオブジェクトが画面の外や他のオブジェクトの後ろにあったりすることでそれらは不可視であれば計算はされません。

まとめ
---

これで 3D の処理の基本的な背景を知ることができました。もし練習に進んだり、動作するデモを見たいのでえあれば、下のチュートリアルを引き続き調べてください。

* Three.js でデモを作る
* Babylon.js を使った基本的なデモの作成
* PlayCanvas を使った基本的なデモの作成
* A-Frame を使った基本的なデモの作成

さらに進んで、クールな最先端な 3D の試みをあなた自身で作ってください！


PlayCanvas を使った基本的なデモの作成 - ゲーム開発

PlayCanvas を使った基本的なデモの作成
========================

PlayCanvas は有名な 3D WebGL ゲームエンジンです 。もともと Will Eastcott と Dave Evans によって作成されました。 GitHub 上でオープンソースとなっており、オンラインで使用できるエディターと優れたドキュメントが特徴です。 オンラインエディターは、パブリックプロジェクトの場合チームメンバー 2 人まで無料で使用できますが、商用でより多くの開発者が参加できるプライベートプロジェクトを希望される場合は 有償プランもあります。

![PlayCanvas website.](/ja/docs/Games/Techniques/3D_on_the_web/Building_up_a_basic_demo_with_PlayCanvas/playcanvas-cover.png)

ゲームやデモ
------

PlayCanvas では、機能紹介を兼ねたデモをいくつか公開しています。

* Tanx は、マルチプレイヤーのタンクゲームで自分のタンクを乗り回したり、他のプレイヤーを射撃したりするゲームです。
* Swooop は、航空機を操縦して魔法の島を飛び回り、宝石や燃料を集めるゲームです。
* Star Lord や BMW i8 のようなビジュアリゼーションもエンジンを活用し、その機能を紹介しています。

![A list of PlayCanvas demos: Tanx, Swooop, Star Lord, BMW i8.](/ja/docs/Games/Techniques/3D_on_the_web/Building_up_a_basic_demo_with_PlayCanvas/playcanvas-demos.png)

**メモ:** さらに事例をご覧になる場合は特集されているデモも確認してください。

エンジンとエディターの違い
-------------

エンジンそのものは、 JavaScript ファイルを HTML に直接入れ込むことで標準ライブラリーとして使用でき、すぐにコーディングすることができます。さらに、 PlayCanvas のツールセットにはオンラインエディターも搭載されています。このオンラインエディターでは、シーンにコンポーネントをドラッグ & ドロップすることができます。コーディングの知識よりも、デザインの知識の方が豊富な方がゲームやシーンを要するアプリを作成する場合など、この機能は大変便利なものとなります。 エディターとエンジンは異なるアプローチですが、最終的な目的の達成という面では同等です。

PlayCanvas エンジン
---------------

 モダンブラウザー向けに構築されている PlayCanvas は、リソースローディング、エンティティシステムやコンポーネントシステム、高度なグラフィック操作、コリジョン、物理エンジン ( ammo.js
 でのビルド)、オーディオ、様々なデバイス（ゲームパッドを含む）からの入力のコントロールを扱う設備を搭載したフル装備の 3D エンジンです。 なかなかの機能が揃っているのではないでしょうか。実際に使用されているところを見てみましょう。詳細については PlayCanvas でベーシックデモをビルドする (en-US)を参照ください。

PlayCanvas エディター
----------------

ゼロからコーディングするのではなく、オンラインエディターを使用するという手もあります。 コーディングが得意というわけでない方でも、心地よく使用いただける環境になっています。 詳細は PlayCanvas でベーシックデモをビルドする (en-US)を参照ください。

まとめ
---

もちろん、自分がどういう方法でビルドしたいか、それが一番です。デザイナーであればオンラインエディターがやりやすいかもしれませんし、プログラマーであればコーディング環境で自らコントロールできるエンジンのソースファイルを好むかもしれません。 選択肢があり、最もいいと思うツールを選ぶことができるのがいい点です。


Babylon.js を使った基本的なデモの作成 - ゲーム開発

Babylon.js を使った基本的なデモの作成
========================

Babylon.js は開発者に使われている最も有名な 3D ゲームエンジンです。他のどんな 3D と同様に、より迅速に共通の3D機能を実装するのを助けるプラグイン機能を提供します。この記事では Babylon.js を使った基礎を通じて開発環境の構築、必要な HTML 構造、 JavaScript の書き方を提供します。

まずは、画面の内側へレンダリングされた立方体という簡単なデモを作成してみることにします。もし、すでにこの基本デモの作成シリーズ (Three.js, PlayCanvas, A-Frame) を通して作業をしたことがある人（あるいは、他の 3D ライブラリーに精通している人）は、 Babylon.js がカメラ、光、オブジェクトという同じような概念で動作することに気づくでしょう。

環境構築
----

Babylon.js で開発を始めるにあたっては、そんなに多くのものを必要としません。以下のようにすぐに始めましょう。

* WebGL によく対応した最新のブラウザー、例えば最新の Firefox や Chrome を使用していることを確認することです。
* 作業用のディレクトリーを作成して下さい。
* ディレクトリーに最新の Babylon.js エンジンをコピーして保存して下さい。
* Babylon.js のドキュメントを別のタブに開いて下さい。 — 参照するのに役に立ちます。
HTML 構造
-------

ここに使う HTML の構造を示します。

```html
<!doctype html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>MDN Games: Babylon.js demo</title>
    <style>
 html,
 body,
 canvas {
 margin: 0;
 padding: 0;
 width: 100%;
 height: 100%;
 font-size: 0;
 }
 </style>
  </head>
  <body>
    <script src="babylon.js"></script>
    <canvas id="render-canvas"></canvas>
    <script>
 var canvas = document.getElementById("render-canvas");
 /\* all our JavaScript code goes here \*/
 </script>
  </body>
</html>
```

ここには文書のタイトル (`<title>`) や、Babylon.js がその内容を描画するための `<canvas>` 要素の幅や高さが利用可能なビューポート領域全体を占めるようにする CSS など、文書の基本的な情報が含まれています。初めの `<script>` 要素は Babylon.js に含みます。次に例となるコードを書いていきます。すでに 1 つのヘルパー変数が取り込まれており、 `<canvas>` 要素への参照が格納されます。

読み進める前に、このコードを新しいテキストファイルにコピーし、作業ディレクトリーに `index.html` という名前で保存してください。

Babylon.js エンジンの初期化
-------------------

ゲームの開発を始める前に、まず Babylon.js エンジンのインスタンスを作成しなければなりません（レンダリングするための `<canvas>` 要素を渡します）。 2 つ目の `<script>` 要素の一番下に、以下のコードを追加してください。

```js
var engine = new BABYLON.Engine(canvas);
```

`BABYLON` グローバルオブジェクトは、エンジンで利用可能なすべての Babylon.js の関数を含んでいます。

シーンの作成
------

シーンとは、すべてのゲームコンテンツが表示される場所です。このデモでは、新しいオブジェクトを作成しながら、それらをすべてシーンに追加して、画面の内側へ表示されるようにします。前のコードのすぐ下に次の行を追加して、シーンを作成しましょう。

```js
var scene = new BABYLON.Scene(engine);
scene.clearColor = new BABYLON.Color3(0.8, 0.8, 0.8);
```

こうしてシーンを作成し、 2 つ目の行で背景色をライトグレーに設定しています。

レンダリングのループを作る
-------------

シーンを実際に見えるようにするためには、レンダリングする必要があります。以下の行を `<script>` 要素の最後、閉じる `</script>` の直前に追加してください。

```js
var renderLoop = function () {
  scene.render();
};
engine.runRenderLoop(renderLoop);
```

エンジンの `runRenderLoop()` メソッドを使用して、 `renderLoop()` 関数をフレームごとに繰り返し実行しています。このループは、停止が指示されるまで無制限にレンダリングしつづけます。

カメラの作成
------

さて、セットアップコードができたところで、標準的なシーンコンポーネントであるカメラ、ライト、オブジェクトの実装について考える必要があります。まず、カメラから始めましょう。シーンの作成と `clearColor` を定義した行の下に、次の行を追加してください。

```js
var camera = new BABYLON.FreeCamera(
  "camera",
  new BABYLON.Vector3(0, 0, -10),
  scene,
);
```

Babylon.js では多くのカメラが利用可能です。 `FreeCamera` は最も基本的で汎用的なカメラです。初期化するためには、 3 つの引数を渡す必要があります。使用したい名前、三次元空間での位置の座標、そして追加したいシーンです。

**メモ:** ここで、`BABYLON.Vector3()` メソッドが使用されていることにお気づきでしょう。これはシーン上の 3D 位置を定義するものです。 Babylon.js には、ベクトル、色、行列などを扱うための完全な数学ライブラリーがバンドルされています。

光あれ
---

Babylon.js では、様々な光源が利用可能です。最も基本的なものは `PointLight` で、これは懐中電灯のように動作し、指定された方向にスポットライトを照らします。カメラ定義の下に、次の行を追加してください。

```js
var light = new BABYLON.PointLight(
  "light",
  new BABYLON.Vector3(10, 10, 0),
  scene,
);
```

引数は、先に定義したカメラと非常によく似ています。ライトの名前、三次元空間での位置、ライトを追加するシーンです。

ジオメトリー
------

これでシーンが正しくレンダリングされたので、3D図形を追加することができます。 Babylon.js は、開発スピードを上げるために、たくさんの定義済みプリミティブを提供しており、これを使用すれば、 1 行のコードで即座に形状を作成することができます。立方体、球体、円柱、そしてもっと複雑な形状が用意されています。まず、箱型の図形を定義してみましょう。前に追加したコードの下に、次の新しいコードを追加してください。

```js
var box = BABYLON.Mesh.CreateBox("box", 2, scene);
```

メッシュはエンジンが幾何学的な図形を作成する方法なので、後で簡単に素材を適用することができます。この例では、 `Mesh.CreateBox` メソッドを使用して、独自の名前とサイズとして 2、そしてどのシーンに追加するかを宣言してボックスを作成します。

**メモ:** サイズや位置の値（ボックスのサイズなど）は単位がなく、基本的にミリメートル、メートル、フィート、マイルなど、シーンに適した値を設定することができます。

今、保存して更新すると、オブジェクトは正方形のように見えます。なぜなら、カメラに面しているからです。オブジェクトの良いところは、シーン上で好きなように動かせることです。例えば、回転させたり、拡大縮小したりできます。複数の面が見えるように、ボックスに少し回転を加えてみましょう。もう一度、これらの線を前の線の下に追加してください。

```js
box.rotation.x = -0.2;
box.rotation.y = -0.4;
```

今のところ、ボックスは黒く見えますが、これはボックスの面に適用する素材を定義していないからです。次にそれを処理しましょう。

素材
--

素材とは、オブジェクトに応じたもの、つまり表面の色や質感のことです。この例では、シンプルな青色を使用して、箱を塗装します。使用できる素材の型はたくさんありますが、今のところ標準的なもので十分でしょう。前の行の下に、次の行を追加してください。

```js
var boxMaterial = new BABYLON.StandardMaterial("material", scene);
boxMaterial.emissiveColor = new BABYLON.Color3(0, 0.58, 0.86);
box.material = boxMaterial;
```

`StandardMaterial` は、名前と追加したいシーンの 2 つの引数を受け取ります。 2 つ目の行は `emissiveColor` を定義しています。この定義には組み込みの `Color3` 関数を使用することができます。 3 行目では、新しく作成した素材をボックスに割り当てています。

おめでとうございます！ Babylon.js を使用して、 3D 環境で最初のオブジェクトを作成することができました。思ったより簡単だったでしょう？こんな風に見えるはずです。

![Blue Babylon.js 3D box on the gray background.](/ja/docs/Games/Techniques/3D_on_the_web/Building_up_a_basic_demo_with_Babylon.js/cube.png)

そして今まで作ったコードはここです。

GitHub 上でも見ることができます。

もっと図形を加える
---------

このシーンにはすでに箱がありますが、さらに図形を追加してみましょう。

### トーラス

トーラスを追加してみましょう。先ほどのコードの下に、以下の行を追加してください。

```js
var torus = BABYLON.Mesh.CreateTorus("torus", 2, 0.5, 15, scene);
torus.position.x = -5;
torus.rotation.x = 1.5;
```

これはトーラスを作成し、シーンに追加します。引数は、名前、直径、厚さ、テセレーション（分割数）、追加するシーンです。また、トーラスを少し左側に配置し、見やすくするために `x` 軸で回転させます。それでは、素材を追加してみましょう。

```js
var torusMaterial = new BABYLON.StandardMaterial("material", scene);
torusMaterial.emissiveColor = new BABYLON.Color3(0.4, 0.4, 0.4);
torus.material = torusMaterial;
```

ボックス要素と同じように見えます。標準的な素材を作成し、グレーがかった色をつけて、トーラスに割り当てています。

### 円柱

円柱とその素材の作成は、トーラスの場合とほぼ同じ方法で行います。次のコードを、やはりスクリプトの一番下に追加してください。

```js
var cylinder = BABYLON.Mesh.CreateCylinder("cylinder", 2, 2, 2, 12, 1, scene);
cylinder.position.x = 5;
cylinder.rotation.x = -0.2;
var cylinderMaterial = new BABYLON.StandardMaterial("material", scene);
cylinderMaterial.emissiveColor = new BABYLON.Color3(1, 0.58, 0);
cylinder.material = cylinderMaterial;
```

円柱の引数は、名前、高さ、上部の直径、下部の直径、テセレーション、高さの細分化、追加するシーンです。そして立方体の右側に配置し、 3D 形状が見えるように少し回転させ、黄色の素材を与えます。

今、このシーンはこうなっているはずです。

![Light gray torus, blue box and yellow cylinder created with Babylon.js on the gray background.](/ja/docs/Games/Techniques/3D_on_the_web/Building_up_a_basic_demo_with_Babylon.js/shapes.png)

これはうまくいくのですが、少し退屈です。ゲームではたいてい何かが起こっています。アニメーションを見たりすることができます。そこで、これらの図形にアニメーションをつけて、生命を吹き込んでみましょう。

アニメーション
-------

すでに `position` と `rotation` を使用して、図形の位置を調整しました。また、拡大縮小も可能です。実際のアニメーションを表示するには、コードの最後にあるレンダリングループの中でこれらの値を変更し、すべてのフレームで更新されるようにする必要があります。アニメーションに使用するヘルパー変数 `t` を `renderLoop` の直前に定義し、ループ内の各フレームでデクリメントするようにします。

```js
var t = 0;
var renderLoop = function () {
  scene.render();
  t -= 0.01;
  // animation code goes here
};
engine.runRenderLoop(renderLoop);
```

変数 `t` はレンダリングフレームごとに増加します。

### 回転

回転を適用するのは、 `renderLoop` 関数の最後にこの行を追加するだけと簡単です。

```js
box.rotation.y = t \* 2;
```

これは、 `y` 軸に沿ってボックスを回転させます。

### 拡大縮小

この行を前の行の下に追加して、トーラスを拡大縮小します。

```js
torus.scaling.z = Math.abs(Math.sin(t \* 2)) + 0.5;
```

アニメーションの見た目を良くするために、少し調整が加えられています。値を変えてみて、アニメーションにどのような影響が出るか試してみてください。

### 移動

円柱の位置を直接変更することで、シーン上で円柱を動かすことができます。この行を前の行の下に追加してください。

```js
cylinder.position.y = Math.sin(t \* 3);
```

円柱は `Math.sin()` 関数のおかげで `y` 軸上で上下に浮き沈みします。

まとめ
---

以下は、最終的なコード一覧と、閲覧可能なライブ例です。

GitHubで見ることや、リポジトリーをフォークすることもできますので、ローカルで遊んでみたい方はどうぞ。これで、 Babylon.js エンジンの基本がわかりましたね。楽しく実験してください！

関連情報
----

* Learning Babylon.js book


Three.js を使った基本的なデモの作成 - ゲーム開発

Three.js を使った基本的なデモの作成
======================

ゲームの一般的な 3D シーンは、たとえ最もシンプルなものであっても、座標系に配置された図形、それらを実際に見るためのカメラ、見栄えを良くするためのライトや素材、生き生きと見せるためのアニメーションなど、標準的なアイテムが含まれています。 **Three.js** は、他の 3D ライブラリーと同様に、一般的な 3D 機能をより迅速に実装するためのヘルパー関数が組み込まれています。この記事では、開発環境の設定、必要な HTML の構成、 Three の基本オブジェクト、基本的なデモの作成方法など、 Three を使用するための本当の基本を紹介します。

**メモ:** 私たちは Three を有名な WebGLライブラリーの 1 つであり、簡単に使い始められるという理由で選びました。Three が他の WebGL ライブラリーと比べて優秀だというつもりはありません。 CopperLicht, GLGE, PlayCanvas など、気軽に試してみてください。

環境構築
----

Three.js で開発を始める上で、必要なものはあまりありません。少なくとも、

* WebGL によく対応した最新のブラウザー、例えば最新の Firefox や Chrome を使用していることを確認することです。
* デモを保存するディレクトリーを用意してください。
* 最新で最小版の Three.js をそのディレクトリーに保存してください。
* ブラウザーの別のタブで Three.js のドキュメント を開いてください — 参照するのに便利です。
HTML の構造
--------

これが今回使用する HTML のコードです。

```html
<!doctype html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>MDN Games: Three.js demo</title>
    <style>
 body {
 margin: 0;
 padding: 0;
 }
 canvas {
 width: 100%;
 height: 100%;
 }
 </style>
  </head>
  <body>
    <script src="three.min.js"></script>
    <script>
 const WIDTH = window.innerWidth;
 const HEIGHT = window.innerHeight;
 /\* すべての JavaScript コードをここに置きます \*/
 </script>
  </body>
</html>
```

これには、文書の `<title>` のような基本情報と、Three.js がページに挿入する `<canvas>` 要素の `width` と `height` を、ビューポート空間全体を埋めるために 100% に設定するためのいくつかの CSS が含まれています。最初の `<script>` 要素は、 Three.js ライブラリをページ内に入れ、 2 つ目の要素内に例のコードを書きます。すでに 2 つのヘルパー変数が含まれており、ウィンドウの `width` と `height` が格納されています。

先に進む前に、このコードを新しいテキストファイルにコピーしデモ用ディレクトリーに`index.html`として保存しましょう。

レンダラー
-----

レンダラーとは、ブラウザ上でシーンを正しく表示するためのツールです。レンダラーにはいくつかの種類があります。既定では WebGL ですが、その他に Canvas、SVG、CSS、DOM を使用することができます。これらはすべてのレンダリング方法が異なるため、 WebGL の実装と CSS の実装は異なります。目標を達成する方法はさまざまですが、ユーザーにとっての体験は同じになります。このアプローチのおかげで、希望する技術がブラウザーで対応していない場合、代替を使用することができます。

```js
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(WIDTH, HEIGHT);
renderer.setClearColor(0xdddddd, 1);
document.body.appendChild(renderer.domElement);
```

新しい WebGL レンダラーを作成し、画面上の空き領域全体にフィットするようにサイズを設定し、DOM 構造をページに追加しているところです。最初の行にある `antialias` 引数にお気づきかもしれませんが、これは図形の縁をより滑らかにレンダリングするためのものです。 `setClearColor()` メソッドは、背景を既定値の黒ではなく、明るい灰色に設定しています。

このコードを 2 つ目の `<script>` 要素に、 JavaScript のコメントのすぐ下に追加してください。

シーン
---

シーンは全てが起こる場所です。新たにオブジェクトを作るときは、シーン内にそれを追加することで画面に表示されるようになります。 Three.js ではシーンは `Scene` オブジェクトで表します。前項のコードの下にこれを追加し、シーンを作成しましょう。

```js
const scene = new THREE.Scene();
```

追加されると、 `.add()` 関数を使いオブジェクトをそのシーンに追加できるようになります。

カメラ
---

レンダリングされたシーンはありますが、私たちの作品を見るためにカメラを追加する必要があります。カメラのない映画のセットを想像してみてください。以下の行で、3D 座標系にカメラを設置し、シーンの方向に向けることで、ようやく何かを見ることができるようになります。

```js
const camera = new THREE.PerspectiveCamera(70, WIDTH / HEIGHT);
camera.position.z = 50;
scene.add(camera);
```

上記の行を、先に追加した行の下に追加してください。

他の種類のカメラ（Cube、Orthographic）もありますが、最もシンプルなのは Perspective（遠近法）です。このカメラを初期化するには、視野と縦横比を設定する必要があります。前者は見える範囲を設定するのに使用し、後者は画面上のオブジェクトがレンダリング時に正しい比率を持ち、引き伸ばされたように見えないようにするために重要です。上のコードで設定している値を説明しましょう。

* 視野率に設定した値 70 は、値を大きくすればするほど、カメラが映し出すシーンの量が増えるというもので、実際に試してみることができます。通常のカメラビューと魚眼効果を想像してください。既定値は 50 です。
* アスペクト比はウィンドウの現在の幅と高さに設定されるため、動的に調整されます。固定された比率を設定することもできます。例：16 ⁄ 9、これはワイドスクリーンテレビのアスペクト比です。既定値は 1 です。
* `z` 位置は 50 単位で、カメラと `z` 軸上のシーンの中心との距離です。ここでは、カメラを後ろに移動して、シーン内のオブジェクトを見ることができるようにしています。 50 はちょうどいい感じです。近すぎず遠すぎず、またオブジェクトの大きさによって、与えられた視野の中でシーンに留まることができます。 `x` と `y` の値は指定しない場合、既定で 0 になります。

これらの値を試してみて、シーンで見えるものがどのように変わるかを見てみるとよいでしょう。

**メモ:** これらの座標（カメラの z 位置など）の引数に決まった単位は存在しないため、シーンに適している単位 (ミリメートル、メートル、フィートやマイルでも) で構いません。あなたの決めるところです。

シーンのレンダリング
----------

全ての準備が終わりましたが、まだ私たちは何も目にしていません。レンダラーを作ったなら、全てをレンダリングしましょう。 `render()` は、そのレンダリングを `requestAnimationFrame()` の助けを借り行います。このコードは、全フレームで常にシーンがレンダリングされるようになります。

```js
function render() {
  requestAnimationFrame(render);
  renderer.render(scene, camera);
}
render();
```

新しいフレームごとに `render` 関数が呼び出され、`renderer` が `scene` と `camera` をレンダリングします。関数宣言の直後、ループを開始するために初めてこの関数を呼び出しています。

もう一度、この新しいコードを、前に追加したコードの下に追加してください。ファイルを保存して、ブラウザーで開いてみてください。グレーのウィンドウが表示されるはずです。おめでとうございます。

ジオメトリー
------

シーンが正しくレンダリングされたら、 3D 図形の追加を開始します。開発スピードを上げるために、 Three.js は定義済みのプリミティブを多数提供しており、これを使用すれば、 1 行のコードで即座に図形を作成することができます。立方体、球体、円柱、そしてもっと複雑な図形も用意されています。与えられた図形に必要な頂点や面の描画などの詳細は、 Three フレームワークで処理されるので、私たちはより高度なコーディングに集中することができるのです。まず、立方体の図形のジオメトリーを定義して、 `render()` 関数のすぐ上に続くことを追加します。

```js
const boxGeometry = new THREE.BoxGeometry(10, 10, 10);
```

このコードでは、 10 x 10 x 10 の簡単な立方体が生成されます。ジオメトリーだけでは不十分で、図形には素材が必要です。

素材
--

素材とは、オブジェクトに応じた、その表面にある色や質感を表すものです。ここでは、シンプルな青色を選んでボックスを塗装します。使用できる素材は、あらかじめ定義されているものが多数あります。基本 (Basic), フォン (Phong), ランバート (Lambert) です。後の 2 つは後で使ってみましょう。

```js
const basicMaterial = new THREE.MeshBasicMaterial({ color: 0x0095dd });
```

前項で追加した定義の下にこれを追加しましょう。

遂に素材も使えるようになりました。さて、次は何をしますか？

メッシュ
----

素材をシェイプのジオメトリーに適用させるには、メッシュを使用します。メッシュは、素材をシェイプの表面に適用してくれます。

```js
const cube = new THREE.Mesh(boxGeometry, basicMaterial);
```

もう一回前項で追加したコードの下にこれを追加しましょう。

立方体をシーンに追加する
------------

これまでに、ジオメトリーや素材を定義して立方体を作り出しました。最後に私たちが行うべきことはシーンに追加することです。さきほどのコードの下にこれを追加してください。

```js
scene.add(cube);
```

コードを保存してページを更新すると、オブジェクトがカメラの方向を向いているのでオブジェクトは正方形に見えます。オブジェクトの良いところは、シーン内で移動できるということです。例えば、私たちの思うままに回転や拡大縮小を行ったり。立方体を少し回転させ、複数の面を見てみましょう。また、コードの下にこれを追加します。

```js
cube.rotation.set(0.4, 0.2, 0);
```

おめでとうございます！ 3D 環境でオブジェクトを作成しましたね。これは、あなたが最初に考えたよりも簡単だったしょうか？こんな感じです。

![Blue cube on a gray background rendered with Three.js.](/ja/docs/Games/Techniques/3D_on_the_web/Building_up_a_basic_demo_with_Three.js/cube.png)

ここまでのサンプルコードは、ここで配布しています。

GitHub でチェックアウトすることもできます。

シェイプや素材の追加
----------

今度は、このシーンにさらに図形を追加し、他の図形や素材、照明などを調べてみましょう。立方体を左側に移動して、友達のための領域を作ってあげましょう。前の行のすぐ下に、次の行を追加してください。

```js
cube.position.x = -25;
```

では、さらに図形や素材を増やしてみましょう。フォンの素材で包まれたトーラスを追加するとどうなるでしょうか。立方体を定義している線のすぐ下に、次の線を加えてみてください。

```js
const torusGeometry = new THREE.TorusGeometry(7, 1, 6, 12);
const phongMaterial = new THREE.MeshPhongMaterial({ color: 0xff9500 });
const torus = new THREE.Mesh(torusGeometry, phongMaterial);
scene.add(torus);
```

`TorusGeometry()` メソッドの引数で定義します。引数は `radius`, `tube diameter`, `radial segment count`, `tubular segment count` です。フォンの素材は箱のシンプルな基本素材よりも光沢があるように見えますが、今のところトーラスはただの黒にしか見えません。

もっと楽しい定義済み図形を選べます。もう少し遊んでみましょう。トーラスを定義している行の下に、次の行を追加してください。

```js
const dodecahedronGeometry = new THREE.DodecahedronGeometry(7);
const lambertMaterial = new THREE.MeshLambertMaterial({ color: 0xeaeff2 });
const dodecahedron = new THREE.Mesh(dodecahedronGeometry, lambertMaterial);
dodecahedron.position.x = 25;
scene.add(dodecahedron);
```

今回は、 12 の平らな面を持つ正十二面体を作成します。引数 `DodecahedronGeometry()' はオブジェクトの大きさを定義します。ランバート素材を使用します。フォンと似ていますが、光沢が少ないほうがいいでしょう。ここでも今のところ黒です。オブジェクトを右に移動して、箱やトーラスと同じ位置にはならないようにしています。

上記のように、新しいオブジェクトは現在、ただ黒く見えるだけです。フォンとランバートの両方の素材をきちんと見えるようにするには、光源を導入する必要があります。

光源
--

Three.js では様々なタイプの光源が利用できます。最も基本的なものは `PointLight` で、これは懐中電灯のように定義された方向にスポットライトを照らすように動作します。以下の行を、図形の定義の下に追加してください。

```js
const light = new THREE.PointLight(0xffffff);
light.position.set(-10, 15, 50);
scene.add(light);
```

白い光の点を定義して、その位置をシーンの中心から少し離して設定し、図形の一部を照らすようにし、最後にシーンに追加します。これはうまくいき、 3 つの図形がすべて見えるようになりました。アンビエント、ディレクショナル、ヘミスフィア、スポットなど、他のタイプのライトについても、ドキュメントで確認する必要があります。それらをシーンに配置して、どのように影響するかを試してみてください。

![Shapes: blue cube, dark yellow torus and dark gray dodecahedron on a gray background rendered with Three.js.](/ja/docs/Games/Techniques/3D_on_the_web/Building_up_a_basic_demo_with_Three.js/shapes.png)

でも、これではちょっと退屈そうですね。ゲームでは、たいてい何かが起こっています。アニメーションを見たりすることもあるでしょう。そこで、この図形に少し命を吹き込んで、アニメーションをつけてみましょう。

アニメーション
-------

立方体の位置を調整するために、すでに回転を使用しました。また、図形を拡大縮小したり、位置を変更したりすることもできます。アニメーションを表示するには、レンダリングループの中でこれらの値を変更し、各フレームで更新する必要があります。

### 回転

回転させるのは簡単です。各フレームで与えられた回転方向の値を追加します。以下のコードを `render` 関数内の `requestAnimationFrame()` 呼び出しの直後に追加してください。

```js
cube.rotation.y += 0.01;
```

これにより、立方体がフレームごとにほんの少し回転し、アニメーションが滑らかに見えるようになります。

### 拡大縮小

また、オブジェクトを拡大縮小することもできます。一定の値を適用して、一度だけ大きくしたり、小さくしたりするのだ。もっと面白いことをやってみよう。まず、経過時間をカウントするためのヘルパー変数 `t` を実装します。これを `render()` 関数の直前に追加します。

```js
let t = 0;
```

さて、フレームごとに値が増えるようにしましょう。 `requestAnimationFrame()` のすぐ後にこれを書き足しましょう。

```js
t += 0.01;
torus.scale.y = Math.abs(Math.sin(t));
```

私たちは `Math.sin` を使用して、非常に興味深い結果にたどり着きました。 `sin` は周期的な関数なので、これはトーラスを拡大縮小し、そのプロセスを繰り返します。拡大縮小する値を `Math.abs` でラップして、 0 以上の絶対値を渡しています。 sin は -1 から 1 までの値なので、負の値はトーラスを予期しない方法でレンダリングするかもしれません。この場合、半分くらいは黒く見えます。

遂に、動かします。

### 動かす

回転と拡大縮小の他に、オブジェクトをシーン上で移動させることもできます。 `requestAnimationFrame()` 呼び出しのすぐ下に、次のようなものを追加します。

```js
dodecahedron.position.y = -7 \* Math.sin(t \* 2);
```

これは、各フレームの y 軸に `sin()` 値を適用することによって、正十二面体を上下に動かし、よりクールな見た目になるように少し調整するものです。これらの値を変えてみて、アニメーションにどのような影響を与えるか見てみましょう。

まとめ
---

これは最終的なコードです。

あなたは今までのコードを GitHubで見ることもできるし、ローカル環境で遊びたいと思ったらリポジトリーをフォークすることもできます。 Three.js の基本が理解できたでしょう。このページの親ページである ウェブ上の 3D に関するドキュメントに戻ることもできます。

WebGL を実際に触ることで、内部で何が起こっているのかをより理解することもできます。私たちの WebGL ドキュメンテーションを参考にしてみてください。