Python(Pyxel)でレトロゲームを作ってみる 書き方の勉強編1

まえおき

Pyxelという、Pythonレトロゲームが簡単に作れるというフレームワークについて、ちょっと触ってみたいと思います。

Pyxelとは?

github.com


Pythonで簡単にレトロゲームがつくれちゃうそうです。
開発者が日本の方らしく、日本語でのAPI説明の情報も用意されています。
READMEにインストール方法も書かれているため、実際に動かしてみるまでの段階は割愛させていただきます。



早速起動!

早速01_hello_pyxel.pyを起動!

f:id:Tiratom:20181206233358p:plain
01_hello_pyxel.pyを起動しました
(ただし画像は上記サイトのキャプチャです(汗))


おお~文字がピカピカしている・・・!
僕もこの画面、作ってみたいぞ・・・!


といって急に作れないのが僕なので(笑)
まずは用意されているサンプルのソースコードが一体どういう書き方になっているのか、一つ一つ見ていこうと思います。



サンプルコードをいじってみる(1-1)読んでみる編

とりあえず、サンプルコードにコメント付けてみました。

import pyxel

class App:
    def __init__(self):
        #Pyxelアプリを横160, 縦120のウィンドウサイズで開く。
        #ウィンドウタイトルは Hello Pyxel にする。
        pyxel.init(160, 120, caption="Hello Pyxel")

        #イメージバンクの0番について、
        #左から0上から0の位置に、assets/pyxel_log_38×16.pngの画像を設定する
        pyxel.image(0).load(0, 0, "assets/pyxel_logo_38x16.png")

        # フレーム更新処理はこのAppクラス内に定義している
        #updateメソッドを使い、描画処理はdrawメソッドを用いるとして、
        #Pyxelアプリを開始する。
        pyxel.run(self.update, self.draw)

    def update(self):
        # キーボードのQが押されたかどうかをチェックする。
        #(フレーム更新のたびにこのupdateメソッドが呼び出されるため、
        #    そのたびにチェックする)
        if pyxel.btnp(pyxel.KEY_Q):

            #Pyxelアプリを終了する。
            pyxel.quit()

    def draw(self):
        #画面を色0(色の対応はREADMEの「カラーパレット」の項目参照。
        # それによると黒色。)でクリア
        #(全面をその色で塗る?)
        pyxel.cls(0)

        #色col(pyxel.frame_count%16)の文字列(Hello, Pyxel!)を、
        # 左から55,上から41の位置に描画する
        pyxel.text(55, 41, "Hello, Pyxel!", pyxel.frame_count % 16)

        # イメージバンク0(3番目の引数)の左0上0(それぞれ4,5番目の引数)から、
        # サイズ横38,縦16分の大きさの領域を、
        # ウィンドウの左から61, 上から66の位置に表示させる
        pyxel.blt(61, 66, 0, 0, 0, 38, 16)

# Appクラスのインスタンスを作成します。
#インスタンスの作成により、
# コンストラクタである__init__の中身が呼び出されます。
# それにより、pyxelアプリがrunします。
App()

少し注意しておきたいのが、イメージバンク。
この記事で実際に使った例を示そうと思いますが、現段階では
・イメージバンクの用意
及び
・ Pyxelファイル( イメージバンク情報を持つ)のロード(pyxel.load(xxxx.pyxel)
もしていません。
そのため、上記ソース内のpyxel.image(0).load(0, 0, "assets/pyxel_logo_38x16.png)" では、ただの真っ黒の画面 を用意し、その上にpyxel_logo_38x16.pngを載せて表示している、という状態になっている、と僕は理解しています。



サンプルコードをいじってみる(1-2) 背景色編

それでは、いくつか値を変えて動かしてみましょう。

ではまず、簡単なところから。
画面の背景色をかえましょう。
drawメソッド内のclsをいじってみます。
このclsとは、画面全体の色を設定するためのメソッドです。

それでは、ソース中の

pxel.cls(0)

pyxel.cls(7)

に変えてみましょう。
変更したら保存して、起動してみましょう!

f:id:Tiratom:20181208100758p:plain
背景色がクリーム色になりました。






サンプルコードをいじってみる(1-3) 表示文字編

では続いて、 drawメソッド内の

pyxel.text(55, 41, "Hello, Pyxel!", pyxel.frame_count % 16)

をいじってみましょう。
まずこの行は、「ウィンドウの左上から右に55, 下に41の位置に『Hello, Pyxel!!』という文字を表示させ、色は現在のフレーム数を16で割ったあまりの値で表示する」という意味でした。
この行を、

pyxel.text(55, 41, f'Hello Pyxel!! count={pyxel.frame_count}', pyxel.frame_count % 16)

にしてみましょう。
そして実際に起動してみましょう。

f:id:Tiratom:20181208101101p:plain
表示文字を変えてみました。

変更後のコードは、「ウィンドウの左上から右に55, 下に41の位置に『Hello, Pyxel!! count=』という文字と現在のフレーム数を表示させ、色は現在のフレーム数を16で割ったあまりの値で表示する」という意味になっています。
f'{変数名}'で変数を文字列に埋め込むことができるのですが、pyxel.frame_count によって現在のフレーム数を表すことができます。
実際に起動すればわかると思いますが、目まぐるしく数字が増えていきます。
__init__メソッド内でpyxel.run(self.update, self.draw) と記述しているため、フレーム更新のたびにself.updateメソッドおよびself.drawが呼ばれ、それにより、表示されるcount(フレーム数)が増え、さらに文字の色も更新されていくようです。

現段階では色の変化と数字の変化のみですが、「パラパラ漫画のように、絵をわずかな時間間隔で少しずつ変化させながら表示させることによって、動きを表していくのだ」というゲーム作成の方針が少し感じられるかと思います。




サンプルコードをいじってみる(1-4) イメージバンク編

さて、イメージバンクについてはサンプルコード2(02_jump_game.py)でがっつり使用しますが、このサンプルコード(01_hello_pyxel.py)でも使用してみちゃいましょう。


まずはイメージバンクの編集画面を開きます。 コマンドプロンプト上で、

$pyxeleditor 01_hello_yxel.pyxel

を実行します。
すると、以下のような画面が表示されます。

f:id:Tiratom:20181208210013p:plain
Pyxel Editor起動画面


f:id:Tiratom:20181208210144p:plain
画面情報のメニューバーにおいて人間マークを選択していると、イメージエディタが表示されています。

f:id:Tiratom:20181208210409p:plain
イメージバンク選択ボタン(IMAGE0~IMAGE2の、計3つイメージバンクを作成することができます。「-」または「+」で各イメージバンクを切り替えることができます)


では早速自由に書いていきましょう。

f:id:Tiratom:20181208210852p:plain
とりあえず、(0,0)から(8,8)の部分にチェック柄を書いてみました。

書き終わったら、下図の赤枠で囲ったボタンを押して保存ができます。

f:id:Tiratom:20181208211022p:plain
保存ボタン


保存できたら、ウィンドウを閉じ、再びソースコードに戻ります。

__init__メソッド内において、pyxel.initの次の行に以下のソースを追加します。

pyxel.load("01_hello_pyxel.pyxel")

※VisualtStudioの実行環境などでは、次のようにそのファイルのディレクトリを取得したうえでpyxelファイルまでのパスを指定する必要がある場合があります。 pyxel.load(f'{os.path.dirname(__file__)}/01_hello_pyxel.pyxel')


これによって、先ほどPyxelEditorで編集した01_hello_pyxel.pyxelファイルのデータを使用することができるようになります。

更に、

pyxel.Image(0).load(0,0, "assets/pyxel_logo_38x16.png")

のソースを

pyxel.Image(0).load(8,8, "assets/pyxel_logo_38x16.png")

に変更します。
これによって、このソースは「イメージバンク0番(さっき編集したやつ)の左から8,上から8の位置に、assetsフォルダの中にあるpyxel_logo_38x16.pngファイルを貼り付ける」という意味になります。

あと1か所修正します。
drawメソッド内の

pyxel.blt(61, 66, 0, 0, 0, 38, 16)

pyxel.blt(61, 66, 0, 0, 0, 46, 24)

に変更します。
これにより、
「イメージバンク0(3番目の引数)の左0上0(それぞれ4,5番目の引数)から、サイズ横38,縦16分の大きさの領域を、ウィンドウの左から61, 上から66の位置に表示させる」
という意味から
「イメージバンク0(3番目の引数)の左0上0(それぞれ4,5番目の引数)から、サイズ横46,縦24分の大きさの領域を、ウィンドウの左から61, 上から66の位置に表示させる」
という意味に変わりました。


実際に動かしてみましょう。

f:id:Tiratom:20181208212609p:plain
起動してみました。

pyxel_logoの部分に、先ほど書いた絵が追加された状態で表示されています。
以下のような図の関係で、画面表示が行われています。
f:id:Tiratom:20181208213633p:plain
pyxel_logoの表示部分の周辺の長さ関係図



サンプルコード(1)の読み取りはこのくらいにしておきましょうか。
次はサンプルコート(2)を読んでいきたいと思います。次は動きがありますよ!
楽しみですね!
最後は編集後のソースコードを載せておきます。


いじった後の最終的なソースコード

ただし、VisualStudio上で実行しているため、パスの指定時にos.path.dirname(__file__)を用いています。

import pyxel
import os


class App:
    def __init__(self):
        #Pyxelアプリを横160, 縦120のウィンドウサイズで開く。
        # ウィンドウタイトルは Hello Pyxel にする。
        pyxel.init(160, 120, caption="Hello Pyxel")

        # 01_hello_pyxel.pyxelファイルを読み込む。
        pyxel.load(f'{os.path.dirname(__file__)}/01_hello_pyxel.pyxel')

        #イメージバンクの0番について、左から8上から8の位置に、
        # assets/pyxel_log_38×16.pngの画像を設定する
        pyxel.image(0).load(8, 8, f'{os.path.dirname(__file__)}/assets/pyxel_logo_38x16.png')

        # フレーム更新処理はこのAppクラス内に定義している
        # updateメソッドを使い、描画処理はdrawメソッドを用るとして、
        # Pyxelアプリを開始する。
        pyxel.run(self.update, self.draw)

    def update(self):
        # キーボードのQが押されたかどうかをチェックする。
        #(フレーム更新のたびにこのupdateメソッドが呼び出されるため、
        # そのたびにチェックする)
        if pyxel.btnp(pyxel.KEY_Q):

            #Pyxelアプリを終了する。
            pyxel.quit()

    def draw(self):
        #画面を色7(クリーム色。)で塗る
        pyxel.cls(7)

        #色col(pyxel.frame_count%16)の文字列
        # (Hello, Pyxel!count=【フレーム数】)を、
        # 左から55,上から41の位置に描画する
        pyxel.text(55, 41, f'Hello Pyxel!! count={pyxel.frame_count}', pyxel.frame_count % 16)

        # イメージバンク0(3番目の引数)の左0上0(それぞれ4,5番目の引数)から、
        # サイズ横46,縦24分の大きさの領域を、
        # ウィンドウの左から61, 上から66の位置に表示させる
        pyxel.blt(61, 66, 0, 0, 0, 46, 24, 3)


App()