荷物を押して所定の位置へ運ぶ。10 ステージすべてを解く
プレイヤーを矢印キーで動かし、荷物を押して、すべてのゴールに乗せると 1 ステージクリアです。 荷物は押すことしかできません(引けません)。壁ぎわに押しつけてしまうと二度と動かせなくなるので、 動かす前に考えるのがこのゲームの面白さです。
全 10 ステージ。最初のステージは荷物 1 個から始まり、だんだん難しくなります。
詰んでしまったときは、R で最初からやり直します。
1 手戻す(アンドゥ)はあえて付けません。
気軽に戻せてしまうと、押す前に一手先を読むというこのゲームのいちばんの面白さが薄れるからです。
主人公は向いている方向の絵になり、歩くときは足踏みしながら隣のマスへすべっていきます。 盤面そのものは静かなゲームで、動くのは主人公と荷物だけ——だからこそ、そこは丁寧に作り込みます。
そして今回は スマホでも遊べるようにします。Pyxel の Web 版はタッチ端末で開くと 画面の下に十字キーとボタンを自動で出してくれるので、コード側は 「キーボードも、その画面ボタンも、どちらも見る」ようにしておくだけで済みます。
| 項目 | 内容 |
|---|---|
| 画面サイズ | 160 × 120 ドット(step0・step1 と同じ) |
| 1 マスの大きさ | 8 × 8 ドット。盤面は最大 18 × 12 マスまで置ける |
| 操作(PC) | 矢印キーで移動・荷物を押す / R でやり直し /
Enter で決定 |
| 操作(スマホ) | 画面下の十字キーで移動 / B ボタンでやり直し / A ボタンで決定。Pyxel がタッチ端末に自動で出す仮想ゲームパッドを使う |
| 主人公の表示 | 4 方向 × 2 コマのドット絵。歩くときは隣のマスへ 8 フレームかけてなめらかにすべる |
| やり直し | R(スマホは B ボタン)でステージの最初から。
1 手戻す機能はなし |
| クリア条件 | すべての荷物がゴールに乗ること。制限時間や手数制限はなし |
| ステージ数 | 10。番号順に進む。クリアしたステージは選び直せる |
| 画面 | タイトル/ステージ選択/プレイ/ステージクリア/全ステージクリアの 5 画面 |
| 表示 | ステージ番号と手数(画面の上) |
update() でやることが
「キーが押されたか」を見るだけになり、ぬるぬる動く処理がなくなります。
そのぶん、「動かしていいかどうかの判断」が中身の主役になります。
解説ページは、フェーズを進めるたびに追加していきます。
| フェーズ | やること | 主に使う技術 |
|---|---|---|
| 1 | タイルの絵を描き、ステージを画面に並べる 壁・床・荷物・ゴールと、主人公の絵 1 枚を描き、地図のとおりに置く |
二次元リスト、マス目とドットの変換、二重ループ |
| 2 | プレイヤーを矢印キーで動かす 壁にぶつかったら動かない。主人公の残り 3 枚を描いて、向いた方向の絵にする |
動かす前に行き先を調べる、btnp、タプル |
| 3 | 荷物を押す 押した先が空いているときだけ、荷物ごと動く。荷物とゴールを 2 組に増やす |
2 マス先まで見る、リストの中身を書き換える |
| 4 | 歩くアニメを入れる(step2 で追加した内容) 足踏みの 2 コマ目 4 枚を描き、隣のマスへ 8 フレームかけてすべらせて歩かせる。 押した荷物も一緒にすべる |
マス目の位置と見た目の位置を分ける、途中の位置の計算、
btnp から btn への切り替え |
| 5 | クリア判定と、やり直し 全部の荷物がゴールに乗ったらクリア。 R で最初から。
ゴールに乗った荷物の絵を 1 枚描き足す |
all()、リストのコピー(浅いコピーの落とし穴)、透過色の選び方 |
| 6 | ステージを 10 個にする クリアしたら Enter で次のステージへ。10 個ぜんぶで全クリア。
ステージの作り方と、解けるかどうかを調べる検算ツールも |
ステージ一覧の持ち方、進行状態の管理、len()、早い return |
| 7 | タイトル画面とステージ選択 | 画面遷移(step1 の復習)、カーソルの移動 |
| 8 | 手数の表示とクリア演出 ステージ番号・手数を出し、クリアの瞬間に間をつくる |
HUD、frame_count による演出 |
| 9 | 効果音と BGM をつける | play / playm(step1 の復習) |
| 10 | スマホで遊べるようにする(step2 で追加した内容) 仮想ゲームパッドの十字キーとボタンも受け付ける。 試しにパッケージして、自分のスマホで実際に動かして確かめる |
GAMEPAD1_BUTTON_*、入力の判定を自分の関数にまとめる |
| 11 | パッケージ化して Web で公開する | pyxel package / app2html(step1 の復習) |
step1 が「ゲームとして成立させるための仕組み」だったのに対し、step2 は 「データでゲームを作る」のが柱です。 ステージを増やすのに、コードを書き足さない—— 地図のデータを 1 つ足すだけでステージが増える、という形を目指します。
| 分類 | 項目 | 登場フェーズ |
|---|---|---|
| データの持ち方 | 二次元リストで盤面を持つ(stage[y][x]) | 1 |
| ステージを「文字の地図」で書き、読んで組み立てる | 1 | |
| 10 個のステージをまとめて持ち、番号で取り出す | 6 | |
| 座標 | マス目の座標とドットの座標を行き来する | 1 |
位置やずれを (x, y) の組(タプル)として扱う | 2・3 | |
| マス目の位置と、画面に見えている位置を別々に持つ | 4 | |
| 移動の判定 | 動かす前に、行き先を調べる(壁なら動かない) | 2 |
| 2 マス先まで見る(荷物を押せるかどうか) | 3 | |
| 絵とアニメーション | 向きを覚えて、絵を差し替える(4 方向) | 2 |
| 出発マスと行き先のあいだを、少しずつ埋める | 4 | |
| 足踏みのコマ替えと、歩いている間は次の入力を待たせる | 4 | |
| 状態の管理 | すべての荷物がゴールに乗ったかを調べる | 5 |
| 初期状態を保存しておき、いつでも戻す | 5 | |
| ゲーム進行 | ステージを順に進める/全クリア | 6 |
| タイトルとステージ選択(step1 の画面遷移の応用) | 7 | |
| 画面表示 | ステージ番号・手数の表示、クリア演出 | 8 |
| サウンド | 押す音・ゴールに乗った音・クリア音(step1 の復習) | 9 |
| スマホ対応 | 仮想ゲームパッドのボタンを受け取る(GAMEPAD1_BUTTON_*) | 10 |
| キーとボタンの判定を自分の関数にまとめる | 10 | |
| 公開 | パッケージ化と Web 公開(step1 の復習) | 11 |
| 概念 | なぜ必要になるか | 登場フェーズ |
|---|---|---|
| 二次元リスト (リストの中のリスト) |
盤面は「縦にも横にも広がる表」です。1 本のリストでは扱いにくいので、
行のリストを、さらにリストで束ねます。
stage[y][x] と縦が先になる理由も、ここで理解します。 |
1 |
| リストのコピーは「参照」 | R でやり直すには、始めの盤面を取っておく必要があります。
ところが backup = stage と書いても控えになりません。
片方を書き換えると両方変わります。
step2 でいちばん引っかかりやすいところです。 |
5 |
all() で「全部そろったか」 |
「すべての荷物がゴールに乗ったか」は、
for と旗(フラグ)でも書けますが、all() を使うと
1 行で、読んだとおりの意味になります。 |
5 |
タプル (x, y) |
位置は2 つの数がいつも一組で動きます。
別々の変数で持つと引数が増えて散らかるので、組にしてまとめます。
向き(上下左右)も (-1, 0) のような組で表しておくと、
4 方向ぶんの処理が 1 本のコードで書けます。 |
3・4 |
| 「いま動いている途中」を 変数で覚えておく |
歩くアニメの 8 フレームのあいだ、プログラムは「いま移動中である」ことを 覚えていないといけません。数えるための変数(タイマー)を 1 つ持ち、 0 なら止まっている・0 でなければ歩いている途中と決めます。 状態を数で表すという、ゲームでいちばんよく使う考え方です。 | 4 |
scene による振り分け)、btnp の使い分け、
frame_count を使った演出の間、チャンネルを分けた効果音、
pyxel package での公開——これらは新しく学び直しません。
step2 で頭を使うのは、データの持ち方と、動かす前の判断の 2 つに集中します。
step1 では、男の子の位置はドットの座標(boy_x = 76 など)でした。
倉庫番ではマス目の座標(左から 3 番目、上から 1 番目)で考えます。
「3 番目のマス」なら、壁があるかどうかを表から一発で引けるからです。
stage[y][x] の順番は、慣れるまで必ず一度は間違えます。「行を選んでから、その中の列を選ぶ」と覚えます"#########" ← stage[0]
"#..O....#" ← stage[1]
"#..$....#" ← stage[2]
まず何行目かを選び、その行の中で何文字目かを選ぶ——
この順番がそのまま stage[y][x] になります。
step1 の当たり判定は「動かしたあとで、重なっていないか」を見ていました。 倉庫番は逆で、「動かす前に、動いていいか」を調べます。 めり込んでから直すのではなく、そもそも動かさないわけです。
調べるのはすぐ前のマスと、荷物があったときのその 1 つ先——最大 2 マスです。
R(やり直し)を、いつでも押せるようにしておきます。歩くアニメを入れると、「盤面の上でどのマスにいるか」と「画面のどこに描かれているか」がずれます。 キーを押したその瞬間に、盤面の上ではもう隣のマスに着いています。 壁の判定もクリア判定も、その新しいマスで行われます。あとから追いつくのは、絵だけです。