1、需求分析
具備功能
-
播放與停止背景音樂(lè)
-
隨機(jī)生成管道與導(dǎo)彈障礙
-
顯示積分
-
跳躍躲避障礙
-
碰撞障礙
2、游戲功能結(jié)構(gòu)
瑪麗冒險(xiǎn)的功能結(jié)構(gòu)主要分為三類(lèi),分別為音效、主窗體以及隨機(jī)出現(xiàn)的障礙物。如下圖
image-20231028213612463
3、游戲業(yè)務(wù)流程
根據(jù)該游戲的需求分析以及功能結(jié)構(gòu)
image-20231028214036292
4、游戲預(yù)覽
image-20231028215603717
5、開(kāi)發(fā)必備
游戲開(kāi)發(fā)運(yùn)行環(huán)境
-
python3.7 以上
-
開(kāi)發(fā)工具 PyCharm
-
Python 內(nèi)置模塊:itertools、random
-
第三方模塊:pygame
文件夾組織結(jié)構(gòu)
瑪麗冒險(xiǎn)游戲的文件夾組織結(jié)構(gòu)主要分為: audio(保存音效文件)和 image (保存圖片)
image-20231028215838389
6、瑪麗冒險(xiǎn)游戲?qū)崿F(xiàn)
6.1、游戲窗體的實(shí)現(xiàn)
在實(shí)現(xiàn)游戲窗體時(shí),首先需要定義窗體的寬度與高度,然后通過(guò) ygame 模塊中的 init0 方法,實(shí)現(xiàn)初始化功能,接下來(lái)需要?jiǎng)?chuàng)建循環(huán),在循環(huán)中通過(guò) pdate0 函數(shù)不斷更新窗體,最后需要判斷用戶是否單擊了關(guān)閉窗體的按鈕,如果單擊了“關(guān)閉”按鈕,將關(guān)閉窗體,否則繼續(xù)循環(huán)顯示窗體
image-20231028220745048
通過(guò) pygame 模塊實(shí)現(xiàn)瑪麗主窗體具體步驟如下
創(chuàng)建文件夾,一個(gè)保存音頻,一個(gè)圖片,創(chuàng)建 marie.py 文件
導(dǎo)入 pygame 庫(kù)與 pygame 中的常用庫(kù),然后定義窗體寬度與高度
import pygame from pygame.locals import * import sys # 設(shè)置游戲窗口的寬度和高度 SCREENWIDTH = 822 SCREENHEIGHT = 199 # 設(shè)置游戲幀率 FPS = 60
創(chuàng)建 mainGame0 方法,在該方法中首先進(jìn)行 pygame 的初始化工作,然后創(chuàng)建時(shí)間對(duì)象用于更新窗體中的畫(huà)面,再創(chuàng)建窗體實(shí)例并設(shè)置窗體的標(biāo)題文字,最后通過(guò)循環(huán)實(shí)現(xiàn)窗體的顯示與刷新。
def mainGame(): score = 0 over = False global SCREEN, FPSCLOCK # 初始化pygame庫(kù) pygame.init() # 初始化時(shí)鐘對(duì)象 FPSCLOCK = pygame.time.Clock() # 創(chuàng)建窗口對(duì)象 SCREEN = pygame.display.set_mode((SCREENWIDTH, SCREENHEIGHT)) # 設(shè)置窗口標(biāo)題 pygame.display.set_caption("瑪麗冒險(xiǎn)") while True: # 處理游戲事件 for event in pygame.event.get(): if event.type == QUIT: pygame.quit() sys.exit() # 更新窗口內(nèi)容 pygame.display.update() # 控制幀率 FPSCLOCK.tick(FPS) if __name__ == "__main__": mainGame()
6.2、地圖加載
image-20231028221849551
創(chuàng)建一個(gè)名稱(chēng)為 MyMap 的滾動(dòng)地圖類(lèi),然后在該類(lèi)的初始化方法中加載背景圖片和定義 X 與 Y 的坐標(biāo)
class MyMap(): def __init__(self, x, y): self.bg = pygame.image.load("image/bg.png").convert_alpha() self.x = x self.y = y
在 MyMap 類(lèi)中創(chuàng)建 map _rolling0 方法,在該方法中根據(jù)地圖背景圖片的 X 坐標(biāo)判斷是否移出窗體,如果移出就給圖片設(shè)置一個(gè)新的坐標(biāo)點(diǎn),否則按照每次 5 個(gè)像素的跨度向左移動(dòng)
`def map_rolling(self): if self.x < -790: self.x = 800 else: self.x -= 5`
在 MyMap 類(lèi)中創(chuàng)建 map update0 方法,在該方法中實(shí)現(xiàn)地圖無(wú)限滾動(dòng)的效果
`def map_update(self): SCREEN.blit(self.bg,(self.x,self.y))`
在 mainGame0 方法中,設(shè)置標(biāo)題文字代碼的下面創(chuàng)建兩個(gè)背景圖片的對(duì)象
`bg1 = MyMap(0,0) bg2 = MyMap(800,0)`
在 mainGame0 方法的循環(huán)中,實(shí)現(xiàn)無(wú)限循環(huán)滾動(dòng)的地圖
`if over == False: bg1.map_update() bg1.map_rolling() bg2.map_update() bg2.map_rolling()`
6.3、瑪麗的跳躍功能
在實(shí)現(xiàn)瑪麗的跳躍功能時(shí),首先需要指定瑪麗的固定坐標(biāo),也就是默認(rèn)顯示在地圖上的固定位置,然后判斷是否按下了鍵盤(pán)中的(空格)鍵,如果按下了就開(kāi)啟瑪麗的跳躍開(kāi)關(guān),讓瑪麗以 5 個(gè)像素的距離向上移動(dòng)。當(dāng)瑪麗到達(dá)窗體頂部的邊緣時(shí),再讓瑪麗以 5 個(gè)像素的距離向下移動(dòng),回到地面后關(guān)閉跳躍的開(kāi)關(guān)?,旣愄S功能的業(yè)務(wù)流程如圖
image-20231028222531648
導(dǎo)入選代工具,創(chuàng)建一個(gè)名稱(chēng)為 Marie 的瑪麗類(lèi),然后在該類(lèi)的初始化方法中,首先定義瑪麗跳躍時(shí)所需要的變量,然后加載瑪麗跑動(dòng)的三張圖片,最后加載瑪麗跳躍時(shí)的音效并設(shè)置瑪麗默認(rèn)顯示的坐標(biāo)位置
from itertools import cycle # 瑪麗類(lèi) class Marie(): def __init__(self): # 初始化角色矩形對(duì)象 self.rect = pygame.Rect(0, 0, 0, 0) # 角色跳躍狀態(tài),默認(rèn)為False self.jumpState = False # 角色跳躍高度 self.jumpHeight = 130 # 角色最低y坐標(biāo) self.lowest_y = 140 # 角色已經(jīng)跳躍的高度 self.jumpValue = 0 # 角色動(dòng)作圖片索引 self.marieIndex = 0 # 產(chǎn)生循環(huán)的角色動(dòng)作圖片索引值生成器 self.marieIndexGen = cycle([0, 1, 2]) # 角色動(dòng)作圖片元組 self.adventure_img = ( pygame.image.load("image/adventure1.png").convert_alpha(), pygame.image.load("image/adventure2.png").convert_alpha(), pygame.image.load("image/adventure3.png").convert_alpha(), ) # 角色跳躍音頻 self.jump_audio = pygame.mixer.Sound("audio/jump.wav") # 設(shè)置角色矩形對(duì)象的大小為第一張動(dòng)作圖片的大小 self.rect.size = self.adventure_img[0].get_size() # 角色初始位置 self.x = 50 self.y = self.lowest_y self.rect.topleft = (self.x, self.y)
在 Marie 類(lèi)中創(chuàng)建 move 方法,在該方法中判斷如果瑪麗的跳躍開(kāi)關(guān)開(kāi)啟時(shí),再判斷瑪麗是否在地面上,如果滿足這兩個(gè)條件瑪麗就以 5 個(gè)像素的距離向上移動(dòng)。當(dāng)瑪麗到達(dá)窗體頂部時(shí)以 5 個(gè)像素的距離向下移動(dòng),當(dāng)瑪麗回到地面后關(guān)閉跳躍開(kāi)關(guān)
`# 瑪麗移動(dòng) def move(self): if self.jumpState: # 如果角色的y坐標(biāo)大于等于最低y坐標(biāo),設(shè)置跳躍值為-5 if self.rect.y >= self.lowest_y: self.jumpValue = -5 # 如果角色的y坐標(biāo)小于等于最低y坐標(biāo)減去跳躍高度,設(shè)置跳躍值為5 if self.rect.y <= self.lowest_y - self.jumpHeight: self.jumpValue = 5 # 修改角色的y坐標(biāo) self.rect.y += self.jumpValue # 如果角色的y坐標(biāo)大于等于最低y坐標(biāo),設(shè)置跳躍狀態(tài)為False if self.rect.y >= self.lowest_y: self.jumpState = False`
在 Marie 類(lèi)中創(chuàng)建 draw marie0 方法,在該方法中首先匹配瑪麗跑步的動(dòng)圖,然后進(jìn)行瑪麗的繪制
`#繪制瑪麗 def draw_marie(self): marieIndex = next(self.marieIndexGen) SCREEN.blit(self.adventure_img[marieIndex],(self.x,self.rect.y))`
在 mainGame()方法中,創(chuàng)建地圖對(duì)象的代碼下面創(chuàng)建瑪麗對(duì)象
`marie = Marie()`
在 mainGame0 方法的 while 循環(huán)中,判斷關(guān)閉窗體的下面判斷是否按下了鍵盤(pán)中的 space>(空格)鍵,如果按下了就開(kāi)啟瑪麗跳躍開(kāi)關(guān)并播放跳躍音效
if event.type == KEYDOWN and event.key == K_SPACE: # 如果瑪麗的y坐標(biāo)大于等于最低y坐標(biāo),播放跳躍音頻,調(diào)用跳躍方法 if marie.rect.y >= marie.lowest_y: marie.jump_audio.play() marie.jump()
在 mainGame0 方法中,繪制地圖的代碼下面實(shí)現(xiàn)瑪麗的移動(dòng)與繪制功能
`marie.move() marie.draw_marie()`
6.4、隨機(jī)出現(xiàn)障礙
在實(shí)現(xiàn)障礙物的出現(xiàn)時(shí),首先需要考慮到障礙物的大小以及障礙物不能相同,如果每次出現(xiàn)的障礙物都是相同的那么該游戲?qū)⑹チ擞螒虻臉?lè)趣。所以需要加載兩個(gè)大小不同的障礙物圖片,然后隨機(jī)抽選并顯示,還需要通過(guò)計(jì)算來(lái)設(shè)置出現(xiàn)一個(gè)障礙并將障礙物顯示在窗體當(dāng)中的時(shí)間間隔
image-20231028223540234
導(dǎo)入隨機(jī)數(shù),創(chuàng)建一個(gè)名稱(chēng)為 Obstacle 的障礙物類(lèi),在該類(lèi)中定義一個(gè)分?jǐn)?shù),然后在初始化方法中加載障礙物圖片、分?jǐn)?shù)圖片以及加分音效。創(chuàng)建 0 至 1 的隨機(jī)數(shù)字,根據(jù)該數(shù)字抽選障礙物是管道還是飛行的導(dǎo)彈,最后根據(jù)圖片的寬、高創(chuàng)建障礙物矩形的大小并設(shè)置障礙物的繪制坐標(biāo)
class Obstacle(): score = 1 # 初始化分?jǐn)?shù)變量為1 move = 5 # 設(shè)置移動(dòng)速度為5 obstacle_y = 150 # 設(shè)置障礙物的y坐標(biāo)為150 def __init__(self): self.rect = pygame.Rect(0,0,0,0) # 創(chuàng)建用于碰撞檢測(cè)的矩形對(duì)象 self.missile = pygame.image.load("image/missile.png").convert_alpha() # 加載導(dǎo)彈圖片 self.pipe = pygame.image.load("image/pipe.png").convert_alpha() # 加載管道圖片 self.numbers = ( # 加載數(shù)字圖片 pygame.image.load("image/0.png").convert_alpha(), pygame.image.load("image/1.png").convert_alpha(), pygame.image.load("image/2.png").convert_alpha(), pygame.image.load("image/3.png").convert_alpha(), pygame.image.load("image/4.png").convert_alpha(), pygame.image.load("image/5.png").convert_alpha(), pygame.image.load("image/6.png").convert_alpha(), pygame.image.load("image/7.png").convert_alpha(), pygame.image.load("image/8.png").convert_alpha(), pygame.image.load("image/9.png").convert_alpha(), ) self.score_audio = pygame.mixer.Sound("audio/score.wav") # 加載得分音效 r = random.randint(0,1) # 生成隨機(jī)數(shù)0或1 if r == 0: # 如果隨機(jī)數(shù)為0,設(shè)置障礙物為導(dǎo)彈,移動(dòng)速度為15,y坐標(biāo)為100 self.image = self.missile self.move = 15 self.obstacle_y = 100 else: # 如果隨機(jī)數(shù)為1,設(shè)置障礙物為管道 self.image = self.pipe # 設(shè)置障礙物的大小和位置 self.rect.size = self.image.get_size() self.width, self.height = self.rect.size self.x = 800 # 設(shè)置障礙物的初始位置為屏幕右側(cè) self.y = self.obstacle_y self.rect.center = (self.x ,self.y)
在 Obstacle 類(lèi)中首先創(chuàng)建 obstacle move0 方法,用于實(shí)現(xiàn)障礙物的移動(dòng),然后創(chuàng)建 drawobstacle()方法用于實(shí)現(xiàn)繪制障礙物
`#障礙物移動(dòng) def obstacle_move(self): self.rect.x -= self.move #繪制障礙物 def draw_obstacle(self): SCREEN.blit(self.image,(self.rect.x, self.rect.y))`
在 mainGame()方法中,創(chuàng)建定義添加障礙物的時(shí)間與障礙物對(duì)象列表(瑪麗對(duì)象的代碼下面)
`addObstackeTimer = 0 list = []`
在 mainGame()方法中繪制計(jì)算障礙物出現(xiàn)的間隔時(shí)間(瑪麗對(duì)象的代碼下面)
if addObstackeTimer >= 100: # 如果生成障礙物的計(jì)時(shí)器達(dá)到100 r = random.randint(0, 50) # 生成一個(gè)0到50之間的隨機(jī)數(shù) if r > 15: # 如果隨機(jī)數(shù)大于15 obstacle = Obstacle() # 創(chuàng)建一個(gè)障礙物對(duì)象 list.append(obstacle) # 將障礙物對(duì)象添加到列表中 addObstackeTimer = 0 # 重置生成障礙物的計(jì)時(shí)器為0
在 mainGame0 方法中計(jì)算循環(huán)遍歷障礙物并進(jìn)行障礙物的繪制(障礙物間隔時(shí)間代碼的下面)
`for i in range(len(list)): list[i].obstacle_move() list[i].draw_obstacle()`
在 mainGame0 方法中更新整個(gè)窗體代碼的上面,增加障礙物時(shí)間
addObstackeTimer += 10
6.5、背景音樂(lè)的播放與停止
創(chuàng)建 Music Button 類(lèi),在該類(lèi)中首先初始化背景音樂(lè)的音效文件與按鈕圖片,然后創(chuàng)建 isselect0 方法用于判斷鼠標(biāo)是否在按鈕范圍內(nèi)
# 背景音樂(lè)按鈕 class Music_Button(): is_open = True # 背景音樂(lè)是否開(kāi)啟的狀態(tài)標(biāo)志 def __init__(self): # 加載開(kāi)啟和關(guān)閉按鈕的圖像資源 self.open_img = pygame.image.load("image/btn_open.png").convert_alpha() self.close_img = pygame.image.load("image/btn_close.png").convert_alpha() # 加載背景音樂(lè)的音頻文件 self.bg_music = pygame.mixer.Sound("audio/bg_music.wav") def is_select(self): # 獲取鼠標(biāo)的位置 point_x, point_y = pygame.mouse.get_pos() # 獲取開(kāi)啟按鈕圖像的寬度和高度 w, h = self.open_img.get_size() # 判斷鼠標(biāo)是否在按鈕范圍內(nèi) in_x = point_x > 20 and point_x < 20 + w in_y = point_y > 20 and point_y < 20 + h return in_x and in_y
mainGame 方法中障礙物對(duì)象列表代碼的下面,創(chuàng)建背景音樂(lè)按鈕對(duì)象,然后設(shè)置按鈕默認(rèn)圖片,最后循環(huán)播放背景音樂(lè)。
`muscic_button = Music_Button() btu_img = muscic_button.open_img muscic_button.bg_music.play(-1)`
在 mainGame0 方法的 while 循環(huán)中,獲取單擊事件代碼的下面實(shí)現(xiàn)單擊按鈕控制背景音樂(lè)的播放與停止功能
if event.type == pygame.MOUSEBUTTONUP: # 判斷是否為鼠標(biāo)按鍵抬起事件 if muscic_button.is_select(): # 判斷鼠標(biāo)是否在背景音樂(lè)按鈕范圍內(nèi) if muscic_button.is_open: # 如果背景音樂(lè)當(dāng)前是開(kāi)啟狀態(tài) btu_img = muscic_button.close_img muscic_button.is_open = False muscic_button.bg_music.stop() else: # 如果背景音樂(lè)當(dāng)前是關(guān)閉狀態(tài) btu_img = muscic_button.open_img muscic_button.is_open = True muscic_button.bg_music.play(-1)
在 mainGame()方法中添加障礙物時(shí)間代碼的下面,繪制背景音樂(lè)按鈕
SCREEN.blit(btu_img, (20, 20))
6.6、碰撞與積分功能實(shí)現(xiàn)
在實(shí)現(xiàn)碰撞與積分時(shí),首先需要判斷瑪麗與障礙物的兩個(gè)矩形圖片是否發(fā)生了碰撞,如果發(fā)生了碰撞就證明該游戲已經(jīng)結(jié)束,否則判斷瑪麗是否躍過(guò)了障礙物,確認(rèn)越過(guò)后進(jìn)行加分操作并將分?jǐn)?shù)顯示在窗體頂部右側(cè)的位置。
image-20231028225019597
在 Obstacle 類(lèi)中,draw obstacle0 方法的下面創(chuàng)建 getScore0 方法用于獲取分?jǐn)?shù)并播放加分音效,然后創(chuàng)建 showScore() 方法用于在窗體頂部右側(cè)的位置顯示分?jǐn)?shù)
def getSocre(self): """ 獲取分?jǐn)?shù)并重置分?jǐn)?shù)為0 """ # 獲取當(dāng)前的分?jǐn)?shù) tmp = self.score # 如果分?jǐn)?shù)為1,播放分?jǐn)?shù)音效 if tmp == 1: self.score_audio.play() # 將分?jǐn)?shù)重置為0 self.score = 0 # 返回原來(lái)的分?jǐn)?shù) return tmp # 顯示分?jǐn)?shù) def showScore(self, score): """ 在游戲界面上顯示分?jǐn)?shù) """ # 將分?jǐn)?shù)轉(zhuǎn)換為一個(gè)數(shù)字列表 self.scoreDigits = [int(x) for x in list(str(score))] # 計(jì)算所有數(shù)字圖像的總寬度 totalWidth = 0 for digit in self.scoreDigits: totalWidth += self.numbers[digit].get_width() # 計(jì)算數(shù)字圖像的起始橫坐標(biāo) Xoffset = (SCREENWIDTH - (totalWidth + 30)) # 遍歷分?jǐn)?shù)的每個(gè)數(shù)字,將對(duì)應(yīng)的數(shù)字圖像繪制到屏幕上 for digit in self.scoreDigits: # 繪制數(shù)字圖像到屏幕上,并更新Xoffset的值 SCREEN.blit(self.numbers[digit], (Xoffset, SCREENHEIGHT * 0.1)) Xoffset += self.numbers[digit].get_width()
在 mainGame()方法的上面最外層創(chuàng)建 game over()方法,在該方法中首先需要加載與播放撞擊的音效,然后獲取窗體的寬度與高度,最后加載游戲結(jié)束的圖片并將該圖片顯示在窗體的中間位置
def game_over(): # 播放碰撞音效 bump_audio = pygame.mixer.Sound("audio/bump.wav") bump_audio.play() # 獲取屏幕的寬度和高度 screen_w = pygame.display.Info().current_w screen_h = pygame.display.Info().current_h # 加載游戲結(jié)束圖片 over_img = pygame.image.load("image/gameover.png").convert_alpha() # 在屏幕上繪制游戲結(jié)束圖片,位置居中顯示在屏幕中央 SCREEN.blit(over_img, ((screen_w - over_img.get_width()) / 2, (screen_h - over_img.get_height()) / 2))
在 mainGame()方法中,繪制障礙物代碼的下面判斷瑪麗與障礙物是否發(fā)生碰撞,如果發(fā)生了碰撞則開(kāi)啟游戲結(jié)束的開(kāi)關(guān),并調(diào)用游戲結(jié)束的方法顯示游戲結(jié)束的圖片,否則判斷瑪麗是否躍過(guò)了障礙物,越過(guò)就進(jìn)行分?jǐn)?shù)的增加并顯示當(dāng)前得分
if pygame.sprite.collide_rect(marie, list[i]): # 瑪麗與物品發(fā)生碰撞 over = True # 游戲結(jié)束標(biāo)志設(shè)為T(mén)rue game_over() # 顯示游戲結(jié)束畫(huà)面 music_button.bg_music.stop() # 停止播放背景音樂(lè) else: if (list[i].rect.x + list[i].rect.width) < marie.rect.x: # 物品已完全移出瑪麗的右側(cè),計(jì)入分?jǐn)?shù) score += list[i].getSocre() list[i].showScore(score)
為了實(shí)現(xiàn)游戲結(jié)束后再次按下鍵盤(pán)上的(空格)鍵時(shí),重新啟動(dòng)游戲。所以需要在 mainGame0 方法中開(kāi)啟瑪麗跳的狀態(tài)代碼的下面判斷游戲結(jié)束的開(kāi)關(guān)是否開(kāi)啟,如果開(kāi)啟將重新調(diào)用 mainGame0)方法重新啟動(dòng)游戲
if over == True: mainGame()
7、結(jié)束
需要源碼留言
點(diǎn)擊下方安全鏈接前往獲取
CSDN大禮包:《Python入門(mén)&進(jìn)階學(xué)習(xí)資源包》免費(fèi)分享文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-837352.html
??Python實(shí)戰(zhàn)案例??
光學(xué)理論是沒(méi)用的,要學(xué)會(huì)跟著一起敲,要?jiǎng)邮謱?shí)操,才能將自己的所學(xué)運(yùn)用到實(shí)際當(dāng)中去,這時(shí)候可以搞點(diǎn)實(shí)戰(zhàn)案例來(lái)學(xué)習(xí)。
??Python書(shū)籍和視頻合集??
觀看零基礎(chǔ)學(xué)習(xí)視頻,看視頻學(xué)習(xí)是最快捷也是最有效果的方式,跟著視頻中老師的思路,從基礎(chǔ)到深入,還是很容易入門(mén)的。
??Python副業(yè)創(chuàng)收路線??
這些資料都是非常不錯(cuò)的,朋友們?nèi)绻行枰禤ython學(xué)習(xí)路線&學(xué)習(xí)資料》,點(diǎn)擊下方安全鏈接前往獲取
CSDN大禮包:《Python入門(mén)&進(jìn)階學(xué)習(xí)資源包》免費(fèi)分享
本文轉(zhuǎn)自網(wǎng)絡(luò),如有侵權(quán),請(qǐng)聯(lián)系刪除。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-837352.html
到了這里,關(guān)于python 實(shí)現(xiàn)超級(jí)瑪麗游戲的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!