見出し画像

[Pyxel] 利用できる画像を増やす

Pyxelでゲームを作っている時によくある悩みだと思うんですが…

「もうちょっと大きい画像使いたいな・・・」
「画像3枚に収まらない!せめてあと1枚・・・」

出典:Pyxel始めた頃の私

これ、実はPyxelの”制限”じゃなくて”標準設定”なんですよね。
何が言いたいかというと、大きい画像も画像枚数も、解決出来ます。


pyxel.images

images
イメージバンク (Imageクラスのインスタンス) のリスト (0-2)


list[Image]
記述例
pyxel.images[0].load(0, 0, "title.png")

https://kitao.github.io/pyxel/web/api-reference/

説明にある通り、imagesは「Imageクラスのインスタンスのlist」です。
んじゃImageクラスとはなんぞ?というと、Advanced(上級者向け)オプション付きでAPIリファレンスを見ると、Imageクラスが次のように説明されています。

Image(width, height) [ADV]
指定サイズで新しいImageインスタンスを作成する。
引数
width (int) — イメージの幅
height (int) — イメージの高さ
戻り値
Image — 新しいImageインスタンス

https://kitao.github.io/pyxel/web/api-reference

つまり、こういう作りになっている感じみたいです。

images = [Image(256,256) for _ in range(3)]

Pyxel Code Makerを使って実験してみますと…

# images拡張
pyxel.images = [pyxel.Image(256,256) for _ in range(8)]
pyxel.images[7].rect(1,1,7,7,6) # 空のイメージに■を書き込み

初期化処理にこんな事を書いてもエラーにはならないのです。
器としてのImageクラス(中身に絵がない状態)を256x256サイズで0-7まで生成して、8個に拡張したimagesを使って普通にImageの操作も出来ますし。

ただ一点問題があって、

blt(x, y, img, u, v, w, h, colkey=None, rotate=0, scale=1)
イメージバンクimg (0-2またはImageインスタンス) の (u, v) からサイズ (w, h) の領域を (x, y) にコピーする。

https://kitao.github.io/pyxel/web/api-reference

blt命令のインスタンス番号指定は0-2と定められていて、imagesのリストインデックスが増えたからと言って番号指定の可能範囲が増える訳ではないんですよね。

bltのimages番号は0-2の範囲外だとエラーになってしまう

だけどbltのリファレンス記述にもある通り「Imageクラスのインスタンス」を指定する事も可能なので、下記のように指定してやれば動くのです。

pyxel.blt(self.x, 60, pyxel.images[7], 0, 0, 8, 8, 2)
Imageクラスを直指定すれば動く


blt

blt命令にImageクラスを直に指定すれば動く話と、Imageクラスはコード内で生成できるという話。
これはつまりこういう書き方も出来るという事です。

import pyxel


class App:
    def __init__(self):
        pyxel.init(160, 120)
        pyxel.load("my_resource.pyxres")
        self.x = 0
        # Imageクラスインスタンスの変数を定義
        self.myimage = pyxel.Image(256,256)
        self.myimage.rect(1,1,7,7,15)
        
        pyxel.run(self.update, self.draw)

    def update(self):
        self.x += 1
        if self.x >= pyxel.width:
            self.x = -8

    def draw(self):
        pyxel.cls(0)
        # Imageクラスで作ったインスタンス変数を指定したblt
        pyxel.blt(self.x, 60, self.myimage, 0, 0, 8, 8, 2)
        pyxel.text(48, 53, "Pyxel Code Maker", pyxel.rndi(1, 15))


App()

何を言ってるのかというと、ただの変数に画像を仕込めるのだからガンガン増やせるという事です。
self.player1, self.player2, self.player3, self.enemyA[0-8],とか。


JRPGのプレイヤーキャラチップだと、前後左右とモーション差分で16x16画像が8枚あれば一応成立すると思います。

DQ3のように4人PTかつ職/性別でグラの種類がいっぱいあるような状況で、blt命令実行時に大きい画像から切り出す場合
「この職/性別のグラは画像のこの位置から始まるからオフセットをこれだけ加味したアドレスから画像をとってきて・・・」
とする必要があります。

でも各職/性別のグラを各キャラの画像変数として読み込ませておけば、描画処理は「自分の画像を対象に向き・差分だけ計算」すれば済みます。
プログラムがシンプルになりますよね。画像データを小さいファイルに分割して管理する事も出来ますし。

そして。


画像サイズ

といえば、Imageクラス初期化時の引数。

引数
width (int) — イメージの幅
height (int) — イメージの高さ

縦横のサイズに”256まで”とか書いてある訳じゃないんですよね。
これは以前試した事があるんですが、4K画像サイズ、3840x2160でも指定可能です。
https://note.com/ronegray/n/n113b725183d8


ちなみに…

Pyxelの各種標準設定ですが、Pyxel API Referenceによれば、以下のような定数が準備されています。
https://kitao.github.io/pyxel/wasm/api-reference/

グラフィック関連
オーディオ関連


例えばtones。音色0が柔らかい音の三角波で音色3はSEに大活躍のノイズサウンドで、というToneクラスのインスタンスが標準設定されていて、その音色=Toneクラスのインスタンスのリストになっています。リストと実体クラスが対になる辺りは、imagesとImageの関係と同じですね。

tonesも、Toneクラスを並べたリストで上書きできます。
Pyxel Editorでデフォルトにない音色を選ぶ事は出来ませんが、MML形式でSoundを定義する場合、@4以降の音色指定も可能です。

channelsもChannelクラスのリストを被せられます。
増やしたchannelsの範囲で、Music.setも出来ます。
こちらは値指定ではなくサウンドリストを不定個指定という形なのでエラーにならず通る感じですね。6音同時再生も可能です。


といった感じで、中身がちゃんとしてれば標準リストの範囲を越えた実装も可能になる、懐の深い部分が素晴らしいなあとつくづく感じます。

Pyxelはいいぞ!