Python游戲開(kāi)發(fā)之魔塔小游戲的實(shí)現(xiàn)
前言
這一期我們繼續(xù)完善我們的魔塔小游戲。
廢話(huà)不多說(shuō),讓我們愉快地開(kāi)始吧~
開(kāi)發(fā)工具
Python版本: 3.7.4
相關(guān)模塊:
cpgames模塊;
以及一些python自帶的模塊。
環(huán)境搭建
安裝Python并添加到環(huán)境變量,pip安裝需要的相關(guān)模塊即可。
原理簡(jiǎn)介
本期我們實(shí)現(xiàn)一些之前還沒(méi)實(shí)現(xiàn)的功能,以及做一些功能優(yōu)化(部分內(nèi)容為了測(cè)試方便,我會(huì)把人物設(shè)置成無(wú)敵狀態(tài))。首先,是拾取物品等游戲事件的提示效果,核心代碼如下:
'''游戲事件提示'''
def showinfo(self, screen):
if self.obtain_tips is None: return
self.show_obtain_tips_count += 1
if self.show_obtain_tips_count > self.max_obtain_tips_count:
self.show_obtain_tips_count = 0
self.obtain_tips = None
# 畫(huà)框
left, top = self.cfg.BLOCKSIZE // 2, 100
width, height = self.cfg.SCREENSIZE[0] // self.cfg.BLOCKSIZE - 1, 2
pygame.draw.rect(screen, (199, 97, 20), (left - 4, top - 4, self.cfg.BLOCKSIZE * width + 8, self.cfg.BLOCKSIZE * height + 8), 7)
for col in range(width):
for row in range(height):
image = self.resource_loader.images['mapelements']['0'][0]
image = pygame.transform.scale(image, (self.cfg.BLOCKSIZE, self.cfg.BLOCKSIZE))
screen.blit(image, (left + col * self.cfg.BLOCKSIZE, top + row * self.cfg.BLOCKSIZE))
# 文字
if isinstance(self.obtain_tips, list):
assert len(self.obtain_tips) == 2
font = pygame.font.Font(self.fontpath, 30)
font_render1 = font.render(self.obtain_tips[0], True, (255, 255, 255))
font_render2 = font.render(self.obtain_tips[1], True, (255, 255, 255))
rect1 = font_render1.get_rect()
rect2 = font_render2.get_rect()
rect1.midtop = left + width * self.cfg.BLOCKSIZE // 2, top + 10
rect2.midtop = left + width * self.cfg.BLOCKSIZE // 2, top + 10 + self.blocksize
screen.blit(font_render1, rect1)
screen.blit(font_render2, rect2)
else:
font = pygame.font.Font(self.fontpath, 40)
font_render = font.render(self.obtain_tips, True, (255, 255, 255))
rect = font_render.get_rect()
rect.midtop = left + width * self.cfg.BLOCKSIZE // 2, top + height * self.cfg.BLOCKSIZE // 2 - 20
screen.blit(font_render, rect)效果:

'''顯示商店'''
def showbuyinterface(self, screen, scenes, shop_type):
# 購(gòu)買(mǎi)函數(shù)
def buy(hero, coins_cost=0, experience_cost=0, add_life_value=0, add_attack_power=0, add_defense_power=0, add_level=0, add_yellow_keys=0, add_purple_keys=0, add_red_keys=0):
if hero.num_coins < coins_cost: return
if hero.experience < experience_cost: return
if add_yellow_keys < 0 and hero.num_yellow_keys < 1: return
if add_purple_keys < 0 and hero.num_purple_keys < 1: return
if add_red_keys < 0 and hero.num_red_keys < 1: return
hero.num_coins -= coins_cost
hero.experience -= experience_cost
hero.life_value += add_life_value + 1000 * add_level
hero.attack_power += add_attack_power + 7 * add_level
hero.defense_power += add_defense_power + 7 * add_level
hero.level += add_level
hero.num_yellow_keys += add_yellow_keys
hero.num_purple_keys += add_purple_keys
hero.num_red_keys += add_red_keys
# 選項(xiàng)定義
# --第三層商店
if self.map_level_pointer == 3 and shop_type == 'buy_from_shop':
choices_dict = {
'增加 800 點(diǎn)生命(25 金幣)': lambda: buy(self.hero, coins_cost=25, add_life_value=800),
'增加 4 點(diǎn)攻擊(25 金幣)': lambda: buy(self.hero, coins_cost=25, add_attack_power=4),
'增加 4 點(diǎn)防御(25 金幣)': lambda: buy(self.hero, coins_cost=25, add_defense_power=4),
'離開(kāi)商店': lambda: buy(self.hero),
}
id_image = self.resource_loader.images['mapelements']['22'][0]
# --第十一層商店
elif self.map_level_pointer == 11 and shop_type == 'buy_from_shop':
choices_dict = {
'增加 4000 點(diǎn)生命(100 金幣)': lambda: buy(self.hero, coins_cost=100, add_life_value=4000),
'增加 20 點(diǎn)攻擊(100 金幣)': lambda: buy(self.hero, coins_cost=100, add_attack_power=20),
'增加 20 點(diǎn)防御(100 金幣)': lambda: buy(self.hero, coins_cost=100, add_defense_power=20),
'離開(kāi)商店': lambda: buy(self.hero),
}
id_image = self.resource_loader.images['mapelements']['22'][0]
# --第五層神秘老人
elif self.map_level_pointer == 5 and shop_type == 'buy_from_oldman':
choices_dict = {
'提升一級(jí)(100 經(jīng)驗(yàn))': lambda: buy(self.hero, experience_cost=100, add_level=1),
'增加 5 點(diǎn)攻擊(30 經(jīng)驗(yàn))': lambda: buy(self.hero, experience_cost=30, add_attack_power=5),
'增加 5 點(diǎn)防御(30 經(jīng)驗(yàn))': lambda: buy(self.hero, experience_cost=30, add_defense_power=5),
'離開(kāi)商店': lambda: buy(self.hero),
}
id_image = self.resource_loader.images['mapelements']['26'][0]
# --第十三層神秘老人
elif self.map_level_pointer == 13 and shop_type == 'buy_from_oldman':
choices_dict = {
'提升三級(jí)(270 經(jīng)驗(yàn))': lambda: buy(self.hero, experience_cost=270, add_level=1),
'增加 17 點(diǎn)攻擊(95 經(jīng)驗(yàn))': lambda: buy(self.hero, experience_cost=95, add_attack_power=17),
'增加 17 點(diǎn)防御(95 經(jīng)驗(yàn))': lambda: buy(self.hero, experience_cost=95, add_defense_power=17),
'離開(kāi)商店': lambda: buy(self.hero),
}
id_image = self.resource_loader.images['mapelements']['26'][0]
# --第五層商人
elif self.map_level_pointer == 5 and shop_type == 'buy_from_businessman':
choices_dict = {
'購(gòu)買(mǎi) 1 把黃鑰匙(10 金幣)': lambda: buy(self.hero, coins_cost=10, add_yellow_keys=1),
'購(gòu)買(mǎi) 1 把藍(lán)鑰匙(50 金幣)': lambda: buy(self.hero, coins_cost=50, add_purple_keys=1),
'購(gòu)買(mǎi) 1 把紅鑰匙(100 金幣)': lambda: buy(self.hero, coins_cost=100, add_red_keys=1),
'離開(kāi)商店': lambda: buy(self.hero),
}
id_image = self.resource_loader.images['mapelements']['27'][0]
# --第十二層商人
elif self.map_level_pointer == 12 and shop_type == 'buy_from_businessman':
choices_dict = {
'賣(mài)出 1 把黃鑰匙(7 金幣)': lambda: buy(self.hero, coins_cost=-7, add_yellow_keys=-1),
'賣(mài)出 1 把藍(lán)鑰匙(35 金幣)': lambda: buy(self.hero, coins_cost=-35, add_purple_keys=-1),
'賣(mài)出 1 把紅鑰匙(70 金幣)': lambda: buy(self.hero, coins_cost=-70, add_red_keys=-1),
'離開(kāi)商店': lambda: buy(self.hero),
}
id_image = self.resource_loader.images['mapelements']['27'][0]
id_image = pygame.transform.scale(id_image, (self.cfg.BLOCKSIZE, self.cfg.BLOCKSIZE))
# 主循環(huán)
clock, selected_idx = pygame.time.Clock(), 1
font = pygame.font.Font(self.cfg.FONT_PATHS_NOPRELOAD_DICT['font_cn'], 20)
while True:
screen.fill((0, 0, 0))
screen.blit(self.background_images['gamebg'], (0, 0))
self.map_parser.draw(screen)
for scene in scenes:
screen.blit(scene[0], scene[1])
self.hero.draw(screen)
# --按鍵檢測(cè)
for event in pygame.event.get():
if event.type == pygame.QUIT:
QuitGame()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
list(choices_dict.values())[selected_idx-1]()
if selected_idx == 4: return
elif event.key == pygame.K_w or event.key == pygame.K_UP:
selected_idx = max(selected_idx - 1, 1)
elif event.key == pygame.K_s or event.key == pygame.K_DOWN:
selected_idx = min(selected_idx + 1, 4)
# --對(duì)話(huà)框
# ----底色
width, height = 8, 3
left, bottom = self.hero.rect.left + self.hero.rect.width // 2 - width // 2 * self.cfg.BLOCKSIZE, self.hero.rect.bottom
for col in range(width):
for row in range(height):
image = self.resource_loader.images['mapelements']['0'][0]
image = pygame.transform.scale(image, (self.cfg.BLOCKSIZE, self.cfg.BLOCKSIZE))
screen.blit(image, (left + col * self.cfg.BLOCKSIZE, bottom + row * self.cfg.BLOCKSIZE))
# ----邊框
pygame.draw.rect(screen, (199, 97, 20), (left - 4, bottom - 4, self.cfg.BLOCKSIZE * width + 8, self.cfg.BLOCKSIZE * height + 8), 7)
# ----展示選項(xiàng)
for idx, choice in enumerate(['請(qǐng)選擇:'] + list(choices_dict.keys())):
if selected_idx == idx and idx > 0:
choice = '?' + choice
font_render = font.render(choice, True, (255, 0, 0))
elif idx > 0:
choice = ' ' + choice
font_render = font.render(choice, True, (255, 255, 255))
else:
font_render = font.render(choice, True, (255, 255, 255))
rect = font_render.get_rect()
rect.left, rect.top = left + self.cfg.BLOCKSIZE + 20, bottom + 10 + idx * 30
screen.blit(font_render, rect)
# ----展示頭像
screen.blit(id_image, (left + 10, bottom + 10))
# --刷新
pygame.display.flip()
clock.tick(self.cfg.FPS)即,商店主要包括三種類(lèi)型:一種的明面上的商店,用金幣進(jìn)行交易,可以獲得生命值、攻擊力和防御力的提升;一種是商人,用金幣進(jìn)行交易,可以獲得/出售不同顏色的鑰匙;還有一種是神秘老人,用經(jīng)驗(yàn)值進(jìn)行交易,可以獲得等級(jí)、攻擊力和防御力的提示。效果如下

接著,我們來(lái)實(shí)現(xiàn)一下地圖中可以撿到的一些寶物的特效,主要包括風(fēng)之羅盤(pán)、圣光徽、星光神榔和幸運(yùn)十字架。
其中,風(fēng)之羅盤(pán)用于在已經(jīng)走過(guò)的樓層間進(jìn)行跳躍,代碼實(shí)現(xiàn)如下:
'''顯示關(guān)卡跳轉(zhuǎn)'''
def showjumplevel(self, screen, scenes):
# 主循環(huán)
clock, selected_level = pygame.time.Clock(), 1
font = pygame.font.Font(self.cfg.FONT_PATHS_NOPRELOAD_DICT['font_cn'], 20)
while True:
screen.fill((0, 0, 0))
screen.blit(self.background_images['gamebg'], (0, 0))
self.map_parser.draw(screen)
for scene in scenes:
screen.blit(scene[0], scene[1])
self.hero.draw(screen)
# --按鍵檢測(cè)
for event in pygame.event.get():
if event.type == pygame.QUIT:
QuitGame()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
return selected_level
elif event.key == pygame.K_w or event.key == pygame.K_UP:
selected_level = max(selected_level - 1, 0)
elif event.key == pygame.K_s or event.key == pygame.K_DOWN:
selected_level = min(selected_level + 1, self.max_map_level_pointer)
# --對(duì)話(huà)框
# ----底色
width, height = 11, 4
left, top = self.cfg.SCREENSIZE[0] // 2 - width // 2 * self.cfg.BLOCKSIZE, self.cfg.SCREENSIZE[1] // 2 - height * self.cfg.BLOCKSIZE
for col in range(width):
for row in range(height):
image = self.resource_loader.images['mapelements']['0'][0]
image = pygame.transform.scale(image, (self.cfg.BLOCKSIZE, self.cfg.BLOCKSIZE))
screen.blit(image, (left + col * self.cfg.BLOCKSIZE, top + row * self.cfg.BLOCKSIZE))
# ----邊框
pygame.draw.rect(screen, (199, 97, 20), (left - 4, top - 4, self.cfg.BLOCKSIZE * width + 8, self.cfg.BLOCKSIZE * height + 8), 7)
# ----展示選項(xiàng)
for idx in list(range(self.max_map_level_pointer+1)):
if selected_level == idx:
text = f'?第 {idx} 層'
font_render = font.render(text, True, (255, 0, 0))
else:
text = f' 第 {idx} 層'
font_render = font.render(text, True, (255, 255, 255))
rect = font_render.get_rect()
rect.left, rect.top = left + 20 + idx // 6 * self.cfg.BLOCKSIZE * 2, top + 20 + (idx % 6) * 30
screen.blit(font_render, rect)
# --刷新
pygame.display.flip()
clock.tick(self.cfg.FPS)效果:

然后是圣光徽,用于查看怪物的基本情況,代碼實(shí)現(xiàn)如下:
'''顯示關(guān)卡怪物信息'''
def showforecastlevel(self, screen, scenes):
# 主循環(huán)
clock = pygame.time.Clock()
font = pygame.font.Font(self.cfg.FONT_PATHS_NOPRELOAD_DICT['font_cn'], 20)
monsters = self.map_parser.getallmonsters()
if len(monsters) < 1: return
monsters_show_pointer, max_monsters_show_pointer = 1, round(len(monsters) / 4)
show_tip_text, show_tip_text_count, max_show_tip_text_count = True, 1, 15
return_flag = False
while True:
screen.fill((0, 0, 0))
screen.blit(self.background_images['gamebg'], (0, 0))
self.map_parser.draw(screen)
for scene in scenes:
screen.blit(scene[0], scene[1])
self.hero.draw(screen)
# --按鍵檢測(cè)
for event in pygame.event.get():
if event.type == pygame.QUIT:
QuitGame()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_l:
return_flag = True
elif event.key == pygame.K_SPACE:
monsters_show_pointer = monsters_show_pointer + 1
if monsters_show_pointer > max_monsters_show_pointer: monsters_show_pointer = 1
elif event.type == pygame.KEYUP:
if event.key == pygame.K_l and return_flag:
return
# --對(duì)話(huà)框
# ----底色
width, height = 14, 5
left, top = self.cfg.SCREENSIZE[0] // 2 - width // 2 * self.cfg.BLOCKSIZE, self.cfg.SCREENSIZE[1] // 2 - height * self.cfg.BLOCKSIZE
for col in range(width):
for row in range(height):
image = self.resource_loader.images['mapelements']['0'][0]
image = pygame.transform.scale(image, (self.cfg.BLOCKSIZE, self.cfg.BLOCKSIZE))
screen.blit(image, (left + col * self.cfg.BLOCKSIZE, top + row * self.cfg.BLOCKSIZE))
# ----邊框
pygame.draw.rect(screen, (199, 97, 20), (left - 4, top - 4, self.cfg.BLOCKSIZE * width + 8, self.cfg.BLOCKSIZE * height + 8), 7)
# ----展示選項(xiàng)
for idx, monster in enumerate(monsters[(monsters_show_pointer-1)*4: monsters_show_pointer*4]):
id_image = self.resource_loader.images['mapelements'][monster[6]][0]
id_image = pygame.transform.scale(id_image, (self.cfg.BLOCKSIZE - 10, self.cfg.BLOCKSIZE - 10))
screen.blit(id_image, (left + 10, top + 20 + idx * self.cfg.BLOCKSIZE))
text = f'名稱(chēng): {monster[0]} 生命: {monster[1]} 攻擊: {monster[2]} 防御: {monster[3]} 金幣: {monster[4]} 經(jīng)驗(yàn): {monster[5]} 損失: {self.hero.winmonster(monster)[1]}'
font_render = font.render(text, True, (255, 255, 255))
rect = font_render.get_rect()
rect.left, rect.top = left + 15 + self.cfg.BLOCKSIZE, top + 30 + idx * self.cfg.BLOCKSIZE
screen.blit(font_render, rect)
# ----操作提示
show_tip_text_count += 1
if show_tip_text_count == max_show_tip_text_count:
show_tip_text_count = 1
show_tip_text = not show_tip_text
if show_tip_text:
tip_text = '空格鍵'
font_render = font.render(tip_text, True, (255, 255, 255))
rect.left, rect.bottom = self.cfg.BLOCKSIZE * width + 30, self.cfg.BLOCKSIZE * (height + 1) + 10
screen.blit(font_render, rect)
# --刷新
pygame.display.flip()
clock.tick(self.cfg.FPS)效果:

然后我們來(lái)實(shí)現(xiàn)一下幸運(yùn)十字架,把它交給序章中的仙子,可以將自身的所有能力提升一些(攻擊防御和生命值)。
# 定義所有對(duì)話(huà)
if self.hero.has_cross:
conversations = [
['仙子, 我已經(jīng)將那個(gè)十字架找到了.'],
['你做得很好. 那么現(xiàn)在我就開(kāi)始', '授予你更強(qiáng)的力量! 咪啦哆咪嗶...', '好了, 我已經(jīng)將你現(xiàn)在的能力提升了!', '記住: 如果你沒(méi)有足夠的實(shí)力的話(huà),', '不要去第二十一層. 在那一層里,', '你所有寶物的法力都會(huì)失去作用.']
]
self.hero.has_cross = False
self.hero.life_value = int(self.hero.life_value * 4 / 3)
self.hero.attack_power = int(self.hero.attack_power * 4 / 3)
self.hero.defense_power = int(self.hero.defense_power * 4 / 3)以上就是Python游戲開(kāi)發(fā)之魔塔小游戲的實(shí)現(xiàn)的詳細(xì)內(nèi)容,更多關(guān)于Python魔塔游戲的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
python自動(dòng)化測(cè)試selenium操作下拉列表實(shí)現(xiàn)
這篇文章主要為大家介紹了python自動(dòng)化測(cè)試selenium操作下拉列表實(shí)現(xiàn)方式,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步2021-11-11
Python使用urllib模塊對(duì)URL網(wǎng)址中的中文編碼與解碼實(shí)例詳解
這篇文章主要介紹了Python使用urllib模塊對(duì)URL網(wǎng)址中的中文編碼與解碼(Python使用urllib模塊對(duì)URL編碼與解碼)實(shí)例詳解,需要的朋友可以參考下2020-02-02
python基礎(chǔ)之類(lèi)型轉(zhuǎn)換函數(shù)
這篇文章主要介紹了python類(lèi)型轉(zhuǎn)換函數(shù),實(shí)例分析了Python中返回一個(gè)返回值與多個(gè)返回值的方法,需要的朋友可以參考下2021-10-10
Python3訪(fǎng)問(wèn)并下載網(wǎng)頁(yè)內(nèi)容的方法
這篇文章主要介紹了Python3訪(fǎng)問(wèn)并下載網(wǎng)頁(yè)內(nèi)容的方法,實(shí)例分析了Python頁(yè)面抓取及寫(xiě)入文件的實(shí)現(xiàn)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-07-07
python實(shí)現(xiàn)文件+參數(shù)發(fā)送request的實(shí)例代碼
這篇文章主要介紹了python實(shí)現(xiàn)文件+參數(shù)發(fā)送request的實(shí)例代碼,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-01-01
Python使用異步線(xiàn)程池如何實(shí)現(xiàn)異步TCP服務(wù)器交互
這篇文章主要介紹了Python使用異步線(xiàn)程池如何實(shí)現(xiàn)異步TCP服務(wù)器交互問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-11-11

