4.4 落ちものブロックゲームを作る

(1/1)
落ちものブロックゲームの画面イメージ
AI生成コンテンツ / AI-generated contents
4.3 ブロック崩し」までのゲームは、プレイヤーが操作するものが1つだけで、ルールも「ボールを落とさない」という単純なものだった。本項では、盤面の上から落ちてくるブロックを積み上げ、横一列を隙間なく埋めて消していく「落ちものブロックゲーム」(fallingBlocks.html)を作る。
このゲームは、ブロックの回転、盤面の管理、そろった列の判定、一定間隔での落下といった処理が組み合わさっており、決めておくべきルールもこれまでより格段に多い。本項では、まずゲームのルールを整理し、続いて複製を作って試す設計、二次元配列による盤面管理、座標変換による回転、壁際で回転を成立させる壁蹴り、ライン消去と詰め直し、一定間隔での落下という6つの要素技術を、プログラムを書いたことがない読者にも分かるように解説する。最後に、Codexへ渡すプログラム仕様書をまとめる。

目次

落ちものブロックゲームの概要

オリジナルの「テトリス」
オリジナルの「テトリス」
AI生成コンテンツ / AI-generated contents
落ち物ブロックゲームとは、画面の上から落ちてくる図形を操作して並べ、一定の条件を満たすと図形が消えるパズルゲームの総称である。この形式を確立したのは、1984年(昭和59年)6月6日、旧ソビエト連邦の科学アカデミー計算センターに勤めていたアレクセイ・パジトノフ(Alexey Pajitnov)が「エレクトロニカ60」というコンピューター上で作り上げた「テトリス」である。日本では1988年(昭和63年)12月にセガがアーケード版を稼働させ、1989年(平成元年)6月14日には任天堂がゲームボーイ版を発売して約424万本を売り上げ、ジャンルとして定着した。

4個の正方形を辺でつないだ図形をテトロミノ(tetromino)と呼ぶ。ギリシャ語で4を意味する「テトラ」に由来する。裏返して重なる図形を同じものとみなせば5種類しかないが、画面上のブロックは裏返せないため、鏡像の関係にあるSとZ、JとLをそれぞれ別の図形として数え、合計7種類になる。本項のゲームも、この7種類を使う。

本項で作る fallingBlocks.html は、横10マス・縦20マスの盤面に7種類のブロックを1個ずつ落とし、横一列を隙間なく埋めて消していく。合計30列を消せばゲームクリア、盤面の上部までブロックが積み上がるか、制限時間の3分を使い切るとゲームオーバーになる。成績はブラウザに直近30回分を保存する。なお「テトリス」は商標であり、名称や画面デザインを流用することはできない。本項のプログラムは、ゲーム名・画面デザイン・説明文・プログラムのすべてを独自に用意している。
画面構成要素
要素役割
盤面横10マス・縦20マスの格子。薄いグリッド線でマスの境界を示す
操作中ブロックいま落下しているブロック。左右移動・回転・落下ができる
固定済みブロック着地して盤面に固定されたブロック。横一列がそろうと消える
次ブロック次に出現するブロックを盤面の横(狭い画面では上下)に表示する
ステータス表示得点、レベル、消去した列数、クリアまでの残り列数
残り時間画面右下に「分:秒」で表示。残り15秒以下で赤色になる
操作ボタンスマートフォン向けの「左」「右」「回転」「下」「即落下」ボタン
ここまでに作った3つのゲームと比べると、このクラスのゲームになると決めておくべきルールが一気に増える。ブロックが7種類あり、それぞれ回転で形が変わる。壁際で回転できないときの扱い、着地の条件、そろった列の消し方、消えたあとの詰め方、レベルによる落下速度と、決めることが次々に出てくる。

同時に、必要な要素技術も増える。「4.3 ブロック崩し」で挙げたHTML5 Canvas、レスポンシブCSS、デルタタイム、Pointer Events APIを土台にしたうえで、さらに6つの新しい要素技術と、細かな工夫がいくつも必要になる。この規模になると、思いついた順に指示を出していくやり方では作りきれない。ルールを漏れなく書き出し、仕様書として整理する作業が欠かせなくなる。

ゲーム・ルール

7種類のブロック(テトロミノ)
AI生成コンテンツ / AI-generated contents
盤面は横10マス・縦20マスの格子である。その上部中央から、ブロックが1個ずつ現れ、一定時間ごとに1マスずつ下へ動く。プレイヤーは落下中のブロックを左右に動かし、時計回りに90度回転させて、置きたい位置と向きを決める。床または先に積まれたブロックの上に着地すると、そのブロックはその場所に固定され、次のブロックが現れる。盤面の外へ動かすことも、床や固定済みブロックを突き抜けることもできない。

横一列10マスがすべて埋まると、その列が消える。消えた列より上に積まれていたブロックは、消えた列の数だけ下へ移動する。2列以上が同時に埋まった場合は、まとめて消える。

7種類のブロックには、形を見分けやすいよう別々の色を割り当てる。出現順は「7種類を1個ずつ袋に入れ、順番を混ぜてから1個ずつ取り出し、空になったら詰め直す」という7個バッグ方式にする。毎回7種類から等確率で選ぶ方式では、同じ形が何度も続いたり、欲しい形が長く来なかったりする。袋方式なら、どの形も7個以内に必ず1回は現れる。
7種類のブロックと割り当てる色
記号
I4個が一直線に並ぶ水色
O2個×2個の正方形黄色
T横3個の中央の下に1個
S2個の段が右上へずれる
Z2個の段が右下へずれる
J横3個の左端の上に1個
L横3個の右端の上に1個
操作の種類
操作内容キーボード
左右移動1マスずつ横へ動かすA/←、D/→
回転時計回りに90度回す。O型は形が変わらないため回転しないW/↑/X
ソフトドロップ通常より速く落下させる。1マスにつき1点S/↓
ハードドロップ着地できる位置まで即座に落とす。1マスにつき2点Space
一時停止落下と残り時間を止める。再度押すと再開するP/Esc
壁際や、積み上がったブロックの隣で回転させると、回転後の形が壁や既存のブロックと重なることがある。この場合はそのままでは回転させず、左右に1マスずらして置けるかどうかを試す。それでも置けなければ回転を取り消す。

また、着地してから固定されるまでに約0.5秒の猶予を設ける。これを固定猶予と呼ぶ。この猶予の間に左右移動または回転が成立した場合は、猶予時間を数え直す。落下が速くなっても、着地の直前に位置を調整する余地を残すための決まりである。

得点・レベルと制限時間

得点
行為得点
1列消去100点 × 現在レベル
2列同時消去300点 × 現在レベル
3列同時消去500点 × 現在レベル
4列同時消去800点 × 現在レベル
ソフトドロップ1マスにつき1点
ハードドロップ1マスにつき2点
レベルは開始時が1で、10列消すごとに1つ上がる。レベルが上がると自動落下の間隔が短くなり、考える時間が減っていく。

1列ずつ4回消せば400点、4列を一度に消せば800点である。まとめて消したほうが得点効率が高い。しかし4列分の高さまで積むには、消したい列を空けたまま積み上げなければならず、上部に近づくほどゲームオーバーの危険が増す。この駆け引きが落ちものブロックゲームの面白さの中心にある。

制限時間は3分(180秒)とする。画面右下に「分:秒」で残り時間を表示し、残り15秒以下になると数字を赤色にして時間切れの緊迫感を演出する。一時停止中は残り時間を減らさない。
勝敗条件
結果条件
ゲームクリア制限時間内に合計30列を消去する
ゲームオーバー新しいブロックを盤面へ置けないほどブロックが積み上がる
ゲームオーバー制限時間内に30列を消去できなかった

要素技術1:複製を作って試す

複製を作って試す仕組み
AI生成コンテンツ / AI-generated contents
本項からは、このゲームで使う要素技術を解説する。これらを理解できなくても、最後に掲げる仕様書(プロンプト)を Codex に投入すればゲーム・プログラムを作ることができる。のちのちゲームを改良したり、別のゲームを創作したりするときの手がかりとして読んでほしい。

落ちものゲームのブロック操作は「左右に動かす」「回転させる」「1マス落とす」の3つに集約できる。ただし、どの操作にも共通の条件がある。動かした結果が盤面の外にはみ出すか、既存のブロックと重なるなら、その操作は無効にしなければならない。ここで、先にブロックを動かしてから重なりを調べ、駄目だったら元に戻すという書き方をすると、戻し忘れによる不具合が起きやすい。

本プログラムは順序を逆にしている。まず操作中のブロックの複製を作り、複製の側の位置や形を変える。次に、その複製が盤面に収まるかどうかを調べる関数(canPlace)に通す。収まるなら操作中のブロックを複製に差し替え、収まらないなら複製を捨てて何もしない。元のブロックには最後まで手を触れないので、戻し忘れが起こらない。JavaScriptでは「{ ...current, x: current.x + 1 }」と書くだけで、1マス右にずらした複製ができる。

この「複製を作って試し、成立したときだけ入れ替える」型は、左右移動、回転、ソフトドロップ、ハードドロップ、着地の判定のすべてに使える。ハードドロップは「1マス下の複製が置ける限り繰り返す」と書くだけで実現できる。

要素技術2:二次元配列による盤面管理

二次元配列による盤面管理
AI生成コンテンツ / AI-generated contents
盤面の状態を覚えておくには、マス目と同じ形のデータを用意するのが素直である。JavaScriptでは、まず20個の要素を持つ配列を作り、その1つ1つに、10個の要素を持つ配列を入れる。こうしてできた「配列の配列」を二次元配列と呼ぶ。board[y][x] と書けば、上からy番目・左からx番目のマスを取り出せる。方眼紙のマスに番号を振り、その番号で場所を指定するのと同じである。

各マスに入れるのは、色ではなくブロックの種類を表す文字('I' や 'T' など)である。空のマスには「何もない」を意味する null を入れる。色を直接入れてしまうと、配色を変えたいときに盤面のデータそのものを書き換えることになる。種類だけを覚えておき、描画するときに「種類から色を引く表」を通せば、配色の変更は表の1か所を直すだけで済む。データと見せ方を分ける、という考え方である。

落下中のブロックは、この盤面には書き込まない。盤面とは別に「種類」「4マスの相対座標」「盤面上の位置」を持つ1個のデータとして扱い、着地したときに初めて盤面へ書き込む。落下中のブロックも盤面に書き込むと、1マス動かすたびに元の4マスを消して新しい4マスを書く必要があり、消し忘れが不具合につながる。動いているものと止まっているものを分けて持つと、処理が単純になる。

要素技術3:座標変換によるブロックの回転

座標変換によるブロックの回転
AI生成コンテンツ / AI-generated contents
ブロックの形は、4個のマスの位置を並べた配列で表す。たとえばT型は [[0,0],[1,0],[2,0],[1,1]] である。「横に3つ並び、その中央の下に1つ」を、左上を原点とした座標で書き並べただけである。この表し方には大きな利点がある。回転が計算だけで済む

画面の座標は、右へ進むとxが増え、下へ進むとyが増える。算数で習う座標とは上下が逆である。この座標系で時計回りに90度回すには、各マスの位置 (x, y) を (−y, x) に置き換えればよい。本プログラムはこれに1を足して (1 − y, x) としている。単純に (−y, x) とすると座標がマイナス側に寄ってしまうため、右へ1マス分ずらして位置を整えているのである。

T型に当てはめてみる。[[0,0],[1,0],[2,0],[1,1]] の各座標を (1 − y, x) に置き換えると、[[1,0],[1,1],[1,2],[0,1]] になる。縦に3つ並び、その中央の左に1つ、つまり下を向いていた突起が左を向いた形である。同じ計算を7種類すべてに使えるので、回転後の形を7種類×4方向の28通りぶん用意する必要はない。ただし正方形のO型は回転しても形が変わらないため、計算をせずそのままにする。

なお、この計算を4回繰り返せば元の形に戻るが、途中の向きでは基準点からのずれが残る。横向きのI型を2回回すと2マス左に寄るため、壁際でI型が回りにくいという癖として現れる。市販のゲームは7種類それぞれに補正量の表を持たせてこの癖を消しているが、本プログラムは最小構成を優先した。

要素技術4:壁蹴り

壁蹴り(ウォールキック)の仕組み
AI生成コンテンツ / AI-generated contents
回転の計算そのものは簡単だが、計算した結果をそのまま採用できるとは限らない。盤面のいちばん右に寄せた横向きのI型を縦向きに回そうとすれば、回転後の形は壁の外に出てしまう。積み上がったブロックの隣でも同じことが起きる。

ここで「置けないなら回転させない」とだけ決めると、操作感が大きく損なわれる。壁際は最後にブロックを収める場所であり、そこで回転できないと、プレイヤーは盤面の中央でしか向きを変えられなくなる。

そこで多くの落ちものゲームは壁蹴り(ウォールキック)と呼ばれる処理を入れている。回転後の形が置けないとき、少しだけ横へずらして置けないかどうかを試すという考え方である。本プログラムでは、ずらさない場合、左に1マス、右に1マスの3通りを順に試し、最初に置けた場所を採用する。3通りすべてで置けなければ回転を取り消す。壁を蹴って跳ね返るように見えるので、この名前が付いている。

試す順番と、ずらす量の上限が、そのままゲームの手触りになる。ずらす量を大きくすれば壁際でも自由に回せるが、ブロックが意図しない位置へ飛ぶ。1マスに抑えれば素直な操作感になる代わりに、壁際で回転が拒否される場面が出る。本プログラムは後者を選んだ。ここは要素技術1の型がそのまま使える場所で、3通りの複製を順に調べ、成功した複製に差し替えるだけである。

要素技術5:ライン消去と詰め直し

ライン消去と詰め直し
AI生成コンテンツ / AI-generated contents
横一列がすべて埋まったら、その列を消して上の列を詰める。素直に考えると「埋まっている列を探す → その列を消す → 上の列を1つずつ下へずらす」という手順になる。しかしこれは意外に間違えやすい。2列以上が同時に消えるとき、上から順にずらすと下の列を先に上書きし、下から順にずらすと消したはずの列の番号が途中で変わる。

本プログラムは、消す列を探すのではなく、残す列を集めるという書き方をしている。盤面の20列を上から順に見て、空きが1つ以上残っている列だけを新しい配列に集める。埋まっていた列は集められないので、自然に消えることになる。集め終わったあと、配列の長さが20に足りない分だけ、空の列を先頭に追加する。これで詰め直しまで完了である。

消えた列の数は「20 − 集まった列の数」で求められる。この数を使って得点を計算し、消去列数に足し込む。列をずらす処理を自分で書かないので、同時に何列消えても同じ手順で正しく動く。JavaScriptでは、条件に合う要素だけを集める filter と、配列の先頭に追加する unshift の2つだけで書ける。処理の順番を考える代わりにデータの作り直しとして表現する、応用範囲の広い書き方である。

要素技術6:一定間隔での落下

一定間隔での落下と時間の累積
AI生成コンテンツ / AI-generated contents
「4.3 ブロック崩し」では、前回の描画からの経過時間(デルタタイム)を使って、ボールを滑らかに動かした。落ちものゲームのブロックは、これとは違って1マスずつ、飛び飛びに動く。0.4マスだけ落ちた状態は存在しない。時間の扱い方そのものが変わる。

本プログラムは、画面を更新するたびに、経過時間を1つの変数に足していく。この変数がレベルごとに決めた落下間隔(レベル1では1000ミリ秒)を超えたら、ブロックを1マス落とし、変数からその間隔ぶんを差し引く。超えた分を0に戻さず、余りとして残すのがこつである。余りを捨てると落下のたびにわずかな遅れが生じ、それが積み重なって落下速度が仕様より遅くなってしまう。

この方式なら、画面の更新が速い端末でも遅い端末でも、1秒あたりに落ちるマス数は変わらない。もう1つの利点は、一定時間ごとに処理を呼び出す setInterval という命令を使わずに済むことである。setIntervalは描画の周期とずれるうえ、開始と停止の管理を誤ると同じ処理が二重に動き出す。落下、残り時間の計算、描画を1つのループにまとめておけば、一時停止はそのループを止めるだけで済む。

レベルと落下間隔の対応は、SPEEDSという名前の配列に15段階分をまとめてある。1000、820、680……と短くなり、最後は70ミリ秒である。速度を調整したいときは、この配列だけを直せばよい。調整する数値を1か所に集めておくのは、ゲームに限らず有効な作法である。

ゲーム進行を支える仕組み

ゲームの6つの状態と遷移
AI生成コンテンツ / AI-generated contents
ここまでの6つがプログラムの骨格である。以下、その骨格を動かすために必要な仕組みを、まとめて紹介する。

まず、7個バッグの並べ替えである。袋の順番を混ぜるには、配列の後ろの要素から順に、それ自身を含む前方のどれかと入れ替えていくという方法を使う。フィッシャー–イェーツのシャッフルと呼ばれ、どの並び順も等しい確率で現れる。「適当に何回か入れ替える」といった素朴な方法では、特定の並びが出やすくなる。乱数そのものについては「3.2 パスワード生成ツール」で触れた。

次に、ゲームの状態である。このゲームは「開始前」「プレイ中」「一時停止」「クリア」「ゲームオーバー」「エラー」の6つの状態のいずれかにある。この状態を1つの変数で持ち、操作を受け付ける前に必ず状態を調べる。プレイ中でなければブロックは動かさず、「ゲームを開始してください」などと表示する。こうしておくと、「ゲームオーバー画面でキーを押したらブロックが動いた」といった不具合を防げる。有限状態機械と呼ばれ、画面の切り替えを伴うプログラムで広く使われる考え方である。

時間の扱いは、開始時刻を覚えておき、現在時刻との差を取るという形に統一してある。固定猶予は、着地した時刻を覚え、現在時刻との差が0.5秒を超えたら固定する。猶予の間に左右移動や回転が成立したときは、覚えていた時刻を現在時刻に書き換えるだけで「操作するたびに猶予が延びる」動きになる。

残り時間も同じで、1秒ごとに変数を1つ減らすのではなく、開始時刻との差から毎回計算し直す。前者は処理が遅れた分だけ時間が余計に残ってしまう。時刻の取得には、パソコンの時計を変更しても影響を受けない performance.now を使う。一時停止していた時間は別に足し合わせ、経過時間から差し引く。これで「一時停止中は残り時間が減らない」という仕様を満たせる。

最後に、ループの多重起動を防ぐ仕組みである。画面更新のループは、開始・再開のたびに必ず「動いているループを止めてから始める」手順にしてある。止め忘れるとループが2本同時に走り、ブロックが1回で2マス落ちる、残り時間が2倍の速さで減るといった、原因の分かりにくい不具合になる。仕様書のテスト観点に書いておくべき項目である。

操作・保存・エラー処理の仕組み

スワイプ操作の判定
AI生成コンテンツ / AI-generated contents
スマートフォンでの操作は、指を置いた位置と離した位置の差から判断する。移動距離が18ピクセル未満ならタップとみなして回転、横の移動量が縦より大きければ左右移動、下向きで移動量が70ピクセルを超えるか0.23秒未満の速い動きならハードドロップ、それ以外の下向きはソフトドロップとする。距離と速さの2つを組み合わせているのは、ゆっくり長く下げる動作と、すばやく払う動作を区別するためである。指が盤面の外へ出ても判定を続けられるよう、押した瞬間に操作の受け付け先を盤面へ固定する(setPointerCapture)。あわせて、画面下部に操作ボタンも置く。

タッチ操作をそのままにしておくと、下へスワイプしたときにページ全体が動いてしまう。盤面には touch-action: none を指定してブラウザの標準動作を止め、ボタンには touch-action: manipulation を指定して二度押しによる拡大を防ぐ。矢印キーやスペースキーによるスクロールも止める。操作をゲームに割り当てるときは、ブラウザが元々持っている動作を打ち消す作業がついてくる

成績はブラウザの localStorage に保存する(「3.4 簡易メモ帳」参照)。日時・結果・得点・消去列数・到達レベル・プレイ時間を1件にまとめ、新しい順に並べた配列を文字列(JSON)に変換して書き込む。31件目からは古いものを捨て、常に30件に保つ。読み込むときは、取り出した内容が本当に配列かどうかを確かめる。また、保存先の名前には形式の版番号を付けてある。保存する項目を増やしたとき、古い形式のデータを読み込んで誤作動するのを避けるためである。localStorageが使えない環境でも、理由を画面に出してゲーム本体は続行する。

想定外のエラーが起きたとき、何もしなければ画面が固まったように見える。本プログラムでは、ループの中身をtry-catchで囲み、さらにブラウザ全体の未処理エラー(error と unhandledrejection)も受け取るようにしてある。エラーを受け取ったら、ループを止め、状態を「エラー」に変え、内容を画面に表示する。プレイヤーは「開始画面へ戻る」ボタンで復帰できる。表示したエラーは、不具合の報告を受けたときの手がかりにもなる。

細かな点だが、成績表は文字列でHTMLを組み立てるのではなく、行とセルを1つずつ作る命令で組んでいる。文字列でHTMLを作る書き方は、入力内容によって意図しないタグが混ざる危険がある。日時や桁区切りの書式は標準の命令(Intl.DateTimeFormat、toLocaleString)に任せ、プログラム全体は1つの関数で包んで変数名の衝突を防いでいる。

落ちものブロックゲームのプログラム仕様書

以上を踏まえて、落ちものブロックゲーム「fallingBlocks.html」のプログラム仕様書を示す。これが Codex に渡すプロンプトそのものになる。

「4.3 ブロック崩し」の仕様書と比べると、ゲームのルールに関する記述が大幅に増えている。ブロックの形、出現順、回転時の処理、固定猶予、得点、レベルと落下速度と、決めごとを1つずつ書き出しているためである。ルールが複雑なゲームでは、この整理を省くとCodexが独自の解釈で作り始めてしまう
プログラム仕様書(プロンプト)
# 落ちものブロックゲーム

# 目標 プレイヤーは、画面上部から落下するブロックを左右移動・回転させて積み上げ、横一列を隙間なく埋めて消去する。ブロックが画面上部まで積み上がらないようにしながら、できるだけ多くの列を消して高得点を目指す。
# プログラム・ファイル名 fallingBlocks.html
# プロジェクト・フォルダ作成 - プログラム・ファイル名の拡張子を除いた主ファイル名と同じ名前のサブフォルダ「fallingBlocks」を作成し、以降の作業はサブフォルダで行う。 - すでにサブフォルダがあれば、そのサブフォルダに移動して以降の作業を進める。 - ユーザーが作成した既存ファイルや変更内容を、許可なく削除または上書きしない。
# ゲーム・ルール ## 勝敗条件 - ゲームクリア:合計30列を消去する。 - ゲームオーバー:新しいブロックを盤面内に配置できないほど、ブロックが画面上部まで積み上がる。 - 制限時間内に30列を消去できなかった場合もゲームオーバーとする。
## 盤面 - 盤面は横10マス、縦20マスとする。 - 盤面の上部中央付近から、ブロックを1個ずつ出現させる。 - 盤面の外へブロックを移動できないようにする。 - 盤面の床または固定済みブロックを突き抜けないようにする。
## ブロック 4個の正方形を組み合わせた、次の7種類のブロックを使用する。
```text I ■■■■
O ■■ ■■
T ■■■ ■
S ■■ ■■
Z ■■ ■■
J ■ ■■■
L ■ ■■■ ```
- ブロックごとに識別しやすい異なる色を割り当てる。 - 出現順は、7種類を1個ずつまとめてシャッフルする「7個バッグ方式」とする。 - 7個をすべて出現させたら、再び7種類をシャッフルする。 - 同じ種類だけが不自然に連続しないようにする。
## 基本的な挙動・メカニクス - 自動落下:操作中のブロックは一定時間ごとに1マス落下する。 - 左右移動:操作中のブロックを左右に1マスずつ移動できる。 - 回転:操作中のブロックを時計回りに90度回転できる。 - ソフトドロップ:下方向の操作中は通常より速く落下する。 - ハードドロップ:操作中のブロックを、着地可能な最下部まで即座に落下させる。 - 固定:ブロックが床または固定済みブロックの上に着地すると、その位置に固定する。 - 固定猶予:着地してから固定されるまで約0.5秒の猶予を設ける。 - 固定猶予中に左右移動または回転が成立した場合は、固定までの時間を再計算する。 - ライン消去:横一列の10マスがすべて埋まった場合、その列を消去する。 - 落下処理:列を消去した後、その列より上にあるブロックを消去した列数だけ下へ移動する。 - 複数ライン:一度に複数の列が完成した場合は、同時に消去する。 - 次ブロック:次に出現するブロックを画面に表示する。 - 最小構成とするため、ブロックのホールド機能、対戦機能、特殊ブロック、アイテムは実装しない。
## 回転時の処理 - 回転後にブロックが壁、床、または固定済みブロックと重なる場合、そのままでは回転させない。 - 回転できない場合は、左右に最大1マスずらして回転できるか確認する。 - 左右にずらしても配置できない場合は、回転前の状態へ戻す。 - O型ブロックは回転しても形状を変化させない。
## 得点 - 1列消去:100点 × 現在レベル - 2列同時消去:300点 × 現在レベル - 3列同時消去:500点 × 現在レベル - 4列同時消去:800点 × 現在レベル - ソフトドロップ:手動で1マス落下するごとに1点 - ハードドロップ:落下した距離1マスにつき2点 - 得点、消去した列数、現在レベルを常に画面へ表示する。
## レベルと落下速度 - ゲーム開始時はレベル1とする。 - 10列消去するごとにレベルを1つ上げる。 - レベル1では、約1秒ごとに1マス自動落下させる。 - レベルが上がるごとに、自動落下の間隔を短くする。 - レベルが上がっても、操作不能になるほど落下間隔を短くしない。 - レベルと落下間隔の関係を、プログラム内の定数として分かりやすく管理する。
# 制限時間 - 制限時間は3分(180秒)とする。 - 画面右下に残り時間を「分:秒」で表示する。 - 残り15秒以下では時間表示を赤色にする。 - 制限時間内に合計30列を消去するとゲームクリアとする。 - 制限時間内にクリアできなければゲームオーバーとする。 - 一時停止中は残り時間を減らさない。
# 操作方法 ## キーボード - Aキーまたは左矢印キー:ブロックを左へ1マス移動 - Dキーまたは右矢印キー:ブロックを右へ1マス移動 - Sキーまたは下矢印キー:ソフトドロップ - Wキー、上矢印キー、またはXキー:時計回りに90度回転 - Spaceキー:ハードドロップ - PキーまたはEscキー:一時停止/再開
## 画面タッチ - 盤面を左へスワイプ:ブロックを左へ移動 - 盤面を右へスワイプ:ブロックを右へ移動 - 盤面を下へ短くスワイプ:ソフトドロップ - 盤面を下へ大きく素早くスワイプ:ハードドロップ - 盤面をタップ:ブロックを時計回りに90度回転 - スマートフォン用に「左」「右」「回転」「下」「即落下」の画面ボタンも表示する。 - スワイプと画面ボタンのどちらでも操作できるようにする。 - タッチ操作中にブラウザ画面が意図せずスクロールしないようにする。
# 画面構成要素 ## ゲーム盤 - 画面中央に横10マス、縦20マスのゲーム盤を表示する。 - 各マスの境界が分かるように薄いグリッド線を表示する。 - 固定済みブロックと操作中のブロックを表示する。 - 盤面の縦横比を保ち、画面サイズに合わせて縮小する。
## 操作中ブロック - 現在プレイヤーが操作しているブロック。 - 左右移動、回転、ソフトドロップ、ハードドロップができる。
## 固定済みブロック - 着地して盤面に固定されたブロック。 - 横一列がすべて埋まると、その列を消去する。
## 次ブロック - 次に出現するブロックを盤面の横に表示する。 - スマートフォンの狭い画面では、盤面の上部または下部に表示する。
## ステータス表示 - 現在の得点 - 現在のレベル - 消去した列数 - クリアに必要な残り列数 - 残り時間
## 操作ボタン - スマートフォン向けに、十分な大きさのタッチ操作ボタンを配置する。 - ボタンを押したときに、視覚的な反応を表示する。 - ボタンがゲーム盤やステータス表示と重ならないようにする。
# 画面構成 - 画面中央:落ちものブロックゲームの盤面 - 盤面周辺:次ブロック、得点、レベル、消去列数 - 画面右下:残り時間 - 画面上部:タイトル、バージョン、著作権者、ライセンス - 画面下部:キーボードとタッチの操作方法 - スマートフォンの狭い画面でも操作できるレスポンシブ構成にする。 - ゲーム開始前に、ゲームの目的と主な操作方法を表示する。 - ゲーム開始前に「ゲーム開始」ボタンを表示する。 - ゲーム中に「一時停止」ボタンを表示する。 - ゲームクリア画面およびゲームオーバー画面には、今回の得点、消去列数、到達レベル、プレイ時間を表示する。 - ゲームクリア画面およびゲームオーバー画面には、それまでの成績を直近30回分表示する。 - 成績には、年月日時分、ゲームクリアまたはゲームオーバー、得点、消去列数、到達レベル、プレイ時間を含める。 - 成績が1画面に表示しきれない場合は、自動縦スクロールできるようにする。 - 結果画面の上段には「もう一度遊ぶ」「終了する」ボタンを常に表示する。 - 「終了する」ボタンを押した場合は、安全にゲームを停止して開始画面へ戻る。 - ブラウザのウィンドウやタブをプログラムから強制的に閉じない。
# データの記録 - ゲームの成績はブラウザのlocalStorageに保存する。 - 保存する成績は直近30回分とする。 - 31回目以降は、最も古い記録から削除する。 - localStorageを利用できない場合でもゲーム本体は続行できるようにする。 - localStorageを利用できない理由を画面へ表示する。 - 外部サーバーへ成績を送信しない。 - 個人情報を記録しない。
# エラー処理 - JavaScript実行中にシステムエラーが発生した場合は、ゲームのタイマーとアニメーションを停止し、処理を安全に終了する。 - エラー内容を、プレイヤーが確認できる形で画面に表示する。 - エラーが発生しても、ブラウザ全体が操作不能にならないようにする。 - 無効な入力やゲーム状態に合わない入力は受け付けない。 - 入力を受け付けなかった場合は、必要に応じて理由をメッセージで表示する。 - ゲーム開始前、ゲーム終了後、一時停止中は、ブロック操作を受け付けない。 - 同じゲームループやタイマーが重複して実行されないようにする。 - localStorageの読み書きで例外が発生した場合は、安全に処理を継続する。
# テスト観点・合格条件 - HTMLファイルをブラウザで直接開き、サーバーなしで動作すること。 - 横10マス、縦20マスの盤面が正しく表示されること。 - 7種類のブロックがすべて出現し、7個バッグ方式が正しく動作すること。 - ブロックを左右へ移動し、時計回りに回転できること。 - 壁、床、固定済みブロックを突き抜けないこと。 - ソフトドロップとハードドロップが正しく動作すること。 - 着地したブロックが固定されること。 - 横一列が埋まると、その列が消去されること。 - 1列から4列までの同時消去で、得点がルールどおり加算されること。 - 10列消去するごとにレベルが上がり、落下速度が速くなること。 - 合計30列を消去するとゲームクリアになること。 - 新しいブロックを配置できない場合にゲームオーバーになること。 - 制限時間が0になるとゲームオーバーになること。 - 残り15秒以下で時間表示が赤色になること。 - 一時停止中にブロックと制限時間が進まないこと。 - 「もう一度遊ぶ」で盤面、得点、レベル、消去列数、時間が初期化されること。 - 成績がlocalStorageへ保存され、直近30回分だけ表示されること。 - キーボード操作とタッチ操作の両方が動作すること。 - PCとスマートフォン相当の画面幅で、表示や操作部分が重ならないこと。 - JavaScriptの構文エラーや未処理の例外がないこと。 - インターネット通信が発生しないこと。 - Codexが可能な範囲でテスト用の内部状態またはデバッグ機能を利用し、ゲームクリアとゲームオーバーを含む合計5回のプレイテストを行うこと。 - テストのために追加したデバッグ機能は、配布版では無効化または削除すること。 - 前提条件および制約条件が守られていること。 - テスト結果を、実施内容、期待結果、実際の結果、合否が分かる形式でユーザーに報告すること。 - 実際に確認できなかった項目を「合格」と推測して報告しないこと。
# 前提条件 - タイトルは「落ちものブロックゲーム」とする。 - バージョン番号、著作権者、MIT Licenseであることを画面に表示する。 - 仕様で分からないことがあり、その違いが実装結果へ大きく影響する場合は、ユーザーに質問すること。 - 安全かつ合理的に判断できる軽微な事項は、判断内容を明記して作業を進めること。 - HTML、CSS、JavaScriptを1つのHTMLファイルに記述すること。 - JavaScriptを使った1本のプログラム・ファイルにすること。 - クライアントPCのブラウザで動作すること。OSやブラウザの種類は問わない。 - スマートフォンでも利用できること。 - HTTPサーバーやNode.jsなどのサーバー技術は使用せず、ブラウザの機能だけで完結すること。 - Canvas APIまたはHTML要素を利用してゲーム画面を描画すること。 - コーディングは「Airbnb JavaScript Style Guide」に可能な限り準拠すること。 - 実装上、ブラウザ環境や単一HTMLファイルという条件と競合する規則がある場合は、その理由をコメントまたはREADME.txtに記載すること。 - プログラムファイルにコメントとして、プログラムの名称、バージョン、目的、動作環境、著作権表示および使用条件、インストール方法、お問い合わせを記載すること。 - ゲーム名、画面デザイン、説明文は独自のものとし、第三者の商標、画像、音声、プログラムコードを無断で使用しないこと。 - 外部の画像、フォント、音声などの素材を使用せず、必要な表示はHTML、CSS、JavaScriptで作成すること。
# 制約条件 - インターネットとのデータ送受信は行わないこと。 - CDNを含む外部ライブラリは使用せず、標準のHTML、CSS、JavaScriptだけで実装すること。 - 外部画像、外部フォント、外部音声、アクセス解析、広告、Cookieを使用しないこと。 - プログラムがMIT Licenseおよび第三者の権利に違反していないこと。 - ユーザーの許可なく、プロジェクトフォルダ外のファイルを変更しないこと。 - ユーザーの許可なく既存ファイルを削除しないこと。 - Gitの履歴を破壊する操作を行わないこと。
# 合格判定 - すべての実装とテストが完了したら、テスト結果を一覧で表示する。 - 合格項目、不合格項目、未確認項目を明確に区別する。 - 不合格項目がある場合は、原因と修正方針を表示する。 - 未確認項目がある場合は、未確認の理由とユーザーによる確認方法を表示する。 - テスト結果を表示した後、合格としてよいかユーザーに質問する。 - ユーザーが合格と回答するまでは、Gitへの最終コミットと配布用ZIPファイルの作成を行わない。 - ユーザーが不合格と回答した場合は、指摘内容を修正して再テストする。
# 簡易取扱説明書の作成 1)HTMLファイルと同じ場所に、簡易取扱説明書「README.txt」を作成する。 2)説明書には、各項目を「# 項目名」と表記して次を含める。 - プログラムの名称 - バージョン - 目的 - ゲーム・ルール - 動作環境 - 著作権表示および使用条件 - インストール方法 - 使い方 - 操作方法 - 成績の保存 - 既知の制限 - 変更履歴 - お問い合わせ 3)インストール方法には、ZIPファイルを展開し、fallingBlocks.htmlをブラウザで直接開く手順を記載する。 4)使い方には、ゲーム開始、一時停止、再開、再プレイ、終了の手順を記載する。 5)キーボード操作と画面タッチ操作を両方記載する。
# 著作権表示および使用条件 このプログラムは OpenAI社の Codex によって作成し、作者が動作を確認しました。 このプログラムは外部とのデータ通信を行いません。
本アプリケーションはMIT Licenseです。 商用を含む無償利用が可能です。自由に改造できます。 再配布の際は、下記の著作権表記、URLおよび本使用条件を必ず明記してください。
Copyright by (c)studio pahoo https://www.pahoo.org/
MITライセンスについては、下記のリンク先を参考にしてください。 http://ja.wikipedia.org/wiki/MIT_License http://www.opensource.org/licenses/mit-license.php
なお、本アプリケーションの利用または改造によって生じた得失については一切関知いたしません。また、二次利用先の組織・企業・団体の目的・内容・活動については一切関知いたしません。
# お問い合わせ ぱふぅ家のホームページ https://www.pahoo.org/
- サイト案内 - お問い合わせ
# プロジェクト・プロンプトの保存 - このプロンプトを、プロジェクトフォルダ内の「PROMPT.md」に保存する。 - 実装中にユーザーと合意して仕様を変更した場合は、PROMPT.mdにも変更内容を反映する。 - PROMPT.mdに記載されたバージョン番号と、プログラムおよびREADME.txtのバージョン番号を一致させる。
# リソース管理 1)作業開始前に、今回の作業が次のどれに該当するかユーザーに質問する。 - 新規作成(評価用) - 新規作成(配布用) - メジャーバージョンアップ - マイナーバージョンアップ - 不具合修正 2)回答に従い、バージョン番号を次のルールで決定する。 - 新規作成(評価用):バージョン0.1.0 - 新規作成(配布用):バージョン1.0.0 - メジャーバージョンアップ:現在のバージョン番号の整数部分を1増やし、小数部分を0にする。 - マイナーバージョンアップ:現在のバージョン番号の小数第1位を1増やし、それより下の桁を0にする。 - 不具合修正:現在のバージョン番号の小数第2位を1増やす。 3)バージョンアップの場合は、既存のバージョン番号をプログラムファイル、README.txt、PROMPT.mdまたはGit履歴から確認する。 4)既存のバージョン番号を確認できない場合は、推測せずユーザーに質問する。 5)決定したバージョン番号を、fallingBlocks.html、README.txt、PROMPT.md、ゲーム画面、配布用ZIPファイル名のすべてに反映する。 6)ユーザーがテスト結果を合格と判定した後、fallingBlocks.html、README.txt、PROMPT.mdをGitへコミットする。 7)Gitリポジトリが存在しない場合やコミットできない場合は、勝手に新規リポジトリを作成せず、理由をユーザーに報告して指示を求める。 8)コミットメッセージには、プログラム名、バージョン番号、変更区分が分かる内容を使用する。
# 配布ファイルの作成 1)ユーザーがテスト結果を合格と判定した後、次の3ファイルを1つのZIPファイルに圧縮する。 - fallingBlocks.html - README.txt - PROMPT.md 2)ZIPファイル名は「fallingBlocks_バージョン番号.zip」とする。 例: ```text fallingBlocks_0.1.0.zip fallingBlocks_1.0.0.zip ``` 3)ZIPファイル内に一時ファイル、テスト用ファイル、Git管理ファイル、デバッグ専用ファイルを含めない。 4)ZIPファイルを作成した後、内容物とファイル名が正しいことを確認する。 5)完了後、作成したZIPファイルの絶対パスをユーザーに伝える。
「## 回転時の処理」に壁蹴りの手順を、「## 基本的な挙動・メカニクス」に固定猶予とライン消去の扱いを、「## レベルと落下速度」に速度の管理方法を書き込んである。「# テスト観点・合格条件」には、実際に確認できなかった項目を「合格」と推測して報告しないことという一文を入れた。ゲームの結末を確かめるには何度もプレイする必要があり、この一文がないとCodexは推測で合格と報告してくることがある。
完成した落ちものブロックゲームの画面
完成した落ちものブロックゲームの画面
AI生成コンテンツ / AI-generated contents

参考サイト

(この項おわり)
header