LEARN

今日 学ぶこと、学んだこと

これは「読みもの」の ページ。さきに 読んでも、あとで 読んでも いい。
ゲームを 作っていて「なんで こう なるの?」と 思ったら、ここに もどって くる。 ぜんぶの「なぜ」に、こたえが 書いてある。

Chapter 1 / Screen & coordinates第1章 がめんと ざひょう

ざひょうって なに?

ざひょうは、ばしょを 数字で いう ための やくそく。「右から 3ばん目、上から 2ばん目の ロッカー」と いうのと 同じ。コンピュータは 目が ないから、「ここ」と ゆびを さす かわりに、数字 2つで ばしょを つたえる。よこの 数字が X、たての 数字が Y。この 2つを ならべて (X, Y) と 書く。これが ざひょう。

学校で ならう ざひょうと、ゲームの ざひょうの ちがい

算数の グラフでは、(0, 0) は 左下に あって、Y は 上に いくほど ふえる。でも ゲームの がめんでは、(0, 0) は 左上に あって、Y は 下に いくほど ふえる。ここが ぎゃく。

学校の グラフ (0, 0) は 左下 x → ↑ y(上に ふえる) ゲームの がめん (0, 0) は 左上 x → ↓ y(下に ふえる) プレイヤー (240, 320)

図1 おなじ「ざひょう」でも、(0,0) の ばしょと Y の むきが ちがう

なんで ゲームは 左上が (0, 0) なの?
むかしの コンピュータの 画面は、テレビと 同じで 左上から 右へ、1行ずつ 下へ と 絵を かいて いた。かきはじめる 場所が 左上だったから、そこを (0, 0) に したのが そのまま 今も つづいている。だから このゲームでも playerY = playerY - playerSpeed のように ひき算すると 上に いく。

X(よこ)・Y(たて)・Z(おくゆき)

X は よこ、Y は たて。じつは もう 1つ、Z と いう ざひょうが ある。Z は おくゆき。がめんの「手前と おく」を あらわす。紙の 上の 絵には おくゆきが ないから、Z を つかうのは 3Dの ゲームだけ。

2Dと 3Dの ちがい

2Dは「2つの むき(X と Y)」で できた 世界。紙に かいた 絵と 同じで、たいらな 世界。マリオの よこスクロールや、この ハレアメ・キャッチが 2D。

3Dは「3つの むき(X と Y と Z)」が ある 世界。おくゆきが あるから、ものの うらがわに まわりこめるし、近くの ものは 大きく、とおくの ものは 小さく 見える。マインクラフトや スプラトゥーンが 3D。

2D(平面) よこ(X)と たて(Y)だけ 3D(りったい) おくゆき(Z)が ある。かげと むきが できる

図2 2Dは 四角、3Dは はこ。ちがいは「おくゆき(Z)」が あるか どうか

今日の ゲームは 2D。だから つかう ざひょうは playerX と playerY の 2つだけ。3Dに なっても、考えかたは 同じで 数字が 1つ ふえるだけ。

リフレッシュレート(Hz)と フレームレート(fps)の ちがい

にて いるけど、べつの ものの はやさを あらわして いる。

ことばだれの はやさ?いみ
リフレッシュレート(Hz)モニター(画面の きかい)画面が 1びょうに 絵を 入れかえられる 回数。60Hz なら 1びょうに 60回。きかいで きまっている
フレームレート(fps)ゲーム(プログラム)ゲームが 1びょうに 絵を 作る 回数。プログラムの いそがしさで かわる

たとえると、ゲームは「絵を かく人」、モニターは「絵を はりだす けいじばん」。かく人が どんなに はやくても、けいじばんの はりかえより はやくは 見せられない。

なぜ ゲームの 画面は 1びょうかんに 60回 かきかわるの?
2つ 理由が ある。① 多くの モニターが 60Hz(1びょうに 60回 はりかえ)だから、ゲームも それに 合わせて 60回 絵を 作ると、むだも カクカクも ない。② 人間の 目は、絵が 1びょうに 何十回も 入れかわると、もう 1まい 1まいを 見分けられなくて「なめらかに うごいている」と かんじる。ぱらぱらまんがと 同じ しくみ。このゲームの requestAnimationFrame は「モニターの はりかえに 合わせて、つぎの 絵を かく 時間だよ」と おしえて くれる めいれい。だから ちょうど 60回に なる。
1まい目 2まい目 3まい目 4まい目… 少しずつ ずれた 絵を、1びょうに 60まい。ぱらぱらまんがと 同じで、目には「うごいて」見える

図3 1びょうに 60まいの ぱらぱらまんが。これが「うごく」の 正体

Chapter 2 / Variables第2章 へんすう

「へんすう」って なに?

へんすうは、名前の ついた 箱。中に 数字や 文字を 入れて おける。let playerSpeed = 5; は「playerSpeed という 名前の 箱を 作って、5 を 入れる」と いう いみ。プログラムの ほかの 場所で playerSpeed と 書くと、箱の 中身(5)が とり出されて つかわれる。だから 箱の 中身を 変えると、それを つかっている ぜんぶの 場所が いっしょに 変わる。

「しょきか(初期化)」って なに?

しょきかは、箱に さいしょの 中身を 入れて おく こと。let score = 0; は「score の 箱を 作って、さいしょは 0 に して おく」。もし 中身を 入れずに つかうと、コンピュータは「箱は あるけど 中身が ない(undefined)」と こまって しまう。ゲームが はじまる 前に、つかう 箱 ぜんぶに さいしょの 中身を 入れて おく——これが しょきか。「さいしょに もどす」ボタンで まっさらに なるのも、しょきかの 状態に もどして いるから。

「★ここの数字を 変えてみよう★」の 7つの「なぜ」

7つの へんすうは、どれも しくみの ぶぶんの どこかで つかわれて いる。だから 数字を 変えると、つかわれている 場所の うごきが 変わる。

へんすう変えるとなぜ 変わるのか
playerSpeedプレイヤーの はやさキーを おしている あいだ、1コマごとに playerX に この数を たしたり ひいたり するから。1コマに すすむ きょりが 大きく なれば、はやく 見える
playerSizeプレイヤーの 大きさまるを かく ときの 大きさに つかわれる。それだけじゃ なく、あたり判定の「どこまで 近づいたら とれた ことに するか」の きょりにも つかわれている。だから 大きく すると、見た目も 大きく なるし、おかしも とりやすく なる
fallSpeedおかしの おちる はやさ1コマごとに おかしの y に この数を たして いるから。y が ふえる=下に いく、だったね(第1章)
appearTimeおかしの 出る 間かくtime % appearTime === 0(time を この数で わった あまりが 0 の とき)に おかしを 出している。40 なら 40コマに 1回。数を 小さく すると「あまりが 0」に なる 回数が ふえて、たくさん 出る
playerColorプレイヤーの 色かく 直前に pen.fillStyle(えんぴつの 色)に この色を セットして いるから
itemColorおかしの 色同じく、おかしを かく 前に えんぴつに セットされる 色だから
bgColorはいけいの 色まいかい さいしょに、がめん ぜんぶを この色で ぬりつぶして いるから(なぜ ぬりつぶすかは 第3章で)

「あたらしい へんすう を ふやす ところ」(置き場A)は なぜ いちばん 上に あるの?

プログラムは 上から 下へ、じゅんばんに 読まれる。箱は「作ります」と 書いた 行で はじめて できるから、つかう より 前に 作って おく ひつようが ある。置き場Aが 上に あるのは、ゲームが はじまる 前に、あたらしい 箱を ぜんぶ 用意して おく ため。

パーツで ふやす へんすうにも、ぜんぶ 理由が ある。

ふやす へんすうなにを おぼえる 箱か
let life = 3;のこりの 命の 数。ばくだんに 当たるたびに 1 ひいて、0 に なったら ゲームオーバーに する ための メモ
let bombs = [];ばくだんの リスト。[ ] は「からっぽの リスト」。おかしの items と 同じ 作りで、ばくだん用を もう 1つ 用意する
let oto = new AudioContext();音を 作る どうぐ 一式。毎回 作ると おもいので、さいしょに 1回だけ 用意して つかいまわす
let myName = "…";画面に 出す 自分の 名前。文字も 箱に 入れられる(文字の ときは " " で かこむ)

Chapter 3 / How it works第3章 しくみを ぜんぶ よむ

「ここから下は しくみ の ぶぶん」に 書いてある ことを、上から じゅんに ぜんぶ せつめいする。

なぜ「キーが おされたか どうかを おぼえておく」の?
キーボードは、キーを おした しゅんかんと はなした しゅんかんにしか おしえて くれない。でも ゲームは 1びょうに 60回「いま おされてる?」と 知りたい。だから おされた ときに keys という ノートに「ArrowRight:おされてる」と メモして、はなされたら メモを 消す。ゲームは 毎回 ノートを 見れば いい。
なぜ「やじるしキーで がめんが うごかないように する」の?
ブラウザにとって、やじるしキーは もともと「ページを スクロールする キー」。なにも しないと、→ を おすたびに ページが ガタガタ うごいて しまう。e.preventDefault() は「ブラウザさん、いつもの しごとは しなくて いいよ」と ことわる めいれい。
なぜ プレイヤーは「うごく」の?
じつは コンピュータの 中では、うごいて いない。playerX の 数字が 変わって いるだけ。→ が おされて いたら playerX = playerX + playerSpeed で 数字を 大きくする。つぎの コマで、新しい 場所に まるが かかれる。数字の 変化が、目には「うごき」に 見える。
なぜ「がめんの そとに 出ないように する」の?
たし算は がめんの はしを 知らない。ほうって おくと playerX は 10000 にも なって、プレイヤーは がめんの そとへ 消えて しまう。だから if (playerX > 480)(480 を こえたら 480 に もどす)と、0 より 小さく ならない ifの、2つの「かべ」を 作って おしもどして いる。480 は がめんの よこはば。
なぜ おかしは「上から 出てくる」の?
新しい おかしを { x: Math.random() * 480, y: 0 } で 作って いるから。y: 0 は がめんの いちばん 上(第1章!)。Math.random() は 0〜1 の でたらめな 数を くれるので、480 を かけると よこの 場所が 毎回 かわる。
なぜ「おかしが とれたか」わかるの?
まいかい、おちている おかし ぜんぶに ついて「プレイヤーとの きょり」を 計算して いるから。きょりが playerSize より 小さければ「くっつくほど 近い=とれた」と 判断して、点を たす。この「ぶつかったか どうかを 数で きめる こと」を あたり判定と いう。
「あたり判定」って なに?
ゲームの 中の ものは ぜんぶ ただの 絵で、本物のように「ぶつかる」ことは ない。だから「この 2つは ぶつかった ことに しよう」と 数字で きめる ルールが ひつよう。それが あたり判定。このゲームでは「2つの きょりが playerSize より 近ければ 当たり」と いう ルールに して いる。
なぜ「よこ×よこ + たて×たて の へいほうこん = きょり」なの?
ななめの きょりは、ものさしで はかれない。でも よこの 差と たての 差なら、ひき算で すぐ わかる。この 2つから ななめを 出す 計算が「よこ×よこ + たて×たて を たして、へいほうこん(√)を とる」。これは 直角三角形の せいしつ(ピタゴラスの 定理。中学で ならう)だけど、つかうのは 今日からで いい。Math.sqrt() が へいほうこんを 計算して くれる。
プレイヤー おかし よこ の さ たて の さ きょり(ななめ) きょり = √(よこ×よこ + たて×たて) …… ななめは ものさしが ないので 計算で 出す

図4 よこの差と たての差から、ななめの きょりを 計算で 出す

なぜ「まいかい ぜんぶ ぬりつぶして、はじめから かきなおしている」の?
キャンバスは ほんものの 画用紙と 同じで、一度 かいた 絵は 自分では 消えない。もし ぬりつぶさずに プレイヤーを 新しい 場所に かくと、前の 場所の プレイヤーも のこって、まるだらけに なって しまう。だから まいかい ①ぜんぶ はいけい色で ぬりつぶす → ②今の 場所に かきなおす。1びょうに 60回 これを くりかえして いる。じつは パーツ6(ざんぞう)は、この ぬりつぶしをわざと うすく して、前の 絵を のこす わざ。
なぜ「おかし」や「プレイヤー」や「スコア」が かけるの?
pen(えんぴつ)に「色を セットして → かたちを めいれいする」と、キャンバスに 絵が 出る しくみだから。おかしと プレイヤーは circle()(まる)、スコアは pen.fillText()(文字を かく めいれい)。かく じゅんばんも だいじで、あとに かいた ものほど 上に かさなる。スコアが いちばん 上に 見えるのは、さいごの ほうで かいて いるから。
なぜ「まる」が かけるの?(まるを かく どうぐ)
pen.arc(x, y, はんけい, 0, Math.PI * 2) は コンパスの めいれい。「中心 (x, y) に はりを さして、はんけいの 長さで、0度から ぐるっと 1しゅう」と いう いみ。Math.PI * 2 が「1しゅうぶんの 角度」。さいごに pen.fill() で 中を ぬると、まるに なる。この 3行を circle() と いう 名前の どうぐに まとめて、どこからでも 1行で よべるように して いる。
コラム:=== true は いらないんじゃ ないの?
するどい! isHit(...) の こたえは もともと true か false だから、 if (isHit(items[i])) と 書いても まったく 同じに うごく。おとなの プログラマーは ふつう そう 書く。
この 教材で わざと === true を つけて いるのは、 「もし 〜の こたえが true なら」と 声に 出して 読める ように する ため。 ぜんぶの if を 同じ かたちに そろえて、読む ことに なれて きたら、はずして いい。

Chapter 4 / Why the parts work第4章 パーツの「なぜ」

パーツカタログの 6つが、それぞれ なぜ 動くのかを たねあかしする。貼る 前に 読むと「ただの コピペ」が「わかって いる コピペ」に なる。

パーツ1 なぜ「スコア」が 大きく なるの?
このパーツは、文字の かきかたを 変えて いる。pen.font = "bold 64px sans-serif" は「ふとい 64ピクセルの 文字で」と えんぴつに おねがいする 行。もとの スコアは 20px だから、3ばい 以上 大きい。おなじ score の 数字でも、えんぴつの 設定しだいで 見た目が 変わる。置き場Cは draw() の さいごだから、大きな 数字が いちばん 上に かさなって 出る。
パーツ2 なぜ「音」が 出るの? 音の 大きさは どこで 変わるの?
スピーカーは、電気の ふるえで 音を 出す きかい。createOscillator() は「決まった はやさで ふるえる 電気」を 作る どうぐで、ふるえが はやいほど 高い音に なる。それが o.frequency.value = hz(beep(880) の 880)。音の 大きさは g.gain.value = 0.08 の 数字。gain は「音量つまみ」で、0 が 無音、1 が さいだい。0.08 を 0.2 に すると 大きく なる(耳を たいせつに!)。音の ファイルを 1つも つかわず、コンピュータが その場で 音を 作って いる。
パーツ3 「ばくだんを よけろ」は なにを して いるの?
おかしの しくみを まるごと もう 1セット 作って、いみを ぎゃくに した パーツ。①置き場Aで ばくだんの リスト bombs と 命 life の 箱を 用意。②置き場Bで ときどき ばくだんを 生み、1コマずつ おとし、あたり判定で「当たったら life を 1 ひく。0 に なったら gameover を true に」。おかしは「当たると うれしい」、ばくだんは「当たると こまる」——ちがいは それだけで、きょりの 計算は おかしと 同じ isHit() を つかいまわして いる。③置き場Cで のこりの life と、ゲームオーバーの 文字を かく。
パーツ4 なぜ「5びょう ごとに」はやく なるの?
time は 1びょうに 60 ふえる 数とり器だから、5びょうは 60 × 5 = 300。if (time % 300 === 0) は「time を 300 で わった あまりが 0 の とき」、つまり 300、600、900…の しゅんかんに だけ 中に 入る。そこで fallSpeed = fallSpeed + 1。第2章で 見た とおり、fallSpeed は まいかい y に たされる 数だから、おかし ぜんぶが 少しずつ はやく なる。
パーツ5 なぜ「なまえ」が 出るの?
置き場Aで let myName = "はれあめ たろう" と、文字の 入った 箱を 作り、置き場Cで pen.fillText(myName, 20, 350)(箱の 中身を、ざひょう (20, 350) に 文字で かく)して いるから。スコアと まったく 同じ しくみで、かく 中身が 数字か 文字か の ちがいだけ。
パーツ6 なぜ「ざんぞう(しっぽ)」が 出るの?
第3章の「まいかい ぜんぶ ぬりつぶす」の たねあかしを つかった パーツ。rgba(18, 18, 26, 0.25) の さいごの 0.25 は「25%だけ ぬる」と いう いみ(すきとおった ペンキ)。まいかいの ぬりつぶしが うすく なるので、前の コマの 絵が 1回ごとに 25%ずつしか 消えず、うっすら 何コマぶんも のこる。それが しっぽのように 見える。
ここまで 読めたら、もう「なぜか わからないまま コピペする人」じゃ ない。
カタログの おかわりミッションは、この ページの 知しきだけで ぜんぶ とける ように 作って ある。