參考:pygame詳細教程
參考案例:游戲模塊
Pygame 作為一個入門級的游戲開發庫,其實並不難學,只要掌握 Python 編程的相關知識就能很輕松地掌握它。
Pygame 語法簡單、明了,秉持了 Python 語言一貫的風格。同時,它作為一個游戲開發庫來說,具有圖形編程的基本特點,如果您對於圖形編程從未了解過,即使您有 Python 編程基礎,也會略感迷茫。因此,在接下來的學習中會詳細介紹 Pygame 的常用模塊,以及圖形編程中的相關概念,幫助您快速掌握 Pygame 的使用。
#導入所需的模塊
import pygame, sys
# 使用pygame之前必須初始化
pygame.init()
# 設置主屏窗口
screen = pygame.display.set_mode((600,400))
# 設置窗口的標題,即游戲名稱
pygame.display.set_caption("小小工坊")
# 加載圖像,存儲在ball變量中,ball是一個圖像對象
ball = pygame.image.load('pygame/images/ball.gif')
#獲得顯示對象的rect區域坐標
ball_rect = ball.get_rect()
# 設置顯示對象居中
ball_rect.center = (300, 200)
# 將准備好的圖像繪制到主屏幕 Screen 上。
screen.blit(ball, ball_rect)
# 建立時鐘對象
fclock = pygame.time.Clock()
# 固定代碼段,實現點擊關閉按鈕退出游戲的功能,幾乎所有的pygame都會使用該段代碼
while True :
# 循環獲取事件,監聽事件狀態
for event in pygame.event.get():
# 判斷用戶是否點了"X"關閉按鈕,並執行if代碼段
if event.type == pygame.QUIT:
#卸載所有模塊
pygame.quit()
#終止程序,確保退出程序
sys.exit()
ball_rect = ball_rect.move(speed,speed)
screen.fill((0,0,0))
screen.blit(ball,ball_rect)
#更新屏幕內容
pygame.display.update()
fclock.tick(60)
Python:pygame包的詳細使用方法
# 使用pygame之前必須初始化
pygame.init()
要使用pygame提供的所有功能之前,需要調用init
方法,它的作用是自動檢測 Pygame 軟件包是否正常可用,並檢查電腦的硬件調用接口、基礎功能是否存在問題,比如音頻、光驅、聲卡驅動等設備。同時,它會完成 Pygame 中所有模塊的初始化操作,比如 display
(顯示模塊)、font
(字體模塊)、mixe
r(聲音控制模塊)、cursors
(光標控制模塊)等。
在游戲結束前需要調用一下quit方法
pygame.init()
導入並初始化所有pygame模塊,使用其他模塊前,必須先調用iinit方法pygame.quit()
卸載所有pygame模塊,在游戲結束之前調用
如圖:
(x, y) (width, height)
(x,y)
是物體坐標,(width, height)
是物體像素大小
x, y
left,top,bottom,right
center,centerx,centery
size,width,height
那麼我們應該如何創建 Surface 對象呢?Pygame 提供了多種創建 Surface 對象的方法,這裡先介紹以下幾種方法。
上述示例,使用如下方式創建了一個 surface 對象:
#也叫screen對象,本質上是一個Surface,大小400*400
screen = pygame.display.set_mode((400,400))
screen 的本質上就是一個 Surface 對象,它是游戲的主窗口,也就是整個游戲中尺寸最大的“紙”,任何其他的 Surface 對象都需要附著在這張最大的“紙”上,比如創建一個圖像的 Surface 對象,通過以下方法將它繪制在主屏幕上:
# 加載圖像,存儲在ball變量中,ball是一個圖像對象
ball = pygame.image.load('pygame/images/ball.gif')
#獲得顯示對象的rect區域坐標
ball_rect = ball.get_rect()
# 設置顯示對象居中
ball_rect.center = (300, 200)
# 將准備好的圖像繪制到主屏幕 Screen 上。
screen.blit(ball, ball_rect)
比如創建一個包含文本的 Surface 對象,通過以下方法將它繪制在主屏幕上:
# 引入字體類型
f = pygame.font.Font('C:/Windows/Fonts/simhei.ttf',50)
#創建一個包含文字的Surface對象
# 生成文本信息,第一個參數文本內容;第二個參數,字體是否平滑;
# 第三個參數,RGB模式的字體顏色;第四個參數,RGB模式字體背景顏色;
text = f.render("小小工坊",True,(255,0,0),(0,0,0))
textRect =text.get_rect()
#通過blit方法將其繪制在主屏幕上,這裡的textRect表示位置坐標
screen.blit(text,textRect)
set_mode()方法
set_ mode( resolution=(0,0),flags=0, depth=0) -> Surface(名字隨意)
- 作用:創建游戲顯示窗口
- 參數
- resolution 指定屏幕的寬和高,默認創建的窗口大小和屏幕大小一致
- flags參數指定屏幕的附加選項,例如是否全屏等等,默認不需要傳遞
- depth參數表示顏色的位數,默認自動匹配
- 返回值:Surface對象
Surface對象是內存中的屏幕數據對象,可以理解為游戲的屏幕,游戲的元素都需要被繪制到游戲的屏幕上
1. 在開發時,可能會需要使用固定的數值,例如屏幕的高度是700
2. 這個時候,建議不要直接使用固定數值,而應該使用常量
3. 當實驗需求發生變化時,只需要修改常量的值就可,不需要在一個一個去找數值更改常量的命名方式:
所有字母都使用大寫,單詞與單詞之間使用下劃線連接
pygame.Rect
是一個比較特殊的類,內部只是封裝了一些數字計算
實例:
import pygame
hero = pygame.Rect(100,200,50,120)
print("英雄的x,y坐標分別是 %d, %d" % (hero.x, hero.y))
print("英雄的寬高分別是:%d,%d" % (hero.width, hero.height))
# Rect中的size屬性是一個元組(寬,高)
print("英雄的寬高分別是:%d,%d" % hero.size))
# Rect中的bottom屬性表示底部的縱坐標 y+height,top屬性表示元素頂部縱坐標y
print("英雄的底部y坐標為:%d,頂部y坐標為:%d" % (hero.bottom, hero.top))
# Rect的right屬性表示元素右邊橫坐標 x+width, left表示元素橫坐標x
print("英雄的最右邊x坐標為%d,最左邊x坐標為:%d" % (hero.right, hero.left))
# Rect的center屬性是一個元組(centerx,centery)
print("英雄的中心點坐標為:%d,%d" % hero.center)
那麼要在創建的窗口中按照指定要求顯示圖片,則需要三個步驟:
1. 使用`pygame.image.load()`加載圖像的數據
2. 使用游戲屏幕對象,調用`blit`方法將圖像繪制到指定位置
3. 調用`pygame.display.update()`方法更新整個屏幕的顯示
注:如果不調用pygame.display.update()
方法,則運行程序後圖片並不會顯示出來,在所有圖像繪制完成後可放在最後統一更新
游戲,在我們日常生活中經常接觸到,無論是手游、還是電腦端游戲,已經成了信息社會中,不可或缺的一部分。
游戲大致來講是由動畫和人機交互的體驗兩部分構成,其中動畫則是由一系列連續靜止的圖片,經過一定頻率的刷新構成的,這個頻率被稱為 FPS,如果頻率值越大則畫面越流暢;如果頻率值越小則畫面會出現卡頓的感,在游戲過程中一般人能接受的最低 FPS
約為 30Hz,如果想要畫面流暢則 FPS
要大於 60 Hz。
FPS 越高,細節越好,體驗也越好,但是文件容量也越高
動畫保證了玩家的視覺體驗,而人機交互則是操作上的體驗。通過移動和點擊鼠標、按下鍵盤上的技能鍵,或是滑動手機屏幕等操作來實現人機交互,這些與游戲程序交互的操作被稱為事件(Event
)。
Pygame 作為一個游戲開發庫,同樣具有設置和監聽事件的功能。它提供了一個 event
事件模塊,這個模塊中包含了所有常用到游戲事件。下面是退出游戲的代碼示例(其他事件類型,後續會做介紹):
# 循環獲取事件,監聽事件狀態,使用get()獲取事件
for event in pygame.event.get():
# 判斷事件類型,用戶是否點了"X"關閉按鈕
# pygame.QUIT 指點擊右上角窗口的"X"號
if event.type == pygame.QUIT:
#點擊後,卸載所有pygame模塊
pygame.quit()
當打我們游戲時可能會觸發游戲中的各種事件,比如鼠標事件、鍵盤按鍵事件、攝像拍照事件等等,因此游戲程序需要一直循環監聽玩家的操作,只有當用戶點擊了游戲“關閉”按鈕時,監聽才會結束。如果想要達到“循環監聽”目的,此時就需要設置一個游戲循環(Game Loop)也稱為游戲的主循環,這樣才能保證人機交互的體驗感。代碼示例如下:
#游戲主循環(游戲循環)
while True:
# 循環獲取事件,監聽事件
for event in pygame.event.get():
# 判斷用戶是否點了關閉按鈕
if event.type == pygame.QUIT:
# 當用戶關閉游戲窗口時執行以下操作
# 這裡必須調用quit()方法,退出游戲
pygame.quit()
#終止系統
sys.exit()
#更新並繪制屏幕內容
pygame.display.flip()
游戲主循環是每個 Pygame 游戲程序中必不可少的一部分,它主要承擔著以下三個重要任務:
圖2:主循環示意圖
游戲畫面和游戲操作狀態會因為動畫效果和玩家的操作而改變,因此需要以循環的方式實時地更新主屏幕(screen)的顯示內容。把下列代碼放入游戲主循環中即可實現實時更新和繪制屏幕內容,如下所示:
#刷新界面顯示
pygame.display.flip()
除了上述方法外,Pygame 還提供了另一個方法。如下所示:
pygame.display.update()
這兩個方法的主要區別是:後者可以根據選定的區域來更新部分內容,而前者則是更新整個待顯示的內容。如果後者沒有提供區域位置參數時,其作用和 display.flip() 相同。
跟電影的原理類似,游戲中的動畫效果,本質上是快速的在屏幕上繪制圖像,電影是將多張靜止的電影膠片連續、快速的播放,產生連貫的視覺效果!
一般在電腦上每秒繪制60次,就能夠達到非常連續高品質的動畫效果,每次繪制的結果被稱為幀Frame
在每次調用pygame.display.update()
方法產生的結果為一幀,也就是說需要每秒鐘調用60次pygame.display.update()
方法,就可以達到高品質動畫效果
如何實現每秒60幀?
pygame專門提供了一個類pygame.time.Clock
可以非常方便的設置屏幕繪制速度- -刷新幀率
要使用時鐘對象需要兩步:
tick
(幀率) 方法,tick
方法會根據.上次被調用的時間, 自動設置游戲循環中的延時實現方法:
# 創建時鐘對象
clock = pygame.time.Clock()
while True:
# 在游戲循環內部調用tick方法,裡面傳入想要的幀數
clock.tick(60)
動畫實現案例:飛機向上飛行
例 :
import pygame
pygame.init()
# 創建游戲窗口
screen = pygame.display.set_mode((480,700))
# 加載游戲中需要的圖像
background = pygame.image.load("./pygame/images/xx.jpg")
plane = pygame.image.load("./pygame/images/xxx.jpg)
# 將圖像顯示到游戲初始化的位置
screen.blit(background, (0, 0))
screen.blit(plane, (120, 500))
# 定義飛機顯示的矩形區域
plane_Rect = pygame.Rect(120, 500, 120, 90)
# 創建時鐘對象
clock = pygame.time.Clock()
while True:
# 定義每秒60幀
clock.tick(60)
# 移動飛機顯示矩形區域的位置
plane_Rect.y = plane_Rect.y -5
# 重繪背景圖像,避免出現殘影
screen.blit(background, (0, 0))
# 重新繪制圖像
screen.blit(plane, place_Rect)
# 更新屏幕
pygame.display.update()
pygame.quit()
●第一種方式判斷event.type == pygame.KEYDOWN
實現代碼:
if event.type == pygame. KEYDOWN and event.key == pygame.K RIGHT:
print("向右移動...")
●第二種方式(按住方向鍵不放可持續移動)
pygame. key.get_ pressed()
返回所有按鍵元組實現代碼:
變量 = pygame.key.get_pressed()
if 變量[pygame.K_RIGHT]:
print("向右移動")
● 兩種方式的區別
第一種方式 event.type 用戶必須抬起按鍵才算一次按鍵事件(利用列表也可實現持續向某一方向移動,具體見)
第二種方式 用戶可按鍵不放,能夠實現持續向某一個方向移動
圖像加載、位置變化、繪制圖像都需要程序員編寫代碼分別處理,為了簡化代碼,避免過多類似重復的代碼,pygame提供了精靈和精靈組類
心得: 其根本就是,將需要創建的多個執行相同動作的元素通過精靈類統一規劃到一起,再通過精靈組統一執行每個元素的動作並繪制到屏幕上,將多次重復的代碼縮減成一次代碼。
pygame.sprite.Sprite
—— 存儲圖像數據image
和位置rect
的對象pygame.sprite.Group
注:在開發時,如果子類的父類不是Object
類,則需要通過super(),__init__()
來調用父類的初始化方法,因為父類中的初始化方法中封裝了許多屬性,在繼承父類後只有通過手動調用父類的初始化方法,才能在子類的初始化方法中使用父類初始化方法封裝的屬性
●精靈
。封裝圖像image、位置rect
。提供update() 方法,根據游戲需求,更新位置rect
# 定義對象的屬性
self.image = pygame.image.load(image)
# 得到圖片的坐標和寬高像素
self.rect = self.image.get_rect()
●精靈組
。包含多個精靈對象
。update 方法,讓精靈組中的所有精靈調用update 方法更新位置
。draw(游戲窗口對象) 方法,在游戲窗口上繪制精靈組中的所有精靈
實例:
#精靈類planeSprites:
import pygame
class planeSprites(pygame.sprite.Sprite):
def __init__(self, image, speed=1):
# 調用父類的初始化方法
super().__init__()
# 定義對象的屬性
self.image = pygame.image.load(image)
# 得到圖片的坐標和寬高像素
self.rect = self.image.get_rect()
# 定義圖片的運行速度
self.speed = speed
def update(self, *args):
# 使飛機斜著飛行
self.rect.x += self.speed
self.rect.y += self.speed
# 殺死精靈,節約內存
self.kill()
主程序中:
import pygame
from plane_sprites import planeSprites
pygame.init()
# 創建敵機1,敵機2
enemy1 = planeSprites("./飛機大戰素材/敵機.png")
enemy2 = planeSprites("./飛機大戰素材/敵機.png")
# 在精靈組中加入敵機1
enemy_group = pygame.sprite.Group(enemy1, enemy2)
while True:
# 調用精靈組的update方法
enemy_group.update()
# 將精靈組中的敵機繪制到屏幕上
enemy_group.draw(screen)
# ***一定記得更新視圖,否則不會顯示出任何圖像
pygame.display.update()
pygame.quit()
pygame.sprite.groupcolide()
groupcollide(group1, group2, dokill1, dokill2, collided = None) -> Sprite_ dict
group1和group2
都是一個精靈組dokill1和dokill2
都是布爾類型
當把dokill1設置為True後,精靈組1和精靈組2碰撞時精靈組1會自動銷毀
當把dokill2設置為True後,精靈組1和精靈組2碰撞時精靈組2會自動銷毀
pygame.sprite.spritecollide()
●判斷某個精靈和指定精靈組中的精靈的碰撞
spritecollide(sprite, group, dokill, collided = None) -> Sprite_ list
●如果將dokill 設置為True,則指定精靈組中發生碰撞的精靈將被自動移除
● collided參數是用於計算碰捶的回調函數
。如果沒有指定,則每個精靈必須有一一個rect 屬性
●返回精靈組中跟精靈發生碰撞的精靈列表
注:這裡是返回一個列表
代碼實現:
enemies = pygame.sprite.spritecollide(self.hero, self.enemyGroup, True)
if len(enemies) > 0:
print("游戲結束,飛機受到損壞")
pygame.quit()
exit()
俗稱跑步機模式
在飛機大戰中游戲背景不斷變化產生向上飛行的視覺效果
實現原理:
實際上是兩張尺寸與屏幕一樣大小的背景圖片向下移動,等第一張圖片剛移除出屏幕後立馬改變坐標移動到第二張圖片之後
代碼實現:
精靈類
import pygame
from plane_main import SCREEN_RECT
class planeSprites(pygame.sprite.Sprite):
def __init__(self, image, speed=1):
# 調用父類的初始化方法
super().__init__()
# 定義對象的屬性
self.image = pygame.image.load(image)
# 得到圖片的坐標和寬高像素
self.rect = self.image.get_rect()
# 定義圖片的運行速度
self.speed = speed
def update(self, *args):
# 使精靈向下移動
self.rect.y += self.speed
# 當父類update更新方法已經無法滿足某一精靈類的條件則可以創建心得精靈子類
class background(planeSprites):
def __init__(self, is_single=False):
super().__init__("./飛機大戰素材/游戲背景.jpg")
if is_single:
#將第二張圖片放在第一張圖片的上面
self.rect.y = - self.rect.height
def update(self, *args):
# 調用父類更新方法
super().update()
if self.rect.y == SCREEN_RECT.height:
self.rect.y = - self.rect.height
主方法:
import pygame
from plane_sprites import *
pygame.init()
SCREEN_RECT = pygame.Rect(0, 0, 480, 700)
class main(object):
def __init__(self):
# 創建游戲屏幕
self.screen = pygame.display.set_mode(SCREEN_RECT.size)
# 創建游戲時鐘
self.clock = pygame.time.Clock()
# 創建游戲精靈組
self.__create_spirits()
# 精靈創建
def __create_spirits(self):
bg1 = background()
bg2 = background(True)
self.backGroup = pygame.sprite.Group(bg1, bg2)
# 精靈更新處理
def __update_spirits(self):
self.backGroup.update()
self.backGroup.draw(self.screen)
●在 pygame中可以使用pygame.time.set.timer()
來添加定時器
●所謂定時器,就是每隔一段時間,去執行些動作
set_timer(eventid, milliseconds) -> None
●set_timer 可以創建一個事件
●可以在游戲循環的事件監聽方法中捕獲到該事件
● 第1個參數事件代號需要基於常量pygame. USEREVENT
來指定
USEREVENT
是一個整數,再增加的事件可以使用USEREVENT + 1
指定,依次類推…
●第2個參數是事件觸發間隔的毫秒值
定時器事件的監聽
●通過pygame.event.get() 可以獲取當前時刻所有的事件列表
●遍歷列表並且判斷event.type 是否等於eventid, 如果相等,表示定時器事件發生
實現方法:
# 創建敵機的定時器,每隔1000ms發出一個事件
pygame.time.set_timer(pygameUSEREVENT, 3000)
# 事件監聽
for event in pygame.event.get():
if event.type == pygameUSEREVENT:
pass
實例(敵機隨機飛進屏幕中):
精靈類
import random
import pygame
# 指定屏幕格式大小
SCREEN_RECT = pygame.Rect(0, 0, 480, 700)
CREATE_EVVENTID = pygame.USEREVENT
class planeSprites(pygame.sprite.Sprite):
def __init__(self, image, speed=1):
# 調用父類的初始化方法
super().__init__()
# 定義對象的屬性
self.image = pygame.image.load(image)
# 得到圖片的坐標和寬高像素
self.rect = self.image.get_rect()
# 定義圖片的運行速度
self.speed = speed
# 創建敵機的定時器,每隔1000ms發出一個事件
pygame.time.set_timer(CREATE_EVVENTID, 3000)
class enemy(planeSprites):
"""敵機精靈"""
def __init__(self):
super().__init__("./飛機大戰素材/敵機.png")
self.rect.bottom = 0
# 飛機速度從1—3中任取
self.speed = random.randint(1, 3)
max_x = SCREEN_RECT.width - self.rect.width
# 飛機的位置從0-屏幕右邊任取
self.rect.x = random.randint(0, max_x)
def update(self, *args):
super().update()
# 判斷精靈飛出屏幕後殺死精靈
if self.rect.y >= SCREEN_RECT.height:
self.kill()
主方法:
import pygame
from plane_sprites import *
pygame.init()
# 精靈創建
def __create_spirits(self):
self.enemyGroup = pygame.sprite.Group()
# 事件監聽處理
def __event_handler(self):
for event in pygame.event.get():
# 判斷事件類型是否是定時器給出的
if event.type == CREATE_EVVENTID:
# 新增精靈
oneEnemy = enemy()
# 向精靈組中添加精靈
self.enemyGroup.add(oneEnemy)
# 精靈更新處理
def __update_spirits(self):
self.enemyGroup.update()
self.enemyGroup.draw(self.screen)
#導入音樂
pygame.mixer.init()
def background_music_load():
global hero_fire_music # 導入函數外部變量
pygame.mixer.music.load("./music/PlaneWarsBackgroundMusic.mp3")#游戲背景音樂
pygame.mixer.music.set_volume(0.3)#設置音量(0-1)
pygame.mixer.music.play(-1)#循環播放
hero_fire_music = pygame.mixer.Sound("./music/hero_fire.wav")#飛機開火音樂
hero_fire_music.set_volume(0.2)#設置音量(0-1)