見出し画像

pygameで始めるpythonプログラム 4(クラス化編)

はじめに

前回の記事でキャラクターを操作できるようにしました。今回はちょっと立ち止まって、プログラム構造を見直してクラス化を行っていきます。

なぜ構造を見直すのか?

これまでは、ゲームの骨格となる部分を作ってきました。つまり、画面を出し、画面にキャラクターを登場させ、キャラクターをキーボードで操作できるようにしました。言い換えると、pygameがどんな風に動作するのか?という確認作業に近いものでした。

今後、本格的なゲームを作るにあたって、敵キャラ、障害物、二人プレイの時の2Pキャラを登場させたいとします。すでに作ったキャラクターをコピー&修正で作っていくと、プログラムが大変読みにくいものになります。だって、キャラクターであっても障害物であっても、画面に配置し、場合によっては動かすという点では同じ要素を持っていますよね。同じ要素を持っているものをコピーして修正してくと、メンテナンスする箇所が増えるわけです。

拡張性、メンテナンス性の高いプログラムを開発するためには、オブジェクト指向という概念を導入します。まずは敵キャラであろうが、障害物であろうが、もう一人の味方プレーヤであろうが簡単に増やせるようにオブジェクト指向の中心でもあるクラス構造を考えていきます。

どう考える?

要するにゲームの登場するモノ(キャラクター、障害物)っていうのは、
- 画像表示
- 表示位置
する必要があります。
まずはこういった概念をGameObjectクラスとして定義したいと思います。

次に、キャラクターっていうのはGameObjectクラスの概念に加えて
- 動き(表示位置移動)
- アクション(攻撃とか?)
する必要があります。これをCharacterクラスとして定義します。

最後に障害物っていうのはGameObjectクラスの概念に加えて
- キャラクターとの当たり判定
が必要となります。障害物を動かすかは後で考えるのでいったん置いておきましょう。これをObstructionクラスとして定義します。

クラス図

とりあえず、ざっくりクラス図を作ってみます。

ざっくりクラス図

コードに落とし込む

先ほど考えたクラス図をコードに落とし込みます。関数名とか変数名は日本語で適当につけちゃったのでプログラムらしいものに変えています。さっき書いたクラス図からプログラムを書くとイマイチな箇所も変えています。(クラス図の方を直せよ

# 登場オブジェクトクラス
class GameObject:
    def __init__(self, x, y, width, height, image_path = None):
        self.image = pygame.image.load(image_path)
        self.image = pygame.transform.scale(self.image, (width, height))
        self.obj = self.image.get_rect(topleft=(x, y))            
    
    def draw(self, screen):
        screen.blit(self.image, self.obj)

# キャラクタークラス
class Character(GameObject):
    def __init__(self, x, y, width, height, image_path, index):
        super().__init__(x, y, width, height, image_path)

    def move(self, dx, dy):
        # 横移動
        if self.obj.x + dx < 0:
            self.obj.x = 0
        elif self.obj.x + dx > SCREEN_WIDTH - 50:
            self.obj.x = SCREEN_WIDTH - 50
        else:
            self.obj.x += dx
        # 縦移動
        self.obj.y += dy

    def attack(self):
        # ビームを生成??(後で考える)
        pass

    def draw(self, screen):
        super().draw(screen)

# 障害物オブジェクト
class Obstruction(GameObject):
    def __init__(self, x, y, width, height, image_path):
        super().__init__(x, y, width, height, image_path)
    
    def check_collision(self, character):
        return self.obj.colliderect(character.rect)

まだ全然構造だけ書いたものなのでまともに動きませんが、クラス構造のイメージとしてはこんな感じです。

では、続きは次回ということで😅

この記事が気に入ったらサポートをしてみませんか?