PyGame:Pythonでのゲームプログラミングの入門書

PyGame:Pythonでのゲームプログラミングの入門書

私が最後の千年紀の後半にコンピュータープログラミングを学び始めたとき、それはコンピューターゲームを書きたいという私の欲求に駆動されました。 Pythonを含め、私が学んだすべての言語とプラットフォームでゲームを書く方法を見つけようとしました。 それが私がpygameを発見し、それを使ってゲームや他のグラフィックプログラムを書く方法を学んだ方法です。 当時、私はpygameの入門書が本当に欲しかったのです。

この記事の終わりまでに、次のことができるようになります。

  • 画面にアイテムを描く

  • 効果音と音楽を再生する

  • ユーザー入力を処理する

  • イベントループを実装する

  • ゲームプログラミングが標準の手続き型Pythonプログラミングとどのように異なるかを説明する

この入門書は、ユーザー定義関数、importsloops、およびconditionalsを含むbasic understanding of writing Python programsがあることを前提としています。 また、プラットフォームのhow to open filesにも精通している必要があります。 basic understanding of object-oriented Pythonも役立ちます。 pygameはほとんどのバージョンのPythonで動作しますが、Python 3.6が推奨され、この記事全体で使用されます。

この記事のすべてのコードを取得して、次の手順を実行できます。

Clone Repo:Click here to clone the repo you’ll useは、このチュートリアルでPyGameを使用する方法を学習します。

背景と設定

pygameは、SDL libraryのPythonラッパーであり、Simple DirectMedia Layerを表します。 SDLは、サウンド、ビデオ、マウス、キーボード、ジョイスティックなど、システムの基盤となるマルチメディアハードウェアコンポーネントへのクロスプラットフォームアクセスを提供します。 pygameは、停止したPySDL projectの代わりとして誕生しました。 SDLとpygameの両方のクロスプラットフォームの性質は、それらをサポートするすべてのプラットフォーム用にゲームとリッチマルチメディアPythonプログラムを作成できることを意味します。

プラットフォームにpygameをインストールするには、適切なpipコマンドを使用します。

$ pip install pygame

ライブラリに付属するサンプルのいずれかをロードすることにより、インストールを確認できます。

$ python3 -m pygame.examples.aliens

ゲームウィンドウが表示されたら、pygameが正しくインストールされています! 問題が発生した場合、Getting Started guideは、すべてのプラットフォームに関するいくつかの既知の問題と警告の概要を示しています。

基本的なPyGameプログラム

詳細に入る前に、基本的なpygameプログラムを見てみましょう。 このプログラムはウィンドウを作成し、背景を白で塗りつぶし、その中央に青い円を描きます。

 1 # Simple pygame program
 2
 3 # Import and initialize the pygame library
 4 import pygame
 5 pygame.init()
 6
 7 # Set up the drawing window
 8 screen = pygame.display.set_mode([500, 500])
 9
10 # Run until the user asks to quit
11 running = True
12 while running:
13
14     # Did the user click the window close button?
15     for event in pygame.event.get():
16         if event.type == pygame.QUIT:
17             running = False
18
19     # Fill the background with white
20     screen.fill((255, 255, 255))
21
22     # Draw a solid blue circle in the center
23     pygame.draw.circle(screen, (0, 0, 255), (250, 250), 75)
24
25     # Flip the display
26     pygame.display.flip()
27
28 # Done! Time to quit.
29 pygame.quit()

このプログラムを実行すると、次のようなウィンドウが表示されます。

A simple pygame program

このコードをセクションごとに分解してみましょう。

  • Lines 4 and 5は、pygameライブラリをインポートして初期化します。 これらの行がないと、pygameはありません。

  • Line 8は、プログラムの表示ウィンドウを設定します。 作成するウィンドウの幅と高さを指定するリストまたはタプルを提供します。 このプログラムはリストを使用して、各辺に500ピクセルの正方形のウィンドウを作成します。

  • Lines 11 and 12は、プログラムがいつ終了するかを制御するためにgame loopを設定します。 このチュートリアルの後半で、ゲームループについて説明します。

  • Lines 15 to 17は、ゲームループ内のeventsをスキャンして処理します。 イベントにも少し遅れて行きます。 この場合、処理されるイベントはpygame.QUITのみです。これは、ユーザーがウィンドウを閉じるボタンをクリックしたときに発生します。

  • Line 20は、ウィンドウを単色で塗りつぶします。 screen.fill()は、色のRGB値を指定するリストまたはタプルのいずれかを受け入れます。 (255, 255, 255)が指定されているため、ウィンドウは白で塗りつぶされます。

  • Line 23は、次のパラメータを使用して、ウィンドウに円を描画します。

    • screen:描画するウィンドウ

    • (0, 0, 255):RGBカラー値を含むタプル

    • (250, 250):円の中心座標を指定するタプル

    • 75:ピクセルで描画する円の半径

  • Line 26は、表示の内容を画面に更新します。 この呼び出しがないと、ウィンドウには何も表示されません!

  • Line 29pygameを終了します。 これは、ループが終了した後にのみ発生します。

これは、「Hello、World」のpygameバージョンです。それでは、このコードの背後にある概念をもう少し深く掘り下げてみましょう。

PyGameの概念

pygameとSDLライブラリは異なるプラットフォームやデバイス間で移植可能であるため、両方ともさまざまなハードウェアの現実の抽象化を定義して操作する必要があります。 これらの概念と抽象化を理解すると、独自のゲームを設計および開発するのに役立ちます。

初期化とモジュール

pygameライブラリはcomposed of a number of Python constructsであり、いくつかの異なるmodulesが含まれています。 これらのモジュールは、システム上の特定のハードウェアへの抽象アクセスと、そのハードウェアを使用するための統一された方法を提供します。 たとえば、displayを使用すると、ビデオディスプレイに均一にアクセスでき、joystickを使用すると、ジョイスティックを抽象的に制御できます。

上記の例でpygameライブラリをインポートした後、最初に行ったのは、pygame.init()を使用したinitialize PyGameでした。 この関数は、含まれているすべてのpygameモジュールのcalls the separate init() functionsです。 これらのモジュールは特定のハードウェアの抽象化であるため、Linux、Windows、およびMacで同じコードを使用するには、この初期化手順が必要です。

ディスプレイと表面

モジュールに加えて、pygameには、ハードウェアに依存しない概念をカプセル化するいくつかのPythonclassesも含まれています。 これらの1つはSurfaceであり、最も基本的には、描画できる長方形の領域を定義します。 Surfaceオブジェクトは、pygameの多くのコンテキストで使用されます。 後で、画像をSurfaceに読み込んで、画面に表示する方法を説明します。

pygameでは、すべてがユーザーが作成した単一のdisplayで表示されます。これは、ウィンドウまたはフルスクリーンの場合があります。 表示は.set_mode()を使用して作成され、ウィンドウの表示部分を表すSurfaceを返します。 pygame.draw.circle()などの描画関数に渡すのはこのSurfaceであり、pygame.display.flip()を呼び出すと、そのSurfaceの内容がディスプレイにプッシュされます。

画像とRects

基本的なpygameプログラムは、ディスプレイのSurfaceに直接図形を描画しましたが、ディスク上の画像を操作することもできます。 image moduleを使用すると、さまざまな一般的な形式のloadおよびsave画像を作成できます。 画像はSurfaceオブジェクトに読み込まれ、さまざまな方法で操作および表示できます。

上記のように、Surfaceオブジェクトは、画像やウィンドウなど、pygameの他の多くのオブジェクトと同様に長方形で表されます。 長方形は非常に頻繁に使用されるため、それらを処理するためだけにspecial Rect classがあります。 ゲームでRectのオブジェクトと画像を使用して、プレーヤーと敵を描画し、それらの間の衝突を管理します。

さて、それで十分な理論です。 ゲームをデザインして書きましょう!

基本的なゲームデザイン

コードの記述を開始する前に、何らかのデザインを用意しておくことをお勧めします。 これはチュートリアルゲームなので、基本的なゲームプレイもデザインしましょう。

  • ゲームの目標は、入ってくる障害物を避けることです:

    • プレーヤーは画面の左側から開始します。

    • 障害物は右からランダムに入り、直線で左に移動します。

  • プレイヤーは、障害物を避けるために、左、右、上、または下に移動できます。

  • プレーヤーは画面から移動できません。

  • プレイヤーが障害物に当たったとき、またはユーザーがウィンドウを閉じると、ゲームは終了します。

彼がソフトウェアプロジェクトについて説明していたとき、former colleague of mineは、「自分が何をしていないかを知るまで、自分が何をしているかわからない」と言っていました。そのことを念頭に置いて、このチュートリアルでは取り上げないことがいくつかあります。

  • 複数の生命はありません

  • スコアキーピングなし

  • プレイヤーの攻撃能力なし

  • 前進レベルなし

  • ボスキャラクターなし

これらの機能や他の機能を自分のプログラムに追加してみてください。

始めましょう!

PyGameのインポートと初期化

pygameをインポートした後、それも初期化する必要があります。 これにより、pygameはその抽象化を特定のハードウェアに接続できます。

 1 # Import the pygame module
 2 import pygame
 3
 4 # Import pygame.locals for easier access to key coordinates
 5 # Updated to conform to flake8 and black standards
 6 from pygame.locals import (
 7     K_UP,
 8     K_DOWN,
 9     K_LEFT,
10     K_RIGHT,
11     K_ESCAPE,
12     KEYDOWN,
13     QUIT,
14 )
15
16 # Initialize pygame
17 pygame.init()

pygameライブラリは、モジュールとクラス以外にも多くのものを定義します。 また、キーストローク、マウスの動き、表示属性などのlocal constantsも定義します。 これらの定数は、構文pygame.<CONSTANT>を使用して参照します。 pygame.localsから特定の定数をインポートすることにより、代わりに構文<CONSTANT>を使用できます。 これにより、キーストロークが節約され、全体的な読みやすさが向上します。

ディスプレイのセットアップ

今、あなたは何かを引き出す必要があります! 全体のキャンバスとなるscreenを作成します。

 1 # Import the pygame module
 2 import pygame
 3
 4 # Import pygame.locals for easier access to key coordinates
 5 # Updated to conform to flake8 and black standards
 6 from pygame.locals import (
 7     K_UP,
 8     K_DOWN,
 9     K_LEFT,
10     K_RIGHT,
11     K_ESCAPE,
12     KEYDOWN,
13     QUIT,
14 )
15
16 # Initialize pygame
17 pygame.init()
18
19 # Define constants for the screen width and height
20 SCREEN_WIDTH = 800
21 SCREEN_HEIGHT = 600
22
23 # Create the screen object
24 # The size is determined by the constant SCREEN_WIDTH and SCREEN_HEIGHT
25 screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))

pygame.display.set_mode()を呼び出し、目的の幅と高さのタプルまたはリストを渡すことにより、使用する画面を作成します。 この場合、ウィンドウは800x600であり、20行目と21行目の定数SCREEN_WIDTHSCREEN_HEIGHTで定義されています。 これは、ウィンドウの内側の寸法を表すSurfaceを返します。 これは制御可能なウィンドウの一部であり、OSはウィンドウの境界線とタイトルバーを制御します。

このプログラムを今すぐ実行すると、ウィンドウが短時間表示され、プログラムが終了するとすぐに消えます。 まばたきしないでください。 次のセクションでは、メインゲームループに焦点を当て、正しい入力が与えられた場合にのみプログラムが終了するようにします。

ゲームループのセットアップ

PongからFortniteまでのすべてのゲームは、game loopを使用してゲームプレイを制御します。 ゲームループは4つの非常に重要なことを行います。

  1. ユーザー入力を処理します

  2. すべてのゲームオブジェクトの状態を更新します

  3. ディスプレイとオーディオ出力を更新します

  4. ゲームの速度を維持します

ゲームループのすべてのサイクルはframeと呼ばれ、各サイクルで実行できる速度が速いほど、ゲームの実行速度は速くなります。 フレームは、ゲームを終了する何らかの条件が満たされるまで発生し続けます。 デザインには、ゲームループを終了できる2つの条件があります。

  1. プレイヤーは障害物と衝突します。 (衝突検出については後で説明します。)

  2. プレーヤーはウィンドウを閉じます。

ゲームループが最初に行うことは、ユーザー入力を処理して、プレーヤーが画面内を移動できるようにすることです。 したがって、さまざまな入力をキャプチャして処理する方法が必要です。 これは、pygameイベントシステムを使用して行います。

イベントの処理

キーを押したり、マウスを動かしたり、ジョイスティックを動かしたりすることは、ユーザーが入力できる方法の一部です。 すべてのユーザー入力により、eventが生成​​されます。 イベントはいつでも発生する可能性があり、多くの場合(常にではないが)プログラムの外部で発生します。 pygame内のすべてのイベントは、イベントキューに配置され、アクセスおよび操作できます。 イベントの処理はhandlingと呼ばれ、そのためのコードはevent handlerと呼ばれます。

pygameのすべてのイベントには、イベントtypeが関連付けられています。 ゲームの場合、注目するイベントの種類はキー入力とウィンドウのクローズです。 キー押下イベントのタイプはKEYDOWNで、ウィンドウ閉鎖イベントのタイプはQUITです。 異なるイベントタイプには、他のデータが関連付けられている場合があります。 たとえば、KEYDOWNイベントタイプには、どのキーが押されたかを示すkeyという変数もあります。

pygame.event.get()を呼び出すことにより、キュー内のすべてのアクティブなイベントのリストにアクセスします。 次に、このリストをループして、各イベントタイプを検査し、それに応じて応答します。

27 # Variable to keep the main loop running
28 running = True
29
30 # Main loop
31 while running:
32     # Look at every event in the queue
33     for event in pygame.event.get():
34         # Did the user hit a key?
35         if event.type == KEYDOWN:
36             # Was it the Escape key? If so, stop the loop.
37             if event.key == K_ESCAPE:
38                 running = False
39
40         # Did the user click the window close button? If so, stop the loop.
41         elif event.type == QUIT:
42             running = False

このゲームループを詳しく見てみましょう。

  • Line 28は、ゲームループの制御変数を設定します。 ループとゲームを終了するには、running = Falseを設定します。 ゲームループは29行目から始まります。

  • Line 31はイベントハンドラーを開始し、現在イベントキューにあるすべてのイベントをウォークスルーします。 イベントがない場合、リストは空になり、ハンドラーは何もしません。

  • Lines 35 to 38は、現在のevent.typeKEYDOWNイベントであるかどうかを確認します。 そうである場合、プログラムはevent.key属性を調べて、どのキーが押されたかを確認します。 キーがK_ESCAPEで示される[.kbd .key-escape]#Esc#キーである場合、running = Falseを設定してゲームループを終了します。

  • Lines 41 and 42は、QUITと呼ばれるイベントタイプに対して同様のチェックを実行します。 このイベントは、ユーザーがウィンドウの閉じるボタンをクリックしたときにのみ発生します。 ユーザーは、他のオペレーティングシステムアクションを使用してウィンドウを閉じることもできます。

これらの行を前のコードに追加して実行すると、空白または黒い画面のウィンドウが表示されます。

An empty

[.kbd .key-escape]#Esc#キーを押すか、ウィンドウを閉じてQUITイベントをトリガーするまで、ウィンドウは消えません。

画面に描画する

サンプルプログラムでは、2つのコマンドを使用して画面に描画しました。

  1. 背景を埋めるためのscreen.fill()

  2. 円を描くためのpygame.draw.circle()

次に、画面に描画する3番目の方法であるSurfaceの使用について学習します。

Surfaceは、白紙のように描画できる長方形のオブジェクトであることを思い出してください。 screenオブジェクトはSurfaceであり、表示画面とは別に独自のSurfaceオブジェクトを作成できます。 その仕組みを見てみましょう。

44 # Fill the screen with white
45 screen.fill((255, 255, 255))
46
47 # Create a surface and pass in a tuple containing its length and width
48 surf = pygame.Surface((50, 50))
49
50 # Give the surface a color to separate it from the background
51 surf.fill((0, 0, 0))
52 rect = surf.get_rect()

45行目で画面が白で塗りつぶされた後、48行目で新しいSurfaceが作成されます。 このSurfaceは、幅50ピクセル、高さ50ピクセルで、surfに割り当てられます。 この時点で、screenと同じように扱います。 51行目では、黒で塗りつぶしています。 .get_rect()を使用して、基になるRectにアクセスすることもできます。 これは、後で使用するためにrectとして保存されます。

.blit()および.flip()の使用

新しいSurfaceを作成するだけでは、画面に表示するのに十分ではありません。 これを行うには、Surfaceを別のSurfaceblitする必要があります。 blitという用語はBlock Transferを表し、.blit()は、あるSurfaceの内容を別のSurfaceにコピーする方法です。 あるSurfaceから別のSurfaceへの.blit()のみが可能ですが、画面は別のSurfaceであるため、問題はありません。 画面にsurfを描画する方法は次のとおりです。

54 # This line says "Draw surf onto the screen at the center"
55 screen.blit(surf, (SCREEN_WIDTH/2, SCREEN_HEIGHT/2))
56 pygame.display.flip()

55行目の.blit()呼び出しには、次の2つの引数があります。

  1. 描画するSurface

  2. ソースSurfaceに描画する場所

座標(SCREEN_WIDTH/2, SCREEN_HEIGHT/2)は、surfを画面の正確な中央に配置するようにプログラムに指示しますが、そのようには見えません。

Blitting a surface onto the screen

画像が中心から外れて見える理由は、.blit()surftop-left cornerを指定された場所に配置するためです。 surfを中央に配置する場合は、計算を行って上下にシフトする必要があります。 これを行うには、画面の幅と高さからsurfの幅と高さを減算し、それぞれを2で割って中心を見つけ、それらの数値を引数としてscreen.blit()に渡します。

54 # Put the center of surf at the center of the display
55 surf_center = (
56     (SCREEN_WIDTH-surf.get_width())/2,
57     (SCREEN_HEIGHT-surf.get_height())/2
58 )
59
60 # Draw surf at the new coordinates
61 screen.blit(surf, surf_center)
62 pygame.display.flip()

blit()の呼び出しの後にpygame.display.flip()が呼び出されていることに注意してください。 これにより、最後のフリップ以降に描画されたすべてのもので画面全体が更新されます。 .flip()を呼び出さないと、何も表示されません。

スプライト

ゲームデザインでは、プレーヤーは左から始まり、障害物は右から入ります。 すべての障害物をSurfaceオブジェクトで表すと、すべてを簡単に描画できますが、どこに描画するかをどのように知ることができますか? 障害物がプレーヤーと衝突したかどうかをどのように確認しますか? 障害物が画面から飛び出すとどうなりますか? 移動する背景画像を描きたい場合はどうしますか? 画像をアニメーション化する場合はどうしますか? spritesを使用すると、これらすべての状況やその他の状況を処理できます。

プログラミング用語では、spriteは画面上の何かの2D表現です。 本質的に、それは写真です。 pygameSprite classを提供します。これは、画面に表示するゲームオブジェクトの1つまたは複数のグラフィック表現を保持するように設計されています。 これを使用するには、Spriteを拡張する新しいクラスを作成します。 これにより、組み込みメソッドを使用できます。

プレイヤー

現在のゲームでSpriteオブジェクトを使用して、プレーヤーを定義する方法は次のとおりです。 行18の後にこのコードを挿入します。

20 # Define a Player object by extending pygame.sprite.Sprite
21 # The surface drawn on the screen is now an attribute of 'player'
22 class Player(pygame.sprite.Sprite):
23     def __init__(self):
24         super(Player, self).__init__()
25         self.surf = pygame.Surface((75, 25))
26         self.surf.fill((255, 255, 255))
27         self.rect = self.surf.get_rect()

最初に、22行目でpygame.sprite.Spriteを拡張して、Playerを定義します。 次に、.__init__().super()を使用してSprite.__init__()メソッドを呼び出します。 これが必要な理由の詳細については、Supercharge Your Classes With Python super()を参照してください。

次に、表示する画像を保持するために.surfを定義して初期化します。これは、現在ホワイトボックスです。 また、.rectを定義して初期化します。これは、後でプレーヤーを描画するために使用します。 この新しいクラスを使用するには、新しいオブジェクトを作成し、描画コードも変更する必要があります。 以下のコードブロックを展開して、すべて一緒に表示します。

このコードを実行します。 画面のほぼ中央に白い長方形が表示されます。

Basic player sprite being drawn

59行目をscreen.blit(player.surf, player.rect)に変更するとどうなると思いますか? 試してみてください。

55 # Fill the screen with black
56 screen.fill((0, 0, 0))
57
58 # Draw the player on the screen
59 screen.blit(player.surf, player.rect)
60
61 # Update the display
62 pygame.display.flip()

Rect.blit()に渡すと、左上隅の座標を使用してサーフェスが描画されます。 これを後で使用して、プレーヤーを動かします!

ユーザー入力

これまで、pygameを設定し、画面にオブジェクトを描画する方法を学習しました。 今、本当の楽しみが始まります! キーボードを使用してプレーヤーを制御可能にします。

以前、pygame.event.get()がイベントキュー内のイベントのリストを返し、KEYDOWNイベントタイプをスキャンすることを確認しました。 キープレスを読む方法はそれだけではありません。 pygamepygame.event.get_pressed()も提供します。これは、キュー内の現在のすべてのKEYDOWNイベントを含むdictionaryを返します。

イベント処理ループの直後にこれをゲームループに入れます。 これは、すべてのフレームの先頭で押されたキーを含む辞書を返します。

54 # Get the set of keys pressed and check for user input
55 pressed_keys = pygame.key.get_pressed()

次に、そのディクショナリを受け入れるメソッドをPlayerに記述します。 これにより、押されたキーに基づいてスプライトの動作が定義されます。 これは次のようなものです。

29 # Move the sprite based on user keypresses
30 def update(self, pressed_keys):
31     if pressed_keys[K_UP]:
32         self.rect.move_ip(0, -5)
33     if pressed_keys[K_DOWN]:
34         self.rect.move_ip(0, 5)
35     if pressed_keys[K_LEFT]:
36         self.rect.move_ip(-5, 0)
37     if pressed_keys[K_RIGHT]:
38         self.rect.move_ip(5, 0)

K_UPK_DOWNK_LEFT、およびK_RIGHTは、キーボードの矢印キーに対応します。 そのキーの辞書エントリがTrueの場合、そのキーは下にあり、プレーヤーを適切な方向に.rect移動します。 ここでは、move in placeを表す.move_ip()を使用して、現在のRectを移動します。

次に、フレームごとに.update()を呼び出して、キーの押下に応じてプレーヤーのスプライトを移動できます。 .get_pressed()への呼び出しの直後にこの呼び出しを追加します。

52 # Main loop
53 while running:
54     # for loop through the event queue
55     for event in pygame.event.get():
56         # Check for KEYDOWN event
57         if event.type == KEYDOWN:
58             # If the Esc key is pressed, then exit the main loop
59             if event.key == K_ESCAPE:
60                 running = False
61         # Check for QUIT event. If QUIT, then set running to false.
62         elif event.type == QUIT:
63             running = False
64
65     # Get all the keys currently pressed
66     pressed_keys = pygame.key.get_pressed()
67
68     # Update the player sprite based on user keypresses
69     player.update(pressed_keys)
70
71     # Fill the screen with black
72     screen.fill((0, 0, 0))

これで、矢印キーを使用してプレーヤーの四角形を画面上で移動できます。

Keypresses moving a sprite in pygame

次の2つの小さな問題に気付くかもしれません。

  1. プレーヤーの長方形は、キーが押されていると非常に速く移動できます。 それについては後で取り組みます。

  2. プレーヤーの四角形は画面から移動できます。 それを今解決しましょう。

プレーヤーを画面に表示したままにするには、rectが画面から移動するかどうかを検出するロジックを追加する必要があります。 これを行うには、rect座標が画面の境界を超えて移動したかどうかを確認します。 その場合、プログラムをエッジに戻すように指示します。

25 # Move the sprite based on user keypresses
26 def update(self, pressed_keys):
27     if pressed_keys[K_UP]:
28         self.rect.move_ip(0, -5)
29     if pressed_keys[K_DOWN]:
30         self.rect.move_ip(0, 5)
31     if pressed_keys[K_LEFT]:
32         self.rect.move_ip(-5, 0)
33     if pressed_keys[K_RIGHT]:
34         self.rect.move_ip(5, 0)
35
36     # Keep player on the screen
37     if self.rect.left < 0:
38         self.rect.left = 0
39     if self.rect.right > SCREEN_WIDTH:
40         self.rect.right = SCREEN_WIDTH
41     if self.rect.top <= 0:
42         self.rect.top = 0
43     if self.rect.bottom >= SCREEN_HEIGHT:
44         self.rect.bottom = SCREEN_HEIGHT

ここでは、.move()を使用する代わりに、.top.bottom.left、または.rightの対応する座標を直接変更するだけです。 これをテストすると、プレイヤーの四角形が画面から移動できなくなります。

敵を追加しましょう!

敵のいないゲームとは? 既に学んだテクニックを使用して基本的な敵のクラスを作成し、プレイヤーが回避するためにそれらの多くを作成します。 まず、randomライブラリをインポートします。

 4 # Import random for random numbers
 5 import random

次に、Playerに使用したのと同じパターンに従って、Enemyという新しいスプライトクラスを作成します。

55 # Define the enemy object by extending pygame.sprite.Sprite
56 # The surface you draw on the screen is now an attribute of 'enemy'
57 class Enemy(pygame.sprite.Sprite):
58     def __init__(self):
59         super(Enemy, self).__init__()
60         self.surf = pygame.Surface((20, 10))
61         self.surf.fill((255, 255, 255))
62         self.rect = self.surf.get_rect(
63             center=(
64                 random.randint(SCREEN_WIDTH + 20, SCREEN_WIDTH + 100),
65                 random.randint(0, SCREEN_HEIGHT),
66             )
67         )
68         self.speed = random.randint(5, 20)
69
70     # Move the sprite based on speed
71     # Remove the sprite when it passes the left edge of the screen
72     def update(self):
73         self.rect.move_ip(-self.speed, 0)
74         if self.rect.right < 0:
75             self.kill()

EnemyPlayerの間には4つの顕著な違いがあります。

  1. On lines 62 to 67の場合、rectを更新して、画面の右端に沿ったランダムな場所にします。 長方形の中心は画面から少し外れています。 右端から20〜100ピクセル離れた位置、および上端と下端の間のどこかにあります。

  2. On line 68の場合、.speedを5から20までの乱数として定義します。 これは、この敵がプレイヤーに向かって移動する速度を指定します。

  3. On lines 73 to 76.update()を定義します。 敵は自動的に移動するため、引数は必要ありません。 代わりに、.update()は、作成時に定義された.speedで、画面の左側に向かって敵を移動します。

  4. On line 74、敵が画面外に移動したかどうかを確認します。 Enemyが画面から完全に外れていて、表示されている間に消えないようにするには、.rectの右側が画面の左側を超えていることを確認します。 敵が画面外に出たら、.kill()を呼び出して、それ以上処理されないようにします。

では、.kill()は何をするのでしょうか? これを理解するには、Sprite Groupsについて知っておく必要があります。

スプライトグループ

pygameが提供するもう1つの非常に便利なクラスは、Sprite Groupです。 これは、Spriteオブジェクトのグループを保持するオブジェクトです。 なぜそれを使用するのですか? 代わりに、リスト内のSpriteオブジェクトを追跡することはできませんか? できますが、Groupを使用する利点は、公開するメソッドにあります。 これらのメソッドは、EnemyPlayerと衝突したかどうかを検出するのに役立ち、更新がはるかに簡単になります。

スプライトグループを作成する方法を見てみましょう。 2つの異なるGroupオブジェクトを作成します。

  1. 最初のGroupは、ゲーム内のすべてのSpriteを保持します。

  2. 2番目のGroupは、Enemyオブジェクトのみを保持します。

コードでは次のようになります。

82 # Create the 'player'
83 player = Player()
84
85 # Create groups to hold enemy sprites and all sprites
86 # - enemies is used for collision detection and position updates
87 # - all_sprites is used for rendering
88 enemies = pygame.sprite.Group()
89 all_sprites = pygame.sprite.Group()
90 all_sprites.add(player)
91
92 # Variable to keep the main loop running
93 running = True

.kill()を呼び出すと、Spriteはそれが属するすべてのGroupから削除されます。 これにより、Spriteへの参照も削除され、Pythonのガベージコレクターが必要に応じてメモリを再利用できるようになります。

all_spritesグループができたので、オブジェクトの描画方法を変更できます。 Playerだけで.blit()を呼び出す代わりに、all_spritesのすべてを反復処理できます。

117 # Fill the screen with black
118 screen.fill((0, 0, 0))
119
120 # Draw all sprites
121 for entity in all_sprites:
122     screen.blit(entity.surf, entity.rect)
123
124 # Flip everything to the display
125 pygame.display.flip()

これで、all_spritesに入力されたものはすべて、敵であろうとプレーヤーであろうと、すべてのフレームで描画されます。

問題が1つだけあります。敵はいません! ゲームの開始時に敵の束を作成できますが、数秒後にすべての敵が画面を離れるとすぐにゲームは退屈になります。 代わりに、ゲームの進行中に敵の安定した供給を維持する方法を検討しましょう。

カスタムイベント

この設計では、敵が一定間隔で出現する必要があります。 これは、設定された間隔で、次の2つのことを行う必要があることを意味します。

  1. 新しいEnemyを作成します。

  2. all_spritesenemiesに追加します。

ランダムイベントを処理するコードが既にあります。 イベントループは、フレームごとに発生するランダムイベントを探して適切に処理するように設計されています。 幸い、pygameは、定義されたイベントタイプのみを使用するように制限していません。 必要に応じて処理する独自のイベントを定義できます。

数秒ごとに生成されるカスタムイベントを作成する方法を見てみましょう。 カスタムイベントに名前を付けて作成できます。

78 # Create the screen object
79 # The size is determined by the constant SCREEN_WIDTH and SCREEN_HEIGHT
80 screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
81
82 # Create a custom event for adding a new enemy
83 ADDENEMY = pygame.USEREVENT + 1
84 pygame.time.set_timer(ADDENEMY, 250)
85
86 # Instantiate player. Right now, this is just a rectangle.
87 player = Player()

pygameはイベントを内部的に整数として定義するため、一意の整数を使用して新しいイベントを定義する必要があります。 最後のイベントpygameの予約はUSEREVENTと呼ばれるため、83行目でADDENEMY = pygame.USEREVENT + 1を定義すると、一意であることが保証されます。

次に、この新しいイベントをゲーム全体で定期的にイベントキューに挿入する必要があります。 そこで、timeモジュールが登場します。 行84は、新しいADDENEMYイベントを250ミリ秒ごと、または1秒間に4回発生させます。 必要なタイマーは1つだけなので、ゲームループの外で.set_timer()を呼び出しますが、ゲーム全体で起動します。

新しいイベントを処理するコードを追加します。

100 # Main loop
101 while running:
102     # Look at every event in the queue
103     for event in pygame.event.get():
104         # Did the user hit a key?
105         if event.type == KEYDOWN:
106             # Was it the Escape key? If so, stop the loop.
107             if event.key == K_ESCAPE:
108                 running = False
109
110         # Did the user click the window close button? If so, stop the loop.
111         elif event.type == QUIT:
112             running = False
113
114         # Add a new enemy?
115         elif event.type == ADDENEMY:
116             # Create the new enemy and add it to sprite groups
117             new_enemy = Enemy()
118             enemies.add(new_enemy)
119             all_sprites.add(new_enemy)
120
121     # Get the set of keys pressed and check for user input
122     pressed_keys = pygame.key.get_pressed()
123     player.update(pressed_keys)
124
125     # Update enemy position
126     enemies.update()

イベントハンドラーは、115行目で新しいADDENEMYイベントを検出すると、Enemyを作成し、それをenemiesall_spritesに追加します。 Enemyall_spritesにあるため、フレームごとに描画されます。 また、行126でenemies.update()を呼び出す必要があります。これにより、enemiesのすべてが更新され、正しく移動するようになります。

Enemies flying by in pygame

ただし、enemiesだけのグループがある理由はそれだけではありません。

衝突検出

ゲームの設計では、敵がプレイヤーと衝突するたびにゲームを終了する必要があります。 衝突のチェックは、ゲームプログラミングの基本的な手法であり、通常、2つのスプライトが互いにオーバーラップするかどうかを判断するために、重要な数学が必要です。

ここで、pygameのようなフレームワークが役立ちます。 衝突検出コードを書くのは面倒ですが、pygameにはたくさんのcollision detection methodsがあります。

このチュートリアルでは、.spritecollideany()というメソッドを使用します。これは、「スプライトが任意に衝突する」と読み取られます。このメソッドは、パラメーターとしてSpriteGroupを受け入れます。 Group内のすべてのオブジェクトを調べ、その.rectSprite.rectと交差するかどうかを確認します。 その場合、Trueを返します。 それ以外の場合は、Falseを返します。 単一のplayerenemiesGroupのいずれかと衝突するかどうかを確認する必要があるため、これはこのゲームに最適です。

コードでは次のようになります。

130 # Draw all sprites
131 for entity in all_sprites:
132     screen.blit(entity.surf, entity.rect)
133
134 # Check if any enemies have collided with the player
135 if pygame.sprite.spritecollideany(player, enemies):
136     # If so, then remove the player and stop the loop
137     player.kill()
138     running = False

135行目では、playerenemies内のオブジェクトのいずれかと衝突したかどうかをテストしています。 その場合、player.kill()が呼び出され、それが属するすべてのグループから削除されます。 レンダリングされるオブジェクトはall_spritesのみであるため、playerはレンダリングされなくなります。 プレーヤーが殺されたら、ゲームも終了する必要があるため、running = Falseを設定して138行目のゲームループから抜け出します。

この時点で、ゲームの基本的な要素が準備できました。

Pygame window

それでは、少しドレスアップしてプレイしやすくし、いくつかの高度な機能を追加して目立たせましょう。

スプライト画像

さて、あなたはゲームを持っていますが、正直に言ってください...それはちょっといです。 プレイヤーと敵は、黒い背景に白いブロックだけです。 Pongが新しくなったとき、それは最先端でしたが、それはもはやそれをカットしません。 それらの退屈な白い長方形を、ゲームを実際のゲームのように感じさせるクールな画像に置き換えましょう。

以前、ディスク上のイメージは、imageモジュールの助けを借りてSurfaceにロードできることを学びました。 このチュートリアルでは、プレーヤー用の小さなジェットと敵用のミサイルを作成しました。 このアートを使用したり、独自のアートを描いたり、free game art assetsをダウンロードして使用したりできます。 以下のリンクをクリックして、このチュートリアルで使用するアートをダウンロードできます。

このチュートリアルで使用されるSample Code:Click here to download the source code for the PyGame sample project

オブジェクトコンストラクターの変更

画像を使用してプレーヤーと敵のスプライトを表現する前に、コンストラクターにいくつかの変更を加える必要があります。 以下のコードは、以前に使用されたコードを置き換えます。

 7 # Import pygame.locals for easier access to key coordinates
 8 # Updated to conform to flake8 and black standards
 9 # from pygame.locals import *
10 from pygame.locals import (
11     RLEACCEL,
12     K_UP,
13     K_DOWN,
14     K_LEFT,
15     K_RIGHT,
16     K_ESCAPE,
17     KEYDOWN,
18     QUIT,
19 )
20
21 # Define constants for the screen width and height
22 SCREEN_WIDTH = 800
23 SCREEN_HEIGHT = 600
24
25
26 # Define the Player object by extending pygame.sprite.Sprite
27 # Instead of a surface, use an image for a better-looking sprite
28 class Player(pygame.sprite.Sprite):
29     def __init__(self):
30         super(Player, self).__init__()
31         self.image = pygame.image.load("jet.png").convert()
32         self.image.set_colorkey((255, 255, 255), RLEACCEL)
33         self.rect = self.image.get_rect()

31行目を少し展開しましょう。 pygame.image.load()は、ディスクからイメージをロードします。 ファイルへのパスを渡します。 Surfaceを返し、.convert()呼び出しはSurfaceを最適化して、将来の.blit()呼び出しを高速化します。

32行目では、.set_colorkey()を使用して、pygameが透明としてレンダリングされる色を示しています。 この場合、ジェット画像の背景色であるため、白を選択します。 RLEACCEL定数はオプションのパラメーターであり、高速化されていないディスプレイでpygameをより迅速にレンダリングするのに役立ちます。 これは、11行目のpygame.localsimportステートメントに追加されます。

他に何も変える必要はありません。 画像はまだSurfaceですが、画像が描かれています。 それでも同じように使用します。

Enemyに対する同様の変更は次のようになります。

59 # Define the enemy object by extending pygame.sprite.Sprite
60 # Instead of a surface, use an image for a better-looking sprite
61 class Enemy(pygame.sprite.Sprite):
62     def __init__(self):
63         super(Enemy, self).__init__()
64         self.surf = pygame.image.load("missile.png").convert()
65         self.surf.set_colorkey((255, 255, 255), RLEACCEL)
66         # The starting position is randomly generated, as is the speed
67         self.rect = self.surf.get_rect(
68             center=(
69                 random.randint(SCREEN_WIDTH + 20, SCREEN_WIDTH + 100),
70                 random.randint(0, SCREEN_HEIGHT),
71             )
72         )
73         self.speed = random.randint(5, 20)

今すぐプログラムを実行すると、これが以前と同じゲームであることが示されますが、画像付きの素敵なグラフィックskinsがいくつか追加されています。 しかし、なぜプレイヤーと敵のスプライトの見栄えを良くするのにとどまらないのですか? 空を飛ぶジェット機の印象を与えるために、いくつかの雲を通過させましょう。

背景画像を追加する

背景雲の場合、PlayerおよびEnemyの場合と同じ原則を使用します。

  1. Cloudクラスを作成します。

  2. クラウドの画像を追加します。

  3. cloudを画面の左側に移動するメソッド.update()を作成します。

  4. カスタムイベントとハンドラーを作成して、設定した時間間隔で新しいcloudオブジェクトを作成します。

  5. 新しく作成されたcloudオブジェクトをcloudsと呼ばれる新しいGroupに追加します。

  6. ゲームループのcloudsを更新して描画します。

Cloudは次のようになります。

 83 # Define the cloud object by extending pygame.sprite.Sprite
 84 # Use an image for a better-looking sprite
 85 class Cloud(pygame.sprite.Sprite):
 86     def __init__(self):
 87         super(Cloud, self).__init__()
 88         self.surf = pygame.image.load("cloud.png").convert()
 89         self.surf.set_colorkey((0, 0, 0), RLEACCEL)
 90         # The starting position is randomly generated
 91         self.rect = self.surf.get_rect(
 92             center=(
 93                 random.randint(SCREEN_WIDTH + 20, SCREEN_WIDTH + 100),
 94                 random.randint(0, SCREEN_HEIGHT),
 95             )
 96
 97     # Move the cloud based on a constant speed
 98     # Remove the cloud when it passes the left edge of the screen
 99     def update(self):
100         self.rect.move_ip(-5, 0)
101         if self.rect.right < 0:
102             self.kill()

それはすべて非常に馴染みがあるはずです。 Enemyとほとんど同じです。

特定の間隔で雲を表示するには、新しい敵の作成に使用したものと同様のイベント作成コードを使用します。 敵の作成イベントのすぐ下に配置します。

116 # Create custom events for adding a new enemy and a cloud
117 ADDENEMY = pygame.USEREVENT + 1
118 pygame.time.set_timer(ADDENEMY, 250)
119 ADDCLOUD = pygame.USEREVENT + 2
120 pygame.time.set_timer(ADDCLOUD, 1000)

これは、次のcloudを作成する前に、1000ミリ秒または1秒待機することを意味します。

次に、新しく作成された各cloudを保持するために、新しいGroupを作成します。

125 # Create groups to hold enemy sprites, cloud sprites, and all sprites
126 # - enemies is used for collision detection and position updates
127 # - clouds is used for position updates
128 # - all_sprites is used for rendering
129 enemies = pygame.sprite.Group()
130 clouds = pygame.sprite.Group()
131 all_sprites = pygame.sprite.Group()
132 all_sprites.add(player)

次に、イベントハンドラーに新しいADDCLOUDイベントのハンドラーを追加します。

137 # Main loop
138 while running:
139     # Look at every event in the queue
140     for event in pygame.event.get():
141         # Did the user hit a key?
142         if event.type == KEYDOWN:
143             # Was it the Escape key? If so, then stop the loop.
144             if event.key == K_ESCAPE:
145                 running = False
146
147         # Did the user click the window close button? If so, stop the loop.
148         elif event.type == QUIT:
149             running = False
150
151         # Add a new enemy?
152         elif event.type == ADDENEMY:
153             # Create the new enemy and add it to sprite groups
154             new_enemy = Enemy()
155             enemies.add(new_enemy)
156             all_sprites.add(new_enemy)
157
158         # Add a new cloud?
159         elif event.type == ADDCLOUD:
160             # Create the new cloud and add it to sprite groups
161             new_cloud = Cloud()
162             clouds.add(new_cloud)
163             all_sprites.add(new_cloud)

最後に、cloudsがフレームごとに更新されることを確認します。

167 # Update the position of enemies and clouds
168 enemies.update()
169 clouds.update()
170
171 # Fill the screen with sky blue
172 screen.fill((135, 206, 250))

行172は、元のscreen.fill()を更新して、画面を心地よいスカイブルーの色で塗りつぶします。 この色を別の色に変更できます。 紫の空、ネオングリーンの有毒な荒れ地、または赤の火星の表面を備えたエイリアンの世界が欲しいかもしれません!

新しいCloudEnemyはそれぞれ、all_spritesと、cloudsenemiesに追加されることに注意してください。 これは、各グループが個別の目的に使用されるために行われます。

  • Renderingは、all_spritesを使用して実行されます。

  • Position updatesは、cloudsenemiesを使用して実行されます。

  • Collision detectionは、enemiesを使用して実行されます。

複数のグループを作成して、他のスプライトの動きや動作に影響を与えることなく、スプライトの動きや動作を変更できるようにします。

ゲームスピード

ゲームのテスト中に、敵が少し速く動くことに気づいたかもしれません。 そうでない場合は、この時点で異なるマシンが異なる結果を見るため、大丈夫です。

これは、プロセッサと環境が許す限りゲームループがフレームを処理するためです。 すべてのスプライトはフレームごとに1回移動するため、毎秒数百回移動できます。 1秒あたりに処理されるフレーム数はframe rateと呼ばれ、これを正しく行うことが、プレイ可能なゲームと忘れられるゲームの違いです。

通常、可能な限り高いフレームレートが必要ですが、このゲームでは、ゲームをプレイ可能にするために少し遅くする必要があります。 幸い、モジュールtimeには、まさにこの目的のために設計されたClockが含まれています。

Clockを使用して再生可能なフレームレートを確立するには、2行のコードが必要です。 1つ目は、ゲームループが始まる前に、新しいClockを作成します。

106 # Setup the clock for a decent framerate
107 clock = pygame.time.Clock()

2番目は.tick()を呼び出して、プログラムがフレームの終わりに到達したことをpygameに通知します。

188 # Flip everything to the display
189 pygame.display.flip()
190
191 # Ensure program maintains a rate of 30 frames per second
192 clock.tick(30)

.tick()に渡される引数は、目的のフレームレートを確立します。 これを行うために、.tick()は、必要なフレームレートに基づいて、各フレームにかかるミリ秒数を計算します。 次に、その数値を、最後に.tick()が呼び出されてから経過したミリ秒数と比較します。 十分な時間が経過していない場合、.tick()は処理を遅らせて、指定されたフレームレートを超えないようにします。

フレームレートを小さくすると、各フレームの計算時間が長くなりますが、フレームレートを大きくすると、よりスムーズな(そしておそらくより高速な)ゲームプレイが提供されます。

Setting the frame rate in pygame

この番号をいじって、自分にとって何が一番いいかを確かめてください!

音響効果

これまで、ゲームプレイとゲームの視覚的側面に焦点を当ててきました。 それでは、ゲームに聴覚的なフレーバーを与えることも検討してみましょう。 pygameは、サウンド関連のすべてのアクティビティを処理するためのmixerを提供します。 このモジュールのクラスとメソッドを使用して、さまざまなアクションのバックグラウンドミュージックとサウンドエフェクトを提供します。

mixerという名前は、モジュールがさまざまなサウンドをまとまりのある全体にミックスするという事実を表しています。 musicサブモジュールを使用すると、MP3OggModなどのさまざまな形式で個々のサウンドファイルをストリーミングできます。 Soundを使用して、Oggまたはuncompressed WAV形式のいずれかで再生される単一のサウンドエフェクトを保持することもできます。 すべての再生はバックグラウンドで行われるため、Soundを再生すると、サウンドが再生されるとすぐにメソッドが戻ります。

pygame documentationは、MP3のサポートが制限されており、サポートされていないフォーマットがシステムクラッシュを引き起こす可能性があることを示している。 この記事で参照されているサウンドはテスト済みです。ゲームをリリースする前にサウンドを徹底的にテストすることをお勧めします。

ほとんどのものpygameと同様に、mixerの使用は初期化ステップから始まります。 幸い、これはすでにpygame.init()によって処理されています。 デフォルトを変更する場合にのみ、pygame.mixer.init()を呼び出す必要があります。

106 # Setup for sounds. Defaults are good.
107 pygame.mixer.init()
108
109 # Initialize pygame
110 pygame.init()
111
112 # Set up the clock for a decent framerate
113 clock = pygame.time.Clock()

pygame.mixer.init()a number of argumentsを受け入れますが、ほとんどの場合、デフォルトで正常に機能します。 デフォルトを変更する場合は、pygame.init()を呼び出す前にpygame.mixer.init()を呼び出す必要があることに注意してください。 そうしないと、変更に関係なくデフォルトが有効になります。

システムの初期化後、サウンドとバックグラウンドミュージックのセットアップを取得できます。

135 # Load and play background music
136 # Sound source: http://ccmixter.org/files/Apoxode/59262
137 # License: https://creativecommons.org/licenses/by/3.0/
138 pygame.mixer.music.load("Apoxode_-_Electric_1.mp3")
139 pygame.mixer.music.play(loops=-1)
140
141 # Load all sound files
142 # Sound sources: Jon Fincher
143 move_up_sound = pygame.mixer.Sound("Rising_putter.ogg")
144 move_down_sound = pygame.mixer.Sound("Falling_putter.ogg")
145 collision_sound = pygame.mixer.Sound("Collision.ogg")

Lines 138 and 139は、バックグラウンドサウンドクリップをロードして、再生を開始します。 名前付きパラメータloops=-1を設定することで、サウンドクリップにループして終了しないように指示できます。

Lines 143 to 145は、さまざまな効果音に使用する3つのサウンドをロードします。 最初の2つは、プレイヤーが上下に移動するときに再生される上昇音と下降音です。 最後は、衝突が発生するたびに使用される音です。 Enemyが作成されたときのサウンドや、ゲームが終了したときの最終サウンドなど、他のサウンドを追加することもできます。

それでは、音響効果をどのように使用しますか? 特定のイベントが発生したときに各サウンドを再生します。 たとえば、船が上に移動したときに、move_up_soundを再生します。 したがって、そのイベントを処理するたびに、.play()への呼び出しを追加します。 設計では、これは、Player.update()に次の呼び出しを追加することを意味します。

26 # Define the Player object by extending pygame.sprite.Sprite
27 # Instead of a surface, use an image for a better-looking sprite
28 class Player(pygame.sprite.Sprite):
29     def __init__(self):
30         super(Player, self).__init__()
31         self.surf = pygame.image.load("jet.png").convert()
32         self.surf.set_colorkey((255, 255, 255), RLEACCEL)
33         self.rect = self.surf.get_rect()
34
35     # Move the sprite based on keypresses
36     def update(self, pressed_keys):
37         if pressed_keys[K_UP]:
38             self.rect.move_ip(0, -5)
39             move_up_sound.play()
40         if pressed_keys[K_DOWN]:
41             self.rect.move_ip(0, 5)
42             move_down_sound.play()

プレーヤーと敵の衝突の場合、衝突が検出されたときの音を再生します。

201 # Check if any enemies have collided with the player
202 if pygame.sprite.spritecollideany(player, enemies):
203     # If so, then remove the player
204     player.kill()
205
206     # Stop any moving sounds and play the collision sound
207     move_up_sound.stop()
208     move_down_sound.stop()
209     collision_sound.play()
210
211     # Stop the loop
212     running = False

ここでは、衝突時にプレイヤーが動いていないため、他の効果音を最初に停止します。 次に、衝突音を再生し、そこから実行を続けます。

最後に、ゲームが終了すると、すべてのサウンドが停止します。 これは、衝突によりゲームが終了した場合でも、ユーザーが手動で終了した場合でも同様です。 これを行うには、ループの後、プログラムの最後に次の行を追加します。

220 # All done! Stop and quit the mixer.
221 pygame.mixer.music.stop()
222 pygame.mixer.quit()

技術的には、プログラムはこの直後に終了するため、これらの最後の数行は必要ありません。 ただし、後でゲームにイントロ画面または終了画面を追加することにした場合、ゲームの終了後に実行されるコードが増える可能性があります。

それでおしまい! もう一度テストすると、次のようなものが表示されるはずです。

Pygame window

ソースに関する注意

バックグラウンドミュージックが読み込まれたときに、136〜137行目にコメントがあり、音楽のソースとCreative Commonsライセンスへのリンクがリストされていることに気付いたかもしれません。 これは、そのサウンドの作成者がそれを必要としたために行われました。 ライセンス要件には、サウンドを使用するために、適切な帰属とライセンスへのリンクの両方を提供する必要があると記載されていました。

役立つコンテンツを検索できる音楽、サウンド、アートのソースは次のとおりです。

  • OpenGameArt.org:サウンド、効果音、スプライト、およびその他のアートワーク

  • Kenney.nl:サウンド、効果音、スプライト、およびその他のアートワーク

  • Gamer Art 2D:スプライトおよびその他のアートワーク

  • CC Mixter:の音と効果音

  • Freesound:の音と効果音

ゲームを作成し、アート、音楽、または他のソースからのコードなどのダウンロードしたコンテンツを使用するときは、それらのソースのライセンス条項を遵守していることを確認してください。

結論

このチュートリアルを通じて、pygameを使用したゲームプログラミングが標準の手続き型プログラミングとどのように異なるかを学びました。 また、次の方法も学びました。

  • イベントループを実装する

  • 画面にアイテムを描く

  • 効果音と音楽を再生する

  • ユーザー入力を処理する

これを行うには、displaymixermusictimeimage、%を含むpygameモジュールのサブセットを使用しました。 (t6)s、およびkeyモジュール。 また、RectSurfaceSoundSpriteなどのいくつかのpygameクラスを使用しました。 しかし、これらはpygameができることのほんの一部にすぎません! 使用可能なモジュールとクラスの完全なリストについては、official pygame documentationを確認してください。

以下のリンクをクリックすると、この記事のすべてのコード、グラフィック、およびサウンドファイルを見つけることができます。

Clone Repo:Click here to clone the repo you’ll useは、このチュートリアルでPyGameを使用する方法を学習します。

以下にもコメントを残してください。 ハッピーパイソン!