學(xué)習(xí)目標(biāo)
- 強(qiáng)化 面向?qū)ο?程序設(shè)計(jì)
- 體驗(yàn)使用 pygame 模塊進(jìn)行 游戲開發(fā)
安裝 pygame
sudo pip3 install pygame
驗(yàn)證安裝
python3 -m pygame.examples.aliens
1.1硼讽、 游戲的初始化和退出
import pygame
pygame.init()
# 游戲代碼...
pygame.quit()
1.2乏德、 理解游戲中的坐標(biāo)系
- 定義 hero_rect 矩形描述 英雄的位置和大小
- 輸出英雄的 坐標(biāo)原點(diǎn)(x 和 y)
- 輸出英雄的 尺寸(寬度 和 高度)
hero_rect = pygame.Rect(100, 500, 120, 126)
print("坐標(biāo)原點(diǎn) %d %d" % (hero_rect.x, hero_rect.y))
print("英雄大小 %d %d" % (hero_rect.width, hero_rect.height))
# size 屬性會(huì)返回矩形區(qū)域的 (寬, 高) 元組
print("英雄大小 %d %d" % hero_rect.size)
1.3寿酌、 創(chuàng)建游戲主窗口
# 創(chuàng)建游戲主窗口
screen = pygame.display.set_mode((480, 700))
1.4、 簡(jiǎn)單的游戲循環(huán)
# 創(chuàng)建游戲主窗口
screen = pygame.display.set_mode((480, 700))
# 游戲循環(huán)
while True:
pass
2啃沪、 理解 圖像 并實(shí)現(xiàn)圖像繪制
2.1枪孩、繪制背景圖像
# 繪制背景圖像
# 1> 加載圖像
bg = pygame.image.load("./images/background.png")
# 2> 繪制在屏幕
screen.blit(bg, (0, 0))
# 3> 更新顯示
pygame.display.update()
2.2、繪制英雄圖像
# 1> 加載圖像
hero = pygame.image.load("./images/me1.png")
# 2> 繪制在屏幕
screen.blit(hero, (200, 500))
# 3> 更新顯示
pygame.display.update()
可以在 screen 對(duì)象完成 所有 blit 方法之后甚侣,統(tǒng)一調(diào)用一次 display.update 方法明吩,同樣可以在屏幕上 看到最終的繪制結(jié)果
案例調(diào)整
# 繪制背景圖像
# 1> 加載圖像
bg = pygame.image.load("./images/background.png")
# 2> 繪制在屏幕
screen.blit(bg, (0, 0))
# 繪制英雄圖像
# 1> 加載圖像
hero = pygame.image.load("./images/me1.png")
# 2> 繪制在屏幕
screen.blit(hero, (200, 500))
# 3> 更新顯示 - update 方法會(huì)把之前所有繪制的結(jié)果,一次性更新到屏幕窗口上
pygame.display.update()
3. 創(chuàng)建游戲時(shí)鐘對(duì)象
3.1殷费、游戲時(shí)鐘
clock = pygame.time.Clock()
i = 0
# 游戲循環(huán)
while True:
# 設(shè)置屏幕刷新幀率
clock.tick(60)
print(i)
i += 1
3.2印荔、 英雄的簡(jiǎn)單動(dòng)畫實(shí)現(xiàn)
# 4. 定義英雄的初始位置
hero_rect = pygame.Rect(150, 500, 102, 126)
while True:
# 可以指定循環(huán)體內(nèi)部的代碼執(zhí)行的頻率
clock.tick(60)
# 更新英雄位置
hero_rect.y -= 1
# 如果移出屏幕,則將英雄的頂部移動(dòng)到屏幕底部
if hero_rect.y <= 0:
hero_rect.y = 700
# 繪制背景圖片
screen.blit(bg, (0, 0))
# 繪制英雄圖像
screen.blit(hero, hero_rect)
# 更新顯示
pygame.display.update()
注意:
- 英雄向上飛行详羡,當(dāng) 英雄完全從上方飛出屏幕后
- 將飛機(jī)移動(dòng)到屏幕的底部
if hero_rect.bottom <= 0:
hero_rect.y = 700
3.3仍律、 在游戲循環(huán)中 監(jiān)聽 事件
# 游戲循環(huán)
while True:
# 設(shè)置屏幕刷新幀率
clock.tick(60)
# 事件監(jiān)聽
for event in pygame.event.get():
# 判斷用戶是否點(diǎn)擊了關(guān)閉按鈕
if event.type == pygame.QUIT:
print("退出游戲...")
pygame.quit()
# 直接退出系統(tǒng)
exit()
4.1、 精靈 和 精靈組
import pygame
class GameSprite(pygame.sprite.Sprite):
"""游戲精靈基類"""
def __init__(self, image_name, speed=1):
# 調(diào)用父類的初始化方法
super().__init__()
# 加載圖像
self.image = pygame.image.load(image_name)
# 設(shè)置尺寸
self.rect = self.image.get_rect()
# 記錄速度
self.speed = speed
def update(self, *args):
# 默認(rèn)在垂直方向移動(dòng)
self.rect.y += self.speed
4.2实柠、 使用 游戲精靈 和 精靈組 創(chuàng)建敵機(jī)
-
導(dǎo)入 plane_sprites 模塊
from plane_sprites import *
修改初始化部分代碼
# 創(chuàng)建敵機(jī)精靈和精靈組
enemy1 = GameSprite("./images/enemy1.png")
enemy2 = GameSprite("./images/enemy1.png", 2)
enemy2.rect.x = 200
enemy_group = pygame.sprite.Group(enemy1, enemy2)
- 修改游戲循環(huán)部分代碼
# 讓敵機(jī)組調(diào)用 update 和 draw 方法
enemy_group.update()
enemy_group.draw(screen)
# 更新屏幕顯示
pygame.display.update()
5.1水泉、實(shí)現(xiàn)飛機(jī)大戰(zhàn)主游戲類
import pygame
from plane_sprites import *
class PlaneGame(object):
"""飛機(jī)大戰(zhàn)主游戲"""
def __init__(self):
print("游戲初始化")
def start_game(self):
print("開始游戲...")
if __name__ == '__main__':
# 創(chuàng)建游戲?qū)ο? game = PlaneGame()
# 開始游戲
game.start_game()
5.2、 游戲初始化部分
-
完成 init() 代碼如下:
def __init__(self): print("游戲初始化") # 1. 創(chuàng)建游戲的窗口 self.screen = pygame.display.set_mode((480, 700)) # 2. 創(chuàng)建游戲的時(shí)鐘 self.clock = pygame.time.Clock() # 3. 調(diào)用私有方法窒盐,精靈和精靈組的創(chuàng)建 self.__create_sprites() def __create_sprites(self): pass
5.3草则、使用 常量 代替固定的數(shù)值
-
在 plane_sprites.py 中增加常量定義
import pygame # 游戲屏幕大小 SCREEN_RECT = pygame.Rect(0, 0, 480, 700)
-
修改 plane_main.py 中的窗口大小
self.screen = pygame.display.set_mode(SCREEN_RECT.size)
5.4、 游戲循環(huán)部分
-
完成 start_game() 基礎(chǔ)代碼如下:
def start_game(self): """開始游戲""" print("開始游戲...") while True: # 1. 設(shè)置刷新幀率 self.clock.tick(60) # 2. 事件監(jiān)聽 self.__event_handler() # 3. 碰撞檢測(cè) self.__check_collide() # 4. 更新精靈組 self.__update_sprites() # 5. 更新屏幕顯示 pygame.display.update() def __event_handler(self): """事件監(jiān)聽""" for event in pygame.event.get(): if event.type == pygame.QUIT: PlaneGame.__game_over() def __check_collide(self): """碰撞檢測(cè)""" pass def __update_sprites(self): """更新精靈組""" pass @staticmethod def __game_over(): """游戲結(jié)束""" print("游戲結(jié)束") pygame.quit() exit()
5.5蟹漓、準(zhǔn)備游戲精靈組
-
創(chuàng)建精靈組方法
def __create_sprites(self): """創(chuàng)建精靈組""" # 背景組 self.back_group = pygame.sprite.Group() # 敵機(jī)組 self.enemy_group = pygame.sprite.Group() # 英雄組 self.hero_group = pygame.sprite.Group()
-
更新精靈組方法
def __update_sprites(self): """更新精靈組""" for group in [self.back_group, self.enemy_group, self.hero_group]: group.update() group.draw(self.screen)
6.1炕横、 背景精靈的基本實(shí)現(xiàn)
-
在 plane_sprites 新建 Background 繼承自 GameSprite
class Background(GameSprite): """游戲背景精靈""" def update(self): # 1. 調(diào)用父類的方法實(shí)現(xiàn) super().update() # 2. 判斷是否移出屏幕,如果移出屏幕葡粒,將圖像設(shè)置到屏幕的上方 if self.rect.y >= SCREEN_RECT.height: self.rect.y = -self.rect.height
6.2份殿、 在 plane_main.py 中顯示背景精靈
__create_sprites 方法
def __create_sprites(self):
# 創(chuàng)建背景精靈和精靈組
bg1 = Background("./images/background.png")
bg2 = Background("./images/background.png")
bg2.rect.y = -bg2.rect.height
self.back_group = pygame.sprite.Group(bg1, bg2)
__update_sprites 方法
def __update_sprites(self):
self.back_group.update()
self.back_group.draw(self.screen)
6.3、 利用初始化方法嗽交,簡(jiǎn)化背景精靈創(chuàng)建
在 plane_sprites.py 中實(shí)現(xiàn) Background 的 初始化方法
def __init__(self, is_alt=False):
image_name = "./images/background.png"
super().__init__(image_name)
# 判斷是否交替圖片伯铣,如果是,將圖片設(shè)置到屏幕頂部
if is_alt:
self.rect.y = -self.rect.height
-
修改 plane_main 的 __create_sprites 方法
# 創(chuàng)建背景精靈和精靈組 bg1 = Background() bg2 = Background(True) self.back_group = pygame.sprite.Group(bg1, bg2)
7.1轮纫、敵機(jī)出場(chǎng)
- 定義事件
-
在 plane_sprites.py 的頂部定義 事件常量
# 敵機(jī)的定時(shí)器事件常量 CREATE_ENEMY_EVENT = pygame.USEREVENT
-
在 PlaneGame 的 初始化方法 中 創(chuàng)建用戶事件
# 4. 設(shè)置定時(shí)器事件 - 每秒創(chuàng)建一架敵機(jī) pygame.time.set_timer(CREATE_ENEMY_EVENT, 1000)
- 監(jiān)聽定時(shí)器事件
-
在 __event_handler 方法中增加以下代碼:
def __event_handler(self): for event in pygame.event.get(): # 判斷是否退出游戲 if event.type == pygame.QUIT: PlaneGame.__game_over() elif event.type == CREATE_ENEMY_EVENT: print("敵機(jī)出場(chǎng)...")
7.2腔寡、設(shè)計(jì) Enemy 類
class Enemy(GameSprite):
"""敵機(jī)精靈"""
def __init__(self):
# 1. 調(diào)用父類方法,創(chuàng)建敵機(jī)精靈掌唾,并且指定敵機(jī)的圖像
super().__init__("./images/enemy1.png")
# 2. 設(shè)置敵機(jī)的隨機(jī)初始速度
# 3. 設(shè)置敵機(jī)的隨機(jī)初始位置
def update(self):
# 1. 調(diào)用父類方法放前,讓敵機(jī)在垂直方向運(yùn)動(dòng)
super().update()
# 2. 判斷是否飛出屏幕,如果是糯彬,需要將敵機(jī)從精靈組刪除
if self.rect.y >= SCREEN_RECT.height:
print("敵機(jī)飛出屏幕...")
7.3凭语、創(chuàng)建敵機(jī)
-
修改 plane_main 的 __create_sprites 方法
# 敵機(jī)組 self.enemy_group = pygame.sprite.Group()
-
修改 plane_main 的 __update_sprites 方法
self.enemy_group.update() self.enemy_group.draw(self.screen)
-
定時(shí)出現(xiàn)敵機(jī)
elif event.type == CREATE_ENEMY_EVENT: self.enemy_group.add(Enemy())
-
修改 plane_sprites.py 增加 random 的導(dǎo)入
import random
7.4、隨機(jī)速度
def __init__(self):
# 1. 調(diào)用父類方法撩扒,創(chuàng)建敵機(jī)精靈似扔,并且指定敵機(jī)的圖像
super().__init__("./images/enemy1.png")
# 2. 設(shè)置敵機(jī)的隨機(jī)初始速度 1 ~ 3
self.speed = random.randint(1, 3)
# 3. 設(shè)置敵機(jī)的隨機(jī)初始位置
self.rect.bottom = 0
max_x = SCREEN_RECT.width - self.rect.width
self.rect.x = random.randint(0, max_x)
7.5吨些、移出屏幕銷毀敵機(jī)
def update(self):
super().update()
# 判斷敵機(jī)是否移出屏幕
if self.rect.y >= SCREEN_RECT.height:
# 將精靈從所有組中刪除
self.kill()
8.1、準(zhǔn)備英雄類
class Hero(GameSprite):
"""英雄精靈"""
def __init__(self):
super().__init__("./images/me1.png", 0)
# 設(shè)置初始位置
self.rect.centerx = SCREEN_RECT.centerx
self.rect.bottom = SCREEN_RECT.bottom - 120
8.2炒辉、 繪制英雄
-
修改 __create_sprites 方法如下:
# 英雄組 self.hero = Hero() self.hero_group = pygame.sprite.Group(self.hero)
-
修改 __update_sprites 方法如下:
self.hero_group.update() self.hero_group.draw(self.screen)
8.3豪墅、移動(dòng)英雄位置
# 返回所有按鍵的元組,如果某個(gè)鍵被按下黔寇,對(duì)應(yīng)的值會(huì)是1
keys_pressed = pygame.key.get_pressed()
# 判斷是否按下了方向鍵
if keys_pressed[pygame.K_RIGHT]:
print("向右移動(dòng)...")
-
在 Hero 類偶器,重寫 update() 方法,根據(jù)速度水平移動(dòng) 英雄的飛機(jī)
def update(self): # 飛機(jī)水平移動(dòng) self.rect.x += self.speed
-
調(diào)整鍵盤按鍵代碼
# 獲取用戶按鍵 keys_pressed = pygame.key.get_pressed() if keys_pressed[pygame.K_RIGHT]: self.hero.speed = 2 elif keys_pressed[pygame.K_LEFT]: self.hero.speed = -2 else: self.hero.speed = 0
8.4缝裤、控制英雄運(yùn)動(dòng)邊界
def update(self):
# 飛機(jī)水平移動(dòng)
self.rect.x += self.speed
# 判斷屏幕邊界
if self.rect.left < 0:
self.rect.left = 0
if self.rect.right > SCREEN_RECT.right:
self.rect.right = SCREEN_RECT.right
9.1屏轰、發(fā)射子彈
-
在 Hero 中定義 fire 方法
def fire(self): print("發(fā)射子彈...")
-
在 plane_main.py 的頂部定義 發(fā)射子彈 事件常量
# 英雄發(fā)射子彈事件 HERO_FIRE_EVENT = pygame.USEREVENT + 1
-
在 init 方法末尾中添加 發(fā)射子彈 事件
# 每隔 0.5 秒發(fā)射一次子彈 pygame.time.set_timer(HERO_FIRE_EVENT, 500)
-
在 __event_handler 方法中讓英雄發(fā)射子彈
elif event.type == HERO_FIRE_EVENT: self.hero.fire()
9.2、定義子彈類
class Bullet(GameSprite):
"""子彈精靈"""
def __init__(self):
super().__init__("./images/bullet1.png", -2)
def update(self):
super().update()
# 判斷是否超出屏幕憋飞,如果是霎苗,從精靈組刪除
if self.rect.bottom < 0:
self.kill()
9.3、發(fā)射子彈
-
初始化方法
# 創(chuàng)建子彈的精靈組 self.bullets = pygame.sprite.Group()
-
修改 fire() 方法
def fire(self): # 1. 創(chuàng)建子彈精靈 bullet = Bullet() # 2. 設(shè)置精靈的位置 bullet.rect.bottom = self.rect.y - 20 bullet.rect.centerx = self.rect.centerx # 3. 將精靈添加到精靈組 self.bullets.add(bullet)
10榛做、碰撞實(shí)現(xiàn)
def __check_collide(self):
# 1. 子彈摧毀敵機(jī)
pygame.sprite.groupcollide(self.hero.bullets, self.enemy_group, True, True)
# 2. 敵機(jī)撞毀英雄
enemies = pygame.sprite.spritecollide(self.hero, self.enemy_group, True)
# 判斷列表時(shí)候有內(nèi)容
if len(enemies) > 0:
# 讓英雄犧牲
self.hero.kill()
# 結(jié)束游戲
PlaneGame.__game_over()