Python遊戲程式設計(Pygame)
安裝Pygame
pip install pygame
C:\Users> pip install pygame Collecting pygame Downloading https://files.pythonhosted.org/packages/3e/f5/feabd88a2856ec86166a897b62bfad828bfe7a94a27cbd7ebf07fd 70399/pygame-1.9.4-cp37-cp37m-win_amd64.whl (4.2MB) 100% |██████████████████████████| 4.2MB 6.6MB/s Installing collected packages: pygam Successfully installed pygame-1.9.4
Pygame常用模組
模組名 | 功能 |
---|---|
pygame.cdrom | 訪問光碟機 |
pygame.cursors | 載入游標 |
pygame.display | 訪問顯示裝置 |
pygame.draw | 繪製形狀、線和點 |
pygame.event | 管理事件 |
pygame.font | 使用字型 |
pygame.image | 載入和儲存圖片 |
pygame.joystick | 使用遊戲手柄或者類似的東西 |
pygame.key | 讀取鍵盤按鍵 |
pygame.mixer | 聲音 |
pygame.mouse | 滑鼠 |
pygame.movie | 播放視訊 |
pygame.music | 播放音訊 |
pygame.overlay | 訪問高階視訊疊加 |
pygame.rect | 管理矩形區域 |
pygame.scrap | 本地剪貼簿訪問 |
pygame.sndarray | 操作聲音資料 |
pygame.sprite | 操作移動影象 |
pygame.surface | 管理影象和螢幕 |
pygame.surfarray | 管理點陣影象資料 |
pygame.time | 管理時間和幀資訊 |
pygame.transform | 縮放和移動影象 |
簡單示例:
import pygame import sys pygame.init() # 初始化pygame size = width, height = 320, 240 # 設定視窗大小 screen = pygame.display.set_mode(size) # 顯示視窗 while True: # 死迴圈確保視窗一直顯示 for event in pygame.event.get(): # 遍歷所有事件 if event.type == pygame.QUIT: # 如果單擊關閉視窗,則退出 sys.exit() pygame.quit() # 退出pygame
執行結果:
製作一個跳躍的小球遊戲
建立一個遊戲視窗,然後在視窗內建立一個小球。以一定的速度移動小球,當小球碰到遊戲視窗的邊緣時,小球彈回,繼續運動按照如下步驟實現該功能:
建立遊戲視窗
1. 建立一個遊戲視窗,寬和高設定為640*480。程式碼如下:
import sys
import pygame
pygame.init() # 初始化pygame
size = width, height = 640, 480 # 設定視窗大小
screen = pygame.display.set_mode() # 顯示視窗
上述程式碼中,首先匯入pygame模組,然後呼叫init()方法初始化pygame模組,接下來,設定視窗的寬和高,最後使用display
模組顯示窗體。
display模組的常用方法
方法名 | 功能 |
---|---|
pygame.display.init() | 初始化display模組 |
pygame.display.quit() | 結束display模組 |
pygame.display.get_init() | 如果display模組已經被初始化,則返回True |
pygame.display.set_mode() | 初始化一個準備顯示的介面 |
pygame.display.get_surface() | 獲取當前的Surface物件 |
pygame.display.flip() | 更新整個待顯示的Surface物件到螢幕上 |
pygame.display.update() | 更新部分內容顯示到螢幕上,如果沒有引數,則與flip功能相同(上一條) |
保持視窗顯示
2. 執行第一步的程式碼後會出現一個一閃而過的黑色視窗,這是因為程式執行完成後,會自動關閉。如果想要讓視窗一直顯示,需要使用while True
讓程式一直執行,此外,還需要設定關閉按鈕。具體程式碼如下:
import pygame
import sys
pygame.init() # 初始化pygame
size = width, height = 320, 240 # 設定視窗大小
screen = pygame.display.set_mode(size) # 顯示視窗
while True: # 死迴圈確保視窗一直顯示
for event in pygame.event.get(): # 遍歷所有事件
if event.type == pygame.QUIT: # 如果單擊關閉視窗,則退出
sys.exit()
pygame.quit() # 退出pygame
上述程式碼中添加了輪詢事件檢測。pygame.event.get()
能夠獲取事件佇列,使用for...in
遍歷事件,然後根據type
屬性判斷事件型別。這裡的事件處理方式與GUI類似,如event.type
等於pygame.QUIT
表示檢測到關閉pygame視窗事件,pygame.KEYDOWN
表示鍵盤按下事件,pygame.MOUSEBUTTONDOWN
表示滑鼠按下事件等。
載入遊戲圖片
3. 在視窗新增小球。我們先準備好一張ball.png
圖片,然後載入該圖片,最後將圖片顯示在視窗中,具體程式碼如下:
import pygame
import sys
pygame.init() # 初始化pygame
size = width, height = 640, 480 # 設定視窗大小
screen = pygame.display.set_mode(size) # 顯示視窗
color = (0, 0, 0) # 設定顏色
ball = pygame.image.load('ball.png') # 載入圖片
ballrect = ball.get_rect() # 獲取矩形區域
while True: # 死迴圈確保視窗一直顯示
for event in pygame.event.get(): # 遍歷所有事件
if event.type == pygame.QUIT: # 如果單擊關閉視窗,則退出
sys.exit()
screen.fill(color) # 填充顏色(設定為0,執不執行這行程式碼都一樣)
screen.blit(ball, ballrect) # 將圖片畫到視窗上
pygame.display.flip() # 更新全部顯示
pygame.quit() # 退出pygame
上述程式碼中使用iamge
模組的load()
方法載入圖片,返回值ball是一個Surface
物件。Surface
是用來代表圖片的pygame物件,可以對一個Surface
物件進行塗畫、變形、複製等各種操作。事實上,螢幕也只是一個Surface
,pygame.display.set_mode()
就返回了一個螢幕Surface
物件。如果將ball這個Surface
物件畫到screen Surface 物件,需要使用blit()
方法,最後使用display模組的flip()方法更新整個待顯示的Surface
物件到螢幕上。
Surface物件的常用方法
方法名 | 功能 |
---|---|
pygame.Surface.blit() | 將一個影象畫到另一個影象上 |
pygame.Surface.convert() | 轉換影象的畫素格式 |
pygame.Surface.convert_alpha() | 轉化影象的畫素格式,包含alpha通道的轉換 |
pygame.Surface.fill() | 使用顏色填充Surface |
pygame.Surface.get_rect() | 獲取Surface的矩形區域 |
移動圖片
4. 下面讓小球動起來,ball.get_rect()
方法返回值ballrect
是一個Rect
物件,該物件有一個move()
方法可以用於移動矩形。move(x, y)
函式有兩個引數,第一個引數是 X 軸移動的距離,第二個引數是 Y 軸移動的距離。視窗的左上角是(0, 0),如果是move(100, 50)就是左移100下移50。
為實現小球不停移動,將move()函式新增到while迴圈內,具體程式碼如下:
import pygame
import sys
pygame.init() # 初始化pygame
size = width, height = 640, 480 # 設定視窗大小
screen = pygame.display.set_mode(size) # 顯示視窗
color = (0, 0, 0) # 設定顏色
ball = pygame.image.load('ball.png') # 載入圖片
ballrect = ball.get_rect() # 獲取矩形區域
speed = [5, 5] # 設定移動的X軸、Y軸
while True: # 死迴圈確保視窗一直顯示
for event in pygame.event.get(): # 遍歷所有事件
if event.type == pygame.QUIT: # 如果單擊關閉視窗,則退出
sys.exit()
ballrect = ballrect.move(speed) # 移動小球
screen.fill(color) # 填充顏色(設定為0,執不執行這行程式碼都一樣)
screen.blit(ball, ballrect) # 將圖片畫到視窗上
pygame.display.flip() # 更新全部顯示
pygame.quit() # 退出pygame
碰撞檢測
5. 執行上述程式碼,發現小球在螢幕中一閃而過,此時,小球並沒有真正消失,而是移動到窗體之外,此時需要新增碰撞檢測的功能。當小球與窗體任一邊緣發生碰撞,則更改小球的移動方向,具體程式碼如下:
import pygame
import sys
pygame.init() # 初始化pygame
size = width, height = 640, 480 # 設定視窗大小
screen = pygame.display.set_mode(size) # 顯示視窗
color = (0, 0, 0) # 設定顏色
ball = pygame.image.load('ball.png') # 載入圖片
ballrect = ball.get_rect() # 獲取矩形區域
speed = [5, 5] # 設定移動的X軸、Y軸
while True: # 死迴圈確保視窗一直顯示
for event in pygame.event.get(): # 遍歷所有事件
if event.type == pygame.QUIT: # 如果單擊關閉視窗,則退出
sys.exit()
ballrect = ballrect.move(speed) # 移動小球
# 碰到左右邊緣
if ballrect.left < 0 or ballrect.right > width:
speed[0] = -speed[0]
# 碰到上下邊緣
if ballrect.top < 0 or ballrect.bottom > height:
speed[1] = -speed[1]
screen.fill(color) # 填充顏色(設定為0,執不執行這行程式碼都一樣)
screen.blit(ball, ballrect) # 將圖片畫到視窗上
pygame.display.flip() # 更新全部顯示
pygame.quit() # 退出pygame
上述程式碼中,添加了碰撞檢測功能。如果碰到左右邊緣,更改X軸資料為負數,如果碰到上下邊緣,更改Y軸資料為負數。
限制移動速度
6. 執行上述程式碼看似有很多球,這是因為執行上述程式碼的時間非常短,執行快的錯覺,使用pygame的time模組,使用pygame時鐘之前,必須先建立Clock物件的一個例項,然後在while迴圈中設定多長時間執行一次。
import pygame
import sys
pygame.init() # 初始化pygame
size = width, height = 640, 480 # 設定視窗大小
screen = pygame.display.set_mode(size) # 顯示視窗
color = (0, 0, 0) # 設定顏色
ball = pygame.image.load('ball.png') # 載入圖片
ballrect = ball.get_rect() # 獲取矩形區域
speed = [5, 5] # 設定移動的X軸、Y軸
clock = pygame.time.Clock() # 設定時鐘
while True: # 死迴圈確保視窗一直顯示
clock.tick(60) # 每秒執行60次
for event in pygame.event.get(): # 遍歷所有事件
if event.type == pygame.QUIT: # 如果單擊關閉視窗,則退出
sys.exit()
ballrect = ballrect.move(speed) # 移動小球
# 碰到左右邊緣
if ballrect.left < 0 or ballrect.right > width:
speed[0] = -speed[0]
# 碰到上下邊緣
if ballrect.top < 0 or ballrect.bottom > height:
speed[1] = -speed[1]
screen.fill(color) # 填充顏色(設定為0,執不執行這行程式碼都一樣)
screen.blit(ball, ballrect) # 將圖片畫到視窗上
pygame.display.flip() # 更新全部顯示
pygame.quit() # 退出pygame
開發Flappy Bird遊戲
Flappy Bird是一款鳥類飛行遊戲,一根手指操控按下小鳥上飛。
分析 在Flappy Bird遊戲中,主要有兩個物件:小鳥、管道。可以建立Brid類和Pineline類來分別表示這兩個物件。小鳥可以通過上下移動來躲避管道,所以在Brid類中建立一個bridUpdate()方法,實現小鳥的上下移動,為了體現小鳥向前飛行的特徵,可以讓管道一直向左側移動,這樣在視窗中就好像小鳥在向前飛行。所以在Pineline類中也建立一個updatePipeline()方法,實現管道的向左側移動。此外還建立了3個函式:createMap()函式用於繪製地圖;checkDead()函式用於判斷小鳥的生命狀態;getResult()函式用於獲取最終分數。最後在主邏輯中例項化並呼叫相關方法,實現相應的功能。
搭建主框架
# -*- coding:utf-8 -*-
import sys # 匯入sys模組
import pygame # 匯入pygame模組
import random
class Bird(object):
"""定義一個鳥類"""
def __init__(self):
"""定義初始化方法"""
pass
def birdUpdate(self):
pass
class Pipeline(object):
"""定義一個管道類"""
def __init__(self):
"""定義初始化方法"""
def updatePipeline(self):
"""水平移動"""
def createMap():
"""定義建立地圖的方法"""
screen.fill((255, 255, 255)) # 填充顏色(screen還沒定義不要著急)
screen.blit(background, (0, 0)) # 填入到背景
pygame.display.update() # 更新顯示
if __name__ == '__main__':
pygame.init() # 初始化pygame
size = width, height = 400, 650 # 設定視窗大小
screen = pygame.display.set_mode(size) # 顯示視窗
clock = pygame.time.Clock() # 設定時鐘
Pipeline = Pipeline() # 例項化管道類
while True:
clock.tick(60) # 每秒執行60次
# 輪詢事件
for event in pygame.event.get():
if event.type == pygame.QUIT: # 如果檢測到事件是關閉視窗
sys.exit()
background = pygame.image.load("assets/background.png") # 載入背景圖片
createMap()
pygame.quit() # 退出
執行結果:
建立小鳥類、建立管道類、計算得分、碰撞檢測
import pygame
import sys
import random
class Bird(object):
"""定義一個鳥類"""
def __init__(self):
"""定義初始化方法"""
self.birdRect = pygame.Rect(65, 50, 50, 50) # 鳥的矩形
# 定義鳥的3種狀態列表
self.birdStatus = [pygame.image.load("assets/1.png"),
pygame.image.load("assets/2.png"),
pygame.image.load("assets/dead.png")]
self.status = 0 # 預設飛行狀態
self.birdX = 120 # 鳥所在X軸座標,即是向右飛行的速度
self.birdY = 350 # 鳥所在Y軸座標,即上下飛行高度
self.jump = False # 預設情況小鳥自動降落
self.jumpSpeed = 10 # 跳躍高度
self.gravity = 5 # 重力
self.dead = False # 預設小鳥生命狀態為活著
def birdUpdate(self):
if self.jump:
# 小鳥跳躍
self.jumpSpeed -= 1 # 速度遞減,上升越來越慢
self.birdY -= self.jumpSpeed # 鳥Y軸座標減小,小鳥上升
else:
# 小鳥墜落
self.gravity += 0.2 # 重力遞增,下降越來越快
self.birdY += self.gravity # 鳥Y軸座標增加,小鳥下降
self.birdRect[1] = self.birdY # 更改Y軸位置
class Pipeline(object):
"""定義一個管道類"""
def __init__(self):
"""定義初始化方法"""
self.wallx = 400 # 管道所在X軸座標
self.pineUp = pygame.image.load("assets/top.png")
self.pineDown = pygame.image.load("assets/bottom.png")
def updatePipeline(self):
""""管道移動方法"""
self.wallx -= 5 # 管道X軸座標遞減,即管道向左移動
# 當管道執行到一定位置,即小鳥飛越管道,分數加1,並且重置管道
if self.wallx < -80:
global score
score += 1
self.wallx = 400
def createMap():
"""定義建立地圖的方法"""
screen.fill((255, 255, 255)) # 填充顏色
screen.blit(background, (0, 0)) # 填入到背景
# 顯示管道
screen.blit(Pipeline.pineUp, (Pipeline.wallx, -300)) # 上管道座標位置
screen.blit(Pipeline.pineDown, (Pipeline.wallx, 500)) # 下管道座標位置
Pipeline.updatePipeline() # 管道移動
# 顯示小鳥
if Bird.dead: # 撞管道狀態
Bird.status = 2
elif Bird.jump: # 起飛狀態
Bird.status = 1
screen.blit(Bird.birdStatus[Bird.status], (Bird.birdX, Bird.birdY)) # 設定小鳥的座標
Bird.birdUpdate() # 鳥移動
# 顯示分數
screen.blit(font.render('Score:' + str(score), -1, (255, 255, 255)), (100, 50)) # 設定顏色及座標位置
pygame.display.update() # 更新顯示
def checkDead():
# 上方管子的矩形位置
upRect = pygame.Rect(Pipeline.wallx, -300,
Pipeline.pineUp.get_width() - 10,
Pipeline.pineUp.get_height())
# 下方管子的矩形位置
downRect = pygame.Rect(Pipeline.wallx, 500,
Pipeline.pineDown.get_width() - 10,
Pipeline.pineDown.get_height())
# 檢測小鳥與上下方管子是否碰撞
if upRect.colliderect(Bird.birdRect) or downRect.colliderect(Bird.birdRect):
Bird.dead = True
# 檢測小鳥是否飛出上下邊界
if not 0 < Bird.birdRect[1] < height:
Bird.dead = True
return True
else:
return False
def getResutl():
final_text1 = "Game Over"
final_text2 = "Your final score is: " + str(score)
ft1_font = pygame.font.SysFont("Arial", 70) # 設定第一行文字字型
ft1_surf = font.render(final_text1, 1, (242, 3, 36)) # 設定第一行文字顏色
ft2_font = pygame.font.SysFont("Arial", 50) # 設定第二行文字字型
ft2_surf = font.render(final_text2, 1, (253, 177, 6)) # 設定第二行文字顏色
screen.blit(ft1_surf, [screen.get_width() / 2 - ft1_surf.get_width() / 2, 100]) # 設定第一行文字顯示位置
screen.blit(ft2_surf, [screen.get_width() / 2 - ft2_surf.get_width() / 2, 200]) # 設定第二行文字顯示位置
pygame.display.flip() # 更新整個待顯示的Surface物件到螢幕上
if __name__ == '__main__':
"""主程式"""
pygame.init() # 初始化pygame
pygame.font.init() # 初始化字型
font = pygame.font.SysFont("Arial", 50) # 設定字型和大小
size = width, height = 400, 650 # 設定視窗
screen = pygame.display.set_mode(size) # 顯示視窗
clock = pygame.time.Clock() # 設定時鐘
Pipeline = Pipeline() # 例項化管道類
Bird = Bird() # 例項化鳥類
score = 0
while True:
clock.tick(60) # 每秒執行60次
# 輪詢事件
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
if (event.type == pygame.KEYDOWN or event.type == pygame.MOUSEBUTTONDOWN) and not Bird.dead:
Bird.jump = True # 跳躍
Bird.gravity = 5 # 重力
Bird.jumpSpeed = 10 # 跳躍速度
background = pygame.image.load("assets/background.png") # 載入背景圖片
if checkDead(): # 檢測小鳥生命狀態
getResutl() # 如果小鳥死亡,顯示遊戲總分數
else:
createMap() # 建立地圖
pygame.quit()
執行結果: