バウンスボールのデモに機能を追加する
この評価では、前の記事のバウンスボールのデモを出発点として用い、いくつかの面白い機能を新たに追加してもらいます。
前提条件: | この評価を試みる前に、このモジュールのすべての記事を学習済みであること。 |
---|---|
目的: |
JavaScript オブジェクトとオブジェクト指向のインスタンス生成を理解しているかテストする。 |
出発点
この評価をスタートするためには、私たちの最新記事からローカル PC の新しいディレクトリーに index-finished.htm、style.css、main-finshed.js をコピーします。
または、あなたの評価のために、JSBin や Glitch を使うことができます。これらのオンラインエディターに HTML、CSS や JavaScript を貼り付けることができます。もしあなたが使用しているオンラインエディタが、別々の JavaScript/CSS のパネルを持っていない場合は、HTML内の <script>
/<style>
要素を使って、インラインで書くことができます。
注: もし行き詰った場合は、サポートを依頼してください。このページの下部にある評価とさらなる支援セクションを参照してください。
ヒントと tips
始める前にいくつかの助言です。
- この評価はかなり難しいです。コーディングを始める前に評価全体を読み、各ステップをゆっくりと注意深く行ってください。
- それぞれのステージを作業した後のデモを、別々のコピーとして保管しておけば、後で困ったときに参照することができます。
プロジェクト概要
このバウンスボールのデモは面白いですが、ここではもう少しインタラクティブにするため、バウンスボールを捕まえたら食べてしまう、ユーザー制御された邪悪な円を追加します。また、バウンスボールや邪悪な円が継承できる一般的な Shape()
オブジェクトを作ることで、あなたのオブジェクト構築スキルも試してみましょう。最後に、残ったボールが数えられるスコアカウンターも追加してみましょう。
次のスクリーンショットでは、完成したプログラムがどのように見えるかのイメージを掴めるでしょう:
さらにヒントを差し上げます。完成デモを見てみましょう。(ソースコードをチラ見しないように!)
完成までの手順
次のセクションでは、必要な操作について説明します。
新しいオブジェクトを作る
まず初めに、既存の Ball()
コンストラクターを Shape()
コンストラクターに変更し、新しい Ball()
コンストラクターを追加します:
Shape()
コンストラクターは、x
、y
、velX
、および、velY
プロパティを、Ball()
コンストラクターが最初に行ったのと同じ方法で定義する必要がありますが、色とサイズのプロパティは指定しません。- また、新しいプロパティとして、ボールが存在するか(邪悪な円に食べられていないか)どうかを追跡するために使用される
exists
を新しく定義する必要があります。これはブール値 (true
/false
) である必要があります。 Ball()
コンストラクターは、x
、y
、velX
、velY
、およびexists
プロパティをShape()
コンストラクターから継承する必要があります。- また、元の
Ball()
コンストラクターのように、color
とsize
プロパティを定義する必要があります。 Ball()
コンストラクターのprototype
とconstructor
を適切に設定してください。
ボールの draw()
、update()
、と collisionDetect()
メソッドの定義は、前とまったく同じである必要があります。
また、new Ball() ( ... )
コンストラクターの呼び出しに新しいパラメーターを追加する必要があります。exists
パラメーターは 5番目のパラメーターにする必要があり、true
の値を指定する必要があります。
この時点で、コードをリロードしてみてください。再設計されたオブジェクトで、前と全く同じように動作するはずです。
EvilCircle() の定義
さあ、悪者 EvilCircle()
の出番です! 私たちのゲームに邪悪な円は1つしか登場しませんが、練習のためにあえて、Shape()
から継承するコンストラクターを使用して定義します。後で、他のプレイヤーによって制御される円、あるいは、コンピューター制御の別の邪悪な円をいくつか加えたいと思うかもしれません。おそらく、あなたは単一の邪悪な円の世界を引き継いでいくつもりはないでしょうが、今回の評価のためにはこれで十分です。
EvilCircle()
コンストラクターは、x
, y
, velX
, velY
と exists
を Shape()
から継承しますが、velX
と velY
は常に20です。
これは Shape.call(this, x, y, 20, 20, exists);
のように呼び出します。
次のように、独自のプロパティも定義する必要があります:
color
—'white'
size
—10
ここでも、継承したプロパティをコンストラクターのパラメーターとして定義し、prototype
と constractor
のプロパティを正しく設定することを忘れないでください。
EvilCircle() のメソッドの定義
EvilCircle()
には、以下に示す 4 つのメソッドがあります。
draw()
このメソッドは、Ball()
の draw()
メソッドと同じく、キャンバス上にオブジェクトインスタンスを描画するという目的を持ちます。とても良く似た動作をするので、Ball.prototype.draw
の定義をコピーすることから始めます。次に、以下の変更を行います。
- 邪悪な円は塗りつぶしせず、枠線(ストローク)だけを持たせたいと思います。そのために、
fillStyle
とfill() (en-US)
をstrokeStyle
とstroke()
に変更します。 - また、線を少し太くすれば、邪悪な円が少し分かりやすくなります。これは、
beginPath()
呼び出しの後のどこかでlineWidth (en-US)
の値(3で十分でしょう)を設定することで実現できます 。
checkBounds()
このメソッドは、Ball()
の update()
関数の最初の部分と同じ機能、すなわち、邪悪な円が画面の端から出そうになったら出ないようにする機能を持ちます。先ほどと同様に、Ball.prototype.update
定義をほぼコピーするだけでできますが、いくつか変更する必要があります。
- 最後の 2行を削除します。後で見られるように、別の方法で邪悪な円を動かすので、フレーム毎に邪悪な円の位置を自動的に更新する必要はありません。
if()
ステートメントの内部でそのテストが true を返す場合、velX
/velY
を更新したくありません。代わりにx
/y
の値を変更して、邪悪な円が画面内に少し跳ね返ってくるようにしたいのです。邪悪な円の size プロパティを(適切に)加えたり減じたりすることは理にかなっています。
setControls()
このメソッドは、onkeydown
イベントリスナーを window
オブジェクトに追加し、特定のキーボードキーが押されたときに、邪悪な円を動かします。次のコードブロックは、メソッド定義の中に置く必要があります。
let _this = this;
window.onkeydown = function(e) {
if (e.key === 'a') {
_this.x -= _this.velX;
} else if (e.key === 'd') {
_this.x += _this.velX;
} else if (e.key === 'w') {
_this.y -= _this.velY;
} else if (e.key === 's') {
_this.y += _this.velY;
}
}
キーが押されると、イベントオブジェクトの key プロパティを調べて、どのキーが押されているかを確認します。押されたキーが、指定された4つのキーの 1 つである場合、邪悪な円は左/右/上/下に移動します。
おまけとして、let _this = this;
をこの場所で設定しなければならない理由を教えてください。関数スコープと関係があります。
collisionDetect()
このメソッドは Ball()
の collisionDetect()
メソッドと非常によく似た方法で動作するので、そのコピーをこの新しいメソッドの基礎として使用することができます。しかし、いくつかの違いがあります。
- 外側の
if
ステートメントでは、反復処理中のボールが、チェックを行っているボールと同じであるかをチェックする必要はなくなりました。なぜなら、それは邪悪な円であって、ボールではないからです! その代わりに、チェックされているボールが存在するかどうかを確認(どのプロパティでこれを行うことができるでしょうか?)するテストを行う必要があります。存在しなければ、それはすでに邪悪な円によって食べられているので、再度チェックする必要はありません。 - 内部の
if
ステートメントでは、衝突が検出されたときにオブジェクトの色を変更する必要がなくなりました。その代わりに、邪悪な円と衝突するボールをもう存在しないように設定します(どうやって実行すると思いますか?)。
プログラムに邪悪な円を持ち込む
さて、邪悪な円を定義したので、実際にそれをシーンに表示させる必要があります。そのためには、loop()
関数をいくつか変更する必要があります。
- まず、(必要なパラメーターを指定して)新しい邪悪な円オブジェクトインスタンスを作成し、その
setControls()
メソッドを呼び出します。これらの 2 つの処理は一度だけ実行すればよく、ループの繰り返し毎に行う必要はありません。 - すべてのボールをループして、ボールが存在する場合にのみ、それぞれの
draw()
、update()
、collisionDetect()
が呼び出されるようにします。 - ループの各繰り返しで、邪悪な円インスタンスの
draw()
、checkBounds()
、およびcollisionDetect()
メソッドを呼び出します。
スコアカウンターの実装
スコアカウンターを実装するには、次の手順に従います。
- HTML ファイルの
<h1>
要素の直下に、"Ball count:" というテキストを含む<p>
要素を追加します。 - あなたの CSS ファイルに、次のスタイルを追加します:
p { position: absolute; margin: 0; top: 35px; right: 5px; color: #aaa; }
- JavaScript では、次の更新を行います:
- 段落への参照を格納する変数を作成します。
- 何らかの方法で画面上のボールの数をカウントしてください。
- ボールをシーンに追加するたびにカウントを増加させ、更新されたボールの数を表示します。
- 邪悪な円がボールを食べる(存在を消す)たびにカウントを減らし、更新されたボールの数を表示します。
評価とさらなる支援
If you would like your work assessed, or are stuck and want to ask for help:
- Put your work into an online shareable editor such as CodePen, jsFiddle, or Glitch.
- Write a post asking for assessment and/or help at the MDN Discourse forum Learning category. Your post should include:
- A descriptive title such as "Assessment wanted for Adding bouncing balls features".
- Details of what you have already tried, and what you would like us to do, e.g. if you are stuck and need help, or want an assessment.
- A link to the example you want assessed or need help with, in an online shareable editor (as mentioned in step 1 above). This is a good practice to get into — it's very hard to help someone with a coding problem if you can't see their code.
- A link to the actual task or assessment page, so we can find the question you want help with.