ゲームエンジンPyxelでは、画像を読み込む場合に以下の方法があります。(※何もファイル名は例です)
pyxel.load("my_resource.pyxres")を使うpyxel.images[x].load("image.png")を使う
今回は、この2つの共存をテーマに、Pyxelで画像を画面に描画する際のちょっとしたテクニックを解説します。
pyxel.images.load関数はpyxresの画像バンクを上書きする
今更ながら、pyxel.images[x].load(【画像ファイルのパス】)(※xは0-2) で、画像をPyxelフォーマットに強制変換して取り込むことができることを知り、活用していました。
が、これ、pyxel.images[x].load()を実行すると、事前にロードしていたpyxresのイメージバンク[x]のグラフィックが上書きされて消えてしまう」という問題がありました。
そこで、この問題を解消する方法を調べたので共有します。
pyxel.Imageインスタンスを個別に生成して対応する
この問題は、標準の画像バンク(pyxel.images[0]など)に依存せず、独立したpyxel.Imageインスタンスを自前で作成することで解決できます。
(※pyxel.ImageはPyxelが画像データを保持するためのクラス)
具体的には、以下の手順で実装します。
- pyxel.Imageクラスのインスタンスを新規作成する。
- そのインスタンスに対してloadを実行する。
- 描画時にblt関数の第一引数として、作成したインスタンスを指定する。
実装サンプル
import pyxel
# 1. 独立したImageインスタンスを作成
# 画像サイズに合わせてImageを作成
my_image = pyxel.Image(128, 128)
# 2. 作成したインスタンスに画像をロード
my_image.load(0, 0, "assets/extra_graphic.png")
def draw():
pyxel.cls(0)
# 3. bltで作成したインスタンスを描画対象に指定
# (x, y, image_obj, u, v, w, h, colkey)
pyxel.blt(10, 10, my_image, 0, 0, 128, 128)
pyxel.init(160, 120)
pyxel.run(None, draw)
pyxel.blt関数の第三引数はイメージバンクの番号だけでなく、Imageクラスのインスタンスを指定することもできるんですね。
この方法であれば、pyxresで読み込んでいる既存のリソースに一切影響を与えることなく、新しい画像を画面上に配置することができます。
画像バンクの制限からの解放
この手法最大のメリットは、pyxresの画像を壊さずに画像ファイルを追加ロードできるという点です。
通常、Pyxelの描画はpyxel.imagesというバンク配列を介して行われますが、この方法を使えば、メモリが許す限りいくらでもpyxel.Imageオブジェクトを生成して保持しておくことが可能です。
- 動的なリソース管理: シーンごとに必要な画像だけをメモリにロードする。
- メモリ効率の最適化: 巨大な一枚絵をバンクに詰め込む必要がなくなる。
- リソース管理の分離: pyxresにはUIやキャラを、外部画像には背景や特殊エフェクトを、といった切り分けが容易になる。
まとめ
pyxel.Imageを直接インスタンス化する手法は、pyresをベースにしつつ、必要な画像は後から読み込めるため、画像管理の自由度が大きく向上します。
pyxresの枠組みに縛られず、より柔軟な画像管理を取り入れることで、Pyxel開発の幅はぐっと広がります。ぜひ試してみてください。