【ChatGPT】プロンプトでPythonコードのゲームを生成してみた

【ChatGPT】プロンプトでPythonコードのゲームを生成してみた

ChatGPTでPythonで動作するシューティングゲームを作成しました。1回のメッセージでは仕様通りとなりませんでしたが、2回目のメッセージによる修正依頼で、想定通りのシューティングゲームを簡単に作成することができました。

ChatGPTを利用して、Pythonで動作するシューティングゲームを作成させてみました。
1回のプロンプトでは要求を満たさない結果となったので、2回目で修正依頼をすることで、想定通りのシューティングゲームを作成することができました。

プロンプト1

まず以下仕様で、ChatGPTにソースコード作成依頼をしてみました。

送信メッセージ1

Pythonでシューティングゲームを作成してください。

#前提
・Python3で動作すること。
・ソースコードをコピーしてそのまま使えること。
・起動時にエラーが発生しないこと。

#仕様
・矢印キーで上下左右に実機を操作できる。
・スペースキーで弾を発射し、長押しで連射できる。
・敵に当たるか敵の弾に当たるとライフが1つ減る。
・実機のライフは3つで、0になったらゲームオーバーになる。
・実機の色は白色とする。
・敵は上から出て来て、上から下に弾を発射する。
・敵のライフは1つ。
・敵の色は赤色とする。
・敵を倒すとスコアが100増える。
・スコアは左側にSCOREと表示する。
・ライフは右側にLIFEと表示する。
・ゲームオーバー後は、Enterキーでゲームを再開できる。

#アウトプット
・上記仕様をすべて満たすソースコード
・ソースコードのファイル名
・Pythonの必要なライブラリがあれば、インストールコマンド
・作成ソースコードの起動方法
・操作方法・仕様の説明書

ChatGPT回答1

Pythonでシューティングゲームを作成するためには、Pygameライブラリを使用します。
以下に、仕様を満たすソースコードを提供します。

必要なライブラリ

まず、Pygameをインストールする必要があります。以下のコマンドを使用してインストールしてください。

pip install pygame

ソースコード

次に、以下のソースコードを shooting_game.py というファイル名で保存してください。

import pygame
import random

# ゲームの初期化
pygame.init()

# 画面サイズの設定
screen_width = 800
screen_height = 600
screen = pygame.display.set_mode((screen_width, screen_height))

# フォントの設定
font = pygame.font.SysFont(None, 36)

# 色の設定
white = (255, 255, 255)
red = (255, 0, 0)
black = (0, 0, 0)

# 実機クラス
class Player(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.image = pygame.Surface((50, 50))
        self.image.fill(white)
        self.rect = self.image.get_rect()
        self.rect.center = (screen_width // 2, screen_height - 50)
        self.speed = 5
        self.lives = 3

    def update(self):
        keys = pygame.key.get_pressed()
        if keys[pygame.K_LEFT] and self.rect.left > 0:
            self.rect.x -= self.speed
        if keys[pygame.K_RIGHT] and self.rect.right < screen_width:
            self.rect.x += self.speed
        if keys[pygame.K_UP] and self.rect.top > 0:
            self.rect.y -= self.speed
        if keys[pygame.K_DOWN] and self.rect.bottom < screen_height:
            self.rect.y += self.speed

    def shoot(self):
        bullet = Bullet(self.rect.centerx, self.rect.top)
        all_sprites.add(bullet)
        player_bullets.add(bullet)

# 弾クラス
class Bullet(pygame.sprite.Sprite):
    def __init__(self, x, y):
        super().__init__()
        self.image = pygame.Surface((5, 10))
        self.image.fill(white)
        self.rect = self.image.get_rect()
        self.rect.centerx = x
        self.rect.bottom = y
        self.speed = -10

    def update(self):
        self.rect.y += self.speed
        if self.rect.bottom < 0:
            self.kill()

# 敵クラス
class Enemy(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.image = pygame.Surface((50, 50))
        self.image.fill(red)
        self.rect = self.image.get_rect()
        self.rect.x = random.randint(0, screen_width - self.rect.width)
        self.rect.y = random.randint(-100, -40)
        self.speed = random.randint(1, 3)
        self.shoot_delay = random.randint(500, 1500)
        self.last_shot = pygame.time.get_ticks()

    def update(self):
        self.rect.y += self.speed
        if self.rect.top > screen_height:
            self.rect.x = random.randint(0, screen_width - self.rect.width)
            self.rect.y = random.randint(-100, -40)
            self.speed = random.randint(1, 3)
        
        now = pygame.time.get_ticks()
        if now - self.last_shot > self.shoot_delay:
            self.shoot()
            self.last_shot = now

    def shoot(self):
        bullet = EnemyBullet(self.rect.centerx, self.rect.bottom)
        all_sprites.add(bullet)
        enemy_bullets.add(bullet)

# 敵の弾クラス
class EnemyBullet(pygame.sprite.Sprite):
    def __init__(self, x, y):
        super().__init__()
        self.image = pygame.Surface((5, 10))
        self.image.fill(red)
        self.rect = self.image.get_rect()
        self.rect.centerx = x
        self.rect.top = y
        self.speed = 5

    def update(self):
        self.rect.y += self.speed
        if self.rect.top > screen_height:
            self.kill()

# スプライトグループの設定
all_sprites = pygame.sprite.Group()
player_bullets = pygame.sprite.Group()
enemy_bullets = pygame.sprite.Group()
enemies = pygame.sprite.Group()

# プレイヤーの生成
player = Player()
all_sprites.add(player)

# 敵の生成
for _ in range(5):
    enemy = Enemy()
    all_sprites.add(enemy)
    enemies.add(enemy)

# スコアとゲームオーバーフラグ
score = 0
game_over = False

# ゲームループ
running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_SPACE and not game_over:
                player.shoot()
            if event.key == pygame.K_RETURN and game_over:
                # リスタート
                player.lives = 3
                score = 0
                game_over = False
                for bullet in enemy_bullets:
                    bullet.kill()
                for enemy in enemies:
                    enemy.kill()
                for _ in range(5):
                    enemy = Enemy()
                    all_sprites.add(enemy)
                    enemies.add(enemy)

    # ゲームがオーバーでない場合の処理
    if not game_over:
        all_sprites.update()

        # プレイヤーの弾と敵の衝突判定
        hits = pygame.sprite.groupcollide(enemies, player_bullets, True, True)
        for hit in hits:
            score += 100
            enemy = Enemy()
            all_sprites.add(enemy)
            enemies.add(enemy)

        # プレイヤーと敵の弾の衝突判定
        hits = pygame.sprite.spritecollide(player, enemy_bullets, True)
        for hit in hits:
            player.lives -= 1
            if player.lives <= 0:
                game_over = True

        # プレイヤーと敵の衝突判定
        hits = pygame.sprite.spritecollide(player, enemies, False)
        for hit in hits:
            player.lives -= 1
            hit.kill()
            enemy = Enemy()
            all_sprites.add(enemy)
            enemies.add(enemy)
            if player.lives <= 0:
                game_over = True

    # 画面の描画
    screen.fill(black)
    all_sprites.draw(screen)

    # スコアとライフの表示
    score_text = font.render(f"SCORE: {score}", True, white)
    screen.blit(score_text, (10, 10))
    lives_text = font.render(f"LIFE: {player.lives}", True, white)
    screen.blit(lives_text, (screen_width - 150, 10))

    # ゲームオーバーの表示
    if game_over:
        game_over_text = font.render("GAME OVER - Press Enter to Restart", True, red)
        screen.blit(game_over_text, (screen_width // 4, screen_height // 2))

    pygame.display.flip()
    pygame.time.delay(30)

pygame.quit()

起動方法

上記のソースコードを shooting_game.py というファイル名で保存します。
コマンドラインまたはターミナルで以下のコマンドを実行してゲームを起動します。

python shooting_game.py

操作方法・仕様の説明

  • 矢印キーで実機を上下左右に移動できます。
  • スペースキーで弾を発射できます(長押しで連射可能)。
  • 敵や敵の弾に当たるとライフが1つ減り、ライフが0になるとゲームオーバーです。
  • 敵を倒すとスコアが100増えます。
  • スコアは画面左上に SCORE として表示されます。
  • ライフは画面右上に LIFE として表示されます。
  • ゲームオーバー後はEnterキーでゲームを再開できます。
  • このコードをコピーして実行すれば、指定された仕様を満たすシューティングゲームが動作します。

動作テスト1

まず回答の指定通り、pygameをインストールしました。

$ pip install pygame
Defaulting to user installation because normal site-packages is not writeable
Collecting pygame
  Downloading pygame-2.6.0-cp312-cp312-win_amd64.whl.metadata (13 kB)
Downloading pygame-2.6.0-cp312-cp312-win_amd64.whl (10.8 MB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 10.8/10.8 MB 12.6 MB/s eta 0:00:00
Installing collected packages: pygame
Successfully installed pygame-2.6.0

[notice] A new release of pip is available: 24.0 -> 24.1.2
[notice] To update, run: C:\Users\dorae\AppData\Local\Microsoft\WindowsApps\PythonSoftwareFoundation.Python.3.12_qbz5n2kfra8p0\python.exe -m pip install --upgrade pip

shooting_game.pyファイルを保存し、以下コマンドで起動します。

python shooting_game.py

実行中画面1

ゲームが起動しましたが、動きがもっさりとしていました。
また、弾の発射はできましたが、連射ができませんでした。

alt text

ゲームオーバー画面1

ライフが0になるとゲームオーバーになり、Enterキーでリスタートできました。
こちらは想定通りの動きです。
alt text

プロンプト2

弾の連射ができないことと、動きがもっさりしていたので、以下の通り修正依頼をすることにしました。

送信メッセージ2

生成ありがとうございます。確認しました。
長押しで連射できず、以下使用が満たされていませんでした。
・スペースキーで弾を発射し、長押しで連射できる。

また動きがもっさりしているので、スムーズに動作するように改善お願いします。

ChatGPT回答2

連射機能と動作のスムーズさを改善するために、次のようにコードを更新します。

  • 連射機能のために、弾の発射にクールダウン(発射間隔)を設定します。
  • 動作をスムーズにするために、フレームレートを管理し、更新を高速化します。

以下の修正されたソースコードを shooting_game.py にコピーして実行してください。

import pygame
import random

# ゲームの初期化
pygame.init()

# 画面サイズの設定
screen_width = 800
screen_height = 600
screen = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption("Shooting Game")

# フォントの設定
font = pygame.font.SysFont(None, 36)

# 色の設定
white = (255, 255, 255)
red = (255, 0, 0)
black = (0, 0, 0)

# 実機クラス
class Player(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.image = pygame.Surface((50, 50))
        self.image.fill(white)
        self.rect = self.image.get_rect()
        self.rect.center = (screen_width // 2, screen_height - 50)
        self.speed = 5
        self.lives = 3
        self.shoot_delay = 250  # ミリ秒
        self.last_shot = pygame.time.get_ticks()

    def update(self):
        keys = pygame.key.get_pressed()
        if keys[pygame.K_LEFT] and self.rect.left > 0:
            self.rect.x -= self.speed
        if keys[pygame.K_RIGHT] and self.rect.right < screen_width:
            self.rect.x += self.speed
        if keys[pygame.K_UP] and self.rect.top > 0:
            self.rect.y -= self.speed
        if keys[pygame.K_DOWN] and self.rect.bottom < screen_height:
            self.rect.y += self.speed
        if keys[pygame.K_SPACE]:
            self.shoot()

    def shoot(self):
        now = pygame.time.get_ticks()
        if now - self.last_shot > self.shoot_delay:
            self.last_shot = now
            bullet = Bullet(self.rect.centerx, self.rect.top)
            all_sprites.add(bullet)
            player_bullets.add(bullet)

# 弾クラス
class Bullet(pygame.sprite.Sprite):
    def __init__(self, x, y):
        super().__init__()
        self.image = pygame.Surface((5, 10))
        self.image.fill(white)
        self.rect = self.image.get_rect()
        self.rect.centerx = x
        self.rect.bottom = y
        self.speed = -10

    def update(self):
        self.rect.y += self.speed
        if self.rect.bottom < 0:
            self.kill()

# 敵クラス
class Enemy(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.image = pygame.Surface((50, 50))
        self.image.fill(red)
        self.rect = self.image.get_rect()
        self.rect.x = random.randint(0, screen_width - self.rect.width)
        self.rect.y = random.randint(-100, -40)
        self.speed = random.randint(1, 3)
        self.shoot_delay = random.randint(1000, 2000)
        self.last_shot = pygame.time.get_ticks()

    def update(self):
        self.rect.y += self.speed
        if self.rect.top > screen_height:
            self.rect.x = random.randint(0, screen_width - self.rect.width)
            self.rect.y = random.randint(-100, -40)
            self.speed = random.randint(1, 3)
        
        now = pygame.time.get_ticks()
        if now - self.last_shot > self.shoot_delay:
            self.shoot()
            self.last_shot = now

    def shoot(self):
        bullet = EnemyBullet(self.rect.centerx, self.rect.bottom)
        all_sprites.add(bullet)
        enemy_bullets.add(bullet)

# 敵の弾クラス
class EnemyBullet(pygame.sprite.Sprite):
    def __init__(self, x, y):
        super().__init__()
        self.image = pygame.Surface((5, 10))
        self.image.fill(red)
        self.rect = self.image.get_rect()
        self.rect.centerx = x
        self.rect.top = y
        self.speed = 5

    def update(self):
        self.rect.y += self.speed
        if self.rect.top > screen_height:
            self.kill()

# スプライトグループの設定
all_sprites = pygame.sprite.Group()
player_bullets = pygame.sprite.Group()
enemy_bullets = pygame.sprite.Group()
enemies = pygame.sprite.Group()

# プレイヤーの生成
player = Player()
all_sprites.add(player)

# 敵の生成
for _ in range(5):
    enemy = Enemy()
    all_sprites.add(enemy)
    enemies.add(enemy)

# スコアとゲームオーバーフラグ
score = 0
game_over = False

# クロックオブジェクトの生成
clock = pygame.time.Clock()

# ゲームループ
running = True
while running:
    clock.tick(60)  # フレームレートを60FPSに設定
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_RETURN and game_over:
                # リスタート
                player.lives = 3
                score = 0
                game_over = False
                for bullet in enemy_bullets:
                    bullet.kill()
                for enemy in enemies:
                    enemy.kill()
                for _ in range(5):
                    enemy = Enemy()
                    all_sprites.add(enemy)
                    enemies.add(enemy)

    # ゲームがオーバーでない場合の処理
    if not game_over:
        all_sprites.update()

        # プレイヤーの弾と敵の衝突判定
        hits = pygame.sprite.groupcollide(enemies, player_bullets, True, True)
        for hit in hits:
            score += 100
            enemy = Enemy()
            all_sprites.add(enemy)
            enemies.add(enemy)

        # プレイヤーと敵の弾の衝突判定
        hits = pygame.sprite.spritecollide(player, enemy_bullets, True)
        for hit in hits:
            player.lives -= 1
            if player.lives <= 0:
                game_over = True

        # プレイヤーと敵の衝突判定
        hits = pygame.sprite.spritecollide(player, enemies, False)
        for hit in hits:
            player.lives -= 1
            hit.kill()
            enemy = Enemy()
            all_sprites.add(enemy)
            enemies.add(enemy)
            if player.lives <= 0:
                game_over = True

    # 画面の描画
    screen.fill(black)
    all_sprites.draw(screen)

    # スコアとライフの表示
    score_text = font.render(f"SCORE: {score}", True, white)
    screen.blit(score_text, (10, 10))
    lives_text = font.render(f"LIFE: {player.lives}", True, white)
    screen.blit(lives_text, (screen_width - 150, 10))

    # ゲームオーバーの表示
    if game_over:
        game_over_text = font.render("GAME OVER - Press Enter to Restart", True, red)
        screen.blit(game_over_text, (screen_width // 4, screen_height // 2))

    pygame.display.flip()

pygame.quit()

この修正後のコードは、以下の改善点があります:

  • スペースキーを長押しで連射ができるようにしました。
  • クロックオブジェクトを使ってフレームレートを60FPSに設定し、動作をスムーズにしました。

これで、よりスムーズな動作と連射機能を備えたシューティングゲームを楽しむことができます。

動作テスト2

ChatGPTの回答通り、連射ができるようになり、動きもスムーズになりました!

実行中画面2

alt text

ゲームオーバー画面2

alt text

まとめ

  • ChatGTPでソースコードを作成する際は、具体的な仕様を記載する。
  • 記載した仕様が満たされていない場合は、修正依頼をする必要がある。

以上で本記事の解説を終わります。
よいITライフを!
Scroll to Top