Pyxel シューティングゲーム(後編)

Pyxel サンプルコードからゲーム開発の基礎を学ぶ

 Python向けレトロゲームエンジン「Pyxel(ピクセル)」を使ってのゲーム作成を通してプログラミングを学習します。
 Pyxelのサンプルコード 09_shooter.py 「画面遷移のあるシューティングゲーム」を写して,キャラクターが画面上を動く仕組みや衝突判定の方法を見てみましょう。
 
 前編の記事kinutani.hateblo.jp

 

シューティングゲームのコード例

 ※リソースファイルはPyxelのサンプルを使用します。以下の記事を参照してください。 
 Pyxel サンプルリソースを使う - 勉強ボックス管理者ブログ

 ※ソースファイルの内容(list10_01 ~ list10_07)
 シューティングゲーム01 - Google ドライブ

 

05 敵を出現させる

 画面上に敵をたくさん出現させましょう。サンプルコードでは左右に動きながら下方向へ移動する敵ですが,ここでは右側に出現して左方向へ進み,画面外に出たら消えるようにします。また,ドット絵の表示を切り替えて動いているように見せる処理を作ります。

【ソースコード】はこちらのリンクから確認してください(Googleドキュメント)
list10_05.py 抜粋

ENEMY_ANIMA =[ (0,48),(8,48),(16,48) ]

enemies = []

class Enemy:
    def __init__(self, x, y, dx, dy):
  ・・・
        self.tmr = 0
  ・・・

    def update(self):
        self.tmr += 1
  ・・・

    def draw(self):
        u,v = ENEMY_ANIMA[(self.tmr//4)%3]
        pyxel.blt(self.x, self.y, 0, u, v, self.w, self.h, 0)
・・・
class App:
 ・・・
    def update_play_scene(self):
        if pyxel.frame_count % 20 == 0:
            Enemy(pyxel.width,pyxel.rndi(0,pyxel.height - ENEMY_HEIGHT),-2,0)

実行結果
 

・ENEMY_ANIMA =[ (0,48),(8,48),(16,48) ]
 animationを略してANIMAとしています。敵のドット絵3パターンの座標をタプル型のリストにして設定し,update()メソッドでカウンターを増やしてその値によってdraw()メソッドでの描画を切り替えています。

・Enemy(pyxel.width,pyxel.rndi(0,pyxel.height - ENEMY_HEIGHT),-2,0)
 Enemyクラスのコンストラクタ(__init__()メソッド)の引数にdx,dyとしてxとyの変化量を追加しました。インスタンス作成時にdxに-2を指定しているので,update()のたびにx座標が-2されます。(yは0指定なので変化なし)

 

06 衝突判定の追加

 自機の撃った弾が敵に当たったら敵と弾が爆発して消える。という処理を追加します。具体的には敵のリストを先頭から一体一体取り出して,弾のリストの座標と比較してヒットチェック(衝突判定)を行います。

【ソースコード】はこちらのリンクから確認してください(Googleドキュメント)
list10_06.py 抜粋

class App:
・・・
    def update_play_scene(self):
  ・・・
        for enemy in enemies:
            for bullet in bullets:
                if (
                    enemy.x + enemy.w > bullet.x
                    and bullet.x + bullet.w > enemy.x
                    and enemy.y + enemy.h > bullet.y
                    and bullet.y + bullet.h > enemy.y
                ):
                    enemy.is_alive = False
                    bullet.is_alive = False
                    blasts.append(
                        Blast(enemy.x + ENEMY_WIDTH / 2,
                              enemy.y + ENEMY_HEIGHT / 2)
                    )
                    pyxel.play(1, 1)
                    self.score += 10

実行結果
 

・if ( ) :
 if文の条件式が長くなる場合に,複数行に分けて記述すると見やすくなります。しかし,単純に改行した場合は実行時にifの行に「:」がないというエラーとなってしまいます。そこでカッコ()をつけて条件式の範囲を示して記述しています。

 衝突判定で比較している座標のイメージです。
 サンプルコードのこの衝突判定は,弾の形が縦長でも横長でも利用できます。また同じアルゴリズムで自機と敵の衝突判定も次の手順で追加します。

 

07 画面遷移の追加

 画面遷移(タイトル画面→プレイ画面→ゲームオーバー画面)の処理を追加します。更新処理と描画処理をそれぞれ画面ごとの処理に分け,キー操作による遷移と自機が敵に衝突したときのゲームオーバーとなる仕組みを追加しましょう。

【ソースコード】はこちらのリンクから確認してください(Googleドキュメント)
list10_07.py 抜粋

SCENE_TITLE = 0
SCENE_PLAY = 1
SCENE_GAMEOVER = 2
・・・
class App:
    def __init__(self):
  ・・・
        self.scene = SCENE_TITLE
  ・・・

    def update(self):
        self.background.update()
        if self.scene == SCENE_TITLE:
            self.update_title_scene()
        elif self.scene == SCENE_PLAY:
            self.update_play_scene()
        elif self.scene == SCENE_GAMEOVER:
            self.update_gameover_scene()
        return
・・・
    def draw(self):
        pyxel.cls(0)
        self.background.draw()
        if self.scene == SCENE_TITLE:
            self.draw_title_scene()
        elif self.scene == SCENE_PLAY:
            self.draw_play_scene()
        elif self.scene == SCENE_GAMEOVER:
            self.draw_gameover_scene()
        pyxel.text(10, 4, f"SCORE {self.score:5}", 7)
        return
・・・

実行結果
 


 以上で,サンプルコードのシューティングゲームを横画面に変更しながら写す手順は完了です。サンプルコードには,ゲームパッドのキー操作や,アプリ終了キー操作のコードも載っていますので調べてみてください。


 シューティングゲームの改造内容としては以下のようなものがあります。
 ・敵の種類を増やす
 ・敵が弾を撃つ
 ・アイテムを取って自機がパワーアップする
 ・タイルマップで背景を作りスクロールさせる
 ・1回のミスでゲームオーバーにしない。
 ・ボスが登場する。
 ・ステージクリア,エンディングをつくる。

 
 次の記事「敵の種類を増やす,敵が弾を撃つ」kinutani.hateblo.jp


 

関連記事

 kinutani.hateblo.jp