PyGameで簡単なHi-Lo(トランプゲーム)のサンプルゲームを作る方法を解説する

スポンサーリンク

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です。

ボタン用のテキストを配置するには、複数のステップが必要です。

  1. テキストにフォントをレンダリングする
  2. テキストの矩形被覆を取得する
  3. 矩形を画面上に配置する
# 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()関数はイメージやテキストなどのゲームオブジェクトと、その配置位置を受け取ります。

エンドゲームの管理

ゲームロジックでは、チャンスが終了すると、変数 overTrue に変更されます。

その効果は以下の通りです。

# 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()

完全なるコード

Hi Lo Pygame Cards
The images for playing cards

まとめ

PyGameを使って独自のHi-Loゲームを作るのは簡単な作業のように思えます。

このチュートリアルが、読者の今後のPyGameの試行錯誤と冒険の基礎になることを願っています。

お読みいただきありがとうございました。

ご質問やご提案がありましたら、お気軽にコメントください。

タイトルとURLをコピーしました