Pyxel カラーパレットの変更

Pyxelで基本の16色以外の色を使う

 Python向けレトロゲームエンジン Pyxel で使える色は16色ですが,その色自体はプログラムから変更ができます。

 ※公式サイトの課題管理(GitHub issue)では,次のバージョンのPyxelでパレット変更機能が使える予定となっています。(記事作成時点のバージョンはPyxel 1.8)
 Change palette colors in Pyxres editor? · Issue #432 · kitao/pyxel · GitHub

 (2022-12-22追記 新機能の記事)
  Pyxel 1.9版の新機能 パレットファイルを指定する - 勉強ボックス管理者ブログ

 (2024-04-26追記 Pyxel 2.0で16色より多くの色を使う方法)
  Pyxel 表示する色の数を増やす - 勉強ボックス管理者ブログ


 バージョン1.8でも,プログラム実行時に「パレットの表示色を個別に変更」「表示色リストをまとめて設定」が可能ですのでコード例を紹介します。

APIリファレンス

グラフィッククラス
・colors
 パレットの表示色リスト。表示色は 24 ビット数値で指定します。Python リストを直接代入、取得する場合はcolors.from_listとcolors.to_listを使用してください。

org_colors = pyxel.colors.to_list() # 表示色リストの取得
pyxel.colors[15] = 0x112233 # 表示色の指定
pyxel.colors.from_list(org_colors) # 表示色リストの代入

 

プログラムからの変更例

 リソースエディタで作成したドット絵(キャラクターのメインの色を3番で作成)
 

 ソースコード

import pyxel
pyxel.init(64,64,capture_scale=4)
pyxel.load("mycol.pyxres")

def update():
    pyxel.colors[3] = 0x00aa00
    if 32 < pyxel.mouse_x :
        pyxel.colors[3] += 0xff0000
    if 32 < pyxel.mouse_y :
        pyxel.colors[3] += 0x0000ff
    return

def draw():
    pyxel.cls(0)
    pyxel.blt( pyxel.mouse_x, pyxel.mouse_y, 0,  0,0, 16,16, 0)
    return

pyxel.run(update,draw)

実行結果
 

・pyxel.colors[3] = 0x00aa00
 Pythonで数値の頭に「0x」(ゼロエックス)をつけると,16進数として扱われます。RGB(Red,Green,Blue)の順に0~255の値を0x00~0xffの固まりで3つ分まとめて設定する値になっています。

 赤 0xFF0000 緑 0x00FF00 青 0x0000FF
 16進数のa~fは大文字小文字どちらでも使用できます。

・pyxel.colors[3] += 0xff0000
 「a+=b」の記述は「a = a + b」の代入の記述と同じ動作をします。
 コード例では,pyxel.colors[3] の値が 0x00aa00 + 0xff0000 (合計 0xffaa00)になります。

 
 (2022-12-22追記 16進数の解説記事)
 10進法,2進法,16進法と24ビットカラー - 勉強ボックス管理者ブログ

 

画像ファイルの読み込み

 Pyxelのimage()命令で,PNG画像ファイルをイメージバンクに読み込むことができます。この機能を利用する場合は,画像ファイルは読み込み時にカラーパレットの16色に変換されることを知っておきましょう。

APIリファレンス

グラフィッククラス
・image(img)
 イメージバンクimg (0-2) を操作します。(イメージクラスを参照のこと)
 例:pyxel.image(0).load(0, 0, "title.png")

フルカラー画像(24ビット)を読み込んだ例

 下記は撮影した写真ファイルをサイズを縮小してPNG画像ファイルに保存したものです。
 
 これを次のプログラムでPyxel画面に表示してみます。

import pyxel
pyxel.init(256,256)
pyxel.cls(0)

pyxel.image(0).load(0, 0, "kaminarimon.png")
pyxel.blt(0,0, 0, 0,0, 256,256)

pyxel.text(10,210,"full color -> default palette",15)
pyxel.show()

 
 基本の16色で色が近いものに置き換えられます。
 余談ですが,ドット絵の練習に写真の解像度を下げて物を観察して絵にしてみるという方法があるそうです。この変換を利用したらいい勉強になりそうですね。

 

グレースケール画像を読み込んだ例

 レタッチソフトで写真を灰色にしてから読み込んでみます。
 
 
 グレースケールの中間色は,5番や6番も使って置き換えられます。
 

カラーパレットを変更してから読み込む例

 Pyxelデフォルトのパレットでも十分いい感じで画像が表示されていますが,自作のタイトル画面などでどうしても表示したい色があるケースも考えられます。対応方法としてimage()のload()命令前にカラーパレットを変更してみます。

import pyxel
pyxel.init(256,256)
pyxel.cls(0)

for i in range(16):
    pyxel.colors[i] = i *  0x101010

pyxel.image(0).load(0, 0, "kaminarimon.png")
pyxel.blt(0,0, 0, 0,0, 256,256)

pyxel.text(10,210,"full color -> gray palette",15)
pyxel.show()

 フルカラー画像を読み込んで表示
 
 灰色画像を読み込んで表示
 
 中間の色のパレットが分かれて,門の中の風神が判別できるようになりました。(ソースを確認したわけではありませんが,image()のload()命令はその時点でのカラーパレットで近い色に変換してくれるようです)

 

デフォルトパレットと切り替えて使う

 ゲームのタイトル,エンディングに他のペイントツールで作成したドット絵を表示したい。ゲーム中はPyxelのエディタで作成したリソースを使いたい。そのような場合の切り替え例です。

import pyxel
pyxel.init(256,256)

# リソースファイルを読み込む
pyxel.load("ninja.pyxres")

# デフォルトのカラーパレットを退避
org_colors = pyxel.colors.to_list()
#for col in org_colors:
#    print(hex(col))

# パレットをグレースケールに書き換え
for i in range(16):
    pyxel.colors[i] = i * 0x101010
    #print(hex(pyxel.colors[i]))

# 画像ファイルをイメージバンク2に読み込み
pyxel.image(2).load(0, 0, "kaminarimon_gray.png")

scene = 0
tmr = 0
def update():
    global scene,tmr

    if pyxel.btnp(pyxel.KEY_SPACE):
        # スペースキーを押すたびに0と1を切り替え
        scene = 1 - scene
        tmr = 0

    if 0 == tmr :
        if 0 == scene :
            # パレットをグレースケールに書き換え
            for i in range(16):
                pyxel.colors[i] = i * 0x101010
        else:
            # デフォルトのカラーパレットで復帰
            pyxel.colors.from_list(org_colors)

    # タイマー変数を更新して処理を初回のみにする
    tmr = tmr + 1
        
    return

def draw():
    pyxel.cls(0)

    if 0 == scene :
        # イメージバンク2の画像を表示
        pyxel.blt(0,0, 2, 0,0, 256,256)
    elif 1 == scene :
        # リソースファイルのタイルマップを表示
        pyxel.bltm(0,0, 0, 0,0, pyxel.width,pyxel.height, 0)
        pyxel.blt( 8, 100, 0,  0, 8, 8,8, 0)
    else:
        pass
    
    return

pyxel.run(update,draw)

 実行結果
 
 リソースを読み込んでから,カラーパレットを変更して画像ファイルを(空きイメージバンクに)読み込んでいます。プログラム中のscene変数の値によって,カラーパレットと表示する内容を切り替えてみたところ,どちらの色も表示することができました。

 例ではグレースケールでしたが,他の色で中間色も作成できます。ペイントツールのパレットに合わせて指定してみてください。
 

関連記事

 kinutani.hateblo.jp