はじめに
お世話になっております。
watnow所属の山内と申します。
ますます厳しさを増す寒さの中、お身体の調子はいかがでしょうか。どうかお体を温め、ご自身の健康を最優先にお過ごしください。
さて、現在私は大学で「オブジェクト指向論」を履修しております。この学びを実践する一環として、以前pythonで作成した横スクロールゲームをオブジェクト指向に書き直しました。その過程での変更点や課題について、この記事で共有していきたいと思います。
初めての記事執筆、拙いコードですが、どうか温かい目で見守っていただければと願っております。
目次
Before
元のコードの特徴として、ほとんどの処理がmain内に記述されていました。さすがに見にくすぎたのか、いくつかの機能は関数として定義されています。
import pygame
from pygame.locals import *
import sys
def map_make(map_data, screen, map_now, size):
# 配列 map_data のデータからブロックを配置
# ...
def map_check(map_data, x_now, y_now, next_x, next_y, size):
# 当たり判定の計算
# ...
# リスタート状態
def restart(setup):
#リスタートの際のマップ、プレイヤーの状態
# ...
def main():
# 各変数初期化
# ...
# マップデータの入った.txtファイルの読み込み、配列に保存
# ...
# ステージの読み込み、ブロックの配置
# ...
# キー入力に応じたプレイヤーの移動
# ...
# 以下たくさんのコード
# ...
if __name__ == "__main__":
main()
下の画像がゲーム画面です。黄緑の丸がプレイヤーです。青のブロックには触れても問題なく、赤のブロックに触れたらゲームオーバーです。
After
こんな感じになりました。
(一部の機能しか実装できていません)
import pygame
import sys
class GameObject:
def __init__(self, x, y, size, color):
self.rect = pygame.Rect(x, y, size, size)
self.color = color
def draw(self, screen):
pygame.draw.rect(screen, self.color, self.rect)
class Player(GameObject):
def __init__(self, x, y, size, color):
super().__init__(x, y, size, color)
self.speed = 5
self.jump_status = False
self.jump_status_up = 1
self.jump_speed = self.speed * 2
self.jump_high = size * 5
self.jump_start = 0
def move(self, direction):
if direction == "a":
self.rect.x -= self.speed
elif direction == "d":
self.rect.x += self.speed
elif direction == "space" and not self.jump_status:
self.jump_status = True
self.jump_start = self.rect.y
def jump(self):
if self.jump_status:
if self.jump_status_up == 1:
if self.jump_start - self.rect.y >= self.jump_high:
self.jump_status_up *= -1
else:
if self.jump_start - self.rect.y == 0:
self.jump_status = False
self.jump_status_up *= -1
self.rect.y -= self.jump_speed * self.jump_status_up
class Game:
def __init__(self, width, height, size):
self.width = width
self.height = height
self.screen = pygame.display.set_mode((width, height))
pygame.display.set_caption("main")
self.clock = pygame.time.Clock()
self.player = Player(size*2, height-size*3, size, (0, 255, 0))
self.game_objects = [self.player]
def handle_events(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
def update(self):
keys = pygame.key.get_pressed()
if keys[pygame.K_a]:
self.player.move("a")
if keys[pygame.K_d]:
self.player.move("d")
if keys[pygame.K_SPACE]:
self.player.move("space")
if keys[pygame.K_ESCAPE]:
pygame.quit()
sys.exit()
self.player.jump()
def draw(self):
self.screen.fill((0, 0, 0))
for obj in self.game_objects:
obj.draw(self.screen)
pygame.display.flip()
def run(self):
while True:
self.handle_events()
self.update()
self.draw()
self.clock.tick(60)
if __name__ == "__main__":
pygame.init()
game = Game(1000, 500, 25)
game.run()
GameObjectクラス:
・ゲーム内のオブジェクトを表す基底クラス
・_init_メソッド : 引数からpygame.Rect オブジェクトと色を初期化
・draw メソッド : オブジェクトを画面に描画
Player クラス:
・GameObject クラスを継承したプレイヤークラス
・_init_メソッド : プレイヤー固有の変数を初期化
・move メソッド : キー入力に応じてプレイヤーの移動、ジャンプの開始を制御
・jump メソッド : ジャンプの制御
Game クラス:
・ゲーム全体の制御を行うクラス
・_init_メソッド: ウィンドウ、ゲームオブジェクトのリストなどの初期化
・handle_events メソッド: Pygameイベントの処理
・update メソッド: キー入力に応じてプレイヤーの移動やジャンプを制御
・draw メソッド: 背景、ゲームオブジェクトの描画
・run メソッド: ゲームのメインループ
main:
・Pygame の初期化、Gameクラスのインスタンスの作成、runメソッドの呼び出し
感想
オブジェクト指向で作成したプログラムのほうが可読性と保守性を高めることができたと思います。
授業の内容だけではうまくプログラムを作成できなかったため、chatGPT君にたくさん助けてもらいました。時間的な問題で一部の機能しか実装できなかったので、いつか完成させたいです。
最後まで見ていただきありがとうございます。