Merge pull request #157 from silverskyvicto/translate-ja/6-space-game
translate 6-space-game into japanesepull/158/head
commit
d1c9283e1d
@ -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)
|
@ -0,0 +1,11 @@
|
||||
# ゲームのモックアップ
|
||||
|
||||
## 説明書
|
||||
|
||||
レッスンで使用したコードサンプルを使用して、好きなゲームの表現を書いてください。単純なゲームである必要がありますが、目標は、クラスまたは構成パターンと pub/sub パターンのいずれかを使用して、ゲームがどのように起動するかを示すことです。創造力を発揮してください。
|
||||
|
||||
## ルーブリック
|
||||
|
||||
| 基準 | 模範的な例 | 適切な | 改善が必要 |
|
||||
| -------- | ------------------------------------------------------- | ----------------------------------------------------- | --------------------------------------------------- |
|
||||
| | 3つの要素を画面上に配置して操作する | 2つの要素を画面上に配置して操作する | 1つの要素を画面上に配置して操作する |
|
@ -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
|
||||
<canvas id="myCanvas" width="200" height="100"></canvas>
|
||||
```
|
||||
|
||||
上では `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)
|
@ -0,0 +1,11 @@
|
||||
# Canvas API で遊ぶ
|
||||
|
||||
## 説明書
|
||||
|
||||
Canvas API の要素を 1 つ選んで、その周りに何か面白いものを作りましょう。星が繰り返される小さな銀河を作ることができますか? 色のついた線で面白いテクスチャを作ることができますか? インスピレーションを得るために CodePen を見ることができます (ただし、コピーはしないでください)。
|
||||
|
||||
## ルーブリック
|
||||
|
||||
| 基準 | 模範的な例 | 適切な | 改善が必要 |
|
||||
| -------- | --------------------------------------------------------- | ----------------------------------- | --------------------- |
|
||||
| | 興味深い質感や形状を示すコードが提出されている | コードは送信されたが実行されない | コードが提出されていない |
|
@ -0,0 +1,11 @@
|
||||
# コードをコメントする
|
||||
|
||||
## 説明書
|
||||
|
||||
ゲームフォルダ内の現在の /app.js ファイルに目を通し、コメントを付けて片付ける方法を見つけてください。コードはいとも簡単に制御不能になります。今はコメントを追加して、後で使えるように読みやすいコードにする良い機会です。
|
||||
|
||||
## ルーブリック
|
||||
|
||||
| 基準 | 模範的な例 | 適切な | 改善が必要 |
|
||||
| -------- | ------------------------------------------------------------------ | ------------------------------------- | -------------------------------------------------------------- |
|
||||
| | `app.js` のコードは完全にコメントされ、論理的なブロックに整理されています。 | `app.js` のコードは適切にコメントされています。 | `app.js` のコードはやや乱れていて、良いコメントがありません。 |
|
@ -0,0 +1,298 @@
|
||||
# スペースゲーム構築プロジェクト その 4: レーザーを追加して衝突を検出する
|
||||
|
||||
## レッスン前の小テスト
|
||||
|
||||
[レッスン前の小テスト](https://nice-beach-0fe9e9d0f.azurestaticapps.net/quiz/35)
|
||||
|
||||
このレッスンでは、JavaScript でレーザーを撃つ方法を学びます! 私たちはゲームに2つのものを追加します。
|
||||
|
||||
- **レーザー**: このレーザーはあなたのヒーローの宇宙船から垂直に上向きに撃たれます
|
||||
- **衝突検出**、発射する能力を実装する一環として、我々はまたいくつかの素敵なゲームのルールを追加します
|
||||
- **レーザーが敵に当たる**: レーザーが当たると敵が破壊される
|
||||
- **レーザーがトップ画面に当たる**: 画面上部に当たるとレーザーが破壊されます
|
||||
- **敵とヒーローの衝突**: 敵とヒーローがぶつかると破壊されます
|
||||
- **敵が画面の下に当たる**: 敵が画面下に当たると敵とヒーローが破壊されます
|
||||
|
||||
要するに、あなた - *ヒーロー* - は画面の下部に移動するために管理する前に、レーザーですべての敵をヒットする必要があります。
|
||||
|
||||
✅ これまでに書かれた最初のコンピュータゲームについて少し調べてみてください。その機能は何だったのでしょうか?
|
||||
|
||||
一緒にヒーローになりましょう!
|
||||
|
||||
## 衝突検出
|
||||
|
||||
どのようにして衝突を検出するのか? ゲームオブジェクトを移動する長方形と考える必要があります。なぜでしょうか? ゲームオブジェクトの描画に使われる画像は矩形です。`x`、`y`、`width`、`height` を持っています。
|
||||
|
||||
2 つの長方形、つまりヒーローと敵が交差すると、衝突します。そのときに何が起こるかは、ゲームのルール次第です。したがって、衝突検出を実装するためには以下のものが必要です。
|
||||
|
||||
1. ゲームオブジェクトの矩形表現を取得する方法。こんな感じです
|
||||
|
||||
```javascript
|
||||
rectFromGameObject() {
|
||||
return {
|
||||
top: this.y,
|
||||
left: this.x,
|
||||
bottom: this.y + this.height,
|
||||
right: this.x + this.width
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
2. 比較関数で、この関数は次のようになります
|
||||
|
||||
```javascript
|
||||
function intersectRect(r1, r2) {
|
||||
return !(r2.left > r1.right ||
|
||||
r2.right < r1.left ||
|
||||
r2.top > r1.bottom ||
|
||||
r2.bottom < r1.top);
|
||||
}
|
||||
```
|
||||
|
||||
## オブジェクトをどうやって破壊するか
|
||||
|
||||
ゲーム内のオブジェクトを破壊するには、一定の間隔で発生するゲームループの中で、このアイテムをペイントしないようにゲームに知らせる必要があります。これを行うには、以下のように、何かが起こったときにゲームオブジェクトを *dead* としてマークする方法があります。
|
||||
|
||||
```javascript
|
||||
// 衝突が発生します
|
||||
enemy.dead = true
|
||||
```
|
||||
|
||||
その後、画面を再描画する前に、このように、*dead* オブジェクトをソートしていきます。
|
||||
|
||||
```javascript
|
||||
gameObjects = gameObject.filter(go => !go.dead);
|
||||
```
|
||||
|
||||
## レーザーの撃ち方
|
||||
|
||||
レーザーを発射することは、キーイベントに反応して、特定の方向に移動するオブジェクトを作成することになります。そのため、以下のような作業を行う必要があります。
|
||||
|
||||
1. **レーザーオブジェクトを作成します**: ヒーローの船の上部から、作成時に画面の上部に向かって上向きに移動を開始します
|
||||
2. **キーイベントにコードを添付します**: レーザーを撮影しているプレイヤーを表すキーボードのキーを選択する必要があります
|
||||
3. キーを押すと**レーザーのように見えるゲームオブジェクトを作成します**
|
||||
|
||||
## レーザーのクールダウン
|
||||
|
||||
レーザーは、例えば*スペース*のように、キーを押すたびに発射する必要があります。短時間で多くのレーザーが発射されるのを防ぐために、この問題を解決する必要があります。これを修正するには、いわゆる *クールダウン*、タイマーを実装することで、レーザーはそれほど頻繁にしか発射することができないことを保証します。以下の方法で実装できます。
|
||||
|
||||
```javascript
|
||||
class Cooldown {
|
||||
constructor(time) {
|
||||
this.cool = false;
|
||||
setTimeout(() => {
|
||||
this.cool = true;
|
||||
}, time)
|
||||
}
|
||||
}
|
||||
|
||||
class Weapon {
|
||||
constructor {
|
||||
}
|
||||
fire() {
|
||||
if (!this.cooldown || this.cooldown.cool) {
|
||||
// レーザーを作る
|
||||
this.cooldown = new Cooldown(500);
|
||||
} else {
|
||||
// 何もしない-まだクールダウンしていない。
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
✅ スペースゲームシリーズのレッスン1を参照して、*クールダウン*について思い出してください。
|
||||
|
||||
## 何を構築するか
|
||||
|
||||
前回のレッスンで使用した既存のコード (クリーンアップしてリファクタリングしたはずのコード) を使用して、それを拡張します。
|
||||
パート II のコードから始めるか、[パートIII - スターター](../../your-work)のコードを使用してください。
|
||||
|
||||
> ヒント: 作業に使用するレーザーはすでにアセットフォルダにあり、コードで参照されています。
|
||||
|
||||
- **衝突検出を追加します**、レーザーが何かに衝突するときは、次のルールを適用する必要があります
|
||||
1. **レーザーが敵に当たる**: レーザーが当たると敵が破壊される
|
||||
2. **レーザーが画面上部に当たる**: レーザーが画面の上部に当たると破壊される
|
||||
3. **敵とヒーローの衝突**: 敵とヒーローがぶつかると破壊される
|
||||
4. **画面下に敵が当たる**: 敵が画面下部に当たると敵とヒーローが破壊される
|
||||
|
||||
## 推奨される手順
|
||||
|
||||
あなたのために作成されたファイルを `your-work` サブフォルダ内で探します。以下のファイルが含まれているはずです。
|
||||
|
||||
```bash
|
||||
-| assets
|
||||
-| enemyShip.png
|
||||
-| player.png
|
||||
-| laserRed.png
|
||||
-| index.html
|
||||
-| app.js
|
||||
-| package.json
|
||||
```
|
||||
|
||||
次のコマンドをタイピングして、あなたのプロジェクトを `your_work` フォルダから開始します。
|
||||
|
||||
```bash
|
||||
cd your-work
|
||||
npm start
|
||||
```
|
||||
|
||||
上記は、`http://localhost:5000` というアドレスで HTTP サーバを起動します。ブラウザを開いてそのアドレスを入力すると、今はヒーローと全ての敵が表示されるはずですが、まだ何も動いていません。
|
||||
|
||||
### コードの追加
|
||||
|
||||
1. **衝突を処理するためにゲームオブジェクトの矩形表現を設定する** 以下のコードでは、`GameObject` の矩形表現を取得することができます。GameObject クラスを編集して拡張します
|
||||
|
||||
```javascript
|
||||
rectFromGameObject() {
|
||||
return {
|
||||
top: this.y,
|
||||
left: this.x,
|
||||
bottom: this.y + this.height,
|
||||
right: this.x + this.width,
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
2. **衝突をチェックするコードの追加** これは、2 つの矩形が交差するかどうかをテストする新しい関数になります
|
||||
|
||||
```javascript
|
||||
function intersectRect(r1, r2) {
|
||||
return !(
|
||||
r2.left > r1.right ||
|
||||
r2.right < r1.left ||
|
||||
r2.top > r1.bottom ||
|
||||
r2.bottom < r1.top
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
3. **レーザー発射機能の追加**
|
||||
1. **キーイベントメッセージを追加します**。*スペース*キーはヒーローの宇宙船の真上にレーザーを作成する必要があります。Messages オブジェクトに3つの定数を追加します
|
||||
|
||||
```javascript
|
||||
KEY_EVENT_SPACE: "KEY_EVENT_SPACE",
|
||||
COLLISION_ENEMY_LASER: "COLLISION_ENEMY_LASER",
|
||||
COLLISION_ENEMY_HERO: "COLLISION_ENEMY_HERO",
|
||||
```
|
||||
|
||||
1. **スペースキーを処理します**。スペースを扱うために、`window.addEventListener` のキーアップ関数を編集します
|
||||
|
||||
```javascript
|
||||
} else if(evt.keyCode === 32) {
|
||||
eventEmitter.emit(Messages.KEY_EVENT_SPACE);
|
||||
}
|
||||
```
|
||||
|
||||
1. **リスナーを追加します**。スペースバーがヒットした時にヒーローが発射できるように `initGame()` 関数を編集します
|
||||
|
||||
```javascript
|
||||
eventEmitter.on(Messages.KEY_EVENT_SPACE, () => {
|
||||
if (hero.canFire()) {
|
||||
hero.fire();
|
||||
}
|
||||
```
|
||||
|
||||
そして、敵がレーザーに衝突したときの動作を保証するために、新しい `eventEmitter.on()` 関数を追加します
|
||||
|
||||
```javascript
|
||||
eventEmitter.on(Messages.COLLISION_ENEMY_LASER, (_, { first, second }) => {
|
||||
first.dead = true;
|
||||
second.dead = true;
|
||||
})
|
||||
```
|
||||
|
||||
1. **オブジェクトを移動させ**、レーザーが徐々に画面上部に移動するようにします。先ほどと同じように `GameObject`を継承した Laser クラスを新たに作成します
|
||||
|
||||
```javascript
|
||||
class Laser extends GameObject {
|
||||
constructor(x, y) {
|
||||
super(x,y);
|
||||
(this.width = 9), (this.height = 33);
|
||||
this.type = 'Laser';
|
||||
this.img = laserImg;
|
||||
let id = setInterval(() => {
|
||||
if (this.y > 0) {
|
||||
this.y -= 15;
|
||||
} else {
|
||||
this.dead = true;
|
||||
clearInterval(id);
|
||||
}
|
||||
}, 100)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
1. **衝突の処理**、レーザーの衝突ルールの実装 衝突したオブジェクトのヒットをテストする `updateGameObjects()` 関数を追加します
|
||||
|
||||
```javascript
|
||||
function updateGameObjects() {
|
||||
const enemies = gameObjects.filter(go => go.type === 'Enemy');
|
||||
const lasers = gameObjects.filter((go) => go.type === "Laser");
|
||||
// レーザーが当たる
|
||||
lasers.forEach((l) => {
|
||||
enemies.forEach((m) => {
|
||||
if (intersectRect(l.rectFromGameObject(), m.rectFromGameObject())) {
|
||||
eventEmitter.emit(Messages.COLLISION_ENEMY_LASER, {
|
||||
first: l,
|
||||
second: m,
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
gameObjects = gameObjects.filter(go => !go.dead);
|
||||
}
|
||||
```
|
||||
|
||||
必ず `window.onload` のゲームループに `updateGameObjects()` を追加してください。
|
||||
|
||||
4. レーザーに**クールダウンを実装**して、それがそんなに頻繁にしか発射できないようにします
|
||||
|
||||
最後に、Hero クラスをクールダウンできるように編集します
|
||||
|
||||
```javascript
|
||||
class Hero extends GameObject {
|
||||
constructor(x, y) {
|
||||
super(x, y);
|
||||
(this.width = 99), (this.height = 75);
|
||||
this.type = "Hero";
|
||||
this.speed = { x: 0, y: 0 };
|
||||
this.cooldown = 0;
|
||||
}
|
||||
fire() {
|
||||
gameObjects.push(new Laser(this.x + 45, this.y - 10));
|
||||
this.cooldown = 500;
|
||||
|
||||
let id = setInterval(() => {
|
||||
if (this.cooldown > 0) {
|
||||
this.cooldown -= 100;
|
||||
} else {
|
||||
clearInterval(id);
|
||||
}
|
||||
}, 200);
|
||||
}
|
||||
canFire() {
|
||||
return this.cooldown === 0;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
この時点で、あなたのゲームはいくつかの機能を持っています! 矢印キーで移動したり、スペースバーでレーザーを発射したり、敵はあなたがそれらを打つときに消えることができます。よくできました!
|
||||
|
||||
---
|
||||
|
||||
## 🚀 チャレンジ
|
||||
|
||||
爆発を追加しましょう! [スペースアートレポ](../../solution/spaceArt/readme.txt)のゲームアセットを見て、レーザーがエイリアンに当たったときに爆発を追加してみてください。
|
||||
|
||||
## レッスン後の小テスト
|
||||
|
||||
[レッスン後の小テスト](https://nice-beach-0fe9e9d0f.azurestaticapps.net/quiz/36)
|
||||
|
||||
## 復習と自己学習
|
||||
|
||||
これまでのゲームの間隔を実験してみてください。それらを変更するとどうなるでしょうか? [JavaScript のタイミングイベント](https://www.freecodecamp.org/news/javascript-timing-events-settimeout-and-setinterval/)についての詳細はこちら。
|
||||
|
||||
## 課題
|
||||
|
||||
[衝突を調べる](assignment.ja.md)
|
@ -0,0 +1,11 @@
|
||||
# 衝突を調べる
|
||||
|
||||
## 説明書
|
||||
|
||||
衝突がどのように機能するかを理解するために、衝突するいくつかのアイテムで非常に小さなゲームを構築します。キープレスやマウスクリックでアイテムを移動させ、アイテムが当たったときに何かが起こるようにします。隕石が地球に衝突したり、バンパーカーに衝突したりします。創造力を発揮してください。
|
||||
|
||||
## ルーブリック
|
||||
|
||||
| 基準 | 模範的な例 | 適切な | 改善が必要 |
|
||||
| -------- | ------------------------------------------------------------------------------------------------------------------------ | ------------------------------ | ----------------- |
|
||||
| | アイテムがキャンバスに描画され、基本的な衝突が発生し、反応が発生する完全な動作コードサンプルが作成されます。 | コードが不完全な場合 | コードの誤動作 |
|
@ -0,0 +1,190 @@
|
||||
# スペースゲーム構築プロジェクト その 5: スコアリングとライフ
|
||||
|
||||
## レッスン前の小テスト
|
||||
|
||||
[レッスン前の小テスト](https://nice-beach-0fe9e9d0f.azurestaticapps.net/quiz/37)
|
||||
|
||||
このレッスンでは、ゲームに得点を加えてライフを計算する方法を学びます。
|
||||
|
||||
## 画面上にテキストを描画
|
||||
|
||||
ゲームのスコアを画面に表示できるようにするには、画面にテキストを配置する方法を知っておく必要があります。その答えは、canvas オブジェクトの `fillText()` メソッドを使用することです。また、使用するフォント、テキストの色、配置 (左、右、中央) などの他の要素を制御することもできます。以下は、画面上にテキストを描画するコードです。
|
||||
|
||||
```javascript
|
||||
ctx.font = "30px Arial";
|
||||
ctx.fillStyle = "red";
|
||||
ctx.textAlign = "right";
|
||||
ctx.fillText("show this on the screen", 0, 0);
|
||||
```
|
||||
|
||||
✅ [canvas にテキストを追加する方法](https://developer.mozilla.org/ja/docs/Drawing_text_using_a_canvas)について詳しくはこちらをご覧ください。そうすれば自由にファンシーな外観を作ることができます。
|
||||
|
||||
|
||||
## ゲームの概念としてのライフ
|
||||
|
||||
ゲームにおけるライフの概念は数字でしかありません。スペースゲームの文脈では、自分の宇宙船がダメージを受けたときに一つずつ差し引かれるライフを割り当てるのが一般的です。これを数字ではなく、ミニシップやハートのようにグラフィカルに表現できるといいですね。
|
||||
|
||||
## 何を構築するか
|
||||
|
||||
以下のようなものをゲームに追加してみましょう。
|
||||
|
||||
- **ゲームのスコア**: 敵艦が破壊されるごとに、ヒーローにはいくつかのポイントが与えられるはずですが、私たちは1隻につき100ポイントをお勧めします。ゲームスコアは左下に表示されます
|
||||
- **ライフ**: あなたの宇宙船には3つのライフがあります。敵の船が衝突するたびにライフを失います。ライフスコアは右下に表示され、次のグラフィックで作成されます。![life image](../solution/assets/life.png)
|
||||
|
||||
## 推奨される手順
|
||||
|
||||
あなたのために作成されたファイルを `your-work` サブフォルダ内で探します。以下のファイルが含まれているはずです。
|
||||
|
||||
```bash
|
||||
-| assets
|
||||
-| enemyShip.png
|
||||
-| player.png
|
||||
-| laserRed.png
|
||||
-| index.html
|
||||
-| app.js
|
||||
-| package.json
|
||||
```
|
||||
|
||||
次のように入力して、`your_work` フォルダからプロジェクトを起動します。
|
||||
|
||||
```bash
|
||||
cd your-work
|
||||
npm start
|
||||
```
|
||||
|
||||
上記のようにすると、`http://localhost:5000` というアドレスに HTTP サーバーが起動します。ブラウザを開いてそのアドレスを入力すると、ヒーローと敵が表示され、左右の矢印を打つとヒーローが動き、敵を撃ち落とすことができます。
|
||||
|
||||
### コードの追加
|
||||
|
||||
1. `solution/assets/` フォルダから `your-work` フォルダに**必要なアセットをコピー**して、`life.png` アセットを追加します。lifeImg を window.onload 関数に追加します
|
||||
|
||||
```javascript
|
||||
lifeImg = await loadTexture("assets/life.png");
|
||||
```
|
||||
|
||||
1. アセットのリストに `lifeImg` を追加します
|
||||
|
||||
```javascript
|
||||
let heroImg,
|
||||
...
|
||||
lifeImg,
|
||||
...
|
||||
eventEmitter = new EventEmitter();
|
||||
```
|
||||
|
||||
2. **変数を追加します**。あなたの合計スコア (0) とその左に (3) のライフを表すコードを追加し、画面上にこれらのスコアを表示します
|
||||
|
||||
3. **`updateGameObjects()` 関数を拡張します**。`updateGameObjects()` 関数を拡張し、敵の衝突に対応するようにします
|
||||
|
||||
```javascript
|
||||
enemies.forEach(enemy => {
|
||||
const heroRect = hero.rectFromGameObject();
|
||||
if (intersectRect(heroRect, enemy.rectFromGameObject())) {
|
||||
eventEmitter.emit(Messages.COLLISION_ENEMY_HERO, { enemy });
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
4. **`life` と `points` を追加します**
|
||||
1. **変数を初期化します**。`Hero` クラスの `this.cooldown = 0` の下で、ライフとポイントを設定します
|
||||
|
||||
```javascript
|
||||
this.life = 3;
|
||||
this.points = 0;
|
||||
```
|
||||
|
||||
1. **画面上に変数を描画します**。これらの値を画面に描画します
|
||||
|
||||
```javascript
|
||||
function drawLife() {
|
||||
// TODO, 35, 27
|
||||
const START_POS = canvas.width - 180;
|
||||
for(let i=0; i < hero.life; i++ ) {
|
||||
ctx.drawImage(
|
||||
lifeImg,
|
||||
START_POS + (45 * (i+1) ),
|
||||
canvas.height - 37);
|
||||
}
|
||||
}
|
||||
|
||||
function drawPoints() {
|
||||
ctx.font = "30px Arial";
|
||||
ctx.fillStyle = "red";
|
||||
ctx.textAlign = "left";
|
||||
drawText("Points: " + hero.points, 10, canvas.height-20);
|
||||
}
|
||||
|
||||
function drawText(message, x, y) {
|
||||
ctx.fillText(message, x, y);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
1. **Game ループにメソッドを追加します**。`updateGameObjects()` の下の window.onload 関数にこれらの関数を追加します
|
||||
|
||||
```javascript
|
||||
drawPoints();
|
||||
drawLife();
|
||||
```
|
||||
|
||||
1. **ゲームのルールを実装します**。以下のゲームルールを実装します
|
||||
|
||||
1. **ヒーローと敵の衝突ごとに**、ライフを差し引きます
|
||||
|
||||
`Hero` クラスを拡張してこの差し引きを行います
|
||||
|
||||
```javascript
|
||||
decrementLife() {
|
||||
this.life--;
|
||||
if (this.life === 0) {
|
||||
this.dead = true;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
2. **レーザーが敵に当たるたびに**、ゲームスコアを100点アップさせます
|
||||
|
||||
このインクリメントを行うために Hero クラスを拡張します
|
||||
|
||||
```javascript
|
||||
incrementPoints() {
|
||||
this.points += 100;
|
||||
}
|
||||
```
|
||||
|
||||
これらの機能を衝突イベントエミッタに追加します
|
||||
|
||||
```javascript
|
||||
eventEmitter.on(Messages.COLLISION_ENEMY_LASER, (_, { first, second }) => {
|
||||
first.dead = true;
|
||||
second.dead = true;
|
||||
hero.incrementPoints();
|
||||
})
|
||||
|
||||
eventEmitter.on(Messages.COLLISION_ENEMY_HERO, (_, { enemy }) => {
|
||||
enemy.dead = true;
|
||||
hero.decrementLife();
|
||||
});
|
||||
```
|
||||
|
||||
✅ JavaScript/Canvas を使用して作成された他のゲームを少し調べてみてください。これらのゲームに共通する特徴は何ですか?
|
||||
|
||||
この作品が終わる頃には、右下に小さな「ライフ」の船、左下にポイントが表示され、敵と衝突するとライフカウントが減少し、敵を撃つとポイントが増加するのがわかるはずです。よくできました! これでゲームはほぼ完成です。
|
||||
|
||||
---
|
||||
|
||||
## 🚀 チャレンジ
|
||||
|
||||
あなたのコードはほぼ完成しています。次のステップをイメージできますか?
|
||||
|
||||
## レッスン後の小テスト
|
||||
|
||||
[レッスン後の小テスト](https://nice-beach-0fe9e9d0f.azurestaticapps.net/quiz/38)
|
||||
|
||||
## 復習と自己学習
|
||||
|
||||
ゲームのスコアやライフを増減させる方法をいくつか研究してみましょう。[PlayFab](https://playfab.com) のような面白いゲームエンジンがあります。これらのエンジンを使用することで、どのようにゲームを強化することができるでしょうか?
|
||||
|
||||
## 課題
|
||||
|
||||
[スコアリングゲームの構築](assignment.ja.md)
|
@ -0,0 +1,11 @@
|
||||
# スコアリングゲームの構築
|
||||
|
||||
## 説明書
|
||||
|
||||
ライフとポイントを独創的な方法で表示するゲームを作成します。提案としては、ライフをハートで表示し、ポイントを画面中央下部の大きな数字で表示することです。[無料のゲームリソース](https://www.kenney.nl/)はこちらをご覧ください。
|
||||
|
||||
# ルーブリック
|
||||
|
||||
| 基準 | 模範的な例 | 適切な | 改善が必要 |
|
||||
| -------- | ---------------------- | --------------------------- | -------------------------- |
|
||||
| | フルゲームが提示されています | 部分的に提示されたゲーム | 部分的なゲームにはバグが含まれています |
|
@ -0,0 +1,19 @@
|
||||
# サンプルゲームを作る
|
||||
|
||||
## インストラクション
|
||||
|
||||
異なる終了条件で練習する小さなゲームを構築してみてください。ポイントの数を取得する間に変化し、主人公はすべてのライフを失うか、またはすべてのモンスターが退治されてしています。コンソールベースのアドベンチャーゲームのようなシンプルなものを作ってみてください。インスピレーションとして以下のゲームの流れを使用してください。
|
||||
|
||||
```
|
||||
Hero> Strikes with broadsword - orc takes 3p damage
|
||||
Orc> Hits with club - hero takes 2p damage
|
||||
Hero> Kicks - orc takes 1p damage
|
||||
Game> Orc is defeated - Hero collects 2 coins
|
||||
Game> ****No more monsters, you have conquered the evil fortress****
|
||||
```
|
||||
|
||||
## ルーブリック
|
||||
|
||||
| 基準 | 模範的な例 | 適切な | 改善が必要 |
|
||||
| -------- | ---------------------- | --------------------------- | -------------------------- |
|
||||
| | フルゲームが提示されています | 部分的に提示されたゲーム | 部分的なゲームにはバグが含まれています |
|
@ -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/ から入手しました。
|
||||
ゲームを作るのが好きなら、これらのアセットはとても良いもので、多くは無料で、一部有料のものがあります。
|
Loading…
Reference in new issue