レッスンの目標

Pythonを使ったPyxelというというレトロゲームエンジンを使ってレトロゲームをつくってみましょう。

Pyxel Code Maker

Pyxel Code Makerを使うとブラウザで簡単にPyxelを試すことができます。

Pyxel Code Makerにアクセスすると、左側にサンプルコードが表示され、右側にその実行結果が出力されます。

サンプルでは、右の画面をクリックすると中央に「Pyxel Code Maker」という文字が表示され、人の顔のような黄色いキャラクターが中央の左から右に移動します。

プログラムの説明

import pyxel    # pyxelライブラリを呼び出します。

class App:    # メインプログラム
    def __init__(self):    初期化関数
        pyxel.init(160, 120)    # 画面を160x120で初期化します
        pyxel.load("my_resource.pyxres")    # 画像データを読み込みます
        self.x = 0    # 画像のx方向の表示位置を0に設定します。
        pyxel.run(self.update, self.draw)    # 更新関数と描画関数を指定してメインプログラムを実行します。

    def update(self):    # 更新関数
        self.x += 1    # 更新のたびに画像のx方向に表示位置を1つずつ増やします
        if self.x >= pyxel.width:    # 右端まで到達したら
            self.x = 0    # 画像の位置を左端(0)に戻します

    def draw(self):    # 描画関数
        pyxel.cls(0)    # 画面をクリアします
        pyxel.blt(self.x, 60, 0, 0, 0, 8, 8, 2)    # (x, 60)の位置に8x8の画像を描画します。
        pyxel.text(48, 53, "Pyxel Code Maker", pyxel.rndi(1, 15))
        # (48, 53)の位置に「Pyxel Code Maker」という文字を表示します。
        # 色は毎回ランダムに変わります。(1から15のパレット色の間で)


App()    # メインプログラムを実行します

敵のキャラクターを作ろう

敵のキャラクターを作ってみましょう。

画面の上の「Res」というタブを押してください。

左側がプログラムから画像編集に切り替わります。

画像は上下左右に縦横8ピクセルずつ、4つの部分に分割されていて現在表示されているキャラクターは左上に表示されています。なお、キャラクターの上下左右に紫色の部分がありますが、これはpyxel.blt(self.x, 60, 0, 0, 0, 8, 8, 2)の最後の「2」の部分で2番めのパレット色(紫色)が透明になるという指定にんっているので、右側の画面上では表示されていません。

現在表示されているキャラクターを変えたいときは、左上の部分を書き換えます。

今回は、新しい敵キャラクターを作るので、右上の8x8に部分に新規のキャラクターを書き加えます。

左下の16色のパレットを選んで、好きなキャラクターを作ってみましょう。透明にしたい部分は今回も2番めのパレット色(紫色)で書きましょう。

敵のキャラクターを表示してみよう

右上の8x8の部分に敵のキャラクターを作成したら、画面の上の「Code」というタブを押します。左側が元のプログラム画面に戻ります。

pyxel.blt(self.x, 60, 0, 0, 0, 8, 8, 2)の部分を

pyxel.blt(self.x, 60, 0, 8, 0, 8, 8, 2)に書き換えて、画面の上の「Run」というタブを押してください。

移動するキャラクターが、先ほど作成した敵のキャラクターに変わります。

pyxel.blt(self.x, 60, 0, a, b, c, d, 2)のa, b, c, dの部分は16x16の元画像から(a, b)の位置から(c, d)の画像を切り出すという意味です。

最初は(0, 0, 8, 8)となっていたので、元画像の左上(0, 0)から8 x 8分の画像を切り出します。

変更後は(8, 0, 8, 8)となっていたので、元画像から左上から右に8ピクセル移動した位置(8, 0)から8 x 8分の画像を切り出します。

元のキャラクターと、敵のキャラクターを両方表示してみよう

元のキャラクターと、新しく作った敵のキャラクターを両方表示してみましょう。

同じ位置に表示すると上書きされてしまって1つのキャラクターしか見えなくなってしまうので、それぞれ表示する位置を変えてみましょう。

一番簡単なのは、2つのキャラクターで表示するyの位置(高さ方向)を変えることです。

先ほど修正した部分を以下のように書き換えてみましょう。

pyxel.blt(self.x, 60, 0, 0, 0, 8, 8, 2)
pyxel.blt(self.x, 40, 0, 8, 0, 8, 8, 2)

上に敵キャラクター、下に元のキャラクターが同じx位置に表示されるようになります。

敵のキャラクターを反対方向に移動させてみよう

元のキャラクターと敵のキャラクターが同じ方向に移動していてはおもしろくないので、敵のキャラクターは逆方向に移動させてみましょう。このときyの位置(高さ方向)は同じにしてみましょう。

まず、敵のキャラクターのx位置の変数としてself.exを新たに作成しまします。

def __init__(self)self.x = 0の後にself.ex = pyxel.widthを追加します。pixel.widthというのは画面の右端の位置を意味します。

左に移動する部分はupdate(self)の後ろに以下のプログラムを追加します。

def update(self):
    ...
    self.ex -= 1
    if self.ex <= 0:
        self.ex = pyxel.width + 8

これで、敵は左に進み、左端に着いたら右端に移動します。

最後に、def draw(self)の敵の画像を表示する部分を

pyxel.blt(self.ex, 60, 0, 8, 0, 8, 8, 2)に書き換えます。

同じ高さで元のキャラクターと敵のキャラクターが反対方向に交差するように移動します。

元のキャラクターをジャンプさせて、敵のキャラクターからよけられるようにしよう

このままだと毎回敵のキャラクターとぶつかってしまうので、元のキャラクターをジャンプさせて、敵のキャラクターとぶつからないようにしてみましょう。

スペースボタンを押したらジャンプするようにします。

ジャンプするために以下のような値をもたせます。

y … 高さ

vy… 高さ方向の速度

g… 重力

式は以下の通りです。

vy は毎フレーム g ずつ増える
y += vy

初期値を以下のように追加します。

def __init__(self):
    ...
    self.y = 60
    self.vy = 0
    self.g = 0.4
    self.jump = False
    ...

以下のように更新します。

def update(self):
    # スペースキーでジャンプする
    if pyxel.btnp(pyxel.KEY_SPACE) and not self.jump:
        self.jump = True
        self.vy = -5

    # ジャンプ後の動き
    if self.jump:
        self.vy += self.g
        self.y += self.vy

        # 地面に落ちたら終了
        if self.y > 60:
            self.y = 60
            self.jump = False
    ... 

描画を以下のように変更します。

def draw(self):
    ...
     pyxel.blt(self.x, self.y, 0, 0, 0, 8, 8, 2)
    ...

これで、スペースキーを押すと、元のキャラクターがジャンプするようになり、敵をよけれるようになりました。

敵のキャラクターにぶつかったらゲームオーバーになる

このままだと、敵のキャラクターにぶつかってもすれちがうだけなので、敵のキャラクターにぶつかったらゲームオーバーになるようにします。

現在表示されている「Pyxel Code Maker」を「Game Over」に変更し、通常は非表示としてゲームオーバーになったら表示するようにします。このとき、キャラクターは非表示にします。

元のキャラクターと敵のキャラクターがぶつかったかどうかは以下の式で判断します。

if abs(self.x - self.ex) < 6 and abs(self.y - 60) < 6:

元キャラクターと敵キャラクターのx位置の差が6ピクセル以内かつ、y位置の差が6ピクセル以内のとき、ぶつかったと判断しています。

初期化部分にgameoverフラグを追加します。

def __init__(self):
    ...
    self.gameover = False
    ...

更新部分でぶつかったかどうかの判断をし、ぶつかったらgameoverフラグをTrueにします。

def update(self):
    ...
    if abs(self.x - self.ex) < 6 and abs(self.y - 60) < 6:
        self.gameover = True

描画部分でgameoverフラグによって描画処理を変えます

def draw(self):
    pyxel.cls(0)
    if self.gameover:
        pyxel.text(48, 53, "Game Over", pyxel.rndi(1, 15))
    else:
        pyxel.blt(self.x, self.y, 0, 0, 0, 8, 8, 2)
        pyxel.blt(self.ex, 60, 0, 8, 0, 8, 8, 2)        

これでぶつかったときだけ、ゲームオーバーになります。

自由に改造してゲームをおもしろくしよう

あとは自分のアイデアでゲームを面白くしてみましょう。

  • 敵にぶつからないで右端までいけたら得点を加算する

  • 敵のキャラクターのスピードを登場するたびにランダムに変化させる

  • キャラクターがぶつかってもすぐにゲームオーバーにせず、ライフの値をもたせて、ぶつかったらライフを減らし、ライフが0になったらゲームオーバーにする

  • 敵のキャラクターが複数登場するようにする

など、いろいろ工夫してください。