見出し画像

生成AIでプログラミング・・・簡単なゲームを作ったよ

簡単なゲームを作るよ

前報でオブジェクトが動くようになりました。今度は簡単なゲームを作りましょう。

まずはレイアウト

文夫
600×600の画面があって、下100ピクセルに茶色の土があります。その上で横方向中央部に茶色の丸いボールがあります。このプログラムを書いてください
ChatGPT

import pygame
import sys

# 初期化
pygame.init()

# ウィンドウのサイズ
width, height = 600, 600

# 土の高さ
ground_height = 100

# 土の色
ground_color = (139, 69, 19)  # 茶色

# ボールの半径と色
ball_radius = 30
ball_color = (139, 69, 19)  # 茶色

# ウィンドウの作成
screen = pygame.display.set_mode((width, height))
pygame.display.set_caption("土とボール")

# ゲームループ
clock = pygame.time.Clock()
while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()

    # 画面をクリア
    screen.fill((255, 255, 255))  # 白色でクリア

    # 土を描画
    pygame.draw.rect(screen, ground_color, (0, height - ground_height, width, ground_height))

    # ボールを描画
    ball_x = (width - ball_radius) // 2
    ball_y = height - ground_height - ball_radius - 5  # ボールを地面から浮かせるため5ピクセル上に配置
    pygame.draw.circle(screen, ball_color, (ball_x, ball_y), ball_radius)

    # 画面を更新
    pygame.display.flip()

    # フレームレートを制限
    clock.tick(60)

作成したのが次です。白い背景では見にくいので背景を青にしときました。

指示が拙くてボールと地面を同じ茶色にしています。これとボールがなぜか5ピクセルほど浮いています。簡単にこれを直して次に行きます。

ボールをジャンプさせます

文夫
次に、スペースキーを押すとボールが300ピクセルほどジャンプし、加速度を考慮した速度で落下し、地面に接してとまります。なお、ボールの色を橙色にして、ボールの初期位置は地面に接するとします。

import pygame
import sys

# 初期化
pygame.init()

# ウィンドウのサイズ
width, height = 600, 600

# 土の高さ
ground_height = 100

# 土の色
ground_color = (139, 69, 19)  # 茶色

# ボールの半径と色
ball_radius = 30
ball_color = (255, 165, 0)  # 橙色

# 初速度と重力加速度
initial_jump_velocity = -10
gravity = 0.5

# ウィンドウの作成
screen = pygame.display.set_mode((width, height))
pygame.display.set_caption("ジャンプと落下")

# ボールの初期位置
ball_x = (width - ball_radius) // 2
ball_y = height - ground_height - ball_radius

# ボールの速度
velocity = 0

# ゲームループ
clock = pygame.time.Clock()
while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()
        elif event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
            # スペースキーが押されたらジャンプ
            velocity = initial_jump_velocity

    # 速度を更新し、ボールの位置を更新
    velocity += gravity
    ball_y += velocity

    # 地面に接したら位置を修正
    if ball_y >= height - ground_height - ball_radius:
        ball_y = height - ground_height - ball_radius
        velocity = 0

    # 画面をクリア
    screen.fill((255, 255, 255))  # 白色でクリア

    # 土を描画
    pygame.draw.rect(screen, ground_color, (0, height - ground_height, width, ground_height))

    # ボールを描画
    pygame.draw.circle(screen, ball_color, (int(ball_x), int(ball_y)), ball_radius)

    # 画面を更新
    pygame.display.flip()

    # フレームレートを制限
    clock.tick(60)

ボールが右から出てきます

次に赤い同じ大きさのボールが、右から適当なランダムな時間間隔で転がってきます。

import pygame
import sys
import random

# 初期化
pygame.init()

# ウィンドウのサイズ
width, height = 600, 600

# 土の高さ
ground_height = 100

# 土の色
ground_color = (139, 69, 19)  # 茶色

# プレイヤーのボールの半径と色
player_radius = 30
player_color = (255, 165, 0)  # 橙色

# ジャンプの初速度と重力加速度
initial_jump_velocity = -12
gravity = 0.5

# 敵のボールの半径と色
enemy_radius = 30
enemy_color = (255, 0, 0)  # 赤色

# ウィンドウの作成
screen = pygame.display.set_mode((width, height))
pygame.display.set_caption("ジャンプと敵ボール")

# プレイヤーのボールの初期位置
player_x = (width - player_radius) // 2
player_y = height - ground_height - player_radius

# プレイヤーのボールの速度
player_velocity = 0

# 敵ボールの初期位置と速度
enemy_x = width + enemy_radius  # 右端からスタート
enemy_y = height - ground_height - enemy_radius
enemy_velocity = random.uniform(1, 5)  # ランダムな速度

# 敵ボールのリセットまでの時間
enemy_reset_time = random.randint(50, 200)  # ランダムな時間

# ゲームループ
clock = pygame.time.Clock()
while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()
        elif event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE and player_y == height - ground_height - player_radius:
            # スペースキーが押され、かつプレイヤーが地面に接している場合にジャンプ
            player_velocity = initial_jump_velocity

    # プレイヤーの速度を更新し、ボールの位置を更新
    player_velocity += gravity
    player_y += player_velocity

    # プレイヤーが地面に接したら位置を修正
    if player_y >= height - ground_height - player_radius:
        player_y = height - ground_height - player_radius
        player_velocity = 0

    # 敵ボールの位置を更新
    enemy_x -= enemy_velocity

    # 敵ボールが左端まで到達したらリセット
    if enemy_x < -enemy_radius:
        enemy_x = width + enemy_radius
        enemy_velocity = random.uniform(1, 5)  # ランダムな速度
        enemy_reset_time = random.randint(50, 200)  # ランダムな時間

    # 画面をクリア
    screen.fill((255, 255, 255))  # 白色でクリア

    # 土を描画
    pygame.draw.rect(screen, ground_color, (0, height - ground_height, width, ground_height))

    # プレイヤーのボールを描画
    pygame.draw.circle(screen, player_color, (int(player_x), int(player_y)), player_radius)

    # 敵ボールを描画
    pygame.draw.circle(screen, enemy_color, (int(enemy_x), int(enemy_y)), enemy_radius)

    # 画面を更新
    pygame.display.flip()

    # フレームレートを制限
    clock.tick(60)

    # 敵ボールのリセットまでの時間を減少させる
    enemy_reset_time -= 1

    # 敵ボールのリセットまでの時間が0になったらリセット
    if enemy_reset_time == 0:
        enemy_x = width + enemy_radius
        enemy_velocity = random.uniform(1, 5)  # ランダムな速度
        enemy_reset_time = random.randint(50, 200)  # ランダムな時間

ちょっと、赤いボールが途中で消えてしまうのが難点ですが、とにかく右からボールが出てきました。

このことを伝えて、つぎへ進みます。

衝突の判定と得点

文夫
素晴らしいですね。敵ボールの速度まで変わっている(^^♪ 敵ボールは左端まで行って消してください。 次に、プレイヤーボールと敵ボールが当たると5点減点で、敵ボールが左端まで通り過ぎると1点加点し、10秒間ゲームします。得点がプラスならGame Win でマイナスなら Game Loseを表示してください。

import pygame
import sys
import random

# 初期化
pygame.init()

# ウィンドウのサイズ
width, height = 600, 600

# 土の高さ
ground_height = 100

# 土の色
ground_color = (139, 69, 19)  # 茶色

# プレイヤーのボールの半径と色
player_radius = 30
player_color = (255, 165, 0)  # 橙色

# ジャンプの初速度と重力加速度
initial_jump_velocity = -12
gravity = 0.5

# 敵のボールの半径と色
enemy_radius = 30
enemy_color = (255, 0, 0)  # 赤色

# ウィンドウの作成
screen = pygame.display.set_mode((width, height))
pygame.display.set_caption("ジャンプと敵ボール")

# プレイヤーのボールの初期位置
player_x = (width - player_radius) // 2
player_y = height - ground_height - player_radius

# プレイヤーのボールの速度
player_velocity = 0

# 敵ボールの初期位置と速度
enemy_x = width + enemy_radius  # 右端からスタート
enemy_y = height - ground_height - enemy_radius
enemy_velocity = random.uniform(1, 5)  # ランダムな速度

# 敵ボールのリセットまでの時間
enemy_reset_time = random.randint(50, 200)  # ランダムな時間

# ゲームの得点と制限時間
score = 0
time_limit = 60 * 60  # 60秒をフレーム数に変換

# ゲームの状態
game_over = False

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

# ゲームループ
clock = pygame.time.Clock()
while not game_over:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()
        elif event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE and player_y == height - ground_height - player_radius:
            # スペースキーが押され、かつプレイヤーが地面に接している場合にジャンプ
            player_velocity = initial_jump_velocity

    # プレイヤーの速度を更新し、ボールの位置を更新
    player_velocity += gravity
    player_y += player_velocity

    # プレイヤーが地面に接したら位置を修正
    if player_y >= height - ground_height - player_radius:
        player_y = height - ground_height - player_radius
        player_velocity = 0

    # 敵ボールの位置を更新
    enemy_x -= enemy_velocity

    # 敵ボールが左端まで到達したらリセット
    if enemy_x < -enemy_radius:
        enemy_x = width + enemy_radius
        enemy_velocity = random.uniform(1, 5)  # ランダムな速度
        enemy_reset_time = random.randint(50, 200)  # ランダムな時間

    # プレイヤーボールと敵ボールの当たり判定
    distance = ((player_x - enemy_x) ** 2 + (player_y - enemy_y) ** 2) ** 0.5
    if distance < player_radius + enemy_radius:
        # 当たった場合は得点を減点
        score -= 5

    # 得点の計算
    if enemy_x < player_x < enemy_x + enemy_radius and player_y == height - ground_height - player_radius:
        # プレイヤーが地面にいて、敵ボールが通り過ぎた場合は得点を加点
        score += 1

    # 画面をクリア
    screen.fill((255, 255, 255))  # 白色でクリア

    # 土を描画
    pygame.draw.rect(screen, ground_color, (0, height - ground_height, width, ground_height))

    # プレイヤーのボールを描画
    pygame.draw.circle(screen, player_color, (int(player_x), int(player_y)), player_radius)

    # 敵ボールを描画
    pygame.draw.circle(screen, enemy_color, (int(enemy_x), int(enemy_y)), enemy_radius)

    # 得点を描画
    score_text = font.render(f"Score: {score}", True, (0, 0, 0))
    screen.blit(score_text, (10, 10))

    # 残り時間を描画
    time_text = font.render(f"Time: {max(0, time_limit // 60)}", True, (0, 0, 0))
    screen.blit(time_text, (width - 100, 10))

    # 画面を更新
    pygame.display.flip()

    # フレームレートを制限
    clock.tick(60)

    # 時間制限を減少
    time_limit -= 1

    # 時間制限が0になったらゲームオーバー
    if time_limit == 0:
        game_over = True

# ゲーム結果の表示
result_text = font.render("Game Win" if score >= 0 else "Game Lose", True, (0, 0, 0))
screen.blit(result_text, (width // 2 - 50, height // 2 - 50))
pygame.display.flip()

# ゲーム終了までの待機
pygame.time.delay(2000)

pygame.quit()
sys.exit()


ちょっと見にくいですが、得点が大きくなっています。これは衝突判定の場合よくあるミスかと思います。

これからがうまくコミュニケーションが取れず、混乱します。ChatGPTは細かい修正が苦手のようで、修正を一か所だけやって、これでいいでしょうといって来ます。的確な指示を出せばいいのでしょうが、それも初心者にとっては難しいですね( ノД`)シクシク…

そこでbingに添削してもらうことにしました。

Bing

  • 敵ボールのリセットまでの時間は使っていないようです。不要な変数は削除した方が良いです。

  • プレイヤーのボールの位置を修正するときに、player_y = height - ground_height - player_radiusという式を使っていますが、これはプレイヤーのボールの初期位置と同じです。なので、player_y = player_y_initialという変数を定義して使った方が良いです。そうすれば、もしプレイヤーのボールの初期位置を変えたいときに、一箇所だけ変更すれば済みます。

  • プレイヤーのボールと敵ボールの当たり判定は、pygame.sprite.collide_circleという関数を使うと簡単に書けます。この関数は、二つのスプライト(画像)が円形の当たり判定を持つと仮定して、衝突しているかどうかを判定します。スプライトとは、ゲームで使われる画像のことです。この関数を使うには、ボールをスプライトとして定義する必要があります。スプライトの定義方法は[こちら]を参考にしてください。

  • 得点の計算は、敵ボールが左端に到達したときに行う方が簡単です。そうすれば、player_x < enemy_x + enemy_radiusという条件をチェックする必要がなくなります。また、敵ボールが左端に到達したときに、player_hit_enemyのフラグをチェックして、当たっていなければ得点を加点するようにすれば、player_hit_enemyのフラグをリセットする必要もなくなります。

ChatGPT+文夫
ChatGPTも直してくれてマイナーチェンジして、つぎのコードを今回の最終的なコードとします。

import pygame
import sys
import random

# 初期化
pygame.init()

# ウィンドウのサイズ
width, height = 600, 600

# 土の高さ
ground_height = 100

# 土の色
ground_color = (139, 69, 19)  # 茶色

# プレイヤーのボールの半径と色
player_radius = 30
player_color = (255, 165, 0)  # 橙色

# ジャンプの初速度と重力加速度
initial_jump_velocity = -15
gravity = 0.4


# 敵のボールの半径と色
enemy_radius = 30
enemy_color = (255, 0, 0)  # 赤色

# ウィンドウの作成
screen = pygame.display.set_mode((width, height))
pygame.display.set_caption("ジャンプと敵ボール")

# プレイヤーのボールの初期位置
player_x_initial = 100
player_y_initial = height - ground_height - player_radius
player_x = player_x_initial
player_y = player_y_initial

# プレイヤーのボールの速度
player_velocity = 0

# 敵ボールの初期位置と速度
enemy_x = width + enemy_radius  # 右端からスタート
enemy_y = height - ground_height - enemy_radius
enemy_velocity = random.uniform(3, 5)  # ランダムな速度

# ゲームの得点と制限時間
score = 0
time_limit = 60 * 60  # 60秒をフレーム数に変換

# ボールとプレイヤーの当たり判定を制御するフラグ
player_hit_enemy = False

# ゲームの状態
game_over = False

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

# プレイヤーのボールをスプライトとして定義
player = pygame.sprite.Sprite()
player.image = pygame.Surface((player_radius * 2, player_radius * 2))
player.image.fill((0, 0, 0))  # 透明色
player.image.set_colorkey((0, 0, 0))  # 透明色を設定
pygame.draw.circle(player.image, player_color, (player_radius, player_radius), player_radius)  # 円を描画
player.rect = player.image.get_rect()  # 矩形を取得
player.rect.center = (player_x, player_y)  # 中心座標を設定

# 敵のボールをスプライトとして定義
enemy = pygame.sprite.Sprite()
enemy.image = pygame.Surface((enemy_radius * 2, enemy_radius * 2))
enemy.image.fill((0, 0, 0))  # 透明色
enemy.image.set_colorkey((0, 0, 0))  # 透明色を設定
pygame.draw.circle(enemy.image, enemy_color, (enemy_radius, enemy_radius), enemy_radius)  # 円を描画
enemy.rect = enemy.image.get_rect()  # 矩形を取得
enemy.rect.center = (enemy_x, enemy_y)  # 中心座標を設定

all_sprites = pygame.sprite.Group()

# ゲームループ
clock = pygame.time.Clock()
while not game_over:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()
        elif event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE and player_y == player_y_initial:
        # スペースキーが押され、かつプレイヤーが地面に接している場合にジャンプ
            player_velocity = initial_jump_velocity


        elif event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
            # スペースキーが押され、かつプレイヤーが地面に接している場合にジャンプ
            player_velocity = initial_jump_velocity // 5

    # プレイヤーの速度を更新し、ボールの位置を更新
    player_velocity += gravity
    player_y += player_velocity

    # プレイヤーが地面に接したら位置を修正
    if player_y >= player_y_initial:
        player_y = player_y_initial
        player_velocity = 0

    # 敵ボールの位置を更新
    enemy_x -= enemy_velocity

    # 敵ボールが左端まで到達したらリセット
    if enemy_x < -enemy_radius:
        enemy_x = width + enemy_radius
        enemy_velocity = random.uniform(1, 5)  # ランダムな速度
        if not player_hit_enemy:
            # 当たっていなければ得点を加点
            score += 1
        else:
            score -= 1
        player_hit_enemy = False  # フラグをクリア

    # プレイヤーボールと敵ボールの当たり判定
    if pygame.sprite.collide_circle(player, enemy) and not player_hit_enemy:
        # 当たった場合は得点を減点
        #score  -= 5
        player_hit_enemy = True  # フラグをセット

    # 画面をクリア
    screen.fill((0, 127, 255, 80))  # 白色でクリア

    # 土を描画
    pygame.draw.rect(screen, ground_color, (0, height - ground_height, width, ground_height))

    # プレイヤーのボールを描画
    player.rect.center = (int(player_x), int(player_y))  # 中心座標を更新
    screen.blit(player.image, player.rect)  # 画像を描画

    # 敵ボールを描画
    enemy.rect.center = (int(enemy_x), int(enemy_y))  # 中心座標を更新
    screen.blit(enemy.image, enemy.rect)  # 画像を描画

    # 得点を描画
    score_text = font.render(f"Score: {score}", True, (0, 0, 0))
    screen.blit(score_text, (10, 10))

  # 残り時間を描画
    time_text = font.render(f"Time: {max(0, time_limit // 60)}", True, (0, 0, 0))
    screen.blit(time_text, (width - 100, 10))

    # スプライトを更新
    all_sprites.update()

    # スプライトを描画
    all_sprites.draw(screen)

    # 画面を更新
    pygame.display.flip()

    # フレームレートを制限
    clock.tick(60)

    # 時間制限を減少
    time_limit -= 1

    # 時間制限が0になったらゲームオーバー
    if time_limit == 0:
        game_over = True

# ゲーム結果の表示
result_text = font.render("Game Win" if score >= 0 else "Game Lose", True, (0, 0, 0))
screen.blit(result_text, (width // 2 - 50, height // 2 - 50))
pygame.display.flip()

# ゲーム終了までの待機
pygame.time.delay(2000)

pygame.quit()
sys.exit()

次は完成したゲームです。

今後のために

とりあえずは3回のChatGPTとのコミュニケーションで簡単なゲームを作ることが出来ました。
今後のためにどういうことが大事かと聞きました。

  • 初期化と設定の集約: ゲームの初期化と設定の部分を関数にまとめることができます。これにより、コードがきれいになります。例えば、initialize_gameなどの関数を作成し、それを呼び出すことができます。

  • ボールの描画コードの最適化: プレイヤーと敵のボールを描画する際に、透明な背景を持つサーフェスを作成してから円を描画しています。代わりに、直接円を描画することができます。これにより、コードが簡潔になります。

  • 変数の名前: 変数の名前が十分に明示的でない場合、コメントを追加して何をしているかを説明すると良いです。

  • スプライトの利用: pygame.sprite.Sprite を活用して、スプライトグループを管理することができます。これにより、all_sprites.update()all_sprites.draw(screen) のような一括処理が可能になり、コードがスッキリします。

  • 衝突判定の修正: 衝突判定について、現在はすべての画面において衝突を判定しています。もし地面など特定の領域においてのみ衝突を判定したい場合、それに合った条件を追加すると良いです。

コードとしてのサンプルも書いてくれました。

import pygame
import sys
import random

# 初期化と設定の関数
def initialize_game():
    pygame.init()
    width, height = 600, 600
    ground_height = 100
    ground_color = (139, 69, 19)  # 茶色
    player_radius = 30
    player_color = (255, 165, 0)  # 橙色
    initial_jump_velocity = -15
    gravity = 0.4
    enemy_radius = 30
    enemy_color = (255, 0, 0)  # 赤色
    screen = pygame.display.set_mode((width, height))
    pygame.display.set_caption("ジャンプと敵ボール")
    font = pygame.font.Font(None, 36)
    clock = pygame.time.Clock()
    return width, height, ground_height, ground_color, player_radius, player_color, initial_jump_velocity, gravity, enemy_radius, enemy_color, screen, font, clock

# プレイヤーと敵のボールを描画
def draw_ball(surface, color, position, radius):
    pygame.draw.circle(surface, color, position, radius)

# メインのゲームループ
def main_game_loop():
    # (中略)
    player = pygame.sprite.Sprite()
    player.image = pygame.Surface((player_radius * 2, player_radius * 2), pygame.SRCALPHA)
    pygame.draw.circle(player.image, player_color, (player_radius, player_radius), player_radius)
    player.rect = player.image.get_rect()
    player.rect.center = (player_x, player_y)

    enemy = pygame.sprite.Sprite()
    enemy.image = pygame.Surface((enemy_radius * 2, enemy_radius * 2), pygame.SRCALPHA)
    pygame.draw.circle(enemy.image, enemy_color, (enemy_radius, enemy_radius), enemy_radius)
    enemy.rect = enemy.image.get_rect()
    enemy.rect.center = (enemy_x, enemy_y)

    all_sprites = pygame.sprite.Group(player, enemy)

    while not game_over:
        for event in pygame.event.get():
            # (中略)

        # (中略)

        # 画面をクリア
        screen.fill((255, 255, 255))  # 白色でクリア

        # 土を描画
        pygame.draw.rect(screen, ground_color, (0, height - ground_height, width, ground_height))

        # プレイヤーと敵ボールを描画
        all_sprites.draw(screen)

        # (中略)

# ゲームの初期化
width, height, ground_height, ground_color, player_radius, player_color, initial_jump_velocity, gravity, enemy_radius, enemy_color, screen, font, clock = initialize_game()

# メインのゲームループ
main_game_loop()

文夫
提案されたコードにClassでの定義がないのですが、Spriteがそれにあたりますか

ChatGPT
はい、正しいです。提供されたコードでは、pygame.sprite.Sprite クラスを利用して、プレイヤーのボールと敵のボールをスプライトとして定義しています。以下がその一部です:

# プレイヤーのボールをスプライトとして定義
player = pygame.sprite.Sprite()
player.image = pygame.Surface((player_radius * 2, player_radius * 2))
# ...(以下省略)

# 敵のボールをスプライトとして定義
enemy = pygame.sprite.Sprite()
enemy.image = pygame.Surface((enemy_radius * 2, enemy_radius * 2))
# ...(以下省略)

これにより、playerenemy オブジェクトは pygame.sprite.Sprite クラスのインスタンスとなり、これを pygame.sprite.Group() クラスで管理しています。pygame.sprite.Group() クラスは、複数のスプライトをまとめて管理するためのコンテナです。

all_sprites = pygame.sprite.Group()
all_sprites.add(player, enemy)

このようにして、all_sprites にはプレイヤーと敵のボールが含まれ、ゲームループ内で一括して更新および描画されています。

なお、pygame.sprite.Sprite クラスを継承して、独自のスプライトクラスを定義することも可能ですが、今回のコードでは直接 pygame.sprite.Sprite クラスのインスタンスを使っています。
以上は二日目に勉強したClassとGroupの追加の勉強ですね。

まとめ

一つ一つやってきましたが、若干のコミュニケーション不足で前に進めないといったときにもbingが役立ってくれました。

次回からこのアドバイスをできるだけ使っていこうかと思います。

補足01

同じものをcatとfoxを使い、ChatGPTに頼んでみた。いろいろとあったが最終的にはこのようなプログラムになり、スケールを変えたが、ちょっとcat,foxの縦横比がおかしい気もする。

import pygame
import sys
import random

# 初期化
pygame.init()

# ウィンドウのサイズ
width, height = 480, 360

background_image = pygame.image.load("background.jpg")
background_rect = background_image.get_rect()

# 土の高さ
ground_height = 50

# 土の色
ground_color = (139, 69, 19)  # 茶色

# プレイヤーのボールの半径と色
player_radius = 15  # 半分のサイズ
# player_color = (255, 165, 0)  # 橙色

# ジャンプの初速度と重力加速度
initial_jump_velocity = -15
gravity = 0.4

# 敵のボールの半径と色
enemy_radius = 15  # 半分のサイズ
# enemy_color = (255, 0, 0)  # 赤色

# ウィンドウの作成
screen = pygame.display.set_mode((width, height))
pygame.display.set_caption("ジャンプと敵ボール")

# プレイヤーのボールの初期位置
player_x_initial = 100
player_y_initial = height - ground_height - player_radius
player_x = player_x_initial
player_y = player_y_initial

# プレイヤーのボールの速度
player_velocity = 0

# 敵ボールの初期位置と速度
enemy_x = width + enemy_radius  # 右端からスタート
enemy_y = height - ground_height - enemy_radius
enemy_velocity = random.uniform(3, 5)  # ランダムな速度

# ゲームの得点と制限時間
score = 0
time_limit = 60 * 60  # 60秒をフレーム数に変換

# ボールとプレイヤーの当たり判定を制御するフラグ
player_hit_enemy = False

# ゲームの状態
game_over = False

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

# プレイヤーのボールをスプライトとして定義
player = pygame.sprite.Sprite()
player_image = pygame.image.load("cat.svg")
player_image = pygame.transform.scale(player_image, (player_radius * 3, player_radius * 2))
player.rect = player_image.get_rect()  # 矩形を取得
# player.rect.center = (player_x, player_y)  # 中心座標を設定

# 敵のボールをスプライトとして定義
enemy = pygame.sprite.Sprite()
fox_image = pygame.image.load("fox.svg")
fox_image = pygame.transform.flip(fox_image, True, False)
fox_image = pygame.transform.scale(fox_image, (enemy_radius * 2, enemy_radius * 2))
enemy.rect = fox_image.get_rect()  # 矩形を取得
# enemy.rect.center = (enemy_x, enemy_y)  # 中心座標を設定

all_sprites = pygame.sprite.Group()

# ゲームループ
clock = pygame.time.Clock()
while not game_over:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()
        elif event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE and player_y == player_y_initial:
            # スペースキーが押され、かつプレイヤーが地面に接している場合にジャンプ
            player_velocity = initial_jump_velocity

        elif event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
            # スペースキーが押され、かつプレイヤーが地面に接している場合にジャンプ
            player_velocity = initial_jump_velocity // 5

    # プレイヤーの速度を更新し、ボールの位置を更新
    player_velocity += gravity
    player_y += player_velocity

    # プレイヤーが地面に接したら位置を修正
    if player_y >= player_y_initial:
        player_y = player_y_initial
        player_velocity = 0

    # 敵ボールの位置を更新
    enemy_x -= enemy_velocity

    # 敵ボールが左端まで到達したらリセット
    if enemy_x < -enemy_radius:
        enemy_x = width + enemy_radius
        enemy_velocity = random.uniform(1, 5)  # ランダムな速度
        if not player_hit_enemy:
            # 当たっていなければ得点を加点
            score += 1
        elif player_hit_enemy:
            score -= 1
        player_hit_enemy = False  # フラグをクリア

    # プレイヤーボールと敵ボールの当たり判定
    if pygame.sprite.collide_circle(player, enemy) and not player_hit_enemy:
        # 当たった場合は得点を減点
        # score -= 5
        player_hit_enemy = True  # フラグをセット

    # 画面をクリア
    screen.fill((0, 127, 255, 80))  # 白色でクリア

    # 背景画像を描画
    screen.blit(background_image, background_rect)

    # 土を描画
    pygame.draw.rect(screen, ground_color, (0, height - ground_height, width, ground_height))

    # プレイヤーのボールを描画
    player.rect.center = (int(player_x), int(player_y))  # 中心座標を更新
    screen.blit(player_image, player.rect)  # 画像を描画

    # 敵ボールを描画
    enemy.rect.center = (int(enemy_x), int(enemy_y))  # 中心座標を更新
    screen.blit(fox_image, enemy.rect)  # 画像を描画

    # 得点を描画
    score_text = font.render(f"Score: {score}", True, (0, 0, 0))
    screen.blit(score_text, (10, 10))

    # 残り時間を描画
    time_text = font.render(f"Time: {max(0, time_limit // 60)}", True, (0, 0, 0))
    screen.blit(time_text, (width - 100, 10))

    # スプライトを更新
    all_sprites.update()

    # スプライトを描画
    all_sprites.draw(screen)

    # 画面を更新
    pygame.display.flip()

    # フレームレートを制限
    clock.tick(60)

    # 時間制限を減少
    time_limit -= 1

    # 時間制限が0になったらゲームオーバー
    if time_limit == 0:
        game_over = True

# ゲーム結果の表示
result_text = font.render("Game Win" if score >= 0 else "Game Lose", True, (0, 0, 0))
screen.blit(result_text, (width // 2 - 50, height // 2 - 50))
pygame.display.flip()

# ゲーム終了までの待機
pygame.time.delay(2000)

pygame.quit()
sys.exit()



ちょっとした遊びでも、こういう背景、猫、キツネなどを入れた方が可愛く見えるかな。

2023・11/26作成


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