今日 学ぶこと、学んだこと
これは「読みもの」の ページ。さきに 読んでも、あとで 読んでも いい。
ゲームを 作っていて「なんで こう なるの?」と 思ったら、ここに もどって くる。
ぜんぶの「なぜ」に、こたえが 書いてある。
ざひょうは、ばしょを 数字で いう ための やくそく。「右から 3ばん目、上から 2ばん目の ロッカー」と いうのと 同じ。コンピュータは 目が ないから、「ここ」と ゆびを さす かわりに、数字 2つで ばしょを つたえる。よこの 数字が X、たての 数字が Y。この 2つを ならべて (X, Y) と 書く。これが ざひょう。
算数の グラフでは、(0, 0) は 左下に あって、Y は 上に いくほど ふえる。でも ゲームの がめんでは、(0, 0) は 左上に あって、Y は 下に いくほど ふえる。ここが ぎゃく。
図1 おなじ「ざひょう」でも、(0,0) の ばしょと Y の むきが ちがう
playerY = playerY - playerSpeed のように ひき算すると 上に いく。X は よこ、Y は たて。じつは もう 1つ、Z と いう ざひょうが ある。Z は おくゆき。がめんの「手前と おく」を あらわす。紙の 上の 絵には おくゆきが ないから、Z を つかうのは 3Dの ゲームだけ。
2Dは「2つの むき(X と Y)」で できた 世界。紙に かいた 絵と 同じで、たいらな 世界。マリオの よこスクロールや、この ハレアメ・キャッチが 2D。
3Dは「3つの むき(X と Y と Z)」が ある 世界。おくゆきが あるから、ものの うらがわに まわりこめるし、近くの ものは 大きく、とおくの ものは 小さく 見える。マインクラフトや スプラトゥーンが 3D。
図2 2Dは 四角、3Dは はこ。ちがいは「おくゆき(Z)」が あるか どうか
playerX と playerY の 2つだけ。3Dに なっても、考えかたは 同じで 数字が 1つ ふえるだけ。にて いるけど、べつの ものの はやさを あらわして いる。
| ことば | だれの はやさ? | いみ |
|---|---|---|
| リフレッシュレート(Hz) | モニター(画面の きかい) | 画面が 1びょうに 絵を 入れかえられる 回数。60Hz なら 1びょうに 60回。きかいで きまっている |
| フレームレート(fps) | ゲーム(プログラム) | ゲームが 1びょうに 絵を 作る 回数。プログラムの いそがしさで かわる |
たとえると、ゲームは「絵を かく人」、モニターは「絵を はりだす けいじばん」。かく人が どんなに はやくても、けいじばんの はりかえより はやくは 見せられない。
requestAnimationFrame は「モニターの はりかえに 合わせて、つぎの 絵を かく 時間だよ」と おしえて くれる めいれい。だから ちょうど 60回に なる。図3 1びょうに 60まいの ぱらぱらまんが。これが「うごく」の 正体
へんすうは、名前の ついた 箱。中に 数字や 文字を 入れて おける。let playerSpeed = 5; は「playerSpeed という 名前の 箱を 作って、5 を 入れる」と いう いみ。プログラムの ほかの 場所で playerSpeed と 書くと、箱の 中身(5)が とり出されて つかわれる。だから 箱の 中身を 変えると、それを つかっている ぜんぶの 場所が いっしょに 変わる。
しょきかは、箱に さいしょの 中身を 入れて おく こと。let score = 0; は「score の 箱を 作って、さいしょは 0 に して おく」。もし 中身を 入れずに つかうと、コンピュータは「箱は あるけど 中身が ない(undefined)」と こまって しまう。ゲームが はじまる 前に、つかう 箱 ぜんぶに さいしょの 中身を 入れて おく——これが しょきか。「さいしょに もどす」ボタンで まっさらに なるのも、しょきかの 状態に もどして いるから。
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が 上に あるのは、ゲームが はじまる 前に、あたらしい 箱を ぜんぶ 用意して おく ため。
パーツで ふやす へんすうにも、ぜんぶ 理由が ある。
| ふやす へんすう | なにを おぼえる 箱か |
|---|---|
| let life = 3; | のこりの 命の 数。ばくだんに 当たるたびに 1 ひいて、0 に なったら ゲームオーバーに する ための メモ |
| let bombs = []; | ばくだんの リスト。[ ] は「からっぽの リスト」。おかしの items と 同じ 作りで、ばくだん用を もう 1つ 用意する |
| let oto = new AudioContext(); | 音を 作る どうぐ 一式。毎回 作ると おもいので、さいしょに 1回だけ 用意して つかいまわす |
| let myName = "…"; | 画面に 出す 自分の 名前。文字も 箱に 入れられる(文字の ときは " " で かこむ) |
「ここから下は しくみ の ぶぶん」に 書いてある ことを、上から じゅんに ぜんぶ せつめいする。
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 より 小さければ「くっつくほど 近い=とれた」と 判断して、点を たす。この「ぶつかったか どうかを 数で きめる こと」を あたり判定と いう。Math.sqrt() が へいほうこんを 計算して くれる。図4 よこの差と たての差から、ななめの きょりを 計算で 出す
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 を 同じ かたちに そろえて、読む ことに なれて きたら、はずして いい。
パーツカタログの 6つが、それぞれ なぜ 動くのかを たねあかしする。貼る 前に 読むと「ただの コピペ」が「わかって いる コピペ」に なる。
pen.font = "bold 64px sans-serif" は「ふとい 64ピクセルの 文字で」と えんぴつに おねがいする 行。もとの スコアは 20px だから、3ばい 以上 大きい。おなじ score の 数字でも、えんぴつの 設定しだいで 見た目が 変わる。置き場Cは draw() の さいごだから、大きな 数字が いちばん 上に かさなって 出る。createOscillator() は「決まった はやさで ふるえる 電気」を 作る どうぐで、ふるえが はやいほど 高い音に なる。それが o.frequency.value = hz(beep(880) の 880)。音の 大きさは g.gain.value = 0.08 の 数字。gain は「音量つまみ」で、0 が 無音、1 が さいだい。0.08 を 0.2 に すると 大きく なる(耳を たいせつに!)。音の ファイルを 1つも つかわず、コンピュータが その場で 音を 作って いる。bombs と 命 life の 箱を 用意。②置き場Bで ときどき ばくだんを 生み、1コマずつ おとし、あたり判定で「当たったら life を 1 ひく。0 に なったら gameover を true に」。おかしは「当たると うれしい」、ばくだんは「当たると こまる」——ちがいは それだけで、きょりの 計算は おかしと 同じ isHit() を つかいまわして いる。③置き場Cで のこりの life と、ゲームオーバーの 文字を かく。time は 1びょうに 60 ふえる 数とり器だから、5びょうは 60 × 5 = 300。if (time % 300 === 0) は「time を 300 で わった あまりが 0 の とき」、つまり 300、600、900…の しゅんかんに だけ 中に 入る。そこで fallSpeed = fallSpeed + 1。第2章で 見た とおり、fallSpeed は まいかい y に たされる 数だから、おかし ぜんぶが 少しずつ はやく なる。let myName = "はれあめ たろう" と、文字の 入った 箱を 作り、置き場Cで pen.fillText(myName, 20, 350)(箱の 中身を、ざひょう (20, 350) に 文字で かく)して いるから。スコアと まったく 同じ しくみで、かく 中身が 数字か 文字か の ちがいだけ。rgba(18, 18, 26, 0.25) の さいごの 0.25 は「25%だけ ぬる」と いう いみ(すきとおった ペンキ)。まいかいの ぬりつぶしが うすく なるので、前の コマの 絵が 1回ごとに 25%ずつしか 消えず、うっすら 何コマぶんも のこる。それが しっぽのように 見える。