お化けに捕まらずに、どれだけお菓子を集められるか
男の子を矢印キーで動かし、画面に出てくるお菓子を拾い集めます。お化けが男の子を追いかけてきて、 触れられたらゲームオーバー。集めたお菓子の数がそのままスコアです。 お菓子を集めるほどお化けが増えていくので、後半になるほど逃げ場がなくなります。
| 項目 | 内容 |
|---|---|
| 画面サイズ | 160 × 120 ドット(step0 と同じ) |
| 操作 | 矢印キーで上下左右に移動。Enter でゲーム開始・再挑戦 |
| スコア | 集めたお菓子の数。画面左上に表示する |
| 終了条件 | お化けに触れられたらゲームオーバー(制限時間はなし) |
| 難易度 | お菓子 5 個ごとにお化けが 1 体増える(最大 4 体) |
| 画面 | タイトル/ゲーム/ゲームオーバーの 3 画面 |
完成までを 10 のフェーズに分けます。上から順に、少しずつ書き足していきます。 解説ページは、フェーズを進めるたびに追加していきます。
| フェーズ | やること | 主に使う API・機能 |
|---|---|---|
| 1 | リソースエディタで 3 つのドット絵を描く 男の子・お化け・お菓子を描き、画面に出して確かめる | pyxel edit、イメージバンク、.pyxres |
| 2 | 画面を出して、男の子を矢印キーで動かす step0 の復習にあたる土台づくり | pyxel.init / run / cls / blt / btn |
| 3 | お菓子を 1 個置き、重なったら消して次を出す この step の山場のひとつ | 当たり判定、random、関数の戻り値 |
| 4 | 集めた数をスコアとして画面に表示する | pyxel.text、カウント用の変数 |
| 5 | お化けを 1 体出して、男の子を追いかけさせる | 相対位置による場合分け |
| 6 | お化けに捕まったらゲームオーバー画面へ | 状態変数、シーンごとの処理の振り分け |
| 7 | タイトル画面を足して 3 画面にする もう一度あそべるようにする | 画面遷移の完成、ゲームの初期化 |
| 8 | お菓子を集めるほどお化けを増やす(最大 4 体) | リストで複数を管理、繰り返しで当たり判定 |
| 9 | 効果音と BGM をつける | pyxel.play / playm、サウンド編集 |
| 10 | パッケージ化して Web で公開する | pyxel package / pyxel app2html |
step0 が「Pyxel の機能を広く浅く体験する」だったのに対し、step1 は 「ゲームとして成立させるための仕組み」を学びます。 描画やキー入力は step0 で身につけたものをそのまま使い、新しいのは次の 4 つが柱です。
| 分類 | 項目 | 登場フェーズ |
|---|---|---|
| 当たり判定 | 四角どうしの重なりを調べる(横と縦の 2 方向で見る) | 3・6 |
| 判定する範囲を絵の見た目より小さくして、遊びやすくする | 6 | |
| ゲーム進行 | 状態変数による画面遷移(タイトル/ゲーム/ゲームオーバー) | 6・7 |
| ゲームの初期化と、もう一度あそべるようにする処理 | 7 | |
| 敵の動き | 相対位置で場合分けして追いかける | 5 |
| 難易度を段階的に上げる(数を増やす) | 8 | |
| データの持ち方 | リストで同じものを複数まとめて管理する | 8 |
| 繰り返しで、全員ぶんの移動と当たり判定を回す | 8 | |
| 画面表示 | スコアの表示(HUD) | 4 |
| 複数のドット絵を 1 つのイメージバンクに並べて使い分ける | 1・2 | |
| サウンド | 効果音の再生(pyxel.play)と BGM の使い分け | 9 |
| 公開 | パッケージ化と Web 公開(step0 の復習) | 10 |
step0 でクラスと二次元リストを扱いました。step1 ではさらに次の 3 つが登場します。 出てきたフェーズで、必要になった理由とセットで解説します。
| 概念 | なぜ必要になるか | 登場フェーズ |
|---|---|---|
| 関数が値を返す ( return と真偽値) |
「当たっているか」を調べる処理は、何度も別の場所から呼びたくなります。
結果を True / False で持ち帰る書き方を覚えると、
if の条件がそのまま日本語のように読めるようになります。 |
3 |
| 定数で「状態」を表す | 画面が 3 つに増えると scene == 1 のような数字では意味が読み取れません。
SCENE_TITLE = 0 のように名前を付けて扱います。 |
6 |
| リストの要素を安全に取り除く | お化けやお菓子を複数持つと、「繰り返しの最中にリストから消す」場面が出てきます。 step0 の復習作品で使った「残すものだけ新しいリストに詰め直す」書き方を、あらためて整理します。 | 8 |
「男の子とお菓子が重なったか」を一度に考えようとすると難しく感じますが、 横だけ・縦だけに分けると、どちらもただの数直線の問題になります。 そして横も縦も重なっているときだけ、2 つの四角は本当に重なっています。
四角の位置は左上の座標で持っているので、たとえば横の範囲は
「左端 = x」から「右端 = x + 幅」までです。
2 つの範囲が重なっている条件は、次の 2 つが同時に成り立つことだと言いかえられます。
縦もまったく同じ形になります。この 4 つの条件をすべて満たしたときが「当たり」です。 実際のコードはフェーズ 3 で書きます。
step0 の作品は画面が 1 つだけでした。step1 ではタイトル・ゲーム・ゲームオーバーの 3 つを 行き来します。このとき、画面ごとに別のプログラムを作るのではなく、 「今どの画面か」を覚えておく変数を 1 つ用意するのが定石です。
scene の値を書き換えることが、そのまま画面の切り替えになる
毎フレーム呼ばれる update() と draw() は、どちらも最初に
「今どの画面か」で処理を振り分けます。タイトル画面なら、動かすものは何もなく、
タイトル文字を描くだけ。ゲーム画面なら、男の子とお化けを動かして当たり判定をする、という具合です。
scene を書き換えるだけで、次のフレームから
update() も draw() も自動的にゲームオーバー画面のふるまいに変わります。