PyGame 是 Python 中的 2D 游戏开发库。它包含程序员从头开始创建简单或复杂游戏所需的特定函数和类。
在本教程中,我们将使用 PyGame 库创建我们自己的 Hi-Lo 游戏。Hi-Lo 是一款非常简单的赌场游戏,玩家必须猜测牌组中的下一张牌是否比当前牌更高或更低。
建议:如果这是您第一次创建游戏,请尝试在 Python 中使用命令行实现 hi-lo 游戏。它更容易,并且会让您更好地了解游戏机制。但是,如果您已经熟悉 Python,请继续阅读!
卡牌的排名系统从 Ace(排名最低的卡牌)开始,到 King(排名最高的卡牌)结束。
Python 中的 GUI 高低游戏
导入 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 时要记住的一件事是,大小参数作为两个值的元组传入:宽度和高度。
设置窗口后,我们使用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()
函数接受一个字符串作为参数并将其作为标题。为了设置图标,我们首先需要使用load()
接收图像文件名的函数加载图像。
该set_icon()
函数将图像设置为游戏图标。
注意:如果图像文件与 python 游戏文件不在同一目录中,那么我们需要添加相对路径以及图像名称。
定义游戏字体
在屏幕上渲染文本之前,我们需要定义某些字体。
# Types of fonts to be used small_font = pygame.font.Font( None , 32 ) large_font = pygame.font.Font( None , 50 ) |
该Font()
函数有两个参数:字体类型(None
默认字体)和字体大小。
设置游戏按钮的文本
我们的游戏中有两个按钮:高和低。为按钮放置文本需要多个步骤:
- 将字体渲染到文本
- 获取文本的矩形覆盖范围
- 将矩形放在屏幕上
# 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()
函数接受以下参数:
- 文字——“高”
- 应用抗锯齿功能使文本边缘平滑?– 真的
- 文字颜色 – 白色
该get_rect()
函数返回所提供文本的矩形覆盖物。
下一行指定矩形覆盖物中心的位置,从而放置文本。
定义我们的牌组
为了定义我们的牌组,我们首先必须定义一张单独的牌。我们将借助Python 类来完成此任务。
# Card class definition class Card: def __init__( self , suit_type, value): self .suit_type = suit_type self .value = value |
任何牌都有两个特征:花色类型及其面值。继续讨论卡片定义,我们使用三种定义数据结构:
# 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)) |
设置卡片图像
与图标图像类似,我们首先需要加载卡牌图像,然后再将其渲染到游戏表面上。为此,我们需要为这副牌中的每张牌提供一个图像。值得庆幸的是,它可以很容易地从互联网上获得。
这些卡片是这样的:
正如我们所看到的,命名约定是必要的,因为当 Python 脚本从牌组中拾取卡片时,就会加载卡片。命名约定很简单:牌值后面跟着花色的第一个字母。
# 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 )) |
放置原始图像文件可能会覆盖整个屏幕,因此,我们需要根据屏幕的宽度和高度缩放图像。在 PyGame 中,它是通过scale()
获取输入图像和目标大小进行转换的函数来完成的。
根据高低游戏规则,起始牌不能是最高牌或最低牌,即 A 或 K。我们运行一个循环,直到从牌堆中挑选的牌都不是它们中的一张为止。
选择卡片后,我们需要加载特定的卡片图像以显示在屏幕上。这是通过load()
函数完成的,该函数接受相对路径,后跟图像名称。
声明游戏变量
游戏所需的游戏变量很少:
# 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 |
上述变量的主要焦点是over
用于停止游戏功能的变量,例如按钮单击。
游戏循环
游戏循环是代码中永远运行的部分,负责维护游戏窗口、其组件以及游戏逻辑。
# The GAME LOOP while True : # Tracking the mouse movements mouse = pygame.mouse.get_pos() |
游戏循环的第一个议程是跟踪鼠标移动。这对于识别鼠标点击的位置和其他事情非常有用。
该get_pos()
函数返回鼠标在屏幕上的位置的 Python 元组(X 轴,Y 轴)。
处理 PyGame 事件
PyGame 开发中最重要的部分是处理游戏窗口内发生的事件。
PyGame 将发生的每个事件注册到 Event 对象列表中。我们将遍历每个事件对象来处理它。
# 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 |
我们检查事件的类型并执行所需的任务。必须注意的是,在退出 python 代码之前,我们退出了 PyGame 模块。
游戏逻辑
游戏逻辑涉及:
- 将当前卡放到上一张卡的位置。
- 从牌组中选择一张新牌。
- 从牌组中取出所选的牌。
- 检查新卡是否更高或更低。
- 如果牌较低,那么剩下的机会就会减少。
- 如果牌较高,则增加分数。
- 重置玩家选择
# 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 ]) |
在此代码片段中,我们首先检查鼠标位置是否位于按钮内部。如果是,那么我们在屏幕上绘制一个矩形,其颜色比原始按钮颜色浅,否则为原始按钮颜色。
这里的函数pygame.draw.rect()
接受三个参数,显示表面(我们的游戏窗口)、矩形的颜色、盒子的尺寸[起始x坐标、起始y坐标、宽度、高度]。
显示记分牌
我们需要显示一个计分板,其中包含当前得分和剩余机会数。
# 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 ) |
我们使用与按钮文本类似的文本渲染。
设置整个显示
所有显示组件初始化后,我们终于可以使用该blit()
函数将它们放置在游戏窗口上。
# 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()
函数接收图像或文本等游戏对象及其放置位置。
管理最终游戏
在游戏逻辑中,当机会结束时,over
变量更改为True
。其效果如下所示。
# 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() |
完整代码
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 试验和冒险的基础。
感谢您的阅读。如有疑问或建议,请随时在下面发表评论。