pygame開發滑雪者游戲
一、實驗說明
下述介紹為實驗樓默認環境,如果您使用的是定制環境,請修改成您自己的環境介紹。
1. 環境登錄
無需密碼自動登錄,系統用戶名 shiyanlou,該用戶具備 sudo 的權限,可以執行安裝軟件等管理員操作。
2. 環境介紹
本實驗環境采用帶桌面的Ubuntu Linux環境,實驗中會用到桌面上的程序:
- LX終端(LXTerminal): Linux命令行終端,打開后會進入Bash環境,可以使用Linux命令
- Firefox:瀏覽器,可以用在需要前端界面的課程里,只需要打開環境里寫的HTML/JS頁面即可
- GVim:非常好用的編輯器,最簡單的用法可以參考課程Vim編輯器
3. 環境使用
使用編輯器輸入實驗所需的代碼及文件,使用命令行終端運行所需命令進行操作。
“實驗記錄”頁面可以在“我的主頁”中查看,每次實驗的截圖及筆記,以及有效學習時間(指的是在實驗桌面內操作的時間,如果沒有操作,系統會記錄為發呆時間)。這些都是您在實驗樓學習的真實性證明。
本課程中的所有源碼可以在 Xfce 終端中執行下列命令獲取:
wget http://labfile.oss.aliyuncs.com/courses/826/skierGames.py
二、課程介紹
1. 知識點:
本實驗中將介紹在 Linux 桌面環境下使用 Python 及 pygame 快速開發小游戲的方式。
2. 參考文檔:
http://www.pygame.org/docs/
3. 安裝依賴包
$ sudo apt-get update
$ sudo apt-get install python-pygame
4. 依賴文件
因為我們的游戲包含一些圖片和背景音樂,所以請下載背景音樂和圖片:
wget http://labfile.oss.aliyuncs.com/courses/826/bg_music.tar.gz
wget http://labfile.oss.aliyuncs.com/courses/826/bg_img.tar.gz
然后對其進行解壓
tar zcvf bg_music.tar.gz
tar bg_img.tar.gz
運行方式:將源代碼文件和圖像聲音文件放到一起然后在終端中運行
python skierGames.py
5. 游戲介紹:
主人公就是滑雪者,在滑雪的時候可能會撞上樹,當撞上樹的時候會扣分,地圖中也有小旗子當撞上小旗子的時候會加分 ---很傳統的游戲。
6. 注意事項:
因為實驗樓不提供音頻播放功能,所以在源代碼中將音頻部分注釋了,當您在本機運行的時候可以將代碼中的注釋去掉,從而播放音頻。
三、技術設計
重要的事情說三遍:
當您在學習Pygame模塊的時候有不懂的要參考 Pygame的文檔
http://www.pygame.org/docs/
×3
1. 角色設計
class SkierClass(pygame.sprite.Sprite): # 創建滑雪者
def __init__(self):
pygame.sprite.Sprite.__init__(self) # 基類的init方法
self.image = pygame.image.load("./bg_img/skier_down.png") # 這個是滑雪者的美照。
self.rect = self.image.get_rect() # 用於獲得Image的矩形大小
self.rect.center = [320, 100] # 指定矩形的中心位置
self.angle = 0
def turn(self, direction): # 滑雪者 轉向函數 其中的direction參數是指定滑雪者移動的方向和程度(點擊兩次右鍵比一次右鍵滑動的幅度要大,一會自己試着運行一下試試)
self.angle = self.angle + direction #滑雪者當前的移動速度
if self.angle < -2: self.angle = -2 # 用於將滑雪者的移動方式固定到這五個方式當中
if self.angle > 2: self.angle = 2
center = self.rect.center
self.image = pygame.image.load(skier_images[self.angle]) #這個時候滑雪者應該有的姿態圖片。
self.rect = self.image.get_rect()
self.rect.center = center
speed = [self.angle, 6 - abs(self.angle) * 2] #滑雪者的速度。
return speed
def move(self, speed): #滑雪者左右移動
self.rect.centerx = self.rect.centerx + speed[0] #滑雪者所在位置
if self.rect.centerx < 20: self.rect.centerx = 20 # 滑雪者所在位置不應該超過的最大最小值。
if self.rect.centerx > 620: self.rect.centerx = 620
該類創建出來滑雪者的形象和其行為(左右滑動和跌倒時候的形態),計算滑雪者不同的運動速度,和左右移動時候的界限(不應該超過界面的范圍)。
2. 創建樹和小旗子
class ObstacleClass(pygame.sprite.Sprite): #創建書和小旗
def __init__(self, image_file, location, type):
pygame.sprite.Sprite.__init__(self)
self.image_file = image_file #image_file可能是樹或者小旗
self.image = pygame.image.load(image_file) #載入當前的圖片
self.location = location
self.rect = self.image.get_rect()
self.rect.center = location
self.type = type
self.passed = False
def scroll(self, terrainPos): #場景上滾,造成下滑假象。
self.rect.centery = self.location[1] - terrainPos
該類創建出來 樹或者小旗子並且造成場景運動的鏡像。
3. 樹和小旗的隨機位置
def create_map(start, end): # 創建一個窗口,包含隨機的樹和小旗
obstacles = pygame.sprite.Group() # 創建獨立運動的組織
locations = []
gates = pygame.sprite.Group()
for i in range(10):
row = random.randint(start, end) #獲得隨機數在 start-end之間
col = random.randint(0, 9)
location = [col * 64 + 20, row * 64 + 20] # 確定所在位置
if not (location in locations): # 如果上面定義的物體不在已經確定屬性(位置等參數)的物體里面。
locations.append(location)
type = random.choice(["tree", "flag"])#隨機選擇是樹還是小旗
if type == "tree": img = "./bg_img/skier_tree.png" #選擇相應的圖片
elif type == "flag": img = "./bg_img/skier_flag.png"
obstacle = ObstacleClass(img, location, type) #將上面的形成的物體添加到游戲
obstacles.add(obstacle)
return obstacles
用於創建窗口,並且隨機生成樹和小旗子在隨機位置。並且將相應圖片放到隨機的位置。
4. 繪制屏幕背景並進行圖像的更新
代碼很簡單,見下方:
def animate(): # 如果發生移動就重新繪制屏幕
screen.fill([255, 255, 255]) #指定背景顏色 (RGB)
pygame.display.update(obstacles.draw(screen))#這個函數就pygame.display.flip的優化版本。它只允許屏幕的一部分更新,而不是整個區域。如果沒有參數傳遞它更新整個表面積就像pygame.display.flip()一樣。
screen.blit(skier.image, skier.rect)# 用於繪制位圖 在屏幕的skier.rect位置繪制skier.image
screen.blit(score_text, [10, 10])
pygame.display.flip()
四、程序邏輯:
首先我們應該初始化Pygame模塊和聲音播放模塊(因為實驗樓不提供音頻支持,所以將音頻部分代碼注釋掉了,在本機運行的時候請去掉注釋。)。
然后我們初始化游戲窗口,載入時間監聽模塊。隨機生成樹和小旗子
然后開始運行游戲進行無限循環,設置游戲的更新幀率,使用鍵盤監控左右按鍵,設置滑雪者的運動軌跡。隨機生成樹和小旗子然后檢測 是否撞到樹和小旗子然后進行相應的操作
pygame.init() #初始化pygame的所有模塊
#pygame.mixer.init() # 初始化混音部分 進行聲音的加載和播放---播放音頻之用
#pygame.mixer.music.load("./bg_music/bg_music.mp3") # 將會加載這一個音樂的文件名並且准備播放!
#pygame.mixer.music.set_volume(0.3)#設置音樂 的音量參數之在 0-1之間
#pygame.mixer.music.play(-1) #這將播放載入的音樂流。如果音樂已經播放,它就會重新啟動。其中的參數時控制音樂播放的次數。如果是-1的話就是無限重復播放。
screen = pygame.display.set_mode([640,640])# 用於初始化窗口,其中的參數就是分辨率
clock = pygame.time.Clock()# 載入監聽時間的模塊 clock在下面還可以看到 clock.tick等方法
skier = SkierClass() # 初始化SkierClass對象
speed = [0, 6]
map_position = 0
points = 0
map0 = create_map(20, 29)
map1 = create_map(10, 19)
activeMap = 0
obstacles = updateObstacleGroup(map0, map1)
font = pygame.font.Font(None, 50)
while True:
clock.tick(30) # 每秒更新30次圖形 ---這就是幀率。
for event in pygame.event.get(): # 檢查按鍵或者窗口是否關閉
if event.type == pygame.QUIT: sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
speed = skier.turn(-1)
elif event.key == pygame.K_RIGHT:
speed = skier.turn(1)
skier.move(speed) # 移動滑雪者
map_position += speed[1] # 滾動場景
if map_position >=640 and activeMap == 0: # 從場景的一個窗口切換到下一個窗口
activeMap = 1
map0 = create_map(20, 29)
obstacles = updateObstacleGroup(map0, map1)
if map_position >=1280 and activeMap == 1:
activeMap = 0
for ob in map0:
ob.location[1] = ob.location[1] - 1280
map_position = map_position - 1280
map1 = create_map(10, 19)
obstacles = updateObstacleGroup(map0, map1)
for obstacle in obstacles:
obstacle.scroll(map_position)
hit = pygame.sprite.spritecollide(skier, obstacles, False) # 檢查是否碰到樹或者小旗。
if hit:
if hit[0].type == "tree" and not hit[0].passed:# 如果撞到的是樹的話
points = points - 100
skier.image = pygame.image.load("./bg_img/skier_crash.png")
animate()
pygame.time.delay(1000) # 游戲暫停 1秒。
skier.image = pygame.image.load("./bg_img/skier_down.png")
skier.angle = 0
speed = [0, 6]
hit[0].passed = True
elif hit[0].type == "flag" and not hit[0].passed:
points += 10
obstacles.remove(hit[0])
#顯示得分
score_text = font.render("Score: " +str(points), 1, (0, 0, 0))
animate()
五、完整代碼參考
import pygame, sys, random
skier_images = ["./bg_img/skier_down.png", "./bg_img/skier_right1.png", "./bg_img/skier_right2.png",
"./bg_img/skier_left2.png", "./bg_img/skier_left1.png"] # 將可能用到的圖片列表化
class SkierClass(pygame.sprite.Sprite): # 創建滑雪者
def __init__(self):
pygame.sprite.Sprite.__init__(self) # 基類的init方法
self.image = pygame.image.load("./bg_img/skier_down.png") # 這個是滑雪者的美照。
self.rect = self.image.get_rect() # 用於獲得Image的矩形大小
self.rect.center = [320, 100] # 指定矩形的中心位置
self.angle = 0
def turn(self, direction): # 滑雪者 轉向函數 其中的direction參數是指定滑雪者移動的方向和程度(點擊兩次右鍵比一次右鍵滑動的幅度要大,一會自己試着運行一下試試。)
self.angle = self.angle + direction #滑雪者當前的移動速度
if self.angle < -2: self.angle = -2 # 用於將滑雪者的移動方式固定到這五個方式當中
if self.angle > 2: self.angle = 2
center = self.rect.center
self.image = pygame.image.load(skier_images[self.angle]) #這個時候滑雪者應該有的姿態圖片。
self.rect = self.image.get_rect()
self.rect.center = center
speed = [self.angle, 6 - abs(self.angle) * 2] #滑雪者的速度。
return speed
def move(self, speed): #滑雪者左右移動
self.rect.centerx = self.rect.centerx + speed[0] #滑雪者所在位置
if self.rect.centerx < 20: self.rect.centerx = 20 # 滑雪者所在位置不應該超過的最大最小值。
if self.rect.centerx > 620: self.rect.centerx = 620
class ObstacleClass(pygame.sprite.Sprite): #創建書和小旗
def __init__(self, image_file, location, type):
pygame.sprite.Sprite.__init__(self)
self.image_file = image_file #image_file可能是樹或者小旗
self.image = pygame.image.load(image_file) #載入當前的圖片
self.location = location
self.rect = self.image.get_rect()
self.rect.center = location
self.type = type
self.passed = False
def scroll(self, terrainPos): #場景上滾,造成下滑假象。
self.rect.centery = self.location[1] - terrainPos
def create_map(start, end): # 創建一個窗口,包含隨機的樹和小旗
obstacles = pygame.sprite.Group() # 創建獨立運動的組織
locations = []
gates = pygame.sprite.Group()
for i in range(10):
row = random.randint(start, end) #獲得隨機數在 start-end之間
col = random.randint(0, 9)
location = [col * 64 + 20, row * 64 + 20] # 確定所在位置
if not (location in locations): # 如果上面定義的物體不在已經確定屬性(位置等參數)的物體里面。
locations.append(location)
type = random.choice(["tree", "flag"])#隨機選擇是樹還是小旗
if type == "tree": img = "./bg_img/skier_tree.png" #選擇相應的圖片
elif type == "flag": img = "./bg_img/skier_flag.png"
obstacle = ObstacleClass(img, location, type) #將上面的形成的物體添加到游戲
obstacles.add(obstacle)
return obstacles
def animate(): # 如果發生移動就重新繪制屏幕
screen.fill([255, 255, 255]) #指定背景顏色 (RGB)
pygame.display.update(obstacles.draw(screen))#這個函數就pygame.display.flip的優化版本。它只允許屏幕的一部分更新,而不是整個區域。如果沒有參數傳遞它更新整個表面積就像pygame.display.flip()一樣。
screen.blit(skier.image, skier.rect)# 用於繪制位圖 在屏幕的skier.rect位置繪制skier.image
screen.blit(score_text, [10, 10])
pygame.display.flip()
def updateObstacleGroup(map0, map1): # 切換到場景的下一屏
obstacles = pygame.sprite.Group()
for ob in map0: obstacles.add(ob)
for ob in map1: obstacles.add(ob)
return obstacles
pygame.init() #初始化pygame的所有模塊
#pygame.mixer.init() # 初始化混音部分 進行聲音的加載和播放---播放音頻之用
#pygame.mixer.music.load("./bg_music/bg_music.mp3") # 將會加載這一個音樂的文件名並且准備播放!
#pygame.mixer.music.set_volume(0.3)#設置音樂 的音量參數之在 0-1之間
#pygame.mixer.music.play(-1) #這將播放載入的音樂流。如果音樂已經播放,它就會重新啟動。其中的參數時控制音樂播放的次數。如果是-1的話就是無限重復播放。
screen = pygame.display.set_mode([640,640])# 用於初始化窗口,其中的參數就是分辨率
clock = pygame.time.Clock()# 載入監聽時間的模塊 clock在下面還可以看到 clock.tick等方法
skier = SkierClass() # 初始化SkierClass對象
speed = [0, 6]
map_position = 0
points = 0
map0 = create_map(20, 29)
map1 = create_map(10, 19)
activeMap = 0
obstacles = updateObstacleGroup(map0, map1)
font = pygame.font.Font(None, 50)
while True:
clock.tick(30) # 每秒更新30次圖形 ---這就是幀率。
for event in pygame.event.get(): # 檢查按鍵或者窗口是否關閉
if event.type == pygame.QUIT: sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
speed = skier.turn(-1)
elif event.key == pygame.K_RIGHT:
speed = skier.turn(1)
skier.move(speed) # 移動滑雪者
map_position += speed[1] # 滾動場景
if map_position >=640 and activeMap == 0: # 從場景的一個窗口切換到下一個窗口
activeMap = 1
map0 = create_map(20, 29)
obstacles = updateObstacleGroup(map0, map1)
if map_position >=1280 and activeMap == 1:
activeMap = 0
for ob in map0:
ob.location[1] = ob.location[1] - 1280
map_position = map_position - 1280
map1 = create_map(10, 19)
obstacles = updateObstacleGroup(map0, map1)
for obstacle in obstacles:
obstacle.scroll(map_position)
hit = pygame.sprite.spritecollide(skier, obstacles, False) # 檢查是否碰到樹或者小旗。
if hit:
if hit[0].type == "tree" and not hit[0].passed:
points = points - 100
skier.image = pygame.image.load("./bg_img/skier_crash.png")
animate()
pygame.time.delay(1000)
skier.image = pygame.image.load("./bg_img/skier_down.png")
skier.angle = 0
speed = [0, 6]
hit[0].passed = True
elif hit[0].type == "flag" and not hit[0].passed:
points += 10
obstacles.remove(hit[0])
#顯示得分
score_text = font.render("Score: " +str(points), 1, (0, 0, 0))
animate()
完整代碼可以從這里獲得:
wget http://labfile.oss.aliyuncs.com/courses/826/skierGames.py