step0:星空を飛ぶ宇宙船
160×120 ドットの黒いウィンドウが開き、タイトルバーに Star Voyager と
表示される。Esc キーで閉じられる。ここまでを 11 行で作ります。
Pyxel のアプリは、次の 3 つの部品を用意して Pyxel に渡す、という形で作ります。 自分で「ずっと繰り返す」ループを書く必要はありません。繰り返しは Pyxel 側が面倒を見てくれます。
| 部品 | 役割 | 呼ばれる回数 |
|---|---|---|
| 画面の準備 | ウィンドウの大きさとタイトルを決める | 最初に 1 回だけ |
更新(update) | 座標を変える・キー入力を調べる。描画はしない | 1 秒間に 30 回 |
描画(draw) | 画面を描き直す。状態は変えない | 1 秒間に 30 回 |
このフェーズでは update にはまだ何もさせず、draw で
画面を黒く塗りつぶすだけ にします。
Pyxel の画面は、前のフレームに描いた絵がそのまま残り続けます。
消さずに描き続けると、動くものが軌跡を引いて汚れていきます。
そこで毎フレームの描画のいちばん最初に画面全体を塗りつぶして、
まっさらな状態から描き直します。これが cls(clear screen=画面消去)です。
| API | 意味 |
|---|---|
pyxel.init(width, height, title) |
画面を width×height ドットで用意する。title はウィンドウのタイトルバーに出る文字(省略時は "Pyxel") |
pyxel.run(update, draw) |
ゲームループを開始する。以降 1 秒間に 30 回、update → draw の順で呼び続ける |
pyxel.cls(col) |
画面全体を色番号 col で塗りつぶす。0 は黒 |
pyxel.init や pyxel.cls のように、pyxel. に続けて書きます。
プロジェクト直下に step0 フォルダを作り、その中に
star_voyager.py という名前で保存してください。
# star_voyager.py
# step0 フェーズ1:ウィンドウを出して、黒い画面を表示する
import pyxel
def update():
"""毎フレームの更新処理。このフェーズではまだ何もしない"""
pass
def draw():
"""毎フレームの描画処理"""
pyxel.cls(0) # 画面全体を色番号 0(黒)で塗りつぶす
pyxel.init(160, 120, title="Star Voyager") # 画面を用意する
pyxel.run(update, draw) # ゲームループを開始する
VS Code のターミナルで、プロジェクト直下から次を実行します。
python step0/star_voyager.py
Star Voyager と出ているEsc キーで閉じられる4 つとも確認できたらフェーズ 1 は完了です。
import pyxel
Pyxel のモジュールを読み込みます。これ以降 pyxel.〇〇 の形で
Pyxel の命令が使えるようになります。
def update(): と def draw():
更新用・描画用の関数を定義しています。ここではまだ定義しただけで、実行はされません。
実際に呼ぶのは Pyxel の役目です(後述の pyxel.run)。
"""毎フレームの更新処理。..."""
関数の直後に置いた文字列は docstring(説明文) と呼ばれ、
「この関数が何をするか」を書き残すためのものです。動作には影響しません。
コメント(#)と役割は似ていますが、docstring は関数の説明という決まった位置に置きます。
pass「何もしない」ことを表す文です。Python では関数の中身を空っぽにするとエラーになるので、 中身がまだ無いことを明示するために置きます。フェーズ 3 で中身を書いたら消します。
pyxel.cls(0)
画面全体を色番号 0(黒)で塗りつぶします。Pyxel の色は
#RRGGBB ではなく 0〜15 の番号で指定します。用意されているのは次の 16 色だけです。
pyxel.COLOR_YELLOW のように名前でも書けます(10 と同じ意味)pyxel.init(160, 120, title="Star Voyager")画面を横 160 ドット・縦 120 ドットで用意します。実際のウィンドウは 画面の大きさに合わせて自動で何倍かに拡大表示されます。
title="Star Voyager" のように 名前を書いて渡す 書き方を
キーワード引数と呼びます。init には title のほかにも
fps など省略可能な引数がいくつもあり、順番で渡すと分かりにくいため、
名前で指定します。省略した引数は既定値(fps なら 30)が使われます。
pyxel.run(update, draw) — このフェーズいちばんの新概念update() ではなく update と書く(カッコを付けない)
ここを pyxel.run(update(), draw()) と書くとエラーになります。
Python では、関数名をカッコ付きで書くと「今すぐ実行して、その結果を使う」意味になります。 一方、カッコなしで書くと「その関数そのもの」を指します。 関数は数値や文字列と同じように変数として持ち運べるのです。
pyxel.run は渡された関数を Pyxel 側が毎フレーム呼ぶための仕組みなので、
関数そのもの(カッコなし)を渡します。
なお pyxel.run はそこで止まったままになり、ウィンドウを閉じるまで
次の行には進みません。だから run はいつもいちばん最後に書きます。
コードを少し書き換えて、動きが変わることを確かめてみてください。
| 変える場所 | 変えてみる値 | どうなるか |
|---|---|---|
pyxel.cls(0) | pyxel.cls(1) や pyxel.cls(8) | 画面の色が変わる(上のパレット図と見比べる) |
pyxel.init(160, 120, ...) | pyxel.init(256, 256, ...) | ウィンドウの大きさと形が変わる |
title="Star Voyager" | 好きな文字列 | タイトルバーの表示が変わる |
確認できたら、値は元に戻しておいてください(160, 120 と cls(0))。
| 症状 | 原因と対処 |
|---|---|
ModuleNotFoundError: No module named 'pyxel' |
Pyxel が入っていないか、別の Python から実行している。pip install pyxel を実行する |
can't open file ...star_voyager.py |
実行しているフォルダが違う。VS Code のターミナルがプロジェクト直下(learning_pyxel)にいるか確認する |
IndentationError |
関数の中身のインデント(字下げ)がずれている。def の次の行は半角スペース 4 つ下げる |
| ウィンドウが一瞬で閉じる | pyxel.run(update, draw) の行が抜けている可能性が高い |
| ウィンドウが固まって閉じない | ターミナルで Ctrl + C を押す |
pyxel.text でタイトル文字を表示します。