PyGameは、Pythonによる2Dゲーム開発ライブラリです。
プログラマーがゼロからシンプルまたは複雑なゲームを作成するために必要な特定の関数とクラスが含まれています。
この記事では、PyGameライブラリを使用して独自のHi-Loゲームを作成する予定です。
Hi-Lo は非常に簡単なカジノゲームで、プレイヤーは山札の次のカードが現在のカードより高いか低いかを当てなければなりません。
提案:もしあなたが初めてゲームを作るのであれば、Pythonのコマンドライン実装のHi-Loゲームを試してみてください。
その方が簡単で、ゲームの仕組みをよりよく理解できるはずです。
カードのランク付けは、最低ランクのAceから始まり、最高ランクのKingまでです。
PythonでGUIハイローゲーム
PyGame : ハイ・ロー・ゲーム
PyGame のインポート
pygameのモジュールを使用する前に、ライブラリをインポートする必要があります。
import pygame
|
PyGameのすべての関数には、pygame
の後に'.'
と関数名を付けてアクセスできます。
ゲーム定数の宣言
すべてのゲームデザインは、ゲームの主要な機能を指定するためにいくつかの定数を必要とします。
# Margins MARGIN_LEFT = 230
MARGIN_TOP = 150
# WINDOW SIZE WIDTH = 800
HEIGHT = 600
# COLORS BLACK = ( 0 , 0 , 0 )
WHITE = ( 255 , 255 , 255 )
GRAY = ( 110 , 110 , 110 )
GREEN = ( 0 , 255 , 0 )
LIGHT_GREEN = ( 0 , 120 , 0 )
RED = ( 255 , 0 , 0 )
LIGHT_RED = ( 120 , 0 , 0 )
|
定数の種類と値はプログラマによって異なります。
このような定数をあらかじめ定義しておくと、万が一、値が変わったときに、あちこちで修正する必要がなくなるので、良い習慣と言えます。
ゲームモジュールの初期化
PyGameのモジュールを利用するために、まず、以下のように初期化する必要があります。
# Initializing PyGame pygame.init() |
すべてのゲームは、あるゲームウィンドウでプレイされますが、これはプログラマーの必要に応じて変更することができます。
このゲームウィンドウは、サイズパラメータが必要です。
# WINDOW SIZE WIDTH = 800
HEIGHT = 600
# Setting up the screen and background screen = pygame.display.set_mode((WIDTH, HEIGHT))
screen.fill(GRAY) |
組み込みの set_mode()
関数を使用して、ウィンドウサイズを定義します。
PyGameで作業する際に注意しなければならないのは、サイズパラメータは幅と高さの2つの値のタプルとして渡されることです。
ウィンドウを設定した後、fill()
コマンドを使って背景色を設定します。
キャプションとアイコンのセットアップ
このゲームには、タイトルとアイコンが必要です。
# Setting up caption pygame.display.set_caption( "Hi-Lo Game" )
# Loading image for the icon icon = pygame.image.load( 'icon.jpeg' )
# Setting the game icon pygame.display.set_icon(icon) |
set_caption()関数は String を引数として受け取り、それをキャプションとして配置します。
アイコンを設定するには、まず画像ファイルの名前を受け取るload()` 関数で画像をロードする必要があります。
set_icon()` 関数は、その画像をゲームのアイコンとして設定します。
Note: もし画像ファイルがpythonゲームファイルと同じディレクトリにない場合は、画像名と一緒に相対パスを追加する必要があります。
ゲームフォントの定義
画面にテキストを表示する前に、ある種のフォントを定義する必要があります。
# Types of fonts to be used small_font = pygame.font.Font( None , 32 )
large_font = pygame.font.Font( None , 50 )
|
Font()関数は 2 つの引数をとります: font-type (
None` はデフォルトのフォント) と font-size です。
ゲームボタンのテキストを設定する
このゲームには2つのボタンがあります。
HighとLowです。
ボタン用のテキストを配置するには、複数のステップが必要です。
- テキストにフォントをレンダリングする
- テキストの矩形被覆を取得する
- 矩形を画面上に配置する
# Hign and Low Game Buttons high_button = large_font.render( "HIGH" , True , WHITE)
# Gets_rectangular covering of text high_button_rect = high_button.get_rect()
# Places the text high_button_rect.center = ( 280 , 400 )
low_button = large_font.render( "LOW" , True , WHITE)
low_button_rect = low_button.get_rect()
low_button_rect.center = ( 520 , 400 )
|
render()` 関数は、以下のパラメータを受け取ります。
- テキスト – “HIGH”
- アンチエイリアスを適用して、テキストのエッジを滑らかにするか?- 真
- テキストの色 – WHITE
get_rect()` 関数は、指定されたテキストを矩形で覆う領域を返します。
次の行では、その矩形被覆の中心位置を指定して、テキストを配置します。
私たちのデッキを定義する
カードのデッキを定義するために、まず個々のカードを定義する必要があります。
この作業にはPythonのクラスの助けを借りることにします。
# Card class definition class Card:
def __init__( self , suit_type, value):
self .suit_type = suit_type
self .value = value
|
どんなカードも2つの特徴を持っています。
スーツの種類とその額面。
カードの定義に移って、我々は3つのデータ構造を定義します。
# The type of suit suits = [ "Spades" , "Hearts" , "Clubs" , "Diamonds" ]
# The type of card cards = [ "A" , "2" , "3" , "4" , "5" , "6" , "7" , "8" , "9" , "10" , "J" , "Q" , "K" ]
# The card value cards_values = { "A" : 1 , "2" : 2 , "3" : 3 , "4" : 4 , "5" : 5 , "6" : 6 , "7" : 7 , "8" : 8 , "9" : 9 , "10" : 10 , "J" : 11 , "Q" : 12 , "K" : 13 }
|
これらのカードの格納は、Pythonのオブジェクトのリストの中で行われます。
# The deck of cards - List of Objects deck = []
# Loop for every type of suit for suit in suits:
# Loop for every type of card in a suit
for card in cards:
# Adding the card to the deck
deck.append(Card(suit, card))
|
カード画像のセットアップ
アイコン画像と同様に、ゲーム画面にレンダリングする前に、まずカード画像を読み込む必要があります。
この目的のために、デッキの各カードの画像が必要です。
ありがたいことに、それはインターネットから簡単に手に入れることができます。
カードはこのような感じです。
# Load the card image prev_card = pygame.image.load(r './cards/card_cover.png' )
# Scale the loaded image prev_card = pygame.transform.scale(prev_card , ( 100 , 160 ))
# Choose the starting card from the deck current_card = random.choice(deck)
# Keep choosing until it is not the highest or lowest while current_card.value = = "A" or current_card.value = = "K" :
current_card = random.choice(deck)
# Load the card image cur_card = pygame.image.load(r './cards/' + current_card.value + current_card.suit_type[ 0 ] + '.png' )
# Scale the loaded card image cur_card = pygame.transform.scale(cur_card , ( 100 , 160 ))
# Remove the card from the deck deck.remove(current_card) # Loading the card image next_card = pygame.image.load(r './cards/card_cover.png' )
# Scaling the loaded image next_card = pygame.transform.scale(next_card , ( 100 , 160 ))
|
Pythonスクリプトがデッキからカードを読み込むときに、命名規則が必要なのはおわかりでしょう。
命名規則は単純です。
カードの値の後にスーツの最初の文字が続きます。
# Number of chances left chances = 3
# The current score score = 0
# User's choice initialized choice = - 1
# Used to stop game functioning, if True over = False
|
生の画像ファイルを置くと画面全体を覆ってしまうので、画面の幅と高さに応じて画像を拡大縮小する必要があります。
PyGameでは、入力画像と変換のターゲットサイズを受け取る scale()
関数によって行われます。
ハイローゲームのルールでは、スタート時のカードは最高位と最低位のカード(それぞれAceとKing)であってはいけません。
そこで、山札から選ばれたカードがそのどちらでもない場合、ループを実行します。
カードが選ばれたら、そのカードの画像を画面に表示するためにロードする必要がある。
これは load()
関数で行われ、相対パスの後に画像の名前が続きます。
ゲーム変数の宣言
ゲームに必要な変数がいくつかあります。
# The GAME LOOP while True :
# Tracking the mouse movements
mouse = pygame.mouse.get_pos()
|
上記の変数で注目すべきは、over
変数で、これはゲームの機能、例えばボタンクリックを停止させるために使用される。
ゲームのループ
ゲームループは、ゲームウィンドウとその構成要素、そしてゲームロジックを管理する、永遠に動き続けるコード部分です。
# Loop events occuring inside the game window for event in pygame.event.get():
# Qutting event
if event. type = = pygame.QUIT:
pygame.quit()
quit()
# Left-mouse clicked event
if not over and event. type = = pygame.MOUSEBUTTONDOWN:
# Clicked on the High Button
if 220 < = mouse[ 0 ] < = 220 + 125 and 370 < = mouse[ 1 ] < = 370 + 60 :
choice = 1
# Clicked on the Low Button
if 460 < = mouse[ 0 ] < = 460 + 120 and 370 < = mouse[ 1 ] < = 370 + 60 :
choice = 0
|
ゲームループの最初の課題は、マウスの動きを追跡することです。
これはマウスをクリックした位置を認識したりするのに便利です。
get_pos()`関数は画面上のマウスの位置を(X軸, Y軸)としてPythonのタプルで返します。
PyGameのイベントを処理する
PyGameの開発で最も重要なのは、ゲームウィンドウ内で発生するイベントを処理することです。
PyGameは発生するすべてのイベントをEventオブジェクトのリストに登録します。
ここでは、それぞれのEventオブジェクトを処理するために見ていきます。
# If a valid choice, the game logic if choice ! = - 1 :
# Change current card to previous
previous_card = current_card
prev_card = pygame.image.load(r './cards/' + previous_card.value + previous_card.suit_type[ 0 ] + '.png' )
prev_card = pygame.transform.scale(prev_card , ( 100 , 160 ))
# Set up the current card
current_card = random.choice(deck)
deck.remove(current_card)
cur_card = pygame.image.load(r './cards/' + current_card.value + current_card.suit_type[ 0 ] + '.png' )
cur_card = pygame.transform.scale(cur_card , ( 100 , 160 ))
# Check the result, that is, High or Low
if cards_values[current_card.value] > cards_values[previous_card.value]:
result = 1
elif cards_values[current_card.value] < cards_values[previous_card.value]:
result = 0
else :
result = - 1 # Manage the game variables
if result = = - 1 :
continue
elif result = = choice:
score = score + 1
else :
chances = chances - 1 # End the game if chances are finished
if chances = = 0 :
over = True
# Reset the choice
choice = - 1
|
Eventの種類を確認し、必要な処理を行います。
Pythonのコードを終了する前に、PyGameのモジュールを終了することに注意しなければなりません。
ゲームロジック
ゲームのロジックは以下の通りです。
- 現在のカードを前のカードの場所に置く。
- 山札から新しいカードを1枚選びます。
- 選ばれたカードを山札から取り除く。
- 新しいカードが上か下かチェックします。
- もし低いカードなら、残されたチャンスを減らします。
- より高いカードなら、スコアを増やします。
- プレイヤーの選択をリセットします。
# Manage the button hovering animation if 220 < = mouse[ 0 ] < = 220 + 125 and 370 < = mouse[ 1 ] < = 370 + 60 :
pygame.draw.rect(screen,LIGHT_GREEN,[ 220 , 370 , 125 , 60 ])
else :
pygame.draw.rect(screen,GREEN,[ 220 , 370 , 125 , 60 ])
if 460 < = mouse[ 0 ] < = 460 + 120 and 370 < = mouse[ 1 ] < = 370 + 60 :
pygame.draw.rect(screen,LIGHT_RED,[ 460 , 370 , 120 , 60 ])
else :
pygame.draw.rect(screen,RED,[ 460 , 370 , 120 , 60 ])
|
ボタンアニメーション
トラッキングされたマウスの動きを使って、マウスがボタンの上に乗ったときにボタンアニメーションを作成することができます。
# Displaying scoreboard pygame.draw.rect(screen, WHITE, [ 270 , 40 , 255 , 90 ])
score_text = small_font.render( "Score = " + str (score), True , BLACK)
score_text_rect = score_text.get_rect()
score_text_rect.center = (WIDTH / / 2 , 70 )
chances_text = small_font.render( "Chances = " + str (chances), True , BLACK)
chances_text_rect = chances_text.get_rect()
chances_text_rect.center = (WIDTH / / 2 , 100 )
|
このコードでは、まずマウスの位置がボタンの内側にあるかどうかをチェックします。
もしそうであれば、元のボタンの色よりも明るい色で、そうでなければ元のボタンの色で、画面に矩形を描きます。
ここで pygame.draw.rect()
関数は、表示面(ゲームウィンドウ)、矩形の色、ボックスの寸法 [開始 x 座標、開始 y 座標、幅、高さ] の 3 つのパラメータを受け取ります。
スコアボードを表示する
現在のスコアと残りチャンス数をスコアボードに表示する必要がある。
# Setting up all the buttons, images and texts on the screen screen.blit(high_button, high_button_rect) screen.blit(low_button, low_button_rect) screen.blit(score_text, score_text_rect) screen.blit(chances_text, chances_text_rect) screen.blit(prev_card, (MARGIN_LEFT,MARGIN_TOP)) screen.blit(cur_card, (MARGIN_LEFT + 120 , MARGIN_TOP))
screen.blit(next_card, (MARGIN_LEFT + 240 , MARGIN_TOP))
|
ボタンのテキストと同じようなテキストレンダリングを使用します。
ディスプレイ全体を設定する
すべての表示コンポーネントを初期化したら、最後に blit()
関数を使ってゲーム・ウィンドウに配置します。
# If the game is finished, display the final score if over = = True :
pygame.draw.rect(screen, WHITE, [ 270 , 40 , 255 , 90 ])
score_text = small_font.render( "Final Score = " + str (score), True , BLACK)
score_text_rect = score_text.get_rect()
score_text_rect.center = (WIDTH / / 2 , 85 )
screen.blit(score_text, score_text_rect)
|
blit()
関数はイメージやテキストなどのゲームオブジェクトと、その配置位置を受け取ります。
エンドゲームの管理
ゲームロジックでは、チャンスが終了すると、変数 over
が True
に変更されます。
その効果は以下の通りです。
# Update the display after each game loop pygame.display.update() |
ゲーム終了後、スコアボードに最終的なスコアを表示します。
ゲーム表示を更新する
最後に、ゲームループの終了時に、ゲーム表示を更新します。
import pygame
import random
# Card class definition class Card:
def __init__( self , suit_type, value):
self .suit_type = suit_type
self .value = value
if __name__ = = '__main__' :
# Margins
MARGIN_LEFT = 230
MARGIN_TOP = 150
# WINDOW SIZE
WIDTH = 800
HEIGHT = 600
# COLORS
BLACK = ( 0 , 0 , 0 )
WHITE = ( 255 , 255 , 255 )
GRAY = ( 110 , 110 , 110 )
GREEN = ( 0 , 255 , 0 )
LIGHT_GREEN = ( 0 , 120 , 0 )
RED = ( 255 , 0 , 0 )
LIGHT_RED = ( 120 , 0 , 0 )
# The type of suit
suits = [ "Spades" , "Hearts" , "Clubs" , "Diamonds" ]
# The type of card
cards = [ "A" , "2" , "3" , "4" , "5" , "6" , "7" , "8" , "9" , "10" , "J" , "Q" , "K" ]
# The card value
cards_values = { "A" : 1 , "2" : 2 , "3" : 3 , "4" : 4 , "5" : 5 , "6" : 6 , "7" : 7 , "8" : 8 , "9" : 9 , "10" : 10 , "J" : 11 , "Q" : 12 , "K" : 13 }
# The deck of cards - List of Objects
deck = []
# Loop for every type of suit
for suit in suits:
# Loop for every type of card in a suit
for card in cards:
# Adding the card to the deck
deck.append(Card(suit, card))
# Initializing PyGame
pygame.init()
# Setting up the screen and background
screen = pygame.display.set_mode((WIDTH, HEIGHT))
screen.fill(GRAY)
# Setting up caption
pygame.display.set_caption( "Hi-Lo Game" )
# Loading image for the icon
icon = pygame.image.load( 'icon.jpeg' )
# Setting the game icon
pygame.display.set_icon(icon)
# Types of fonts to be used
small_font = pygame.font.Font( None , 32 )
large_font = pygame.font.Font( None , 50 )
# Hign and Low Game Buttons
high_button = large_font.render( "HIGH" , True , WHITE)
# Gets_rectangular covering of text
high_button_rect = high_button.get_rect()
# Places the text
high_button_rect.center = ( 280 , 400 )
low_button = large_font.render( "LOW" , True , WHITE)
low_button_rect = low_button.get_rect()
low_button_rect.center = ( 520 , 400 )
# Load the card image
prev_card = pygame.image.load(r './cards/card_cover.png' )
# Scale the loaded image
prev_card = pygame.transform.scale(prev_card , ( 100 , 160 ))
# Choose the starting card from the deck
current_card = random.choice(deck)
# Keep choosing until it is not the highest or lowest
while current_card.value = = "A" or current_card.value = = "K" :
current_card = random.choice(deck)
# Load the card image
cur_card = pygame.image.load(r './cards/' + current_card.value + current_card.suit_type[ 0 ] + '.png' )
# Scale the loaded card image
cur_card = pygame.transform.scale(cur_card , ( 100 , 160 ))
# Remove the card from the deck
deck.remove(current_card)
# Loading the card image
next_card = pygame.image.load(r './cards/card_cover.png' )
# Scaling the loaded image
next_card = pygame.transform.scale(next_card , ( 100 , 160 ))
# Number of chances left
chances = 3
# The current score
score = 0
# User's choice initialized
choice = - 1
# Used to stop game functioning, if True
over = False
# The GAME LOOP
while True :
# Tracking the mouse movements
mouse = pygame.mouse.get_pos()
# Loop events occuring inside the game window
for event in pygame.event.get():
# Qutting event
if event. type = = pygame.QUIT:
pygame.quit()
quit()
# Left-mouse clicked event
if not over and event. type = = pygame.MOUSEBUTTONDOWN:
# Clicked on the High Button
if 220 < = mouse[ 0 ] < = 220 + 125 and 370 < = mouse[ 1 ] < = 370 + 60 :
choice = 1
# Clicked on the Low Button
if 460 < = mouse[ 0 ] < = 460 + 120 and 370 < = mouse[ 1 ] < = 370 + 60 :
choice = 0
# Finish the game if the deck is finished
if len (deck) = = 1 :
over = True
# If a valid choice, the game logic
if choice ! = - 1 :
# Change current card to previous
previous_card = current_card
prev_card = pygame.image.load(r './cards/' + previous_card.value + previous_card.suit_type[ 0 ] + '.png' )
prev_card = pygame.transform.scale(prev_card , ( 100 , 160 ))
# Set up the current card
current_card = random.choice(deck)
deck.remove(current_card)
cur_card = pygame.image.load(r './cards/' + current_card.value + current_card.suit_type[ 0 ] + '.png' )
cur_card = pygame.transform.scale(cur_card , ( 100 , 160 ))
# Check the result, that is, High or Low
if cards_values[current_card.value] > cards_values[previous_card.value]:
result = 1
elif cards_values[current_card.value] < cards_values[previous_card.value]:
result = 0
else :
result = - 1 # Manage the game variables
if result = = - 1 :
continue
elif result = = choice:
score = score + 1
else :
chances = chances - 1 # End the game if chances are finished
if chances = = 0 :
over = True
# Reset the choice
choice = - 1
# Manage the button hovering animation
if 220 < = mouse[ 0 ] < = 220 + 125 and 370 < = mouse[ 1 ] < = 370 + 60 :
pygame.draw.rect(screen,LIGHT_GREEN,[ 220 , 370 , 125 , 60 ])
else :
pygame.draw.rect(screen,GREEN,[ 220 , 370 , 125 , 60 ])
if 460 < = mouse[ 0 ] < = 460 + 120 and 370 < = mouse[ 1 ] < = 370 + 60 :
pygame.draw.rect(screen,LIGHT_RED,[ 460 , 370 , 120 , 60 ])
else :
pygame.draw.rect(screen,RED,[ 460 , 370 , 120 , 60 ])
# Displaying scoreboard
pygame.draw.rect(screen, WHITE, [ 270 , 40 , 255 , 90 ])
score_text = small_font.render( "Score = " + str (score), True , BLACK)
score_text_rect = score_text.get_rect()
score_text_rect.center = (WIDTH / / 2 , 70 )
chances_text = small_font.render( "Chances = " + str (chances), True , BLACK)
chances_text_rect = chances_text.get_rect()
chances_text_rect.center = (WIDTH / / 2 , 100 )
# Setting up all the buttons, images and texts on the screen
screen.blit(high_button, high_button_rect)
screen.blit(low_button, low_button_rect)
screen.blit(score_text, score_text_rect)
screen.blit(chances_text, chances_text_rect)
screen.blit(prev_card, (MARGIN_LEFT,MARGIN_TOP))
screen.blit(cur_card, (MARGIN_LEFT + 120 , MARGIN_TOP))
screen.blit(next_card, (MARGIN_LEFT + 240 , MARGIN_TOP))
# If the game is finished, display the final score
if over = = True :
pygame.draw.rect(screen, WHITE, [ 270 , 40 , 255 , 90 ])
score_text = small_font.render( "Final Score = " + str (score), True , BLACK)
score_text_rect = score_text.get_rect()
score_text_rect.center = (WIDTH / / 2 , 85 )
screen.blit(score_text, score_text_rect)
# Update the display after each game loop
pygame.display.update()
|
完全なるコード
まとめ
PyGameを使って独自のHi-Loゲームを作るのは簡単な作業のように思えます。
このチュートリアルが、読者の今後のPyGameの試行錯誤と冒険の基礎になることを願っています。
お読みいただきありがとうございました。
ご質問やご提案がありましたら、お気軽にコメントください。