Python 3およびPygameでゲームを作成する:パート5

画像






これは、Python 3とPyGameを使用してゲームを作成するチュートリアルの5つのパートの最後です。 4番目の部分では、衝突を認識し、ボールが異なるゲームオブジェクトと衝突するという事実に対応し、独自のボタンを備えたゲームメニューを作成することを学びました。



(チュートリアルの残り: firstsecondthirdfour )。



最後の部分では、ゲームの終わり、ライフとポイントの管理、効果音、音楽、さらには特殊効果の柔軟なシステムなど、さまざまなトピックを見ていきます。 デザートについては、今後の改善の可能性と方向性を検討します。



ゲームの終わり



遅かれ早かれ、ゲームは終了するはずです。 このバージョンのブレイクアウトでは、ゲームは次の2つの方法のいずれかで終了します。プレーヤーはすべてのライフを失うか、すべてのレンガを破壊します。 ゲームには次のレベルはありません(ただし、簡単に追加できます)。



ゲームオーバー!



Gameクラスの__init__()



メソッドで、Gameクラスのgame_over



がFalseに設定されています。 メインループは、 game_over



変数がTrueに変わるまで続きます。



 class Game: def __init__(self, caption, width, height, back_image_filename, frame_rate): ... self.game_over = False ... def run(self): while not self.game_over: self.surface.blit(self.background_image, (0, 0)) self.handle_events() self.update() self.draw() pygame.display.update() self.clock.tick(self.frame_rate)
      
      





これはすべて、次の場合にBreakoutクラスで発生します。





 def on_quit(button): self.game_over = True self.is_game_running = False def handle_ball_collisions(self): ... #    if self.ball.top > c.screen_height: self.lives -= 1 if self.lives == 0: self.game_over = True if not self.bricks: self.show_message('YOU WIN!!!', centralized=True) self.is_game_running = False self.game_over = True return def update(self): ... if not self.bricks: self.show_message('YOU WIN!!!', centralized=True) self.is_game_running = False self.game_over = True return
      
      





ゲーム終了メッセージ表示



通常、ゲームの終了時に、ゲームウィンドウが静かに消えることは望ましくありません。 例外は、メニューの[QUIT]ボタンをクリックした場合です。 プレイヤーが最後のライフを失うと、ブレイクアウトは従来のメッセージ「ゲームオーバー!」を表示し、プレイヤーが勝つとメッセージ「YOU WIN!」を表示します。



どちらの場合も、 show_message()



関数が使用されます。 現在の画面の上部にテキストを表示し(ゲームが一時停止します)、数秒待ってから戻ります。 ゲームループの次の反復で、 game_over



フィールドgame_over



チェックすると、それがTrueであるgame_over



判断され、その後プログラムが終了します。



show_message()



関数は次のようになります。



 def show_message(self, text, color=colors.WHITE, font_name='Arial', font_size=20, centralized=False): message = TextObject(c.screen_width // 2, c.screen_height // 2, lambda: text, color, font_name, font_size) self.draw() message.draw(self.surface, centralized) pygame.display.update() time.sleep(c.message_duration)
      
      





ゲーム間で記録を保存する



このバージョンのゲームでは、レベルが1つしかないため、記録を保持しません。レンガを破壊した後のすべてのプレイヤーの結果は同じになります。 一般に、レコードの保存はローカルに実装でき、レコードをファイルに保存し、プレーヤーがレコードを壊した場合に別のメッセージを表示します。



効果音と音楽を追加する



ゲームは視聴覚プロセスです。 多くのゲームには効果音があります-プレイヤーがモンスターを殺したり、宝物を見つけたり、ひどい死をしたときに再生される短いオーディオクリップです。 一部のゲームには、雰囲気に貢献するバックグラウンドミュージックもあります。 ブレイクアウトには効果音しかありませんが、ゲームで音楽を再生する方法を紹介します。



音響効果



サウンドエフェクトを再生するには、サウンドファイルが必要です(イメージファイルの場合と同様)。 これらのファイルは、.wav、.mp3、または.ogg形式にすることができます。 Breakoutは、サウンド効果をsound_effects



フォルダーに保存します。



  〜/ git / pygame-breakout>ツリーsound_effects /
 sound_effects /
 ├──brick_hit.wav
 ──effect_done.wav
 ├──level_complete.wav
 └──paddle_hit.wav 


これらの効果音が適切なタイミングでどのように読み込まれて再生されるかを見てみましょう。 まず、効果音(またはバックグラウンドミュージック)を再生するには、Pygameサウンドシステムを初期化する必要があります。 これはGameクラスで行われます: pygame.mixer.pre_init(44100, 16, 2, 4096)







次に、Breakoutクラスで、すべてのサウンドエフェクトがconfigからpygame.mixer.Sound



オブジェクトにロードされ、辞書に保存されます。



 #  config.py sounds_effects = dict( brick_hit='sound_effects/brick_hit.wav', effect_done='sound_effects/effect_done.wav', paddle_hit='sound_effects/paddle_hit.wav', level_complete='sound_effects/level_complete.wav', ) #  breakout.py class Breakout(Game): def __init__(self): ... self.sound_effects = { name: pygame.mixer.Sound(sound) for name, sound in c.sounds_effects.items()} ...
      
      





これで、面白いことが起こったときに効果音を再生できます。 たとえば、ボールがレンガに当たった場合:



 #    for brick in self.bricks: edge = intersect(brick, self.ball) if not edge: continue self.sound_effects['brick_hit'].play()
      
      





効果音は非同期で再生されます。つまり、ゲームのプレイ中にゲームは停止しません。 同時に複数の効果音を再生できます。



独自の効果音とメッセージを録音する



独自の効果音を録音することは、簡単で楽しい体験になります。 ビジュアルリソースの作成とは異なり、多くの才能は必要ありません。 誰でも「ブーム!」または「ジャンプ」と言うか、「彼らはあなたを殺した。 幸運を祈ります!」



私はよく子供に、「YOU WIN!」などのテキストメッセージに付随する効果音や音声メッセージを録音するように頼みます または「ゲームオーバー!」 ここでの唯一の制限は、あなた自身の想像力です。



バックグラウンドミュージックの再生



バックグラウンドミュージックは連続して再生する必要があります。 理論的には、非常に長いサウンドエフェクトを作成できますが、ループバックグラウンドミュージックが最もよく使用されます。 音楽ファイルは、.wav、.mp3、または.midi形式にすることができます。 音楽の実装方法は次のとおりです。



 music = pygame.mixer.music.load('background_music.mp3') pygame.mixer.music.play(-1, 0.0)
      
      





一度に再生できるバックグラウンドミュージックは1つだけです。 ただし、バックグラウンドミュージックに加えていくつかの効果音を再生できます。 これがミキシングと呼ばれるものです。



高度な機能の追加



奇妙なことをしましょう。 ボールでレンガを破壊するのは面白いですが、すぐに退屈になります。 全体的な特殊効果システムについてはどうですか? レンガに関連する拡張可能な特殊効果システムを開発します。これは、ボールがレンガに当たったときにアクティブになります。



これが計画です。 効果には寿命があります。 効果は、レンガが崩壊したときに始まり、効果が切れると終了します。 ボールが特殊効果で別のレンガに当たった場合はどうなりますか? 理論的には、互換性のある効果を作成できますが、元の実装のすべてを単純化するために、アクティブな効果は停止し、新しい効果が代わりに使用されます。



特殊効果システム



最も一般的な場合、特殊効果は2つの関数として定義できます。 最初の関数はエフェクトをアクティブにし、2番目の関数はそれをリセットします。 レンガにエフェクトを付加し、プレイヤーに特定のポイントでヒットまたは回避を試みることができるように、どのレンガが特別であるかを明確に理解させたいと考えています。



特殊効果は、 breakout.py



モジュールの辞書によって定義されます。 各エフェクトには、名前(long_paddleなど)と、レンガ色で構成される値、および2つの関数があります。 関数は、ゲームインスタンスを取得するラムダ関数として定義されます。これには、Breakoutの特殊効果を変更できるすべてのものが含まれます。



 special_effects = dict( long_paddle=( colors.ORANGE, lambda g: g.paddle.bounds.inflate_ip( c.paddle_width // 2, 0), lambda g: g.paddle.bounds.inflate_ip( -c.paddle_width // 2, 0)), slow_ball=( colors.AQUAMARINE2, lambda g: g.change_ball_speed(-1), lambda g: g.change_ball_speed(1)), tripple_points=( colors.DARKSEAGREEN4, lambda g: g.set_points_per_brick(3), lambda g: g.set_points_per_brick(1)), extra_life=( colors.GOLD1, lambda g: g.add_life(), lambda g: None))
      
      





ブリックを作成するとき、それらに特殊効果の1つを割り当てることができます。 コードは次のとおりです。



 def create_bricks(self): w = c.brick_width h = c.brick_height brick_count = c.screen_width // (w + 1) offset_x = (c.screen_width - brick_count * (w + 1)) // 2 bricks = [] for row in range(c.row_count): for col in range(brick_count): effect = None brick_color = c.brick_color index = random.randint(0, 10) if index < len(special_effects): x = list(special_effects.values())[index] brick_color = x[0] effect = x[1:] brick = Brick(offset_x + col * (w + 1), c.offset_y + row * (h + 1), w, h, brick_color, effect) bricks.append(brick) self.objects.append(brick) self.bricks = bricks
      
      





Brickクラスには効果フィールドがあり、通常は値Noneを持ちますが、上記で定義した特殊効果のいずれかを(確率30%で)含めることができます。 このコードは、どのような効果が存在するかを知らないことに注意してください。 彼は単にレンガの効果と色を受け取り、必要に応じてそれらを割り当てます。



ブレイクアウトのこのバージョンでは、ブリックに当たったときにのみエフェクトをトリガーしますが、イベントをトリガーするための他のオプションを考え出すことができます。 前のエフェクトが破棄され(存在する場合)、新しいエフェクトが起動されます。 リセット機能とエフェクト開始時間は、将来の使用のために保存されます。



 if brick.special_effect is not None: #       if self.reset_effect is not None: self.reset_effect(self) #   self.effect_start_time = datetime.now() brick.special_effect[0](self) #      self.reset_effect = brick.special_effect[1]
      
      





新しいエフェクトが起動されない場合、現在のエフェクトをその有効期間後にリセットする必要があります。 これはupdate()



メソッドで発生します。 各フレームで、現在の効果のリセット機能がreset_effect



フィールドに割り当てられます。 現在の効果を開始してからの時間が効果の持続時間を超える場合、 reset_effect()



関数がreset_effect()



reset_effect



フィールドがNoneにreset_effect



れます(現在アクティブな効果がないことを意味します)。



 #     if self.reset_effect: elapsed = datetime.now() - self.effect_start_time if elapsed >= timedelta(seconds=c.effect_duration): self.reset_effect(self) self.reset_effect = None
      
      





ラケットの増加



長いラケットの効果は、ラケットを50%増加させることです。 そのリセット機能は、ラケットを通常のサイズに戻します。 レンガの色はオレンジです:



 long_paddle=( colors.ORANGE, lambda g: g.paddle.bounds.inflate_ip( c.paddle_width // 2, 0), lambda g: g.paddle.bounds.inflate_ip( -c.paddle_width // 2, 0)),
      
      





ボールの減速



ボールを追いかけるのに役立つもう1つの効果は、ボールを遅くすることです。つまり、1ユニットずつ速度を下げます。 レンガの色はアクアマリンです。



 slow_ball=(colors.AQUAMARINE2, lambda g: g.change_ball_speed(-1), lambda g: g.change_ball_speed(1)),
      
      





もっとポイント



すばらしい結果が必要な場合は、標準の1ポイントではなく、破壊されたレンガごとに3ポイントを与える、3倍ポイントの効果が気に入っています。 レンガは濃い緑色です。



 tripple_points=(colors.DARKSEAGREEN4, lambda g: g.set_points_per_brick(3), lambda g: g.set_points_per_brick(1)),
      
      





余分な生活



最後に、非常に有用な効果は、余分な生命の効果です。 彼はあなたに別の人生を与えます。 リセットする必要はありません。 レンガの色は金色です。



 extra_life=(colors.GOLD1, lambda g: g.add_life(), lambda g: None))
      
      





今後の機能



ブレイクアウトを展開するには、いくつかの論理的な方向があります。 新しい機能を追加することに興味がある場合は、いくつかのアイデアがあります。



次のレベルに移動



ブレイクアウトを真剣なゲームにするには、レベルが必要です。明らかにそれだけでは不十分です。 各レベルの開始時に画面をリセットしますが、ポイントとライフを保存します。 ゲームを複雑にするために、各レベルでボールの速度をわずかに上げるか、レンガの別のレイヤーを追加できます。



セカンドボール



一時的に2番目のボールを追加すると、大きな混乱が生じます。 ここでの難しさは、どちらがオリジナルであるかに関係なく、両方のボールを同等に扱うことです。 1つのボールが消えると、残りの1つでゲームが続行されます。 命は失われません。



永続的な記録



難易度が高くなるレベルがある場合は、高得点表を作成することをお勧めします。 レコードをファイルに保存して、ゲーム後に保存することができます。 プレーヤーが記録を破ったとき、小さなピザを追加したり、名前を書いたりすることができます(従来は3文字のみ)。



爆弾とボーナス



現在の実装では、すべての特殊効果はレンガに関連付けられていますが、空から落ちてくる効果(良いものと悪いもの)を追加できます。これはプレイヤーが収集または回避できます。



まとめると



Python 3とPygameを使用したBreakoutの開発は、本当に楽しい経験であることが証明されています。 これは、2Dゲーム(および3Dゲーム)を作成するための非常に強力な組み合わせです。 Pythonが大好きで、独自のゲームを作成したい場合は、Pygameを選択してください。



Python、Pygame、その他のゲームを間違いなく作成します。



All Articles