From b676e60d1a6a0dbe41be943ec039997bcfa16450 Mon Sep 17 00:00:00 2001 From: Yuuki Ebihara Date: Sat, 2 Jan 2021 23:35:49 +0900 Subject: [PATCH 1/8] translate 6-space-game README into japanese --- 6-space-game/translations/README.ja.md | 31 ++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 6-space-game/translations/README.ja.md diff --git a/6-space-game/translations/README.ja.md b/6-space-game/translations/README.ja.md new file mode 100644 index 00000000..29ce5995 --- /dev/null +++ b/6-space-game/translations/README.ja.md @@ -0,0 +1,31 @@ +# スペースゲームの構築 + +より高度な JavaScript の基礎を教えるスペースゲーム + +このレッスンでは、あなた自身のスペースゲームを作る方法を学びます。「スペースインベーダー」というゲームをプレイしたことがある方は、このゲームも同じように、宇宙船を操縦して、上から降ってくるモンスターを攻撃するというものです。完成したゲームはこんな感じです。 + +![Finished game](../images/pewpew.gif) + +この6つのレッスンでは、次のことを学びます。 + +- Canvas 要素と**相互にやりとりして**画面上に物を描く +- 直交座標系を**理解する** +- Pub-Sub パターンを**学び**、メンテナンスや拡張が容易なサウンドゲームアーキテクチャを作成できるようになる +- Async/Await を**活用して**ゲームリソースをロードする +- キーボードイベントを**処理する** + +## 概要 + +- 理論 + - [JavaScript を使ったゲーム構築入門](../1-introduction/translations/README.ja.md) +- 実践 + - [キャンバスへの描画](../2-drawing-to-canvas/translations/README.ja.md) + - [画面の周りの要素の移動](../3-moving-elements-around/translations/README.ja.md) + - [衝突の検出](../4-collision-detection/translations/README.ja.md) + - [スコアの保持](../5-keeping-score/translations/README.ja.md) + - [ゲームの終了と再開](../6-end-condition/translations/README.ja.md) + +## クレジット + +このために使用したアセットは https://www.kenney.nl/ から入手しました。 +ゲームを作るのが好きなら、これらのアセットはとても良いもので、多くは無料で、一部有料のものがあります。 From 9be8ed5e86cf0c4cf5350cb57dbcdc5e2db873f6 Mon Sep 17 00:00:00 2001 From: Yuuki Ebihara Date: Sun, 3 Jan 2021 02:33:54 +0900 Subject: [PATCH 2/8] translate 1-introduction into japanese --- .../1-introduction/translations/README.ja.md | 224 ++++++++++++++++++ .../translations/assignment.ja.md | 11 + 2 files changed, 235 insertions(+) create mode 100644 6-space-game/1-introduction/translations/README.ja.md create mode 100644 6-space-game/1-introduction/translations/assignment.ja.md diff --git a/6-space-game/1-introduction/translations/README.ja.md b/6-space-game/1-introduction/translations/README.ja.md new file mode 100644 index 00000000..47546717 --- /dev/null +++ b/6-space-game/1-introduction/translations/README.ja.md @@ -0,0 +1,224 @@ +# スペースゲーム構築プロジェクト その 1: イントロダクション + +![video](../../images/pewpew.gif) + +## レッスン前の小テスト + +[レッスン前の小テスト](https://nice-beach-0fe9e9d0f.azurestaticapps.net/quiz/29) + +### ゲーム開発における継承とコンポジション + +以前のレッスンでは、プロジェクトの規模が非常に小さかったため、構築したアプリの設計アーキテクチャを気にする必要はあまりありませんでした。しかし、アプリケーションの規模や範囲が大きくなると、アーキテクチャの決定がより大きな関心事になります。JavaScript で大規模なアプリケーションを作成するには、大きく分けて2つのアプローチがあります。*コンポジション* と *継承* です。どちらにも長所と短所がありますが、ゲームの文脈から説明してみましょう。 + +✅ これまでに書かれたプログラミング本の中で最も有名なものの一つは、[デザインパターン](https://ja.wikipedia.org/wiki/%E3%83%87%E3%82%B6%E3%82%A4%E3%83%B3%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3_(%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2))と関係があります。 + +ゲームには `ゲームオブジェクト` があり、これは画面上に存在するオブジェクトです。つまり、それらは直交座標系上に位置しており、`x` と `y` の座標を持つことが特徴です。ゲームを開発していくうちに、すべてのゲームオブジェクトには、すべてのゲームに共通する標準的な特性があることに気づくでしょう。 + +- **location-based** すべてではないにしても、ほとんどのゲーム要素は位置情報に基づいています。これは、場所、`x` と `y` を持つことを意味します +- **movable** これらは、新しい場所に移動することができるオブジェクトです。これは典型的にはヒーローやモンスター、NPC (プレイヤーではないキャラクター) などですが、例えば木のような静的なオブジェクトはそうではありません +- **self-destructing** これらのオブジェクトは、削除のために自分自身を設定する前に、一定期間だけ存在します。通常、これは `dead` または `destroyed` ブール値で表され、このオブジェクトがレンダリングされなくなることをゲームエンジンに通知します +- **cool-down** 「クールダウン」は、短命なオブジェクトの典型的なプロパティです。典型的な例としては、数ミリ秒しか見られない爆発のようなテキストやグラフィック効果があります。 + +✅ パックマンのようなゲームについて考えてみましょう。このゲームでは、上に挙げた4つのオブジェクトの種類を特定できますか? + +### 行動の表現 + +上で説明したのは、すべてゲームオブジェクトが持つことのできる動作です。では、それらをどのようにエンコードするのでしょうか? この動作をクラスやオブジェクトに関連付けられたメソッドとして表現することができます。 + +**クラス** + +クラスに特定の振る舞いを追加するために `クラス` を `継承` と組み合わせて使うという考え方です。 + +✅ 継承は理解しておくべき重要な概念です。[継承に関する MdN の記事](https://developer.mozilla.org/ja/docs/Web/JavaScript/Inheritance_and_the_prototype_chain)で詳しく解説しています。 + +コードで表現すると、ゲームオブジェクトは通常このようになります。 + +```javascript + +//GameObject クラスを設定します。 +class GameObject { + constructor(x, y, type) { + this.x = x; + this.y = y; + this.type = type; + } +} + +//このクラスは GameObject の固有のクラスプロパティを拡張します。 +class Movable extends GameObject { + constructor(x,y, type) { + super(x,y, type) + } + +//この移動可能なオブジェクトは、画面上で移動することができます。 + moveTo(x, y) { + this.x = x; + this.y = y; + } +} + +//これは Movable クラスを拡張した特定のクラスで、継承しているすべてのプロパティを利用することができます。 +class Hero extends Movable { + constructor(x,y) { + super(x,y, 'Hero') + } +} + +//一方、このクラスは GameObject のプロパティのみを継承しています。 +class Tree extends GameObject { + constructor(x,y) { + super(x,y, 'Tree') + } +} + +//hero は動くことができます +const hero = new Hero(); +hero.moveTo(5,5); + +//しかし木にはできません +const tree = new Tree(); +``` + +✅ パックマンのヒーロー (例えば、Inky、Pinky、Blinky など) と、それが JavaScript でどのように書かれているかを、数分かけて再定義してみましょう。 + +**コンポジション** + +オブジェクトの継承を処理する別の方法として、*コンポジション* を使用する方法があります。すると、オブジェクトは次のように動作を表現します。 + +```javascript +//定数の gameObject を作成する +const gameObject = { + x: 0, + y: 0, + type: '' +}; + +//そして定数の movable +const movable = { + moveTo(x, y) { + this.x = x; + this.y = y; + } +} +//そして、定数 movableObject は定数 gameObject と movable で構成されます。 +const movableObject = {...gameObject, ...movable}; + +//次に、movableObject のプロパティを継承する新しい Hero を作成する関数を作成します。 +function createHero(x, y) { + return { + ...movableObject, + x, + y, + type: 'Hero' + } +} +//...そして gameObject プロパティのみを継承する静的オブジェクト。 +function createStatic(x, y, type) { + return { + ...gameObject + x, + y, + type + } +} +//hero を作って動かします +const hero = createHero(10,10); +hero.moveTo(5,5); +//そして、周りに立つだけの木を作ります +const tree = createStatic(0,0, 'Tree'); +``` + +**どのパターンを使えばいいのか?** + +どちらのパターンを選ぶかはあなた次第です。JavaScript はこれらのパラダイムの両方をサポートしています。 + +-- + +ゲーム開発に共通するもう一つのパターンは、ゲームのユーザーエクスペリエンスとパフォーマンスを処理する問題を扱っています。 + +## Pub/sub パターン + +✅ Pub/Sub は 'publish-subscribe' の略です。 + +このパターンは、あなたのアプリケーションのバラバラな部分が別のものを知ってはいけないという考えを示しています。それはなぜでしょうか? 様々な部分が分離されていると、一般的に何が起こっているのかを見るのがとても簡単になります。また、必要に応じて突然動作を変更することも容易になります。どのようにしてこれを達成するのでしょうか? いくつかの概念を確立することで実現します。 + +- **message**: メッセージは通常、オプションのペイロード (メッセージの内容を明確にするデータ) を伴ったテキスト文字列です。ゲームにおける典型的なメッセージは `KEY_PRESSED_ENTER` です +- **publisher**: この要素はメッセージを**発行し**、すべての購読者に送信します +- **subscriber**: この要素は、特定のメッセージを *待ち受け*、このメッセージを受信した結果として、レーザーを発射するなどのタスクを実行します + +実装されているのはかなり小さいですが、かなり強力なパターンです。以下に実装方法を紹介します。 + +```javascript +//リスナーを含む EventEmitter クラスを設定します。 +class EventEmitter { + constructor() { + this.listeners = {}; + } +//メッセージを受信したときに、リスナーにそのペイロードを処理させます。 + on(message, listener) { + if (!this.listeners[message]) { + this.listeners[message] = []; + } + this.listeners[message].push(listener); + } +//メッセージを受信したときに、リスナーにそのペイロードを処理させます。 + emit(message, payload = null) { + if (this.listeners[message]) { + this.listeners[message].forEach(l => l(message, payload)) + } + } +} + +``` + +上記のコードを使用するために、非常に小さな実装を作成することができます。 + +```javascript +//メッセージ構造を設定します +const Messages = { + HERO_MOVE_LEFT: 'HERO_MOVE_LEFT' +}; +//上記で設定した EventEmitter を呼び出します。 +const eventEmitter = new EventEmitter(); +//hero を設定します。 +const hero = createHero(0,0); +//イベント送信者に hero が左に移動するメッセージを監視することを知らせ、それに基づいて行動するようにします。 +eventEmitter.on(Messages.HERO_MOVE_LEFT, () => { + hero.move(5,0); +}); + +//keyup イベントをリッスンするためにウィンドウを設定し、具体的には左矢印がヒットした場合、hero を左に移動するためのメッセージを発します。 +window.addEventListener('keyup', (evt) => { + if (evt.key === 'ArrowLeft') { + eventEmitter.emit(Messages.HERO_MOVE_LEFT) + } +}); +``` + +上ではキーボードイベント `ArrowLeft` を接続して `HERO_MOVE_LEFT` メッセージを送信している。私たちはそのメッセージを聞き、その結果として `hero` を移動させます。このパターンの強みは、イベントリスナーとヒーローがお互いのことを知らないことです。`ArrowLeft` を `A` キーにリマップすることができます。さらに、eventEmitter の `on` 関数にいくつかの編集を加えることで、`ArrowLeft` で全く異なることが可能になります。 + +```javascript +eventEmitter.on(Messages.HERO_MOVE_LEFT, () => { + hero.move(5,0); +}); +``` + +ゲームが成長するときに物事がより複雑になったとしても、このパターンは複雑さの中で同じままで、あなたのコードはきれいなままになります。このパターンを採用することをお勧めします。 + +--- + +## 🚀 チャレンジ + +pub-sub パターンがどのようにゲームを盛り上げるかを考えてみましょう。どのパーツがイベントを発生させ、それに対してゲームはどのように反応しますか? 新しいゲームとそのパーツがどのように振る舞うかを考えて、創造性を発揮するチャンスです。 + +## レッスン後の小テスト + +[レッスン後の小テスト](https://nice-beach-0fe9e9d0f.azurestaticapps.net/quiz/30) + +## 復習と自己学習 + +Pub/Sub については、[こちらを読んでみてください](https://docs.microsoft.com/ja-jp/azure/architecture/patterns/publisher-subscriber)。 + +## 課題 + +[ゲームのモックアップ](assignment.ja.md) diff --git a/6-space-game/1-introduction/translations/assignment.ja.md b/6-space-game/1-introduction/translations/assignment.ja.md new file mode 100644 index 00000000..c31bad9f --- /dev/null +++ b/6-space-game/1-introduction/translations/assignment.ja.md @@ -0,0 +1,11 @@ +# ゲームのモックアップ + +## 説明書 + +レッスンで使用したコードサンプルを使用して、好きなゲームの表現を書いてください。単純なゲームである必要がありますが、目標は、クラスまたは構成パターンと pub/sub パターンのいずれかを使用して、ゲームがどのように起動するかを示すことです。創造力を発揮してください。 + +## ルーブリック + +| 基準 | 模範的な例 | 適切な | 改善が必要 | +| -------- | ------------------------------------------------------- | ----------------------------------------------------- | --------------------------------------------------- | +| | 3つの要素を画面上に配置して操作する | 2つの要素を画面上に配置して操作する | 1つの要素を画面上に配置して操作する | \ No newline at end of file From 64d824481f283649cfe321c668cab37888b682ef Mon Sep 17 00:00:00 2001 From: Yuuki Ebihara Date: Sat, 2 Jan 2021 23:35:49 +0900 Subject: [PATCH 3/8] translate 6-space-game README into japanese --- 6-space-game/translations/README.ja.md | 31 ++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 6-space-game/translations/README.ja.md diff --git a/6-space-game/translations/README.ja.md b/6-space-game/translations/README.ja.md new file mode 100644 index 00000000..29ce5995 --- /dev/null +++ b/6-space-game/translations/README.ja.md @@ -0,0 +1,31 @@ +# スペースゲームの構築 + +より高度な JavaScript の基礎を教えるスペースゲーム + +このレッスンでは、あなた自身のスペースゲームを作る方法を学びます。「スペースインベーダー」というゲームをプレイしたことがある方は、このゲームも同じように、宇宙船を操縦して、上から降ってくるモンスターを攻撃するというものです。完成したゲームはこんな感じです。 + +![Finished game](../images/pewpew.gif) + +この6つのレッスンでは、次のことを学びます。 + +- Canvas 要素と**相互にやりとりして**画面上に物を描く +- 直交座標系を**理解する** +- Pub-Sub パターンを**学び**、メンテナンスや拡張が容易なサウンドゲームアーキテクチャを作成できるようになる +- Async/Await を**活用して**ゲームリソースをロードする +- キーボードイベントを**処理する** + +## 概要 + +- 理論 + - [JavaScript を使ったゲーム構築入門](../1-introduction/translations/README.ja.md) +- 実践 + - [キャンバスへの描画](../2-drawing-to-canvas/translations/README.ja.md) + - [画面の周りの要素の移動](../3-moving-elements-around/translations/README.ja.md) + - [衝突の検出](../4-collision-detection/translations/README.ja.md) + - [スコアの保持](../5-keeping-score/translations/README.ja.md) + - [ゲームの終了と再開](../6-end-condition/translations/README.ja.md) + +## クレジット + +このために使用したアセットは https://www.kenney.nl/ から入手しました。 +ゲームを作るのが好きなら、これらのアセットはとても良いもので、多くは無料で、一部有料のものがあります。 From 21c67e1c0ff07aa2892e925111fbd659d6876abe Mon Sep 17 00:00:00 2001 From: Yuuki Ebihara Date: Sun, 3 Jan 2021 02:33:54 +0900 Subject: [PATCH 4/8] translate 1-introduction into japanese --- .../1-introduction/translations/README.ja.md | 224 ++++++++++++++++++ .../translations/assignment.ja.md | 11 + 2 files changed, 235 insertions(+) create mode 100644 6-space-game/1-introduction/translations/README.ja.md create mode 100644 6-space-game/1-introduction/translations/assignment.ja.md diff --git a/6-space-game/1-introduction/translations/README.ja.md b/6-space-game/1-introduction/translations/README.ja.md new file mode 100644 index 00000000..47546717 --- /dev/null +++ b/6-space-game/1-introduction/translations/README.ja.md @@ -0,0 +1,224 @@ +# スペースゲーム構築プロジェクト その 1: イントロダクション + +![video](../../images/pewpew.gif) + +## レッスン前の小テスト + +[レッスン前の小テスト](https://nice-beach-0fe9e9d0f.azurestaticapps.net/quiz/29) + +### ゲーム開発における継承とコンポジション + +以前のレッスンでは、プロジェクトの規模が非常に小さかったため、構築したアプリの設計アーキテクチャを気にする必要はあまりありませんでした。しかし、アプリケーションの規模や範囲が大きくなると、アーキテクチャの決定がより大きな関心事になります。JavaScript で大規模なアプリケーションを作成するには、大きく分けて2つのアプローチがあります。*コンポジション* と *継承* です。どちらにも長所と短所がありますが、ゲームの文脈から説明してみましょう。 + +✅ これまでに書かれたプログラミング本の中で最も有名なものの一つは、[デザインパターン](https://ja.wikipedia.org/wiki/%E3%83%87%E3%82%B6%E3%82%A4%E3%83%B3%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3_(%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2))と関係があります。 + +ゲームには `ゲームオブジェクト` があり、これは画面上に存在するオブジェクトです。つまり、それらは直交座標系上に位置しており、`x` と `y` の座標を持つことが特徴です。ゲームを開発していくうちに、すべてのゲームオブジェクトには、すべてのゲームに共通する標準的な特性があることに気づくでしょう。 + +- **location-based** すべてではないにしても、ほとんどのゲーム要素は位置情報に基づいています。これは、場所、`x` と `y` を持つことを意味します +- **movable** これらは、新しい場所に移動することができるオブジェクトです。これは典型的にはヒーローやモンスター、NPC (プレイヤーではないキャラクター) などですが、例えば木のような静的なオブジェクトはそうではありません +- **self-destructing** これらのオブジェクトは、削除のために自分自身を設定する前に、一定期間だけ存在します。通常、これは `dead` または `destroyed` ブール値で表され、このオブジェクトがレンダリングされなくなることをゲームエンジンに通知します +- **cool-down** 「クールダウン」は、短命なオブジェクトの典型的なプロパティです。典型的な例としては、数ミリ秒しか見られない爆発のようなテキストやグラフィック効果があります。 + +✅ パックマンのようなゲームについて考えてみましょう。このゲームでは、上に挙げた4つのオブジェクトの種類を特定できますか? + +### 行動の表現 + +上で説明したのは、すべてゲームオブジェクトが持つことのできる動作です。では、それらをどのようにエンコードするのでしょうか? この動作をクラスやオブジェクトに関連付けられたメソッドとして表現することができます。 + +**クラス** + +クラスに特定の振る舞いを追加するために `クラス` を `継承` と組み合わせて使うという考え方です。 + +✅ 継承は理解しておくべき重要な概念です。[継承に関する MdN の記事](https://developer.mozilla.org/ja/docs/Web/JavaScript/Inheritance_and_the_prototype_chain)で詳しく解説しています。 + +コードで表現すると、ゲームオブジェクトは通常このようになります。 + +```javascript + +//GameObject クラスを設定します。 +class GameObject { + constructor(x, y, type) { + this.x = x; + this.y = y; + this.type = type; + } +} + +//このクラスは GameObject の固有のクラスプロパティを拡張します。 +class Movable extends GameObject { + constructor(x,y, type) { + super(x,y, type) + } + +//この移動可能なオブジェクトは、画面上で移動することができます。 + moveTo(x, y) { + this.x = x; + this.y = y; + } +} + +//これは Movable クラスを拡張した特定のクラスで、継承しているすべてのプロパティを利用することができます。 +class Hero extends Movable { + constructor(x,y) { + super(x,y, 'Hero') + } +} + +//一方、このクラスは GameObject のプロパティのみを継承しています。 +class Tree extends GameObject { + constructor(x,y) { + super(x,y, 'Tree') + } +} + +//hero は動くことができます +const hero = new Hero(); +hero.moveTo(5,5); + +//しかし木にはできません +const tree = new Tree(); +``` + +✅ パックマンのヒーロー (例えば、Inky、Pinky、Blinky など) と、それが JavaScript でどのように書かれているかを、数分かけて再定義してみましょう。 + +**コンポジション** + +オブジェクトの継承を処理する別の方法として、*コンポジション* を使用する方法があります。すると、オブジェクトは次のように動作を表現します。 + +```javascript +//定数の gameObject を作成する +const gameObject = { + x: 0, + y: 0, + type: '' +}; + +//そして定数の movable +const movable = { + moveTo(x, y) { + this.x = x; + this.y = y; + } +} +//そして、定数 movableObject は定数 gameObject と movable で構成されます。 +const movableObject = {...gameObject, ...movable}; + +//次に、movableObject のプロパティを継承する新しい Hero を作成する関数を作成します。 +function createHero(x, y) { + return { + ...movableObject, + x, + y, + type: 'Hero' + } +} +//...そして gameObject プロパティのみを継承する静的オブジェクト。 +function createStatic(x, y, type) { + return { + ...gameObject + x, + y, + type + } +} +//hero を作って動かします +const hero = createHero(10,10); +hero.moveTo(5,5); +//そして、周りに立つだけの木を作ります +const tree = createStatic(0,0, 'Tree'); +``` + +**どのパターンを使えばいいのか?** + +どちらのパターンを選ぶかはあなた次第です。JavaScript はこれらのパラダイムの両方をサポートしています。 + +-- + +ゲーム開発に共通するもう一つのパターンは、ゲームのユーザーエクスペリエンスとパフォーマンスを処理する問題を扱っています。 + +## Pub/sub パターン + +✅ Pub/Sub は 'publish-subscribe' の略です。 + +このパターンは、あなたのアプリケーションのバラバラな部分が別のものを知ってはいけないという考えを示しています。それはなぜでしょうか? 様々な部分が分離されていると、一般的に何が起こっているのかを見るのがとても簡単になります。また、必要に応じて突然動作を変更することも容易になります。どのようにしてこれを達成するのでしょうか? いくつかの概念を確立することで実現します。 + +- **message**: メッセージは通常、オプションのペイロード (メッセージの内容を明確にするデータ) を伴ったテキスト文字列です。ゲームにおける典型的なメッセージは `KEY_PRESSED_ENTER` です +- **publisher**: この要素はメッセージを**発行し**、すべての購読者に送信します +- **subscriber**: この要素は、特定のメッセージを *待ち受け*、このメッセージを受信した結果として、レーザーを発射するなどのタスクを実行します + +実装されているのはかなり小さいですが、かなり強力なパターンです。以下に実装方法を紹介します。 + +```javascript +//リスナーを含む EventEmitter クラスを設定します。 +class EventEmitter { + constructor() { + this.listeners = {}; + } +//メッセージを受信したときに、リスナーにそのペイロードを処理させます。 + on(message, listener) { + if (!this.listeners[message]) { + this.listeners[message] = []; + } + this.listeners[message].push(listener); + } +//メッセージを受信したときに、リスナーにそのペイロードを処理させます。 + emit(message, payload = null) { + if (this.listeners[message]) { + this.listeners[message].forEach(l => l(message, payload)) + } + } +} + +``` + +上記のコードを使用するために、非常に小さな実装を作成することができます。 + +```javascript +//メッセージ構造を設定します +const Messages = { + HERO_MOVE_LEFT: 'HERO_MOVE_LEFT' +}; +//上記で設定した EventEmitter を呼び出します。 +const eventEmitter = new EventEmitter(); +//hero を設定します。 +const hero = createHero(0,0); +//イベント送信者に hero が左に移動するメッセージを監視することを知らせ、それに基づいて行動するようにします。 +eventEmitter.on(Messages.HERO_MOVE_LEFT, () => { + hero.move(5,0); +}); + +//keyup イベントをリッスンするためにウィンドウを設定し、具体的には左矢印がヒットした場合、hero を左に移動するためのメッセージを発します。 +window.addEventListener('keyup', (evt) => { + if (evt.key === 'ArrowLeft') { + eventEmitter.emit(Messages.HERO_MOVE_LEFT) + } +}); +``` + +上ではキーボードイベント `ArrowLeft` を接続して `HERO_MOVE_LEFT` メッセージを送信している。私たちはそのメッセージを聞き、その結果として `hero` を移動させます。このパターンの強みは、イベントリスナーとヒーローがお互いのことを知らないことです。`ArrowLeft` を `A` キーにリマップすることができます。さらに、eventEmitter の `on` 関数にいくつかの編集を加えることで、`ArrowLeft` で全く異なることが可能になります。 + +```javascript +eventEmitter.on(Messages.HERO_MOVE_LEFT, () => { + hero.move(5,0); +}); +``` + +ゲームが成長するときに物事がより複雑になったとしても、このパターンは複雑さの中で同じままで、あなたのコードはきれいなままになります。このパターンを採用することをお勧めします。 + +--- + +## 🚀 チャレンジ + +pub-sub パターンがどのようにゲームを盛り上げるかを考えてみましょう。どのパーツがイベントを発生させ、それに対してゲームはどのように反応しますか? 新しいゲームとそのパーツがどのように振る舞うかを考えて、創造性を発揮するチャンスです。 + +## レッスン後の小テスト + +[レッスン後の小テスト](https://nice-beach-0fe9e9d0f.azurestaticapps.net/quiz/30) + +## 復習と自己学習 + +Pub/Sub については、[こちらを読んでみてください](https://docs.microsoft.com/ja-jp/azure/architecture/patterns/publisher-subscriber)。 + +## 課題 + +[ゲームのモックアップ](assignment.ja.md) diff --git a/6-space-game/1-introduction/translations/assignment.ja.md b/6-space-game/1-introduction/translations/assignment.ja.md new file mode 100644 index 00000000..c31bad9f --- /dev/null +++ b/6-space-game/1-introduction/translations/assignment.ja.md @@ -0,0 +1,11 @@ +# ゲームのモックアップ + +## 説明書 + +レッスンで使用したコードサンプルを使用して、好きなゲームの表現を書いてください。単純なゲームである必要がありますが、目標は、クラスまたは構成パターンと pub/sub パターンのいずれかを使用して、ゲームがどのように起動するかを示すことです。創造力を発揮してください。 + +## ルーブリック + +| 基準 | 模範的な例 | 適切な | 改善が必要 | +| -------- | ------------------------------------------------------- | ----------------------------------------------------- | --------------------------------------------------- | +| | 3つの要素を画面上に配置して操作する | 2つの要素を画面上に配置して操作する | 1つの要素を画面上に配置して操作する | \ No newline at end of file From a9bfbaa59896e545cf0da8f2a1db486f6a60e49f Mon Sep 17 00:00:00 2001 From: Yuuki Ebihara Date: Sun, 3 Jan 2021 19:07:52 +0900 Subject: [PATCH 5/8] translate 2-drawing-to-canvas into japanese --- .../translations/README.ja.md | 216 ++++++++++++++++++ .../translations/assignment.ja.md | 11 + 2 files changed, 227 insertions(+) create mode 100644 6-space-game/2-drawing-to-canvas/translations/README.ja.md create mode 100644 6-space-game/2-drawing-to-canvas/translations/assignment.ja.md diff --git a/6-space-game/2-drawing-to-canvas/translations/README.ja.md b/6-space-game/2-drawing-to-canvas/translations/README.ja.md new file mode 100644 index 00000000..7c389c65 --- /dev/null +++ b/6-space-game/2-drawing-to-canvas/translations/README.ja.md @@ -0,0 +1,216 @@ +# スペースゲーム構築プロジェクト その 2: ヒーローとモンスターをキャンバスに描く + +## レッスン前の小テスト + +[レッスン前の小テスト](https://nice-beach-0fe9e9d0f.azurestaticapps.net/quiz/31) + +## Canvas + +Canvas は HTML 要素で、デフォルトでは何のコンテンツもありません。何もない白紙の状態です。その上に描画することで、Canvas に追加する必要があります。 + +✅ MDN の [Canvas API についての詳細](https://developer.mozilla.org/ja/docs/Web/API/Canvas_API)はこちらをご覧ください。 + +ページの本文の一部として、一般的にどのように宣言されているかをご紹介します。 + +```html + +``` + +上では `id`, `width`, `height` を設定しています。 + +- `id`: 設定することで、これと対話する必要があるときに参照を取得できるようになります +- `width`: これは要素の幅です +- `height`: これは要素の高さです + +## 簡単な幾何学図形の描画 + +キャンバスは、直交座標系を使って物を描いています。したがって、何かがどこにあるかを表現するために x 軸と y 軸を使用しています。`0,0` の位置が左上の位置で、右下の位置がキャンバスの幅と高さと言ったところです。 + +![the canvas's grid](../canvas_grid.png) +> 画像は [MDN](https://developer.mozilla.org/ja/docs/Web/Guide/HTML/Canvas_tutorial/Drawing_shapes) より + +キャンバス要素に描画するには、以下の手順を踏む必要があります。 + +1. Canvas 要素への**参照を取得します** +1. canvas 要素の上にある Context 要素の**参照を取得します** +1. context 要素を使用して**描画操作を行います** + +上記の手順のコードは、通常次のようになります。 + +```javascript +// 赤い四角を描きます。 +//1. キャンバスの参照を取得します +canvas = document.getElementById("myCanvas"); + +//2. コンテキストを 2D に設定して基本的な図形を描画します。 +ctx = canvas.getContext("2d"); + +//3. 赤で塗りつぶします。 +ctx.fillStyle = 'red'; + +//4. そして、これらのパラメータで矩形を描画し、位置とサイズを設定します。 +ctx.fillRect(0,0, 200, 200) // x, y, width, height +``` + +✅ Canvas API は主に 2D の図形に焦点を当てていますが、Web サイトに 3D の要素を描画することもできます。そのためには、[WebGL API](https://developer.mozilla.org/ja/docs/Web/API/WebGL_API) を使用するとよいでしょう。 + +Canvas API を使っていろいろなものを描くことができます。 + +- **幾何学的な形状**、我々はすでに長方形を描画する方法を示しましたが、あなたが描くことができるはるかに多くのものがあります +- **テキスト**は、任意のフォントと色でテキストを描くことができます +- **画像**では、例えば .jpg や .png のような画像アセットに基づいて画像を描くことができます + +✅ やってみましょう! 長方形の描き方は知っていると思いますが、ページに円を描くことはできますか? CodePen に掲載されている面白い Canvas のドローイングを見てみましょう。ここに[特に印象的な例](https://codepen.io/dissimulate/pen/KrAwx)があります。 + +## 画像アセットの読み込みと描画 + +画像アセットをロードするには、`Image` オブジェクトを作成して `src` プロパティを設定します。そして、`load` イベントを待ち受け、それがいつ使用可能になるかを知ることができます。コードは次のようになります。 + +### アセットの読み込み + +```javascript +const img = new Image(); +img.src = 'path/to/my/image.png'; +img.onload = () => { + // イメージが読み込まれて使用可能な状態になっています +} +``` + +### アセットの読み込みパターン + +上記のようなコンストラクトで包んだ方が使いやすいですし、フルロードした時だけ操作しようとするのでおすすめです。 + +```javascript +function loadAsset(path) { + return new Promise((resolve) => { + const img = new Image(); + img.src = path; + img.onload = () => { + // イメージが読み込まれて使用可能な状態になっています + resolve(img); + } + }) +} + +// 使いまわします + +async function run() { + const heroImg = await loadAsset('hero.png') + const monsterImg = await loadAsset('monster.png') +} + +``` + +ゲームアセットを画面に描画するには、以下のようなコードになります。 + +```javascript +async function run() { + const heroImg = await loadAsset('hero.png') + const monsterImg = await loadAsset('monster.png') + + canvas = document.getElementById("myCanvas"); + ctx = canvas.getContext("2d"); + ctx.drawImage(heroImg, canvas.width/2, canvas.height/2); + ctx.drawImage(monsterImg, 0, 0); +} +``` + +## さあ、あなたのゲームを作り始める時が来ました。 + +### 何を構築するか + +Canvas 要素を使って Web ページを作成します。これは黒い画面 `1024 * 768` をレンダリングする必要があります。画像は2枚用意しました。 + +- Hero の宇宙船 + + ![Hero の宇宙船](../solution/assets/player.png) + +- 5*5 monster + + ![Monster の宇宙船](../solution/assets/enemyShip.png) + +### 開発を始めるための推奨ステップ + +あなたのために作成されたファイルを `your-work` サブフォルダ内で探します。以下のファイルが含まれているはずです。 + +```bash +-| assets + -| enemyShip.png + -| player.png +-| index.html +-| app.js +-| package.json +``` + +このフォルダのコピーを Visual Studio Code で開きます。ローカルの開発環境が設定されている必要があり、できれば Visual Studio Code に NPM と Node がインストールされている必要があります。もしあなたのコンピュータに `npm` がセットアップされていない場合は、[ここにその方法があります](https://www.npmjs.com/get-npm)。 + +`your_work` フォルダに移動してプロジェクトを開始します。 + +```bash +cd your-work +npm start +``` + +以上で、`http://localhost:5000` というアドレスに HTTP サーバが起動します。ブラウザを開いて、そのアドレスを入力してください。今は何も表示されていませんが、そのうち変わるでしょう。 + +> 注: 画面上の変更を確認するには、ブラウザを更新してください。 + +### コードの追加 + +以下の問題を解決するために必要なコードを `your-work/app.js` に追加します。 + +1. 黒い背景のキャンバスを**描画します** + > tip: `/app.js` の適切な TODO の下に 2 行を追加し、`ctx` 要素を黒にして上下の座標を 0,0 にし、高さと幅をキャンバスと同じにします。 +2. テクスチャを**読み込みます** + > tip: プレイヤーと敵の画像を追加するには `await loadTexture` を使用し、画像パスを渡してください。まだ画面には表示されていません! +3. 下半分の画面中央にヒーローを**描画します** + > tip: heroImg を画面に描画するには `drawImage` API を使用し、`canvas.width / 2 - 45` と `canvas.height - canvas.height / 4)` を設定します。 +4. 5*5 のモンスターを**描画します** + > tip: これで、画面上に敵を描画するコードのコメントを解除することができるようになりました。次に、`createEnemies` 関数に移動して、それを構築する。 + + まず、いくつかの定数を設定します。 + + ```javascript + const MONSTER_TOTAL = 5; + const MONSTER_WIDTH = MONSTER_TOTAL * 98; + const START_X = (canvas.width - MONSTER_WIDTH) / 2; + const STOP_X = START_X + MONSTER_WIDTH; + ``` + + そして、モンスターの配列を画面上に描画するループを作成します。 + + ```javascript + for (let x = START_X; x < STOP_X; x += 98) { + for (let y = 0; y < 50 * 5; y += 50) { + ctx.drawImage(enemyImg, x, y); + } + } + ``` + +## 結果 + +仕上がりはこんな感じになるはずです。 + +![hero と 5 * 5 モンスターで黒画面](../partI-solution.png) + +## Solution + +まずはご自身で解決してみていただきたいですが、行き詰った場合は [solution](../solution/app.js) を参考にしてみてください。 + +--- + +## 🚀 チャレンジ + +2D を中心とした Canvas API での描画について学んできましたが、[WebGL API](https://developer.mozilla.org/ja/docs/Web/API/WebGL_API) を参考に、3D オブジェクトを描画してみましょう。 + +## レッスン後の小テスト + +[レッスン後の小テスト](https://nice-beach-0fe9e9d0f.azurestaticapps.net/quiz/32) + +## 復習と自己学習 + +Canvas API については、[こちらを読んでいただく](https://developer.mozilla.org/ja/docs/Web/API/Canvas_API)ことで詳しく知ることができます。 + +## 課題 + +[Canvas API で遊ぶ](assignment.ja.md) \ No newline at end of file diff --git a/6-space-game/2-drawing-to-canvas/translations/assignment.ja.md b/6-space-game/2-drawing-to-canvas/translations/assignment.ja.md new file mode 100644 index 00000000..dc89523d --- /dev/null +++ b/6-space-game/2-drawing-to-canvas/translations/assignment.ja.md @@ -0,0 +1,11 @@ +# Canvas API で遊ぶ + +## 説明書 + +Canvas API の要素を 1 つ選んで、その周りに何か面白いものを作りましょう。星が繰り返される小さな銀河を作ることができますか? 色のついた線で面白いテクスチャを作ることができますか? インスピレーションを得るために CodePen を見ることができます (ただし、コピーはしないでください)。 + +## ルーブリック + +| 基準 | 模範的な例 | 適切な | 改善が必要 | +| -------- | --------------------------------------------------------- | ----------------------------------- | --------------------- | +| | 興味深い質感や形状を示すコードが提出されている | コードは送信されたが実行されない | コードが提出されていない | \ No newline at end of file From 9b99e9816dfe0de28b23e7be54900f5ba7214ce6 Mon Sep 17 00:00:00 2001 From: Yuuki Ebihara Date: Sun, 3 Jan 2021 21:58:49 +0900 Subject: [PATCH 6/8] translate 3-moving-elements-around into japanese --- .../translations/README.ja.md | 387 ++++++++++++++++++ .../translations/assignment.ja.md | 11 + 2 files changed, 398 insertions(+) create mode 100644 6-space-game/3-moving-elements-around/translations/README.ja.md create mode 100644 6-space-game/3-moving-elements-around/translations/assignment.ja.md diff --git a/6-space-game/3-moving-elements-around/translations/README.ja.md b/6-space-game/3-moving-elements-around/translations/README.ja.md new file mode 100644 index 00000000..0f453595 --- /dev/null +++ b/6-space-game/3-moving-elements-around/translations/README.ja.md @@ -0,0 +1,387 @@ +# スペースゲーム構築プロジェクト その 3: モーションの追加 + +## レッスン前の小テスト + +[レッスン前の小テスト](https://nice-beach-0fe9e9d0f.azurestaticapps.net/quiz/33) + +ゲームは、あなたが画面上を走り回るエイリアンを持っているまでは、あまり楽しいものではありません! このゲームでは、2種類の動きを使用しています。このゲームでは、2種類の動きを利用していきます。 + +- **キーボード/マウスの動き**: ユーザーがキーボードやマウスを操作して画面上のオブジェクトを移動させたとき +- **ゲームで誘導された動き**: ゲームが一定の時間間隔でオブジェクトを移動させたとき + +では、どのようにして画面上で物を動かすのでしょうか? それはすべて直交座標に基づいています。オブジェクトの位置 (x,y) を変更してから、画面を再描画します。 + +通常、画面上で *移動* を行うには、以下の手順が必要です。 + +1. オブジェクトの**新しい位置を設定します**。これはオブジェクトが移動したと認識するために必要です +2. **画面をクリアします**が、これは描画の合間に画面をクリアする必要があります。背景色で塗りつぶす矩形を描くことでクリアできます +3. 新しい場所にオブジェクトを**再描画します**。これにより、ある場所から別の場所にオブジェクトを移動させることができます + + コードではこんな感じになります。 + +```javascript +// hero の場所を決めます。 +hero.x += 5; +// hero がいる長方形をクリアします。 +ctx.clearRect(0, 0, canvas.width, canvas.height); +// ゲームの背景と hero 描画し直します。 +ctx.fillRect(0, 0, canvas.width, canvas.height) +ctx.fillStyle = "black"; +ctx.drawImage(heroImg, hero.x, hero.y); +``` + +✅ ヒーローを毎秒何フレームも描き直すとパフォーマンスコストが発生する理由が思いつきますか? [このパターンの代替案](https://www.html5rocks.com/ja/tutorials/canvas/performance/)を読んでみてください。 + +## キーボードイベントの処理 + +コードに特定のイベントをアタッチすることでイベントを処理します。キーボードイベントはウィンドウ全体でトリガーされますが、`click` のようなマウスイベントは特定の要素をクリックすることに接続することができます。このプロジェクトではキーボードイベントを使用します。 + +イベントを処理するには、ウィンドウの `addEventListener()` メソッドを使用し、2つの入力パラメータを指定する必要があります。最初のパラメータはイベントの名前で、例えば `keyup` のようなものです。2 番目のパラメータは、イベントの結果として呼び出される関数です。 + +以下に例を示します。 + +```javascript +window.addEventListener('keyup', (evt) => { + // `evt.key` = キーの文字列表現 + if (evt.key === 'ArrowUp') { + // 何か処理をします。 + } +}) +``` + +キーイベントには、どのキーが押されたかを確認するために使用できる2つのプロパティがあります。 + +- `key`、これは押されたキーの文字列表現で、例えば `ArrowUp` のようなものです +- `keyCode`、これは数値表現であり、例えば `37` は `ArrowLeft` に対応します + +✅ キーイベントの操作はゲーム開発以外でも有用です。他にはどのような用途が考えられますか? + +### 特殊なキー: 注意事項 + +ウィンドウに影響を与える *特殊な* キーがあります。つまり、`keyup` イベントを聞いているときに、これらの特別なキーを使ってヒーローを動かした場合、水平スクロールも行われるということです。そのため、ゲームを構築する際には、このビルトインブラウザの動作を *shut-off* した方が良いかもしれません。このようなコードが必要です。 + +```javascript +let onKeyDown = function (e) { + console.log(e.keyCode); + switch (e.keyCode) { + case 37: + case 39: + case 38: + case 40: // 矢印キー + case 32: + e.preventDefault(); + break; // スペース + default: + break; // 他のキーをブロックしないでください。 + } +}; + +window.addEventListener('keydown', onKeyDown); +``` + +上記のコードでは、矢印キーとスペースキーの *デフォルト* の動作が確実にシャットオフされます。*shut-off* メカニズムは `e.preventDefault()` を呼び出すときに発生します。 + +## ゲームで誘導された動き + +`setTimeout()` や `setInterval()` 関数のようなタイマーを使うことで、オブジェクトの位置を目盛りや時間間隔ごとに更新することができます。これは次のようなものです。 + +```javascript +let id = setInterval(() => { + //敵を Y 軸で動かす + enemy.y += 10; +}) +``` + +## ゲームループ + +ゲームループとは、基本的には一定の間隔で呼び出される関数の概念です。ユーザーに見えるべきものはすべてループに描画されるので、ゲームループと呼ばれています。ゲームループはゲームの一部であるすべてのゲームオブジェクトを利用し、何らかの理由でゲームの一部ではない場合を除いて、すべてのオブジェクトを描画します。例えば、あるオブジェクトがレーザーで撃たれて吹き飛んでしまった場合、そのオブジェクトは現在のゲームループの一部ではなくなります (これについては後のレッスンで詳しく説明します)。 + +ゲームループがどのようなものか、コードで表現すると次のようになります。 + +```javascript +let gameLoopId = setInterval(() => + function gameLoop() { + ctx.clearRect(0, 0, canvas.width, canvas.height); + ctx.fillStyle = "black"; + ctx.fillRect(0, 0, canvas.width, canvas.height); + drawHero(); + drawEnemies(); + drawStaticObjects(); +}, 200); +``` + +上記のループは `200` ミリ秒ごとに呼び出され、キャンバスを再描画します。あなたのゲームに合った最適な間隔を選択することができます。 + +## スペースゲームの続き + +既存のコードを使って、それを拡張していきます。パート Ⅰ で完成させたコードから始めるか、[パートⅡのスターター](../your-work)のコードを使います。 + +- **ヒーローの移動**: 矢印キーを使ってヒーローを移動できるようにコードを追加します +- **敵を移動する**: また、敵が与えられたレートで上から下に移動することを確認するためにコードを追加する必要があります + +## 推奨される手順 + +あなたのために作成されたファイルを `your-work` サブフォルダ内で探します。以下のファイルが含まれているはずです。 + +```bash +-| assets + -| enemyShip.png + -| player.png +-| index.html +-| app.js +-| package.json +``` + +次のコマンドをタイピングして、あなたのプロジェクトを `your_work` フォルダから開始します。 + +```bash +cd your-work +npm start +``` + +上記は、アドレス `http://localhost:5000` の HTTP サーバーを起動します。ブラウザを開いてそのアドレスを入力すると、今はヒーローと全ての敵が表示されるはずです。ただしまだ何も動いていません。 + +### コードの追加 + +1. `hero` と `enemy`、`game object`のための**オブジェクトを追加し**、それらは `x` と `y` のプロパティを持っている必要があります。([継承や合成](../../translations/README.ja.md)の部分を覚えておいてください) + + *ヒント* `game object` は `x` と `y` を持ち、それ自身をキャンバスに描画する機能を持つものでなければなりません。 + + > tip: 以下のようにコンストラクタを定義した新しい GameObject クラスを追加してから、キャンバスに描画します。 + + ```javascript + class GameObject { + constructor(x, y) { + this.x = x; + this.y = y; + this.dead = false; + this.type = ""; + this.width = 0; + this.height = 0; + this.img = undefined; + } + + draw(ctx) { + ctx.drawImage(this.img, this.x, this.y, this.width, this.height); + } + } + ``` + + 次に、この GameObject を拡張して、ヒーローと敵を作成します。 + + ```javascript + class Hero extends GameObject { + constructor(x, y) { + ...x, y, type, speedが必要です。 + } + } + ``` + + ```javascript + class Enemy extends GameObject { + constructor(x, y) { + super(x, y); + (this.width = 98), (this.height = 50); + this.type = "Enemy"; + let id = setInterval(() => { + if (this.y < canvas.height - this.height) { + this.y += 5; + } else { + console.log('Stopped at', this.y) + clearInterval(id); + } + }, 300) + } + } + ``` + +2. (ヒーローを上下左右に動かす) キーナビゲーションを処理するための**キーイベントハンドラを追加します** + + *REMEMBER* これは直交座標系で、左上は `0,0` です。また、*デフォルトの動作*を止めるコードを追加することも忘れないでください*。 + + > tip: onKeyDown 関数を作成して、それをウィンドウにアタッチします。 + + ```javascript + let onKeyDown = function (e) { + console.log(e.keyCode); + ...add the code from the lesson above to stop default behavior + } + }; + + window.addEventListener("keydown", onKeyDown); + ``` + + この時点でブラウザのコンソールを確認し、キー入力がログに記録されているかどうかを確認します。 + +3. [Pub Sub パターン](../../translations/README.ja.md)を**実装する**と、残りの部分に続くようにコードをきれいに保つことができます + + この最後の部分を行うには + + 1. ウィンドウに**イベントリスナーを追加します** + + ```javascript + window.addEventListener("keyup", (evt) => { + if (evt.key === "ArrowUp") { + eventEmitter.emit(Messages.KEY_EVENT_UP); + } else if (evt.key === "ArrowDown") { + eventEmitter.emit(Messages.KEY_EVENT_DOWN); + } else if (evt.key === "ArrowLeft") { + eventEmitter.emit(Messages.KEY_EVENT_LEFT); + } else if (evt.key === "ArrowRight") { + eventEmitter.emit(Messages.KEY_EVENT_RIGHT); + } + }); + ``` + + 1. メッセージを発行して購読するための **EventEmitter クラスを作成します** + + ```javascript + class EventEmitter { + constructor() { + this.listeners = {}; + } + + on(message, listener) { + if (!this.listeners[message]) { + this.listeners[message] = []; + } + this.listeners[message].push(listener); + } + + emit(message, payload = null) { + if (this.listeners[message]) { + this.listeners[message].forEach((l) => l(message, payload)); + } + } + } + ``` + + 1. **定数を追加**して EventEmitter を設定します + + ```javascript + const Messages = { + KEY_EVENT_UP: "KEY_EVENT_UP", + KEY_EVENT_DOWN: "KEY_EVENT_DOWN", + KEY_EVENT_LEFT: "KEY_EVENT_LEFT", + KEY_EVENT_RIGHT: "KEY_EVENT_RIGHT", + }; + + let heroImg, + enemyImg, + laserImg, + canvas, ctx, + gameObjects = [], + hero, + eventEmitter = new EventEmitter(); + ``` + + 1. **ゲームを初期化します** + + ```javascript + function initGame() { + gameObjects = []; + createEnemies(); + createHero(); + + eventEmitter.on(Messages.KEY_EVENT_UP, () => { + hero.y -=5 ; + }) + + eventEmitter.on(Messages.KEY_EVENT_DOWN, () => { + hero.y += 5; + }); + + eventEmitter.on(Messages.KEY_EVENT_LEFT, () => { + hero.x -= 5; + }); + + eventEmitter.on(Messages.KEY_EVENT_RIGHT, () => { + hero.x += 5; + }); + } + ``` + +1. **ゲームのループを設定します** + + window.onload 関数をリファクタリングしてゲームを初期化し、良い間隔でゲームループを設定します。レーザービームも追加します。 + + ```javascript + window.onload = async () => { + canvas = document.getElementById("canvas"); + ctx = canvas.getContext("2d"); + heroImg = await loadTexture("assets/player.png"); + enemyImg = await loadTexture("assets/enemyShip.png"); + laserImg = await loadTexture("assets/laserRed.png"); + + initGame(); + let gameLoopId = setInterval(() => { + ctx.clearRect(0, 0, canvas.width, canvas.height); + ctx.fillStyle = "black"; + ctx.fillRect(0, 0, canvas.width, canvas.height); + drawGameObjects(ctx); + }, 100) + + }; + ``` + +5. 一定間隔で敵を移動させる**コードを追加します** + + 関数 `createEnemies()` をリファクタリングして敵を作成し、それを新しい gameObjects クラスにプッシュします。 + + ```javascript + function createEnemies() { + const MONSTER_TOTAL = 5; + const MONSTER_WIDTH = MONSTER_TOTAL * 98; + const START_X = (canvas.width - MONSTER_WIDTH) / 2; + const STOP_X = START_X + MONSTER_WIDTH; + + for (let x = START_X; x < STOP_X; x += 98) { + for (let y = 0; y < 50 * 5; y += 50) { + const enemy = new Enemy(x, y); + enemy.img = enemyImg; + gameObjects.push(enemy); + } + } + } + ``` + + そして `createHero()` 関数を追加して hero にも同様の処理を行います。 + + ```javascript + function createHero() { + hero = new Hero( + canvas.width / 2 - 45, + canvas.height - canvas.height / 4 + ); + hero.img = heroImg; + gameObjects.push(hero); + } + ``` + + 最後に `drawGameObjects()` 関数を追加して描画を開始します。 + + ```javascript + function drawGameObjects(ctx) { + gameObjects.forEach(go => go.draw(ctx)); + } + ``` + + あなたの敵はあなたのヒーローの宇宙船で前進を開始する必要があります! + +--- + +## 🚀 チャレンジ + +ご覧のように、関数や変数、クラスを追加し始めると、あなたのコードは「スパゲッティコード」になってしまうことがあります。コードをより読みやすく整理するにはどうしたらいいでしょうか? 1つのファイルに存在していても、あなたのコードを整理するためのシステムをスケッチしてみましょう。 + +## レッスン後の小テスト + +[レッスン後の小テスト](https://nice-beach-0fe9e9d0f.azurestaticapps.net/quiz/34) + +## 復習と自己学習 + +フレームワークを使わずにゲームを書いているうちに、JavaScript を使ったゲーム開発用の canvas フレームワークがたくさん出てきました。時間をかけて[これらについて読む](https://github.com/collections/javascript-game-engines)。 + +## 課題 + +[コードをコメントする](assignment.ja.md) diff --git a/6-space-game/3-moving-elements-around/translations/assignment.ja.md b/6-space-game/3-moving-elements-around/translations/assignment.ja.md new file mode 100644 index 00000000..636fb090 --- /dev/null +++ b/6-space-game/3-moving-elements-around/translations/assignment.ja.md @@ -0,0 +1,11 @@ +# コードをコメントする + +## 説明書 + +ゲームフォルダ内の現在の /app.js ファイルに目を通し、コメントを付けて片付ける方法を見つけてください。コードはいとも簡単に制御不能になります。今はコメントを追加して、後で使えるように読みやすいコードにする良い機会です。 + +## ルーブリック + +| 基準 | 模範的な例 | 適切な | 改善が必要 | +| -------- | ------------------------------------------------------------------ | ------------------------------------- | -------------------------------------------------------------- | +| | `app.js` のコードは完全にコメントされ、論理的なブロックに整理されています。 | `app.js` のコードは適切にコメントされています。 | `app.js` のコードはやや乱れていて、良いコメントがありません。 | \ No newline at end of file From 18097eb3e1e1a113c86c0f45600050356eaa82a6 Mon Sep 17 00:00:00 2001 From: Yuuki Ebihara Date: Sun, 3 Jan 2021 19:07:52 +0900 Subject: [PATCH 7/8] translate 2-drawing-to-canvas into japanese --- .../translations/README.ja.md | 216 ++++++++++++++++++ .../translations/assignment.ja.md | 11 + 2 files changed, 227 insertions(+) create mode 100644 6-space-game/2-drawing-to-canvas/translations/README.ja.md create mode 100644 6-space-game/2-drawing-to-canvas/translations/assignment.ja.md diff --git a/6-space-game/2-drawing-to-canvas/translations/README.ja.md b/6-space-game/2-drawing-to-canvas/translations/README.ja.md new file mode 100644 index 00000000..7c389c65 --- /dev/null +++ b/6-space-game/2-drawing-to-canvas/translations/README.ja.md @@ -0,0 +1,216 @@ +# スペースゲーム構築プロジェクト その 2: ヒーローとモンスターをキャンバスに描く + +## レッスン前の小テスト + +[レッスン前の小テスト](https://nice-beach-0fe9e9d0f.azurestaticapps.net/quiz/31) + +## Canvas + +Canvas は HTML 要素で、デフォルトでは何のコンテンツもありません。何もない白紙の状態です。その上に描画することで、Canvas に追加する必要があります。 + +✅ MDN の [Canvas API についての詳細](https://developer.mozilla.org/ja/docs/Web/API/Canvas_API)はこちらをご覧ください。 + +ページの本文の一部として、一般的にどのように宣言されているかをご紹介します。 + +```html + +``` + +上では `id`, `width`, `height` を設定しています。 + +- `id`: 設定することで、これと対話する必要があるときに参照を取得できるようになります +- `width`: これは要素の幅です +- `height`: これは要素の高さです + +## 簡単な幾何学図形の描画 + +キャンバスは、直交座標系を使って物を描いています。したがって、何かがどこにあるかを表現するために x 軸と y 軸を使用しています。`0,0` の位置が左上の位置で、右下の位置がキャンバスの幅と高さと言ったところです。 + +![the canvas's grid](../canvas_grid.png) +> 画像は [MDN](https://developer.mozilla.org/ja/docs/Web/Guide/HTML/Canvas_tutorial/Drawing_shapes) より + +キャンバス要素に描画するには、以下の手順を踏む必要があります。 + +1. Canvas 要素への**参照を取得します** +1. canvas 要素の上にある Context 要素の**参照を取得します** +1. context 要素を使用して**描画操作を行います** + +上記の手順のコードは、通常次のようになります。 + +```javascript +// 赤い四角を描きます。 +//1. キャンバスの参照を取得します +canvas = document.getElementById("myCanvas"); + +//2. コンテキストを 2D に設定して基本的な図形を描画します。 +ctx = canvas.getContext("2d"); + +//3. 赤で塗りつぶします。 +ctx.fillStyle = 'red'; + +//4. そして、これらのパラメータで矩形を描画し、位置とサイズを設定します。 +ctx.fillRect(0,0, 200, 200) // x, y, width, height +``` + +✅ Canvas API は主に 2D の図形に焦点を当てていますが、Web サイトに 3D の要素を描画することもできます。そのためには、[WebGL API](https://developer.mozilla.org/ja/docs/Web/API/WebGL_API) を使用するとよいでしょう。 + +Canvas API を使っていろいろなものを描くことができます。 + +- **幾何学的な形状**、我々はすでに長方形を描画する方法を示しましたが、あなたが描くことができるはるかに多くのものがあります +- **テキスト**は、任意のフォントと色でテキストを描くことができます +- **画像**では、例えば .jpg や .png のような画像アセットに基づいて画像を描くことができます + +✅ やってみましょう! 長方形の描き方は知っていると思いますが、ページに円を描くことはできますか? CodePen に掲載されている面白い Canvas のドローイングを見てみましょう。ここに[特に印象的な例](https://codepen.io/dissimulate/pen/KrAwx)があります。 + +## 画像アセットの読み込みと描画 + +画像アセットをロードするには、`Image` オブジェクトを作成して `src` プロパティを設定します。そして、`load` イベントを待ち受け、それがいつ使用可能になるかを知ることができます。コードは次のようになります。 + +### アセットの読み込み + +```javascript +const img = new Image(); +img.src = 'path/to/my/image.png'; +img.onload = () => { + // イメージが読み込まれて使用可能な状態になっています +} +``` + +### アセットの読み込みパターン + +上記のようなコンストラクトで包んだ方が使いやすいですし、フルロードした時だけ操作しようとするのでおすすめです。 + +```javascript +function loadAsset(path) { + return new Promise((resolve) => { + const img = new Image(); + img.src = path; + img.onload = () => { + // イメージが読み込まれて使用可能な状態になっています + resolve(img); + } + }) +} + +// 使いまわします + +async function run() { + const heroImg = await loadAsset('hero.png') + const monsterImg = await loadAsset('monster.png') +} + +``` + +ゲームアセットを画面に描画するには、以下のようなコードになります。 + +```javascript +async function run() { + const heroImg = await loadAsset('hero.png') + const monsterImg = await loadAsset('monster.png') + + canvas = document.getElementById("myCanvas"); + ctx = canvas.getContext("2d"); + ctx.drawImage(heroImg, canvas.width/2, canvas.height/2); + ctx.drawImage(monsterImg, 0, 0); +} +``` + +## さあ、あなたのゲームを作り始める時が来ました。 + +### 何を構築するか + +Canvas 要素を使って Web ページを作成します。これは黒い画面 `1024 * 768` をレンダリングする必要があります。画像は2枚用意しました。 + +- Hero の宇宙船 + + ![Hero の宇宙船](../solution/assets/player.png) + +- 5*5 monster + + ![Monster の宇宙船](../solution/assets/enemyShip.png) + +### 開発を始めるための推奨ステップ + +あなたのために作成されたファイルを `your-work` サブフォルダ内で探します。以下のファイルが含まれているはずです。 + +```bash +-| assets + -| enemyShip.png + -| player.png +-| index.html +-| app.js +-| package.json +``` + +このフォルダのコピーを Visual Studio Code で開きます。ローカルの開発環境が設定されている必要があり、できれば Visual Studio Code に NPM と Node がインストールされている必要があります。もしあなたのコンピュータに `npm` がセットアップされていない場合は、[ここにその方法があります](https://www.npmjs.com/get-npm)。 + +`your_work` フォルダに移動してプロジェクトを開始します。 + +```bash +cd your-work +npm start +``` + +以上で、`http://localhost:5000` というアドレスに HTTP サーバが起動します。ブラウザを開いて、そのアドレスを入力してください。今は何も表示されていませんが、そのうち変わるでしょう。 + +> 注: 画面上の変更を確認するには、ブラウザを更新してください。 + +### コードの追加 + +以下の問題を解決するために必要なコードを `your-work/app.js` に追加します。 + +1. 黒い背景のキャンバスを**描画します** + > tip: `/app.js` の適切な TODO の下に 2 行を追加し、`ctx` 要素を黒にして上下の座標を 0,0 にし、高さと幅をキャンバスと同じにします。 +2. テクスチャを**読み込みます** + > tip: プレイヤーと敵の画像を追加するには `await loadTexture` を使用し、画像パスを渡してください。まだ画面には表示されていません! +3. 下半分の画面中央にヒーローを**描画します** + > tip: heroImg を画面に描画するには `drawImage` API を使用し、`canvas.width / 2 - 45` と `canvas.height - canvas.height / 4)` を設定します。 +4. 5*5 のモンスターを**描画します** + > tip: これで、画面上に敵を描画するコードのコメントを解除することができるようになりました。次に、`createEnemies` 関数に移動して、それを構築する。 + + まず、いくつかの定数を設定します。 + + ```javascript + const MONSTER_TOTAL = 5; + const MONSTER_WIDTH = MONSTER_TOTAL * 98; + const START_X = (canvas.width - MONSTER_WIDTH) / 2; + const STOP_X = START_X + MONSTER_WIDTH; + ``` + + そして、モンスターの配列を画面上に描画するループを作成します。 + + ```javascript + for (let x = START_X; x < STOP_X; x += 98) { + for (let y = 0; y < 50 * 5; y += 50) { + ctx.drawImage(enemyImg, x, y); + } + } + ``` + +## 結果 + +仕上がりはこんな感じになるはずです。 + +![hero と 5 * 5 モンスターで黒画面](../partI-solution.png) + +## Solution + +まずはご自身で解決してみていただきたいですが、行き詰った場合は [solution](../solution/app.js) を参考にしてみてください。 + +--- + +## 🚀 チャレンジ + +2D を中心とした Canvas API での描画について学んできましたが、[WebGL API](https://developer.mozilla.org/ja/docs/Web/API/WebGL_API) を参考に、3D オブジェクトを描画してみましょう。 + +## レッスン後の小テスト + +[レッスン後の小テスト](https://nice-beach-0fe9e9d0f.azurestaticapps.net/quiz/32) + +## 復習と自己学習 + +Canvas API については、[こちらを読んでいただく](https://developer.mozilla.org/ja/docs/Web/API/Canvas_API)ことで詳しく知ることができます。 + +## 課題 + +[Canvas API で遊ぶ](assignment.ja.md) \ No newline at end of file diff --git a/6-space-game/2-drawing-to-canvas/translations/assignment.ja.md b/6-space-game/2-drawing-to-canvas/translations/assignment.ja.md new file mode 100644 index 00000000..dc89523d --- /dev/null +++ b/6-space-game/2-drawing-to-canvas/translations/assignment.ja.md @@ -0,0 +1,11 @@ +# Canvas API で遊ぶ + +## 説明書 + +Canvas API の要素を 1 つ選んで、その周りに何か面白いものを作りましょう。星が繰り返される小さな銀河を作ることができますか? 色のついた線で面白いテクスチャを作ることができますか? インスピレーションを得るために CodePen を見ることができます (ただし、コピーはしないでください)。 + +## ルーブリック + +| 基準 | 模範的な例 | 適切な | 改善が必要 | +| -------- | --------------------------------------------------------- | ----------------------------------- | --------------------- | +| | 興味深い質感や形状を示すコードが提出されている | コードは送信されたが実行されない | コードが提出されていない | \ No newline at end of file From 12b5de764865e5e410a7fe7957683a6a5dcf72b1 Mon Sep 17 00:00:00 2001 From: Yuuki Ebihara Date: Sun, 3 Jan 2021 21:58:49 +0900 Subject: [PATCH 8/8] translate 3-moving-elements-around into japanese --- .../translations/README.ja.md | 387 ++++++++++++++++++ .../translations/assignment.ja.md | 11 + 2 files changed, 398 insertions(+) create mode 100644 6-space-game/3-moving-elements-around/translations/README.ja.md create mode 100644 6-space-game/3-moving-elements-around/translations/assignment.ja.md diff --git a/6-space-game/3-moving-elements-around/translations/README.ja.md b/6-space-game/3-moving-elements-around/translations/README.ja.md new file mode 100644 index 00000000..0f453595 --- /dev/null +++ b/6-space-game/3-moving-elements-around/translations/README.ja.md @@ -0,0 +1,387 @@ +# スペースゲーム構築プロジェクト その 3: モーションの追加 + +## レッスン前の小テスト + +[レッスン前の小テスト](https://nice-beach-0fe9e9d0f.azurestaticapps.net/quiz/33) + +ゲームは、あなたが画面上を走り回るエイリアンを持っているまでは、あまり楽しいものではありません! このゲームでは、2種類の動きを使用しています。このゲームでは、2種類の動きを利用していきます。 + +- **キーボード/マウスの動き**: ユーザーがキーボードやマウスを操作して画面上のオブジェクトを移動させたとき +- **ゲームで誘導された動き**: ゲームが一定の時間間隔でオブジェクトを移動させたとき + +では、どのようにして画面上で物を動かすのでしょうか? それはすべて直交座標に基づいています。オブジェクトの位置 (x,y) を変更してから、画面を再描画します。 + +通常、画面上で *移動* を行うには、以下の手順が必要です。 + +1. オブジェクトの**新しい位置を設定します**。これはオブジェクトが移動したと認識するために必要です +2. **画面をクリアします**が、これは描画の合間に画面をクリアする必要があります。背景色で塗りつぶす矩形を描くことでクリアできます +3. 新しい場所にオブジェクトを**再描画します**。これにより、ある場所から別の場所にオブジェクトを移動させることができます + + コードではこんな感じになります。 + +```javascript +// hero の場所を決めます。 +hero.x += 5; +// hero がいる長方形をクリアします。 +ctx.clearRect(0, 0, canvas.width, canvas.height); +// ゲームの背景と hero 描画し直します。 +ctx.fillRect(0, 0, canvas.width, canvas.height) +ctx.fillStyle = "black"; +ctx.drawImage(heroImg, hero.x, hero.y); +``` + +✅ ヒーローを毎秒何フレームも描き直すとパフォーマンスコストが発生する理由が思いつきますか? [このパターンの代替案](https://www.html5rocks.com/ja/tutorials/canvas/performance/)を読んでみてください。 + +## キーボードイベントの処理 + +コードに特定のイベントをアタッチすることでイベントを処理します。キーボードイベントはウィンドウ全体でトリガーされますが、`click` のようなマウスイベントは特定の要素をクリックすることに接続することができます。このプロジェクトではキーボードイベントを使用します。 + +イベントを処理するには、ウィンドウの `addEventListener()` メソッドを使用し、2つの入力パラメータを指定する必要があります。最初のパラメータはイベントの名前で、例えば `keyup` のようなものです。2 番目のパラメータは、イベントの結果として呼び出される関数です。 + +以下に例を示します。 + +```javascript +window.addEventListener('keyup', (evt) => { + // `evt.key` = キーの文字列表現 + if (evt.key === 'ArrowUp') { + // 何か処理をします。 + } +}) +``` + +キーイベントには、どのキーが押されたかを確認するために使用できる2つのプロパティがあります。 + +- `key`、これは押されたキーの文字列表現で、例えば `ArrowUp` のようなものです +- `keyCode`、これは数値表現であり、例えば `37` は `ArrowLeft` に対応します + +✅ キーイベントの操作はゲーム開発以外でも有用です。他にはどのような用途が考えられますか? + +### 特殊なキー: 注意事項 + +ウィンドウに影響を与える *特殊な* キーがあります。つまり、`keyup` イベントを聞いているときに、これらの特別なキーを使ってヒーローを動かした場合、水平スクロールも行われるということです。そのため、ゲームを構築する際には、このビルトインブラウザの動作を *shut-off* した方が良いかもしれません。このようなコードが必要です。 + +```javascript +let onKeyDown = function (e) { + console.log(e.keyCode); + switch (e.keyCode) { + case 37: + case 39: + case 38: + case 40: // 矢印キー + case 32: + e.preventDefault(); + break; // スペース + default: + break; // 他のキーをブロックしないでください。 + } +}; + +window.addEventListener('keydown', onKeyDown); +``` + +上記のコードでは、矢印キーとスペースキーの *デフォルト* の動作が確実にシャットオフされます。*shut-off* メカニズムは `e.preventDefault()` を呼び出すときに発生します。 + +## ゲームで誘導された動き + +`setTimeout()` や `setInterval()` 関数のようなタイマーを使うことで、オブジェクトの位置を目盛りや時間間隔ごとに更新することができます。これは次のようなものです。 + +```javascript +let id = setInterval(() => { + //敵を Y 軸で動かす + enemy.y += 10; +}) +``` + +## ゲームループ + +ゲームループとは、基本的には一定の間隔で呼び出される関数の概念です。ユーザーに見えるべきものはすべてループに描画されるので、ゲームループと呼ばれています。ゲームループはゲームの一部であるすべてのゲームオブジェクトを利用し、何らかの理由でゲームの一部ではない場合を除いて、すべてのオブジェクトを描画します。例えば、あるオブジェクトがレーザーで撃たれて吹き飛んでしまった場合、そのオブジェクトは現在のゲームループの一部ではなくなります (これについては後のレッスンで詳しく説明します)。 + +ゲームループがどのようなものか、コードで表現すると次のようになります。 + +```javascript +let gameLoopId = setInterval(() => + function gameLoop() { + ctx.clearRect(0, 0, canvas.width, canvas.height); + ctx.fillStyle = "black"; + ctx.fillRect(0, 0, canvas.width, canvas.height); + drawHero(); + drawEnemies(); + drawStaticObjects(); +}, 200); +``` + +上記のループは `200` ミリ秒ごとに呼び出され、キャンバスを再描画します。あなたのゲームに合った最適な間隔を選択することができます。 + +## スペースゲームの続き + +既存のコードを使って、それを拡張していきます。パート Ⅰ で完成させたコードから始めるか、[パートⅡのスターター](../your-work)のコードを使います。 + +- **ヒーローの移動**: 矢印キーを使ってヒーローを移動できるようにコードを追加します +- **敵を移動する**: また、敵が与えられたレートで上から下に移動することを確認するためにコードを追加する必要があります + +## 推奨される手順 + +あなたのために作成されたファイルを `your-work` サブフォルダ内で探します。以下のファイルが含まれているはずです。 + +```bash +-| assets + -| enemyShip.png + -| player.png +-| index.html +-| app.js +-| package.json +``` + +次のコマンドをタイピングして、あなたのプロジェクトを `your_work` フォルダから開始します。 + +```bash +cd your-work +npm start +``` + +上記は、アドレス `http://localhost:5000` の HTTP サーバーを起動します。ブラウザを開いてそのアドレスを入力すると、今はヒーローと全ての敵が表示されるはずです。ただしまだ何も動いていません。 + +### コードの追加 + +1. `hero` と `enemy`、`game object`のための**オブジェクトを追加し**、それらは `x` と `y` のプロパティを持っている必要があります。([継承や合成](../../translations/README.ja.md)の部分を覚えておいてください) + + *ヒント* `game object` は `x` と `y` を持ち、それ自身をキャンバスに描画する機能を持つものでなければなりません。 + + > tip: 以下のようにコンストラクタを定義した新しい GameObject クラスを追加してから、キャンバスに描画します。 + + ```javascript + class GameObject { + constructor(x, y) { + this.x = x; + this.y = y; + this.dead = false; + this.type = ""; + this.width = 0; + this.height = 0; + this.img = undefined; + } + + draw(ctx) { + ctx.drawImage(this.img, this.x, this.y, this.width, this.height); + } + } + ``` + + 次に、この GameObject を拡張して、ヒーローと敵を作成します。 + + ```javascript + class Hero extends GameObject { + constructor(x, y) { + ...x, y, type, speedが必要です。 + } + } + ``` + + ```javascript + class Enemy extends GameObject { + constructor(x, y) { + super(x, y); + (this.width = 98), (this.height = 50); + this.type = "Enemy"; + let id = setInterval(() => { + if (this.y < canvas.height - this.height) { + this.y += 5; + } else { + console.log('Stopped at', this.y) + clearInterval(id); + } + }, 300) + } + } + ``` + +2. (ヒーローを上下左右に動かす) キーナビゲーションを処理するための**キーイベントハンドラを追加します** + + *REMEMBER* これは直交座標系で、左上は `0,0` です。また、*デフォルトの動作*を止めるコードを追加することも忘れないでください*。 + + > tip: onKeyDown 関数を作成して、それをウィンドウにアタッチします。 + + ```javascript + let onKeyDown = function (e) { + console.log(e.keyCode); + ...add the code from the lesson above to stop default behavior + } + }; + + window.addEventListener("keydown", onKeyDown); + ``` + + この時点でブラウザのコンソールを確認し、キー入力がログに記録されているかどうかを確認します。 + +3. [Pub Sub パターン](../../translations/README.ja.md)を**実装する**と、残りの部分に続くようにコードをきれいに保つことができます + + この最後の部分を行うには + + 1. ウィンドウに**イベントリスナーを追加します** + + ```javascript + window.addEventListener("keyup", (evt) => { + if (evt.key === "ArrowUp") { + eventEmitter.emit(Messages.KEY_EVENT_UP); + } else if (evt.key === "ArrowDown") { + eventEmitter.emit(Messages.KEY_EVENT_DOWN); + } else if (evt.key === "ArrowLeft") { + eventEmitter.emit(Messages.KEY_EVENT_LEFT); + } else if (evt.key === "ArrowRight") { + eventEmitter.emit(Messages.KEY_EVENT_RIGHT); + } + }); + ``` + + 1. メッセージを発行して購読するための **EventEmitter クラスを作成します** + + ```javascript + class EventEmitter { + constructor() { + this.listeners = {}; + } + + on(message, listener) { + if (!this.listeners[message]) { + this.listeners[message] = []; + } + this.listeners[message].push(listener); + } + + emit(message, payload = null) { + if (this.listeners[message]) { + this.listeners[message].forEach((l) => l(message, payload)); + } + } + } + ``` + + 1. **定数を追加**して EventEmitter を設定します + + ```javascript + const Messages = { + KEY_EVENT_UP: "KEY_EVENT_UP", + KEY_EVENT_DOWN: "KEY_EVENT_DOWN", + KEY_EVENT_LEFT: "KEY_EVENT_LEFT", + KEY_EVENT_RIGHT: "KEY_EVENT_RIGHT", + }; + + let heroImg, + enemyImg, + laserImg, + canvas, ctx, + gameObjects = [], + hero, + eventEmitter = new EventEmitter(); + ``` + + 1. **ゲームを初期化します** + + ```javascript + function initGame() { + gameObjects = []; + createEnemies(); + createHero(); + + eventEmitter.on(Messages.KEY_EVENT_UP, () => { + hero.y -=5 ; + }) + + eventEmitter.on(Messages.KEY_EVENT_DOWN, () => { + hero.y += 5; + }); + + eventEmitter.on(Messages.KEY_EVENT_LEFT, () => { + hero.x -= 5; + }); + + eventEmitter.on(Messages.KEY_EVENT_RIGHT, () => { + hero.x += 5; + }); + } + ``` + +1. **ゲームのループを設定します** + + window.onload 関数をリファクタリングしてゲームを初期化し、良い間隔でゲームループを設定します。レーザービームも追加します。 + + ```javascript + window.onload = async () => { + canvas = document.getElementById("canvas"); + ctx = canvas.getContext("2d"); + heroImg = await loadTexture("assets/player.png"); + enemyImg = await loadTexture("assets/enemyShip.png"); + laserImg = await loadTexture("assets/laserRed.png"); + + initGame(); + let gameLoopId = setInterval(() => { + ctx.clearRect(0, 0, canvas.width, canvas.height); + ctx.fillStyle = "black"; + ctx.fillRect(0, 0, canvas.width, canvas.height); + drawGameObjects(ctx); + }, 100) + + }; + ``` + +5. 一定間隔で敵を移動させる**コードを追加します** + + 関数 `createEnemies()` をリファクタリングして敵を作成し、それを新しい gameObjects クラスにプッシュします。 + + ```javascript + function createEnemies() { + const MONSTER_TOTAL = 5; + const MONSTER_WIDTH = MONSTER_TOTAL * 98; + const START_X = (canvas.width - MONSTER_WIDTH) / 2; + const STOP_X = START_X + MONSTER_WIDTH; + + for (let x = START_X; x < STOP_X; x += 98) { + for (let y = 0; y < 50 * 5; y += 50) { + const enemy = new Enemy(x, y); + enemy.img = enemyImg; + gameObjects.push(enemy); + } + } + } + ``` + + そして `createHero()` 関数を追加して hero にも同様の処理を行います。 + + ```javascript + function createHero() { + hero = new Hero( + canvas.width / 2 - 45, + canvas.height - canvas.height / 4 + ); + hero.img = heroImg; + gameObjects.push(hero); + } + ``` + + 最後に `drawGameObjects()` 関数を追加して描画を開始します。 + + ```javascript + function drawGameObjects(ctx) { + gameObjects.forEach(go => go.draw(ctx)); + } + ``` + + あなたの敵はあなたのヒーローの宇宙船で前進を開始する必要があります! + +--- + +## 🚀 チャレンジ + +ご覧のように、関数や変数、クラスを追加し始めると、あなたのコードは「スパゲッティコード」になってしまうことがあります。コードをより読みやすく整理するにはどうしたらいいでしょうか? 1つのファイルに存在していても、あなたのコードを整理するためのシステムをスケッチしてみましょう。 + +## レッスン後の小テスト + +[レッスン後の小テスト](https://nice-beach-0fe9e9d0f.azurestaticapps.net/quiz/34) + +## 復習と自己学習 + +フレームワークを使わずにゲームを書いているうちに、JavaScript を使ったゲーム開発用の canvas フレームワークがたくさん出てきました。時間をかけて[これらについて読む](https://github.com/collections/javascript-game-engines)。 + +## 課題 + +[コードをコメントする](assignment.ja.md) diff --git a/6-space-game/3-moving-elements-around/translations/assignment.ja.md b/6-space-game/3-moving-elements-around/translations/assignment.ja.md new file mode 100644 index 00000000..636fb090 --- /dev/null +++ b/6-space-game/3-moving-elements-around/translations/assignment.ja.md @@ -0,0 +1,11 @@ +# コードをコメントする + +## 説明書 + +ゲームフォルダ内の現在の /app.js ファイルに目を通し、コメントを付けて片付ける方法を見つけてください。コードはいとも簡単に制御不能になります。今はコメントを追加して、後で使えるように読みやすいコードにする良い機会です。 + +## ルーブリック + +| 基準 | 模範的な例 | 適切な | 改善が必要 | +| -------- | ------------------------------------------------------------------ | ------------------------------------- | -------------------------------------------------------------- | +| | `app.js` のコードは完全にコメントされ、論理的なブロックに整理されています。 | `app.js` のコードは適切にコメントされています。 | `app.js` のコードはやや乱れていて、良いコメントがありません。 | \ No newline at end of file