Python游戏开发之魔塔小游戏的实现

作者:Cooci 时间:2022-08-26 16:14:35 

前言

这一期我们继续完善我们的魔塔小游戏。

废话不多说,让我们愉快地开始吧~

开发工具

Python版本: 3.7.4

相关模块:

cpgames模块;

以及一些python自带的模块。

环境搭建

安装Python并添加到环境变量,pip安装需要的相关模块即可。

原理简介

本期我们实现一些之前还没实现的功能,以及做一些功能优化(部分内容为了测试方便,我会把人物设置成无敌状态)。首先,是拾取物品等游戏事件的提示效果,核心代码如下:

'''游戏事件提示'''
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
   # 画框
   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)

效果:

Python游戏开发之魔塔小游戏的实现

'''显示商店'''
def showbuyinterface(self, screen, scenes, shop_type):
   # 购买函数
   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
   # 选项定义
   # --第三层商店
   if self.map_level_pointer == 3 and shop_type == 'buy_from_shop':
       choices_dict = {
           '增加 800 点生命(25 金币)': lambda: buy(self.hero, coins_cost=25, add_life_value=800),
           '增加 4 点攻击(25 金币)': lambda: buy(self.hero, coins_cost=25, add_attack_power=4),
           '增加 4 点防御(25 金币)': lambda: buy(self.hero, coins_cost=25, add_defense_power=4),
           '离开商店': 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 点生命(100 金币)': lambda: buy(self.hero, coins_cost=100, add_life_value=4000),
           '增加 20 点攻击(100 金币)': lambda: buy(self.hero, coins_cost=100, add_attack_power=20),
           '增加 20 点防御(100 金币)': lambda: buy(self.hero, coins_cost=100, add_defense_power=20),
           '离开商店': 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 = {
           '提升一级(100 经验)': lambda: buy(self.hero, experience_cost=100, add_level=1),
           '增加 5 点攻击(30 经验)': lambda: buy(self.hero, experience_cost=30, add_attack_power=5),
           '增加 5 点防御(30 经验)': lambda: buy(self.hero, experience_cost=30, add_defense_power=5),
           '离开商店': 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 = {
           '提升 * (270 经验)': lambda: buy(self.hero, experience_cost=270, add_level=1),
           '增加 17 点攻击(95 经验)': lambda: buy(self.hero, experience_cost=95, add_attack_power=17),
           '增加 17 点防御(95 经验)': lambda: buy(self.hero, experience_cost=95, add_defense_power=17),
           '离开商店': 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 = {
           '购买 1 把黄钥匙(10 金币)': lambda: buy(self.hero, coins_cost=10, add_yellow_keys=1),
           '购买 1 把蓝钥匙(50 金币)': lambda: buy(self.hero, coins_cost=50, add_purple_keys=1),
           '购买 1 把红钥匙(100 金币)': lambda: buy(self.hero, coins_cost=100, add_red_keys=1),
           '离开商店': 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 = {
           '卖出 1 把黄钥匙(7 金币)': lambda: buy(self.hero, coins_cost=-7, add_yellow_keys=-1),
           '卖出 1 把蓝钥匙(35 金币)': lambda: buy(self.hero, coins_cost=-35, add_purple_keys=-1),
           '卖出 1 把红钥匙(70 金币)': lambda: buy(self.hero, coins_cost=-70, add_red_keys=-1),
           '离开商店': 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))
   # 主循环
   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)
       # --按键检测
       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)
       # --对话框
       # ----底色
       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)
       # ----展示选项
       for idx, choice in enumerate(['请选择:'] + 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)

即,商店主要包括三种类型:一种的明面上的商店,用金币进行交易,可以获得生命值、攻击力和防御力的提升;一种是商人,用金币进行交易,可以获得/出售不同颜色的钥匙;还有一种是神秘老人,用经验值进行交易,可以获得等级、攻击力和防御力的提示。效果如下

Python游戏开发之魔塔小游戏的实现

接着,我们来实现一下地图中可以捡到的一些宝物的特效,主要包括风之罗盘、圣光徽、星光神榔和幸运十字架。

其中,风之罗盘用于在已经走过的楼层间进行跳跃,代码实现如下:

'''显示关卡跳转'''
def showjumplevel(self, screen, scenes):
   # 主循环
   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)
       # --按键检测
       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)
       # --对话框
       # ----底色
       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)
       # ----展示选项
       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)

效果:

Python游戏开发之魔塔小游戏的实现

然后是圣光徽,用于查看怪物的基本情况,代码实现如下:

'''显示关卡怪物信息'''
def showforecastlevel(self, screen, scenes):
   # 主循环
   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)
       # --按键检测
       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
       # --对话框
       # ----底色
       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)
       # ----展示选项
       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'名称: {monster[0]}  生命: {monster[1]}  攻击: {monster[2]}  防御: {monster[3]}  金币: {monster[4]}  经验: {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)

效果:

Python游戏开发之魔塔小游戏的实现

然后我们来实现一下幸运十字架,把它交给序章中的仙子,可以将自身的所有能力提升一些(攻击防御和生命值)。

# 定义所有对话
if self.hero.has_cross:
   conversations = [
       ['仙子, 我已经将那个十字架找到了.'],
       ['你做得很好. 那么现在我就开始', '授予你更强的力量! 咪啦哆咪哔...', '好了, 我已经将你现在的能力提升了!', '记住: 如果你没有足够的实力的话,', '不要去第二十一层. 在那一层里,', '你所有宝物的法力都会失去作用.']
   ]
   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)

来源:https://segmentfault.com/a/1190000041384376

标签:Python,魔塔,游戏
0
投稿

猜你喜欢

  • 多按钮共存——don’t make me think

    2010-01-11 20:20:00
  • Laravel中间件的使用详解

    2023-05-27 10:16:40
  • 关于字体的一些思考

    2008-03-03 12:53:00
  • 基于js里调用函数时,函数名带括号和不带括号的区别

    2023-08-24 05:05:41
  • AJAX的jQuery实现入门(一)

    2008-05-01 12:55:00
  • python抓取某汽车网数据解析html存入excel示例

    2023-11-02 16:46:35
  • SQL Server 2008中有关XML的新功能

    2008-06-04 12:57:00
  • python使用正则表达式提取网页URL的方法

    2023-10-09 16:27:18
  • 基于javascript实现全国省市二级联动下拉选择菜单

    2023-09-14 06:08:52
  • SQLServer 2008助你轻松编写T-SQL存储过程

    2010-12-06 13:38:00
  • 网页常用特效整理:中级篇

    2013-07-15 13:43:32
  • 关于设计规范

    2008-06-02 13:10:00
  • Windows 2003服务器上传文件受限制的解决方法

    2011-02-14 11:29:00
  • Oracle 多行记录合并/连接/聚合字符串的几种方法

    2009-11-17 08:53:00
  • AJAX实战实现级联选择

    2009-08-21 12:27:00
  • 如何创建SQL Server 2000故障转移群集

    2009-02-13 17:18:00
  • asp如何取回已忘记的密码?

    2010-05-13 16:33:00
  • 用ASP实现Google在线文章翻译的功能

    2008-10-11 13:55:00
  • 用CSS实现柱状图(Bar Graph)的方法(三)——复杂柱状图的实现

    2008-05-26 13:36:00
  • 使用eval()解析JSON格式字符串应注意的问题

    2008-04-16 15:46:00
  • asp之家 网络编程 m.aspxhome.com