動畫是遊戲不可或缺的要素,要讓遊戲角色動起來,遊戲才擁有生命。PyGame套件透過不斷重新繪製繪圖視窗,來呈現物體動起來的感覺。可以回想一下關閉視窗的程式碼,那裡是用無窮迴圈去做的,那麼動畫的基本架構也能被放在那裡,如下:
import pygame as pg
pg.init()
#設定視窗
width, height = 640, 480
screen = pg.display.set_mode((width, height))
pg.display.set_caption("Sean's game")
bg = pg.Surface(screen.get_size())
bg = bg.convert()
bg.fill((255,255,255))
clock = pg.time.Clock() #建立時間元件
#關閉程式的程式碼
running = True
while running:
clock.tick(30) #每秒執行30次
for event in pg.event.get():
if event.type == pg.QUIT:
running = False
screen.blit(bg, (0,0)) #重繪視窗
pg.display.update() #更新視窗
pg.quit()
這邊建立clock元件,利用它tick()方法來設定每秒重繪次數。當然數值越大,動畫越流暢,但CPU的負擔可就越重喔。那來試試看讓一顆球動起來吧!
import pygame as pg
pg.init()
#設定視窗背景
width, height = 640, 480
screen = pg.display.set_mode((width, height))
pg.display.set_caption("Sean's game")
bg = pg.Surface(screen.get_size())
bg = bg.convert()
bg.fill((255,255,255))
#藍球建立
ball = pg.Surface((70,70)) #建立球矩形繪圖區
ball.fill((255,255,255)) #矩形區塊背景為白色
pg.draw.circle(ball, (0,0,255), (35,35), 35, 0) #畫藍色球
rect = ball.get_rect() #取得球矩形區塊
rect.center = (320,240) #球起始位置
x, y = rect.topleft #球左上角坐標
speed = 3 #球運動速度
clock = pg.time.Clock() #建立時間元件
#關閉程式的程式碼
running = True
while running:
clock.tick(30) #每秒執行30次
for event in pg.event.get():
if event.type == pg.QUIT:
running = False
x += speed #改變水平位置
rect.center = (x,y) #坐標差異讓它移動
if(rect.left <= 0 or rect.right >= screen.get_width()): #到達左右邊界
speed *= -1 #正負值交換
screen.blit(bg, (0,0))
screen.blit(ball, rect.topleft) #繪製藍球
pg.display.update() #更新視窗
pg.quit()
因為關係到隨機跟反彈角度問題,要記得匯入random跟math模組,拿上方例子在稍微做些修改就可以了:
import pygame as pg, random, math
pg.init()
#設定視窗背景
...(略
#藍球建立
ball = pg.Surface((70,70))
ball.fill((255,255,255))
pg.draw.circle(ball, (0,0,255), (35,35), 35, 0)
rect = ball.get_rect()
rect.center = (random.randint(100,250),random.randint(150,250)) #球隨機起始位置
x, y = rect.topleft #球左上角坐標
direction = random.randint(20,70) #起始角度
radian = math.radians(direction ) #轉為弳度
dx = 5 * math.cos(radian) #球水平運動速度
dy = -5 * math.sin(radian) #球垂直運動速度
clock = pg.time.Clock()
#關閉程式的程式碼
running = True
while running:
clock.tick(30) #每秒執行30次
for event in pg.event.get():
if event.type == pg.QUIT:
running = False
x += dx #改變水平位置
y += dy #改變垂直位置
rect.center = (x,y)
if(rect.left <= 0 or rect.right >= screen.get_width()): #到達左右邊界
dx *= -1 #水平速度變號
elif(rect.top <= 1 or rect.bottom >= screen.get_height()-1): #到達上下邊界
dy *= -1 #垂直速度變號
screen.blit(bg, (0,0))
screen.blit(ball, rect.topleft)
pg.display.update()
pg.quit()
在做遊戲時,一定會有許多元件要重複使用,所以用Sprite能創造多個相同的物件,除了複製多個物件,還可以進行動畫繪製及碰撞偵測等。在明天實作中會派上用場,這裡就大概提一下概念語法:
角色群組名稱 = pygame.sprite.Group()
#加入角色物件
角色群組名稱.add(角色物件)
#繪製到畫布上
角色群組名稱.draw(畫布)
簡易舉例:
#建立角色群組
allsprite = pygame.sprite.Group()
ball1 = Ball(8, 100, 100, 10, (0,0,255)) #建立藍球
allsprite.add(ball1) #加入角色群組
ball2 = Ball(6, 200, 250, 10, (255,0,0)) #建立紅球
allsprite.add(ball2)
ball1.update() #物件更新
ball2.update()
allsprite.draw(screen)
角色物件的碰撞有很多不同形式的偵測,這邊用兩種剛剛講到的Sprite來進行偵測。
偵測變數(布林值) = pygame.sprite.collide_rect(角色物件1,角色物件2)
偵測變數為布林值,True為有發生碰撞,False則是沒有。
偵測變數(布林值) = pygame.sprite.spritecollide(角色物件,角色群組,移除值)
移除值為布林值,True會將碰撞到的角色從群組中刪除,False則是沒有。
def collidebounce(self): #定義碰撞後造成反彈
self.dx *= -1
result = pygame.sprite.collide_rect(ball1,ball2)
if result == True: #假如碰撞到,反彈
ball1.collidebounce()
ball2.collidebounce()
最後一個應用在我實作上的是滑鼠事件,雖然還有個鍵盤事件,但我沒用到也就不多提了XD~
最主要分為以下兩類:
按鈕變數 = pygame.mouse.get_pressed()
if 按鈕變數 [按鈕索引]:
程式碼...
位置變數 = pygame.mouse.get_pos()
完整滑鼠事件例子:
import pygame as pg, random, math
pg.init()
#設定視窗背景
width, height = 640, 480
screen = pg.display.set_mode((width, height))
pg.display.set_caption("Sean's game")
bg = pg.Surface(screen.get_size())
bg = bg.convert()
bg.fill((255,255,255))
#藍球建立
ball = pg.Surface((70,70))
ball.fill((255,255,255))
pg.draw.circle(ball, (0,0,255), (35,35), 35, 0)
rect = ball.get_rect()
rect.center = (320,240)
x, y = rect.topleft
clock = pg.time.Clock()
#關閉程式的程式碼
running = True
playing = False #開始時球不能移動
while running:
clock.tick(30) #每秒執行30次
for event in pg.event.get():
if event.type == pg.QUIT:
running = False
buttons = pg.mouse.get_pressed()
if buttons[0]: #按滑鼠左鍵後球可移動
playing = True
elif buttons[2]: #按滑鼠右鍵後球不能移動
playing = False
if playing == True: #球可移動狀態
mouses = pg.mouse.get_pos() #取得滑鼠坐標
rect.centerx = mouses[0] #移動滑鼠
rect.centery = mouses[1]
screen.blit(bg, (0,0))
screen.blit(ball, rect.topleft)
pg.display.update()
pg.quit()
明天最後一天嘞~來看看我最終成果吧~~