Python Pyxel でプログラミング練習 第2回(後編)

Pyxelでじゃんけんゲームを作る(後編)

 Python向けレトロゲームエンジン「Pyxel(ピクセル)」を使ったゲーム制作を通してプログラミングを学習します。
 今回作成するゲームで,画面のクリック判定,乱数の使用,効果音の再生の仕方を紹介します。

 【前編】Pyxelでじゃんけんゲームを作る(前編)
 Python Pyxel でプログラミング練習 第2回(前編) - 勉強ボックス管理者ブログ


 

プログラムの作成 前編からの続き

 ※本記事では「ソースコードを書く」→「実行して確認」→「ソースコードに処理を追加」→「実行して確認」→・・・を繰り返します。各ステップでのソースコード変更部分は,下記pdfファイルに赤文字で示しましたので参考にしてください。
  Pyxel_じゃんけんゲーム_ソース確認用.pdf - Google ドライブ

 

04 クリックした座標からプレーヤーの手を決定する

 Pyxelでは pyxel.mouse_x,pyxel.mouse_y に現在のマウス座標が格納されます。マウスクリック時の座標がプレーヤーの手「グーチョキパーの画像」の範囲にあるかどうか調べる関数 check_area() を作成し,範囲内であればプレーヤーの手を決定する処理を追加します。
 list04_04.py
 前のプログラムからの変更箇所は 確認用pdfファイル の4ページを参照してください。

import pyxel

pyxel.init(80,64,title="rock paper scissors")
pyxel.load("rps_game.pyxres")
pyxel.mouse(True)

com_hand = 0
player_hand = 0
status = 0

def check_area():
    ret = False
    x = pyxel.mouse_x
    y = pyxel.mouse_y
    if 16 <= x and x < 64 and 32 <= y and y < 48:
        ret = True
    return ret

def update():
    global com_hand, status, player_hand
    if status == 0:
        if pyxel.btnp(pyxel.MOUSE_BUTTON_LEFT) and check_area():
            player_hand = int(pyxel.mouse_x / 16) - 1
            com_hand = pyxel.rndi(0,2)
            status = 1
        else:
            # クリック前は次々手を変える
            com_hand = int(pyxel.frame_count / 5) % 3
    elif status == 1:
        pass # 今は何もしない
    
    return

def draw():
    pyxel.cls(0)

    # コンピューターの手を描画
    pyxel.text(4,10, "COM",7)
    pyxel.blt(32,10, 0, com_hand*16,0, 16,16, 0)

    # プレーヤーの手を描画
    pyxel.text(4,32, "YOU",7)
    pyxel.blt(16,32, 0,  0,0, 16,16, 0)
    pyxel.blt(32,32, 0, 16,0, 16,16, 0)
    pyxel.blt(48,32, 0, 32,0, 16,16, 0)
    
    return

pyxel.run(update, draw)

 実行結果
 
 範囲外の場所をクリックしたときは反応せず,プレイヤーの手の範囲をクリックしたときにCOMの手の絵が止まるようになりました。

・check_area()
 check_area()は自作の関数です。現在のマウスの座標について,xが16から63の範囲,yが32から47の範囲にあればTrueを返します。

 
・player_hand = int(pyxel.mouse_x / 16) - 1
 クリックしたx座標がどの手の画像の上にあるか計算をしています。Pythonでは整数÷整数の値が浮動小数点数になるので,int()関数で整数に変換しています。(切り捨て除算の演算子「//」を使ってpyxel.mouse_x // 16 としても整数が得られます)
 グーを0,チョキを1,パーを2にするため1を引いて,プレイヤーの手を決定しています。

 

05 プレーヤーの手の描画処理の変更と,状態1でのクリック判定の追加

 プレーヤーが選んだ手だけ画面に表示するようにdraw()の処理を変更してみましょう。また,何度も繰り返せるようにクリック後の状態をクリック前に戻す処理をupdate()に追加します。
 list04_05.py
 前のプログラムからの変更箇所は 確認用pdfファイル の5ページを参照してください。

import pyxel

pyxel.init(80,64,title="rock paper scissors")
pyxel.load("rps_game.pyxres")
pyxel.mouse(True)

com_hand = 0
player_hand = 0
status = 0

def check_area():
    ret = False
    x = pyxel.mouse_x
    y = pyxel.mouse_y
    if 16 <= x and x < 64 and 32 <= y and y < 48:
        ret = True
    return ret

def update():
    global com_hand, status, player_hand
    if status == 0:
        if pyxel.btnp(pyxel.MOUSE_BUTTON_LEFT) and check_area():
            player_hand = int(pyxel.mouse_x / 16) - 1
            com_hand = pyxel.rndi(0,2)
            status = 1
        else:
            # クリック前は次々手を変える
            com_hand = int(pyxel.frame_count / 5) % 3
    elif status == 1:
        if pyxel.btnp(pyxel.MOUSE_BUTTON_LEFT):
            status = 0
    
    return

def draw():
    pyxel.cls(0)

    # コンピューターの手を描画
    pyxel.text(4,10, "COM",7)
    pyxel.blt(32,10, 0, com_hand*16,0, 16,16, 0)

    # プレーヤーの手を描画
    pyxel.text(4,32, "YOU",7)
    if status == 0:
        pyxel.blt(16,32, 0,  0,0, 16,16, 0)
        pyxel.blt(32,32, 0, 16,0, 16,16, 0)
        pyxel.blt(48,32, 0, 32,0, 16,16, 0)
    elif status == 1:
        pyxel.blt(16*(player_hand+1),32, 0, 16*player_hand,0, 16,16, 0)
    
    return

pyxel.run(update, draw)

 実行結果
 
・update()処理
 statusが1の場合に,マウスクリックを判定してstztusを0にすることで,初めの状態に戻すようにしました。

・draw()処理
 プレイヤーの手を描画する処理を場合分けしました。statusが0のときは今まで通りで,statusが1のときは手によって画面のx座標とイメージバンクのu座標が変わるようにしています。

 

06 じゃんけん結果表示の追加

 じゃんけんの勝負結果をテキストで表示します。勝負の結果は二次元配列にあらかじめ設定しておいて手の組み合わせで値を取り出す仕組みにしました。(※if文を使って結果を判定する処理を作成してもよいです)

 【ゲームの仕様】じゃんけんの結果を数値で表し「引き分けを0,プレイヤー勝ちを1,プレーヤー負けを2」とします。

 list04_06.py
 前のプログラムからの変更箇所は 確認用pdfファイル の6ページを参照してください。

import pyxel

pyxel.init(80,64,title="rock paper scissors")
pyxel.load("rps_game.pyxres")
pyxel.mouse(True)

com_hand = 0
player_hand = 0
status = 0
# result[ player ][ cpu ]  0:draw 1:p win 2:p lose
result = [[0,1,2],
          [2,0,1],
          [1,2,0]]
message = ["DRAW","WIN","LOSE"]

def check_area():
    ret = False
    x = pyxel.mouse_x
    y = pyxel.mouse_y
    if 16 <= x and x < 64 and 32 <= y and y < 48:
        ret = True
    return ret

def update():
    global com_hand, status, player_hand
    if status == 0:
        if pyxel.btnp(pyxel.MOUSE_BUTTON_LEFT) and check_area():
            player_hand = int(pyxel.mouse_x / 16) - 1
            com_hand = pyxel.rndi(0,2)
            status = 1
        else:
            # クリック前は次々手を変える
            com_hand = int(pyxel.frame_count / 5) % 3
    elif status == 1:
        if pyxel.btnp(pyxel.MOUSE_BUTTON_LEFT):
            status = 0
    
    return

def draw():
    pyxel.cls(0)

    # コンピューターの手を描画
    pyxel.text(4,10, "COM",7)
    pyxel.blt(32,10, 0, com_hand*16,0, 16,16, 0)

    # プレーヤーの手を描画
    pyxel.text(4,32, "YOU",7)
    if status == 0:
        pyxel.blt(16,32, 0,  0,0, 16,16, 0)
        pyxel.blt(32,32, 0, 16,0, 16,16, 0)
        pyxel.blt(48,32, 0, 32,0, 16,16, 0)
    elif status == 1:
        pyxel.blt(16*(player_hand+1),32, 0, 16*player_hand,0, 16,16, 0)
        idx = result[player_hand][com_hand]
        pyxel.text(16*(player_hand+1),48, message[idx],7)
    
    return

pyxel.run(update, draw)

 実行結果
 
 
・結果をあらかじめ設定した二次元配列 result を作成しました。プレーヤーの手とコンピューターの手を添え字にして配列を参照すると,その手の組み合わせでの勝敗の値が取得できます。

 

07の準備 効果音の作成

 勝負の結果に応じて効果音を再生したいと思います。Pyxelのエディタを使用すると,ゲームで使うサウンドを作成することができます。
 ドット絵を作成したエディタ上部のモード変更ボタンでサウンドエディタに切り替えて効果音を作成しましょう。
 効果音はサウンド0番に「引き分け」の音,1番に「勝ち」の音,2番に「負け」の3つを作ります。
 
 
 
 ※編集後は保存を忘れずに

 音楽が得意な人は,速さをもっと遅く(値を大きく)して,しっかりとした音を作ってみてください。
・一番下の鍵盤位置を押すと休符になります。
・画面下のTON欄でキー入力で音色 (T:Triangle / S:Square / P:Pulse / N:Noise) が指定できます。
・画面下のVOL欄でキー入力で音量 (0-7) が指定できます。
・画面下のEFX欄でキー入力でエフェクト (N:None / S:Slide / V:Vibrato / F:FadeOut) が指定できます。

 

07 効果音再生処理の追加

 作成した効果音はリソースファイルで画像と一緒に読み込まれます。音はpyxel.play()命令で番号を指定するだけで再生できます。今回のプログラムではプレーヤーとコンピューターの手が決まったところで音を鳴らしましょう。
  list04_07.py
 前のプログラムからの変更箇所は 確認用pdfファイル の7ページを参照してください。

import pyxel

pyxel.init(80,64,title="rock paper scissors")
pyxel.load("rps_game.pyxres")
pyxel.mouse(True)
com_hand = 0
player_hand = 0
status = 0
# result[ player ][ cpu ]  0:draw 1:p win 2:p lose
result = [[0,1,2],
          [2,0,1],
          [1,2,0]]
message = ["DRAW","WIN","LOSE"]

def check_area():
    ret = False
    x = pyxel.mouse_x
    y = pyxel.mouse_y
    if 16 <= x and x < 64 and 32 <= y and y < 48:
        ret = True
    return ret

def update():
    global com_hand, status, player_hand
    if status == 0:
        if pyxel.btnp(pyxel.MOUSE_BUTTON_LEFT) and check_area():
            player_hand = int(pyxel.mouse_x / 16) - 1
            com_hand = pyxel.rndi(0,2)
            idx = result[player_hand][com_hand]
            pyxel.play(0,idx)
            status = 1
        else:
            # クリック前は次々手を変える
            com_hand = int(pyxel.frame_count / 5) % 3
    elif status == 1:
        if pyxel.btnp(pyxel.MOUSE_BUTTON_LEFT):
            status = 0
    
    return

def draw():
    pyxel.cls(0)

    # コンピューターの手を描画
    pyxel.text(4,10, "COM",7)
    pyxel.blt(32,10, 0, com_hand*16,0, 16,16, 0)

    # プレーヤーの手を描画
    pyxel.text(4,32, "YOU",7)
    if status == 0:
        pyxel.blt(16,32, 0,  0,0, 16,16, 0)
        pyxel.blt(32,32, 0, 16,0, 16,16, 0)
        pyxel.blt(48,32, 0, 32,0, 16,16, 0)
    elif status == 1:
        pyxel.blt(16*(player_hand+1),32, 0, 16*player_hand,0, 16,16, 0)
        idx = result[player_hand][com_hand]
        pyxel.text(16*(player_hand+1),48, message[idx],7)
    
    return

pyxel.run(update, draw)

・pyxel.play(ch, snd)
 チャンネルch (0-3) でサウンドsnd (0-63) を再生します。今回は二次元配列で取得した結果がそのまま「0で引き分け,1で勝ち,2で負け」のサウンド番号となっています。

 プレーヤーの手を選んだあと,効果音と結果表示が正しいことを確認してじゃんけんゲームの完成です。

練習

プログラムを改造してみましょう。
・プレイヤーの引き分け数/勝利数/負け数を記録して画面に表示する。
・プレイヤーが手を選択するときにわかりやすくするため,マウス位置の画像に四角形の枠を表示する。