生成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))
# ...(以下省略)
これにより、player と enemy オブジェクトは 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作成
この記事が気に入ったらサポートをしてみませんか?