PyGame:Pythonでのゲームプログラミングの入門書
私が最後の千年紀の後半にコンピュータープログラミングを学び始めたとき、それはコンピューターゲームを書きたいという私の欲求に駆動されました。 Pythonを含め、私が学んだすべての言語とプラットフォームでゲームを書く方法を見つけようとしました。 それが私がpygame
を発見し、それを使ってゲームや他のグラフィックプログラムを書く方法を学んだ方法です。 当時、私はpygame
の入門書が本当に欲しかったのです。
この記事の終わりまでに、次のことができるようになります。
-
画面にアイテムを描く
-
効果音と音楽を再生する
-
ユーザー入力を処理する
-
イベントループを実装する
-
ゲームプログラミングが標準の手続き型Pythonプログラミングとどのように異なるかを説明する
この入門書は、ユーザー定義関数、imports、loops、および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()
このプログラムを実行すると、次のようなウィンドウが表示されます。
このコードをセクションごとに分解してみましょう。
-
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 29は
pygame
を終了します。 これは、ループが終了した後にのみ発生します。
これは、「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_WIDTH
とSCREEN_HEIGHT
で定義されています。 これは、ウィンドウの内側の寸法を表すSurface
を返します。 これは制御可能なウィンドウの一部であり、OSはウィンドウの境界線とタイトルバーを制御します。
このプログラムを今すぐ実行すると、ウィンドウが短時間表示され、プログラムが終了するとすぐに消えます。 まばたきしないでください。 次のセクションでは、メインゲームループに焦点を当て、正しい入力が与えられた場合にのみプログラムが終了するようにします。
ゲームループのセットアップ
PongからFortniteまでのすべてのゲームは、game loopを使用してゲームプレイを制御します。 ゲームループは4つの非常に重要なことを行います。
-
ユーザー入力を処理します
-
すべてのゲームオブジェクトの状態を更新します
-
ディスプレイとオーディオ出力を更新します
-
ゲームの速度を維持します
ゲームループのすべてのサイクルはframeと呼ばれ、各サイクルで実行できる速度が速いほど、ゲームの実行速度は速くなります。 フレームは、ゲームを終了する何らかの条件が満たされるまで発生し続けます。 デザインには、ゲームループを終了できる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.type
がKEYDOWN
イベントであるかどうかを確認します。 そうである場合、プログラムはevent.key
属性を調べて、どのキーが押されたかを確認します。 キーがK_ESCAPE
で示される[.kbd .key-escape]#Esc#キーである場合、running = False
を設定してゲームループを終了します。 -
Lines 41 and 42は、
QUIT
と呼ばれるイベントタイプに対して同様のチェックを実行します。 このイベントは、ユーザーがウィンドウの閉じるボタンをクリックしたときにのみ発生します。 ユーザーは、他のオペレーティングシステムアクションを使用してウィンドウを閉じることもできます。
これらの行を前のコードに追加して実行すると、空白または黒い画面のウィンドウが表示されます。
[.kbd .key-escape]#Esc#キーを押すか、ウィンドウを閉じてQUIT
イベントをトリガーするまで、ウィンドウは消えません。
画面に描画する
サンプルプログラムでは、2つのコマンドを使用して画面に描画しました。
-
背景を埋めるための
screen.fill()
-
円を描くための
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
を別のSurface
にblitする必要があります。 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つの引数があります。
-
描画する
Surface
-
ソース
Surface
に描画する場所
座標(SCREEN_WIDTH/2, SCREEN_HEIGHT/2)
は、surf
を画面の正確な中央に配置するようにプログラムに指示しますが、そのようには見えません。
画像が中心から外れて見える理由は、.blit()
がsurf
のtop-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表現です。 本質的に、それは写真です。 pygame
はSprite
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
を定義して初期化します。これは、後でプレーヤーを描画するために使用します。 この新しいクラスを使用するには、新しいオブジェクトを作成し、描画コードも変更する必要があります。 以下のコードブロックを展開して、すべて一緒に表示します。
このコードを実行します。 画面のほぼ中央に白い長方形が表示されます。
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
イベントタイプをスキャンすることを確認しました。 キープレスを読む方法はそれだけではありません。 pygame
はpygame.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_UP
、K_DOWN
、K_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))
これで、矢印キーを使用してプレーヤーの四角形を画面上で移動できます。
次の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()
Enemy
とPlayer
の間には4つの顕著な違いがあります。
-
On lines 62 to 67の場合、
rect
を更新して、画面の右端に沿ったランダムな場所にします。 長方形の中心は画面から少し外れています。 右端から20〜100ピクセル離れた位置、および上端と下端の間のどこかにあります。 -
On line 68の場合、
.speed
を5から20までの乱数として定義します。 これは、この敵がプレイヤーに向かって移動する速度を指定します。 -
On lines 73 to 76、
.update()
を定義します。 敵は自動的に移動するため、引数は必要ありません。 代わりに、.update()
は、作成時に定義された.speed
で、画面の左側に向かって敵を移動します。 -
On line 74、敵が画面外に移動したかどうかを確認します。
Enemy
が画面から完全に外れていて、表示されている間に消えないようにするには、.rect
の右側が画面の左側を超えていることを確認します。 敵が画面外に出たら、.kill()
を呼び出して、それ以上処理されないようにします。
では、.kill()
は何をするのでしょうか? これを理解するには、Sprite Groupsについて知っておく必要があります。
スプライトグループ
pygame
が提供するもう1つの非常に便利なクラスは、Sprite Group
です。 これは、Sprite
オブジェクトのグループを保持するオブジェクトです。 なぜそれを使用するのですか? 代わりに、リスト内のSprite
オブジェクトを追跡することはできませんか? できますが、Group
を使用する利点は、公開するメソッドにあります。 これらのメソッドは、Enemy
がPlayer
と衝突したかどうかを検出するのに役立ち、更新がはるかに簡単になります。
スプライトグループを作成する方法を見てみましょう。 2つの異なるGroup
オブジェクトを作成します。
-
最初の
Group
は、ゲーム内のすべてのSprite
を保持します。 -
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つのことを行う必要があることを意味します。
-
新しい
Enemy
を作成します。 -
all_sprites
とenemies
に追加します。
ランダムイベントを処理するコードが既にあります。 イベントループは、フレームごとに発生するランダムイベントを探して適切に処理するように設計されています。 幸い、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
を作成し、それをenemies
とall_sprites
に追加します。 Enemy
はall_sprites
にあるため、フレームごとに描画されます。 また、行126でenemies.update()
を呼び出す必要があります。これにより、enemies
のすべてが更新され、正しく移動するようになります。
ただし、enemies
だけのグループがある理由はそれだけではありません。
衝突検出
ゲームの設計では、敵がプレイヤーと衝突するたびにゲームを終了する必要があります。 衝突のチェックは、ゲームプログラミングの基本的な手法であり、通常、2つのスプライトが互いにオーバーラップするかどうかを判断するために、重要な数学が必要です。
ここで、pygame
のようなフレームワークが役立ちます。 衝突検出コードを書くのは面倒ですが、pygame
にはたくさんのcollision detection methodsがあります。
このチュートリアルでは、.spritecollideany()
というメソッドを使用します。これは、「スプライトが任意に衝突する」と読み取られます。このメソッドは、パラメーターとしてSprite
とGroup
を受け入れます。 Group
内のすべてのオブジェクトを調べ、その.rect
がSprite
の.rect
と交差するかどうかを確認します。 その場合、True
を返します。 それ以外の場合は、False
を返します。 単一のplayer
がenemies
のGroup
のいずれかと衝突するかどうかを確認する必要があるため、これはこのゲームに最適です。
コードでは次のようになります。
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行目では、player
がenemies
内のオブジェクトのいずれかと衝突したかどうかをテストしています。 その場合、player.kill()
が呼び出され、それが属するすべてのグループから削除されます。 レンダリングされるオブジェクトはall_sprites
のみであるため、player
はレンダリングされなくなります。 プレーヤーが殺されたら、ゲームも終了する必要があるため、running = False
を設定して138行目のゲームループから抜け出します。
この時点で、ゲームの基本的な要素が準備できました。
それでは、少しドレスアップしてプレイしやすくし、いくつかの高度な機能を追加して目立たせましょう。
スプライト画像
さて、あなたはゲームを持っていますが、正直に言ってください...それはちょっといです。 プレイヤーと敵は、黒い背景に白いブロックだけです。 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.locals
importステートメントに追加されます。
他に何も変える必要はありません。 画像はまだ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
の場合と同じ原則を使用します。
-
Cloud
クラスを作成します。 -
クラウドの画像を追加します。
-
cloud
を画面の左側に移動するメソッド.update()
を作成します。 -
カスタムイベントとハンドラーを作成して、設定した時間間隔で新しい
cloud
オブジェクトを作成します。 -
新しく作成された
cloud
オブジェクトをclouds
と呼ばれる新しいGroup
に追加します。 -
ゲームループの
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()
を更新して、画面を心地よいスカイブルーの色で塗りつぶします。 この色を別の色に変更できます。 紫の空、ネオングリーンの有毒な荒れ地、または赤の火星の表面を備えたエイリアンの世界が欲しいかもしれません!
新しいCloud
とEnemy
はそれぞれ、all_sprites
と、clouds
とenemies
に追加されることに注意してください。 これは、各グループが個別の目的に使用されるために行われます。
-
Renderingは、
all_sprites
を使用して実行されます。 -
Position updatesは、
clouds
とenemies
を使用して実行されます。 -
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()
は処理を遅らせて、指定されたフレームレートを超えないようにします。
フレームレートを小さくすると、各フレームの計算時間が長くなりますが、フレームレートを大きくすると、よりスムーズな(そしておそらくより高速な)ゲームプレイが提供されます。
この番号をいじって、自分にとって何が一番いいかを確かめてください!
音響効果
これまで、ゲームプレイとゲームの視覚的側面に焦点を当ててきました。 それでは、ゲームに聴覚的なフレーバーを与えることも検討してみましょう。 pygame
は、サウンド関連のすべてのアクティビティを処理するためのmixer
を提供します。 このモジュールのクラスとメソッドを使用して、さまざまなアクションのバックグラウンドミュージックとサウンドエフェクトを提供します。
mixer
という名前は、モジュールがさまざまなサウンドをまとまりのある全体にミックスするという事実を表しています。 music
サブモジュールを使用すると、MP3、Ogg、Modなどのさまざまな形式で個々のサウンドファイルをストリーミングできます。 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()
技術的には、プログラムはこの直後に終了するため、これらの最後の数行は必要ありません。 ただし、後でゲームにイントロ画面または終了画面を追加することにした場合、ゲームの終了後に実行されるコードが増える可能性があります。
それでおしまい! もう一度テストすると、次のようなものが表示されるはずです。
ソースに関する注意
バックグラウンドミュージックが読み込まれたときに、136〜137行目にコメントがあり、音楽のソースとCreative Commonsライセンスへのリンクがリストされていることに気付いたかもしれません。 これは、そのサウンドの作成者がそれを必要としたために行われました。 ライセンス要件には、サウンドを使用するために、適切な帰属とライセンスへのリンクの両方を提供する必要があると記載されていました。
役立つコンテンツを検索できる音楽、サウンド、アートのソースは次のとおりです。
-
OpenGameArt.org:サウンド、効果音、スプライト、およびその他のアートワーク
-
Kenney.nl:サウンド、効果音、スプライト、およびその他のアートワーク
-
Gamer Art 2D:スプライトおよびその他のアートワーク
-
CC Mixter:の音と効果音
-
Freesound:の音と効果音
ゲームを作成し、アート、音楽、または他のソースからのコードなどのダウンロードしたコンテンツを使用するときは、それらのソースのライセンス条項を遵守していることを確認してください。
結論
このチュートリアルを通じて、pygame
を使用したゲームプログラミングが標準の手続き型プログラミングとどのように異なるかを学びました。 また、次の方法も学びました。
-
イベントループを実装する
-
画面にアイテムを描く
-
効果音と音楽を再生する
-
ユーザー入力を処理する
これを行うには、display
、mixer
、music
、time
、image
、%を含むpygame
モジュールのサブセットを使用しました。 (t6)s、およびkey
モジュール。 また、Rect
、Surface
、Sound
、Sprite
などのいくつかのpygame
クラスを使用しました。 しかし、これらはpygame
ができることのほんの一部にすぎません! 使用可能なモジュールとクラスの完全なリストについては、official pygame
documentationを確認してください。
以下のリンクをクリックすると、この記事のすべてのコード、グラフィック、およびサウンドファイルを見つけることができます。
Clone Repo:Click here to clone the repo you’ll useは、このチュートリアルでPyGameを使用する方法を学習します。
以下にもコメントを残してください。 ハッピーパイソン!