【Pyxel入門】パックマン風ゲームを作る #3 キャラクターの向き

Python

前回の記事ではパックマンを動かせるようにしました。

【Pyxel入門】パックマン風ゲームを作る #2 キャラクターの移動

今回は、移動する方向に応じてパックマンの向きが変わるようにしていきます。

グラフィックスの反転

bit関数の第4、第5引数それぞれに負の値を渡すことで、グラフィックスを水平、垂直方向に反転させることができます。

blt(x, y, img, u, v, w, h, [colkey])
イメージバンクimg(0-2) の (uv) からサイズ (wh) の領域を (xy) にコピーする。whそれぞれに負の値を設定すると水平、垂直方向に反転する。colkeyに色を指定すると透明色として扱われる

github.com/kitao/pyxel/blob/master/README.ja.mdより引用

要するに、反転させたい場合は-1で乗算すればよいですね。
左右にしか移動しないのであれば、以下のようなコードを書けばよいでしょう。

def move(self):
    if pyxel.btn(self.left):
        self.x -= self.speed
        self.left_right = 1
        self.rotation = 0
    if pyxel.btn(self.right):
       self.x += self.speed
       self.left_right = -1
       self.rotation = 0

def draw(self):
    pyxel.blt(self.x, self.y, 0, self.u * 16, self.h * 16, char_W * self.left_right, char_H, 0)

グラフィックスの回転

横を向いているパックマンを上下に向けるには、90°か270°回転させる必要がありますが、pyxelでは反転はできても回転させる方法は用意されていないようです。

プログラムでどうにかするよりも、上を向いているキャラチップを用意した方が簡単でしょう。

キャラチップ

上下に移動しているときは、キャラチップの読み込み位置を下に64ドットずらすようにします。

def move(self):
    if pyxel.btn(self.up):
        self.y -= self.speed
        self.up_down = 1
        self.rotation = 64
    if pyxel.btn(self.down):
        self.y += self.speed
        self.up_down = -1
        self.rotation = 64
    if pyxel.btn(self.left):
        self.x -= self.speed
        self.left_right = 1
        self.rotation = 0
    if pyxel.btn(self.right):
        self.x += self.speed
        self.left_right = -1
        self.rotation = 0
 
 def draw(self):
    pyxel.blt(self.x, self.y, 0, self.u * 16, self.h * 16 + self.rotation, char_W * self.left_right, char_H * self.up_down, 0)

下へ移動する際は、水平方向に反転させます。

ソースコード

今回のソースコードは以下になります。

前回からの主な変更点

  • キャラチップの追加
  • move関数とdraw関数に向きを変更するためのコードを追加
import pyxel

WINDOW_H = 256
WINDOW_W = 256
char_H = 16
char_W = 16

# キャラクターのクラスを作成
class Player:
    def __init__(self, x, y, h):
        
        # 表示位置の座標を示す変数
        self.x = x
        self.y = y
        
        # 画像の座標を示す変数
        self.u = 0
        self.h = h # プレイヤーの判別にも使用

        # 方向を示す変数
        self.up_down = 1
        self.left_right = 1
        self.rotation = 0

        # 画像切り替えの折返し判断
        self.sw = 0
        
        # 移動速度
        self.speed = 4
        
        # キーバインド
        if h == 0: #プレイヤー1の設定
            self.up = pyxel.KEY_UP
            self.down = pyxel.KEY_DOWN
            self.left = pyxel.KEY_LEFT
            self.right = pyxel.KEY_RIGHT
        if h == 1: #プレイヤー2の設定
            self.up = pyxel.KEY_W
            self.down = pyxel.KEY_S
            self.left = pyxel.KEY_A
            self.right = pyxel.KEY_D
        if h == 2: #プレイヤー3の設定
            pass
        if h == 3: #プレイヤー4の設定
            pass

    # キャラグラフィック変更
    def update(self):
        if self.sw == 0:
            self.u += 1
            if self.u == 2:
                self.sw = 1
        else:
            self.u -= 1
            if self.u == 0:
                self.sw = 0
    
    # キャラクター移動
    def move(self):
        if pyxel.btn(self.up):
            self.y -= self.speed
            self.up_down = 1
            self.rotation = 64
        if pyxel.btn(self.down):
            self.y += self.speed
            self.up_down = -1
            self.rotation = 64
        if pyxel.btn(self.left):
            self.x -= self.speed
            self.left_right = 1
            self.rotation = 0
        if pyxel.btn(self.right):
            self.x += self.speed
            self.left_right = -1
            self.rotation = 0

    def draw(self):
        pyxel.blt(self.x, self.y, 0, self.u * 16, self.h * 16 + self.rotation, char_W * self.left_right, char_H * self.up_down, 0)


class App:
    def __init__(self):
        pyxel.init(WINDOW_W, WINDOW_H, caption="Hello Pyxel")
        pyxel.image(0).load(0, 0, "img/img.png")
        

        # フレーム更新時に1加算する変数
        # [TODO] fpsを揃えること
        self.frame = 0

        # Playerクラスのインスタンスを生成、初期位置の座標を引数に渡す
        self.players = {}
        self.player_1 = Player(16, 16, 0)
        self.player_2 = Player(16, 64, 1)
        self.player_3 = Player(16, 112, 2)
        self.player_4 = Player(16, 160, 3)

        # 参加するプレイヤーを登録
        # [TODO] プレイ人数に応じて変更
        self.players = [self.player_1, self.player_2]

        pyxel.run(self.update, self.draw)

    def update(self):
        
        self.frame += 1

        # 3フレームごとにキャラグラフィックを更新
        if self.frame % 3 == 0:
            for player in self.players:
                player.update()

        # キャラクターの座標を更新
        for player in self.players:
                player.move()

        if pyxel.btnp(pyxel.KEY_Q):
            pyxel.quit()

    def draw(self):
        pyxel.cls(0)
        # キャラクターを描画
        for player in self.players:
                player.draw()

App()

実行結果

pacman
室井

キャラクターの操作はある程度完成しました。
次回はマップを制作していきます。

みゅう

パックマンが進み続ける処理は、マップを作ってから考えるよ。

【Pyxel入門】パックマン風ゲームを作る #4 マップの作成