こんにちは、32リタイア男です。
この記事では、YoutuberであるAkichonさんの下記動画をベースに、JavaScript(JS)による自作テトリス製作時の気付き・トラブル事例を記載します。
- チャンネル名:Akichonプログラミング講座
- タイトル:プログラミング講座 第13回
【テトリスを作る/JavaScript】
今回の記事では、上記動画のテトリスブロックを作成するところまでを解説します。
最初に注意点として、私はプログラミング初心者です。
そのため、この記事は初心者目線での気付き・トラブル事例の紹介が主体となります。
解説内容については、私なりに調べた内容を記載していますが、内容に誤りがある恐れもございますので、その点はご理解お願いいたします。
32リタイア男のプログラミングスキル状況
私のプログラミング学習歴は、約1カ月です。
この記事を書いた時点で、オンラインのプログラミング学習サービス「Progate」による学習が約1カ月経過した状態です。
学習状況の詳細は下記で記事にしています。
「Progate」による学習で、HTML&CSS・JavaScript・JQuery・PHPの基礎はある程度身に付いたと感じます。
しかし、Progateのガイドラインに沿って学習するだけでは、
「自分が今の知識で何か作れるのか?」
という部分が漠然とした状態で、モチベーションも保てなくなってきます。
そのため、目に見える形での成果物を作り、モチベーションおよびスキルを向上しようと考えました。
HTML&CSSのサイト模写もやるつもりですが、JavaScriptのスキルが身に付かないと感じました。
そのため、JavaScriptのスキル向上として、今回テトリスを自作することにしました。
自作テトリスのソースコード(間違い有り)
今回の記事では、上記Akichonさんの動画を模写する形でプログラミングした際の気付き・トラブル事例を挙げていきます。
まず初めに、私が動画を基に作成したソースコードを下記に記載します。
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <title>Tetris</title>
5 </head>
6 <body>
7 <canvas id="can"></canvas>
8 <script>
9 // ブロック一つのサイズ(ピクセル)
10 const BLOCK_SIZE = 30;
11
12 // テトリスブロック(tetro)のサイズ
13 const TETRO_SIZE = 4;
14
15 let can = document.getElementById("can");
16 let con = can.getContext("2d");
17
18 con.fillStyle="red";
19 con.fillRect(0, 0, BLOCK_SIZE, BLOCK_SIZE);
20
21 let tetro = {
22 [0, 0, 0, 0],
23 [1, 1, 0, 0],
24 [0, 1, 1, 0],
25 [0, 0, 0, 0]
26 }
27
28 for(let y=0; y < TETRO_SIZE; y++) {
29 for(let x=0; x < TETRO_SIZE; x++) {
30 if(tetro[y][x] == 1) {
31 let px = x * BLOCK_SIZE;
32 let py = y * BLOCK_SIZE;
33 con.fillStyle = "red";
34 con.fillRect(0, 0, BLOCK_SIZE, BLOCK_SIZE);
35 }
36 }
37 }
38 </script>
39 </body>
40 </html>
実際に試せばわかりますが、上記のコードでHTMLファイルを表示させても何も表示されませんでした。
正しい表示をさせる場合、少なくとも上記コードで5行分の修正が必要となります。
皆さんは分かりますでしょうか?
ちなみに、head部分のcharsetなどの様式的な部分は除きます。
私もまだプログラミング初心者の段階なので、その辺りの様式的な知識は疎いです。
ここでは、あくまで冒頭のYoutube動画のコードを参考にして、私が作成したコードの問題点に限定させてもらいます。
正しいコードを入力していれば、HTMLファイルを開いたときに下図のように表示されます。
自作テトリスのソースコード修正
ここからは、上記のソースコードの間違いを修正していきます。
まず気付いたのは、上記ソースコードの21行目と26行目の { } です。
2次元配列を指定するので、ここは [ ]; (最後にセミコロンも付ける)とすべきでした。
初心者の方は、配列[ ] とオブジェクト { } のカッコ指定の間違いおよびセミコロンの付け忘れはよくあると思います。
上手く動作しないときは、スペル間違いと合わせて、[ ]、{ }、セミコロンの付け忘れからまずは確認しましょう。
この間違いを修正後、再実行しましたが依然として正しく表示されませんでした。
他の問題点を探したところ、34行目の con.fillRect(0, 0, BLOCK_SIZE, BLOCK_SIZE) が動画の記載と違っていました。
正しくは、con.fillRect(px, py, BLOCK_SIZE, BLOCK_SIZE) となります。
この問題、動画を見れば間違いはわかりましたが、なぜpx, py にするのか理解していませんでした。
これを理解するため、fillRect() について調べました。
調べた結果、そもそも fillRect() というメソッドは、指定領域を fillStyle属性で塗りつぶすというものと理解しました。
指定領域のパラメータは、fillRect(x, y, width, height) であり、座標(x, y) を始点に、大きさ(width, height) の領域を指定し、fillStyle属性で塗りつぶします。
それを基に考えれば、34行目の con.fillRect(0, 0, BLOCK_SIZE, BLOCK_SIZE) という指定は、for { } で座標(x, y) を変えていっても同じ場所を塗りつぶすという指示になるのがわかります。
(x, y) が変化するたびに、fillRectの始点座標を変えなければいけません。
そのため、con.fillRect(px, py, BLOCK_SIZE, BLOCK_SIZE) として、始点座標を変更する必要があります。
この修正後、ブロックは無事に表示されました。
しかし、表示の一部がおかしいです。
表示されたブロックと上記のソースコードを見れば、初心者の方でも原因はわかると思います。
問題は18行目と19行目のソースコードです。
このソースコードに記載されたブロックが余分に表示されていました。
そのため、このソースコードは削除しました。
18、19、21、26、34行目のソースコードを修正すれば、HTMLファイルを開いたときに上記の正しいブロックが表示されたかと思います。
動画の通りに記載したつもりですが、自分で入力したコードだと色々間違いが出てきます。
そのたびに「どこが違っているのか?」を調べていくことで、成長している実感が湧いてきます。
今回紹介したソースコードは本当に基礎的なコードです。
私のような初心者は、動画の内容を模写したつもりでも間違いが多いため、まずは簡単なソースコードの模写から始めましょう。
その他ソースコードの学習
上記のソースコードで他に理解不足と感じた内容は以下になります。
以下の内容について、私なりに理解した内容を記載します。
チェックポイント
・canvas
・document.getElementById(“can”)
・can.getContext(“2d”)
・2次元配列の作成 [ [ ], [ ] ]
canvas
canvas要素(要素とは<></>のタグで囲まれた範囲を指す)は、2D および 3D の形状やビットマップ画像をプログラムを用いて動的に生成できるコマンドと理解しました。
canvas要素は、JavaScriptを使って図形を描くためなどに使われるHTML要素になります。
私のイメージとしては、テトリスのブロックをスケッチするための「スケッチブック」を用意するコマンドと認識しています。
document.getElementById(“can”)
このメソッドは、id(この場合は”can”)の要素を表すElementオブジェクトを返すものです。
Elementオブジェクトって何?という感じですが、私の初心者知識では現状詳しく理解できませんでした。
私のイメージとしては、idを「単語」とすると、Elementとは「辞書」のようなものと考えています。
「can」という「単語」をElementという「辞書」に登録して、そこから「単語」を拾うようにすることで、「can」という「単語」が理解できないプログラム箇所でも、「can」とはこういうものですよ!と理解させることができるという認識です。
can.getContext(“2d”)
このメソッドは、canvas要素に対し、canvasとして操作を可能にするcanvas文脈オブジェクトを与えるメソッドです。
(canvas要素には、canvasを操作するために必要なプロパティやメソッドが実装されていないため)
上記の説明ではあまり理解できないかと思います。
正直、私も詳しくは理解できていませんが、2次元グラフィックと3次元グラフィックのどちらの文脈を使用するか指定するものという認識です。
おそらく、 “2d” で2次元グラフィックの文脈を指定するのが一般的かと思います。
私のイメージとしては、canvasという「スケッチブック」に対して、2次元グラフィック(“2d”) は鉛筆や消しゴムなどの道具(プロパティ、メソッド)を準備するという認識です。
それに対して、3次元グラフィック(”webgl”)は彫刻刀などの立体的な絵を描くための道具を準備するコマンドになると考えています。
2次元配列 [ [ ], [ ] ]
今回のテトリスブロックのソースコード(let tetro)の2次元配列[ [ ], [ ], … ] を表で表すと以下のようになると考えます。
[y],[x] | x=0 | x=1 | x=2 | x=3 |
y=0 | [0,0] = 0 | [0,1] = 0 | [0,2] = 0 | [0,3] = 0 |
y=1 | [1,0] = 1 | [1,1] = 1 | [1,2] = 0 | [1,3] = 0 |
y=2 | [2,0] = 0 | [2,1] = 1 | [2,2] = 1 | [2,3] = 0 |
y=3 | [3,0] = 0 | [3,1] = 0 | [3,2] = 0 | [3,3] = 0 |
上記の配列として考えると、tetro[y][x] = 1 ([1, 0]、[1, 1]、[2, 1]、[2, 2] の箇所)の場合、fillRect()メソッドでブロックを描画するという内容のコードになっていると理解しました。
まとめ
最後にまとめとして、今回紹介したソースコードで私が重要と考える点は以下になります。
チェックポイント
・テトリスを描画する画面に関するコードの理解
(canvas要素、getElementById()、getContext(“2d”)など)
・fillRect()メソッドによるブロック描画方法の理解
・2次元配列の理解
・[ ]やセミコロンなどの誤記および付け忘れの注意
JavaScriptによるテトリス製作の続きは、次の記事で解説しています。
コメント