前言
接下來幾期,我會手把手帶大家從零開始實現魔塔這個小遊戲(就是上了年紀的小夥伴小時候經常玩的那個圖片
開發工具
Python版本: 3.7.4
相關模塊:
pygame模塊;
以及一些python自帶的模塊。
環境搭建
安裝Python並添加到環境變量,pip安裝需要的相關模塊即可。
原理簡介
首先,我們打開原版遊戲的開始界面,發現是這樣的:
具體而言,我們的思路是先定義一個按鈕類,來模擬原始遊戲中的“開始遊戲”,“遊戲說明”和“離開遊戲”這三個按鍵的功能:
'''按鈕類'''
class Button(pygame.sprite.Sprite):
def __init__(self, text, fontpath, fontsize, position, color_selected=(255, 0, 0), color_default=(255, 255, 255)):
pygame.sprite.Sprite.__init__(self)
self.text = text
self.color_selected = color_selected
self.color_default = color_default
self.font = pygame.font.Font(fontpath, fontsize)
self.font_render = self.font.render(text, True, color_default)
self.rect = self.font_render.get_rect()
self.rect.center = position
'''更新函數: 不斷地更新檢測鼠標是否在按鈕上'''
def update(self):
mouse_pos = pygame.mouse.get_pos()
if self.rect.collidepoint(mouse_pos):
self.font_render = self.font.render(self.text, True, self.color_selected)
else:
self.font_render = self.font.render(self.text, True, self.color_default)
'''綁定到屏幕上'''
def draw(self, screen):
screen.blit(self.font_render, self.rect)
主要的原理就是不斷檢測鼠標是否在對應的按鈕區域,如果在,則對按鈕的顏色做出改變(這裏是變成紅色),否則按鈕使用默認的顏色(這裏是白色),以此來向玩家表明這是可點擊的按鈕。
然後,我們來實例化它三次來添加這三個按鈕到遊戲的開始界面中:
'''遊戲開始界面'''
class StartGameInterface():
def __init__(self, cfg):
self.cfg = cfg
self.play_btn = Button('開始遊戲', cfg.FONTPATH_CN, 50, (cfg.SCREENSIZE[0]//2, cfg.SCREENSIZE[1] - 400))
self.intro_btn = Button('遊戲說明', cfg.FONTPATH_CN, 50, (cfg.SCREENSIZE[0]//2, cfg.SCREENSIZE[1] - 300))
self.quit_btn = Button('離開遊戲', cfg.FONTPATH_CN, 50, (cfg.SCREENSIZE[0]//2, cfg.SCREENSIZE[1] - 200))
'''外部調用'''
def run(self, screen):
# 魔塔
font = pygame.font.Font(self.cfg.FONTPATH_CN, 80)
font_render_cn = font.render('魔塔', True, (255, 255, 255))
rect_cn = font_render_cn.get_rect()
rect_cn.center = self.cfg.SCREENSIZE[0] // 2, 200
# Magic Tower
font = pygame.font.Font(self.cfg.FONTPATH_EN, 80)
font_render_en = font.render('Magic Tower', True, (255, 255, 255))
rect_en = font_render_en.get_rect()
rect_en.center = self.cfg.SCREENSIZE[0] // 2, 350
# (Ver 1.12)
font = pygame.font.Font(self.cfg.FONTPATH_CN, 40)
font_render_version = font.render('(Ver 1.12)', True, (255, 255, 255))
rect_ver = font_render_version.get_rect()
rect_ver.center = self.cfg.SCREENSIZE[0] // 2, 400
clock = pygame.time.Clock()
while True:
screen.fill((0, 0, 0))
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit(0)
elif event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
mouse_pos = pygame.mouse.get_pos()
if self.play_btn.rect.collidepoint(mouse_pos):
return True
elif self.quit_btn.rect.collidepoint(mouse_pos):
pygame.quit()
sys.exit(0)
elif self.intro_btn.rect.collidepoint(mouse_pos):
self.showgameintro(screen)
for btn in [self.intro_btn, self.play_btn, self.quit_btn]:
btn.update()
btn.draw(screen)
for fr, rect in zip([font_render_cn, font_render_en, font_render_version], [rect_cn, rect_en, rect_ver]):
screen.blit(fr, rect)
pygame.display.flip()
clock.tick(self.cfg.FPS)
'''顯示遊戲簡介'''
def showgameintro(self, screen):
font = pygame.font.Font(self.cfg.FONTPATH_CN, 20)
font_renders = [
font.render('魔塔小遊戲.', True, (255, 255, 255)),
font.render('遊戲素材來自: http://www.4399.com/flash/1749_1.htm.', True, (255, 255, 255)),
font.render('遊戲背景故事爲公主被大魔王抓走, 需要勇士前往魔塔將其救出.', True, (255, 255, 255)),
font.render('python工程獅.', True, (255, 255, 255)),
font.render('微信公衆號: python工程獅.', True, (255, 255, 255)),
font.render('版權所有.', True, (255, 255, 255)),
]
rects = [fr.get_rect() for fr in font_renders]
for idx, rect in enumerate(rects):
rect.center = self.cfg.SCREENSIZE[0] // 2, 50 * idx + 100
clock = pygame.time.Clock()
while True:
screen.fill((0, 0, 0))
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit(0)
elif event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
mouse_pos = pygame.mouse.get_pos()
if self.play_btn.rect.collidepoint(mouse_pos):
return True
elif self.quit_btn.rect.collidepoint(mouse_pos):
pygame.quit()
sys.exit(0)
elif self.intro_btn.rect.collidepoint(mouse_pos):
return
for btn in [self.intro_btn, self.play_btn, self.quit_btn]:
btn.update()
btn.draw(screen)
for fr, rect in zip(font_renders, rects):
screen.blit(fr, rect)
pygame.display.flip()
clock.tick(self.cfg.FPS)
其他額外的代碼主要是顯示遊戲的標題等信息,都很簡單,就不詳細討論了,會pygame的小夥伴肯定都能寫出來
接下來,我們來看下游戲開始之後的界面是長什麼樣子的
具體而言,我們可以先在文本文件裏定義遊戲地圖的樣子,類似下圖所示這樣子,其中每個數字代表一種遊戲元素:
遊戲中的圖片素材我也已經收集到了網上找到的別人整理好的遊戲素材:
於是,我們可以寫一個遊戲地圖文件的解析類,就像這樣:
'''遊戲地圖解析類'''
class MapParser():
def __init__(self, blocksize, filepath, element_images, offset=(0, 0), **kwargs):
self.count = 0
self.switch_times = 15
self.image_pointer = 0
self.offset = offset
self.blocksize = blocksize
self.element_images = element_images
self.map_matrix = self.parse(filepath)
'''解析'''
def parse(self, filepath):
map_matrix = []
with open(filepath, 'r') as fp:
for line in fp.readlines():
line = line.strip()
if not line: continue
map_matrix.append([c.strip() for c in line.split(',')])
return map_matrix
'''將遊戲地圖畫到屏幕上'''
def draw(self, screen):
self.count += 1
if self.count == self.switch_times:
self.count = 0
self.image_pointer = int(not self.image_pointer)
for row_idx, row in enumerate(self.map_matrix):
for col_idx, elem in enumerate(row):
position = col_idx * self.blocksize + self.offset[0], row_idx * self.blocksize + self.offset[1]
if elem+'.png' in self.element_images:
image = self.element_images[elem+'.png'][self.image_pointer]
image = pygame.transform.scale(image, (self.blocksize, self.blocksize))
screen.blit(image, position)
其中parse函數其實就是讀取存放遊戲地圖信息的文本文件,然後draw函數其實就是根據讀取的地圖信息,將對應的遊戲元素圖片綁定到地圖上進行顯示。另外,image_pointer,switch_times,count這三個變量是爲了實現原版地圖中場景元素閃爍的效果,就像這樣:
根據這個原理,我們可以輕鬆地畫出魔塔所有層中的原始地圖,定義的遊戲地圖文件如下圖所示:
效果如下圖所示:
ok,總結一下,就是這期主要實現了魔塔遊戲中每一層的初始畫面,本期完整源代碼詳見個人主頁簡介獲取到
文章到這裏就結束了,感謝你的觀看,Python28個小遊戲系列,下篇文章分享魔塔小遊戲呀(2)
爲了感謝讀者們,我想把我最近收藏的一些編程乾貨分享給大家,回饋每一個讀者,希望能幫到你們。
明天我會帶大家進一步復現魔塔這款小遊戲,感興趣的小夥伴可以多多關注一下~