015 穴あき風船 — 段階式チュートリアル

Python 3.11以上 / Pyxel==2.9.9

5本はそれぞれ独立した完全な1ファイルです。他の段階、原作model.py、画像、フォントは不要。
01_thrust.py      噴射・斜め正規化・惰性
02_air.py         漏れ・消費・端数噴射・浮力
03_wind_walls.py  旧位置の二層風・連続衝突・網と尖り
04_refill.py      低速接続・給気・チェックポイント再開
05_landing.py     連続した低速着陸・任意の紙・原作3航路

まずLESSON.mdを読み、01から順に進めてください。
lessons.jsonは本文・実コード抜粋・確認・練習の構造化版。
lesson_meta.jsonは操作と原作との差、diffs/は実ファイル間の完全差分です。

起動例
Windows:
  python -m venv .venv
  .venv\Scripts\python -m pip install -r requirements.txt
  .venv\Scripts\python 01_thrust.py
macOS/Linux:
  python3 -m venv .venv
  .venv/bin/python -m pip install -r requirements.txt
  .venv/bin/python 01_thrust.py
すでにPyxel導入済みなら python 01_thrust.py。
これは利用者向け手順で、今回のQAで追加インストールは行っていません。

操作
矢印: 押しっぱなしで噴射、離すと惰性。反対方向同時は相殺。
P: 停止／復帰（その更新は進めない）。R: 全初期化。Esc: 終了。
03以降の1/2/3: 航路を選んで初期化。03/04の初期選択は航路2。
04/05のSPACE: 給気口へ接続／離脱。押した瞬間だけ判定。
04/05の失敗後Z: 最後の給気口へ戻す。時間・消費などは保持。
05の成功後N: 次の航路へ。

重要な数値
DT=1/120秒×4step、表示30 FPS。速度はpx/s、下が+y。
漏れ0.5/s、噴射6/s、加速度90、重力65、浮力は消費後air。
速度上限55、接触半径7は一定。独立の質量・気体密度の式はありません。
接続: 距離12以下かつ速さ15以下。給気35/s、上限100。
着陸: 距離14以下かつ速さ18以下を連続0.4シミュレーション秒。
紙は任意。空気0は即死ではなく、網や尖りで失敗。
01/02のみ練習用の外枠。03以降は原作の膨張AABBの衝突近似。
一般的な現実の風船物理や、厳密な円対箱の衝突ではありません。

検査
  python -B test_stages.py
標準ライブラリだけで動きます。原作比較4件は原作未指定なら理由付きskip。
原作がある場合はPYXEL015_ORIGINAL_DIRにそのフォルダの絶対パスを設定。
Pyxel導入済みの環境で:
  python -B qa/render_check.py
全段階の初期、自動チェックポイント、改名した単体ファイルの実描画を再生成。
単体コピーは日本語と空白を含むフォルダへ置き、PNGと状態JSONを比較します。
--headless-smokeと--demo-checkpointは自動QA用で、人のプレイではありません。
初期QA画像は状態を静止表示します。通常起動ではモデルは更新されます。
QAフラグはPyxel import前に検査し、フレーム数を最大600に制限します。
Linux自動検証ではSDL_AUDIODRIVER=dummy。音を聴く検査は行っていません。

配布物の確認
  python -B qa/verify_freeze.py
ファイル集合とSHA-256を確認。改造・再生成は教材のコピーで行ってください。
テスト記録と画像、環境・未確認事項はqa/REVIEW.mdを参照。
原作ソースは読み取りのみ。本教材はSiteや原作の公開・変更を行っていません。

ライセンス
LICENSE.txtは原作の原文、LICENSEは同一バイトの別名。
5本のコードにも原文全文を保持。参照されたNotoのOFLはassets/NOTO-LICENSE.txt。
実行には字形ファイルを使いません。
