Python消消乐,美轮美奂的界面效果

发表于:2021-8-25 09:34  作者:LexSaints   来源:CSDN

字体: | 上一篇 | 下一篇 |我要投稿 | 推荐标签: 软件开发 Python

  效果是这样的 ↓ ↓ ↓
  一、环境要求
  windows系统,python3.6+  pip21+
  开发环境搭建地址
  安装游戏依赖模块
   
  pip install pygame
  二、游戏简介
  消消乐应该大家都玩过,或者看过。这个花里胡哨的小游戏用python的pygame来实现,很简单。今天带大家,用Python来实现一下这个花里胡哨的小游戏。
  三、完整开发流程
  1、项目主结构
  首先,先整理一下项目的主结构,其实看一下主结构,基本就清晰了。
  modules:相关定义的Python类位置
  ——game.py:主模块
   
  res:存放引用到的图片、音频等等
  ——audios:音频资源
  ——imgs:图片资源
  ——fonts:字体
   
  cfg.py:为主配置文件
   
  xxls.py:主程序文件
   
  requirements.txt:需要引入的python依赖包
  2、详细配置
  cfg.py
  配置文件中,需要引入os模块,并且配置打开游戏的屏幕大小。
  '''主配置文件'''
  import os
   
  '''屏幕设置大小'''
  SCREENSIZE = (700, 700)
  '''元素尺寸'''
  NUMGRID = 8
  GRIDSIZE = 64
  XMARGIN = (SCREENSIZE[0] - GRIDSIZE * NUMGRID) // 2
  YMARGIN = (SCREENSIZE[1] - GRIDSIZE * NUMGRID) // 2
  '''获取根目录'''
  ROOTDIR = os.getcwd()
  '''FPS'''
  FPS = 30
  3、消消乐所有图形加载
  game.py:第一部分
  把整个项目放在一整个game.py模块下了,把这个代码文件拆开解读一下。
  拼图精灵类:首先通过配置文件中,获取方块精灵的路径,加载到游戏里。
  定义move()移动模块的函数,这个移动比较简单。模块之间,只有相邻的可以相互移动。
  '''
  Function:
      主游戏
  '''
  import sys
  import time
  import random
  import pygame
   
   
  '''拼图精灵类'''
  class pacerSprite(pygame.sprite.Sprite):
      def __init__(self, img_path, size, position, downlen, **kwargs):
          pygame.sprite.Sprite.__init__(self)
          self.image = pygame.image.load(img_path)
          self.image = pygame.transform.smoothscale(self.image, size)
          self.rect = self.image.get_rect()
          self.rect.left, self.rect.top = position
          self.downlen = downlen
          self.target_x = position[0]
          self.target_y = position[1] + downlen
          self.type = img_path.split('/')[-1].split('.')[0]
          self.fixed = False
          self.speed_x = 9
          self.speed_y = 9
          self.direction = 'down'
      def move(self):
                  #下移
          if self.direction == 'down':
              self.rect.top = min(self.target_y, self.rect.top+self.speed_y)
              if self.target_y == self.rect.top:
                  self.fixed = True
                  #上移
          elif self.direction == 'up':
              self.rect.top = max(self.target_y, self.rect.top-self.speed_y)
              if self.target_y == self.rect.top:
                  self.fixed = True
                  #左移
          elif self.direction == 'left':
              self.rect.left = max(self.target_x, self.rect.left-self.speed_x)
              if self.target_x == self.rect.left:
                  self.fixed = True
                  #右移
          elif self.direction == 'right':
              self.rect.left = min(self.target_x, self.rect.left+self.speed_x)
              if self.target_x == self.rect.left:
                  self.fixed = True
      '''获取当前坐标'''
      def getPosition(self):
          return self.rect.left, self.rect.top
      '''设置星星坐标'''
      def setPosition(self, position):
          self.rect.left, self.rect.top = position
  4、随机生成初始布局、相邻消除、自动下落
  game.py  第二部分
  设置游戏主窗口启动的标题,设置启动游戏的主方法。
  '''主游戏类'''
  class pacerGame():
      def __init__(self, screen, sounds, font, pacer_imgs, cfg, **kwargs):
          self.info = 'pacer'
          self.screen = screen
          self.sounds = sounds
          self.font = font
          self.pacer_imgs = pacer_imgs
          self.cfg = cfg
          self.reset()
      '''开始游戏'''
      def start(self):
          clock = pygame.time.Clock()
          # 遍历整个游戏界面更新位置
          overall_moving = True
          # 指定某些对象个体更新位置
          individual_moving = False
          # 定义一些必要的变量
          pacer_selected_xy = None
          pacer_selected_xy2 = None
          swap_again = False
          add_score = 0
          add_score_showtimes = 10
          time_pre = int(time.time())
          # 游戏主循环
          while True:
              for event in pygame.event.get():
                  if event.type == pygame.QUIT or (event.type == pygame.KEYUP and event.key == pygame.K_ESCAPE):
                      pygame.quit()
                      sys.exit()
                  elif event.type == pygame.MOUSEBUTTONUP:
                      if (not overall_moving) and (not individual_moving) and (not add_score):
                          position = pygame.mouse.get_pos()
                          if pacer_selected_xy is None:
                              pacer_selected_xy = self.checkSelected(position)
                          else:
                              pacer_selected_xy2 = self.checkSelected(position)
                              if pacer_selected_xy2:
                                  if self.swappacer(pacer_selected_xy, pacer_selected_xy2):
                                      individual_moving = True
                                      swap_again = False
                                  else:
                                      pacer_selected_xy = None
              if overall_moving:
                  overall_moving = not self.droppacers(0, 0)
                  # 移动一次可能可以拼出多个3连块
                  if not overall_moving:
                      res_match = self.isMatch()
                      add_score = self.removeMatched(res_match)
                      if add_score > 0:
                          overall_moving = True
              if individual_moving:
                  pacer1 = self.getpacerByPos(*pacer_selected_xy)
                  pacer2 = self.getpacerByPos(*pacer_selected_xy2)
                  pacer1.move()
                  pacer2.move()
                  if pacer1.fixed and pacer2.fixed:
                      res_match = self.isMatch()
                      if res_match[0] == 0 and not swap_again:
                          swap_again = True
                          self.swappacer(pacer_selected_xy, pacer_selected_xy2)
                          self.sounds['mismatch'].play()
                      else:
                          add_score = self.removeMatched(res_match)
                          overall_moving = True
                          individual_moving = False
                          pacer_selected_xy = None
                          pacer_selected_xy2 = None
              self.screen.fill((135, 206, 235))
              self.drawGrids()
              self.pacers_group.draw(self.screen)
              if pacer_selected_xy:
                  self.drawBlock(self.getpacerByPos(*pacer_selected_xy).rect)
              if add_score:
                  if add_score_showtimes == 10:
                      random.choice(self.sounds['match']).play()
                  self.drawAddScore(add_score)
                  add_score_showtimes -= 1
                  if add_score_showtimes < 1:
                      add_score_showtimes = 10
                      add_score = 0
              self.remaining_time -= (int(time.time()) - time_pre)
              time_pre = int(time.time())
              self.showRemainingTime()
              self.drawScore()
              if self.remaining_time <= 0:
                  return self.score
              pygame.display.update()
              clock.tick(self.cfg.FPS)
  5、随机初始化消消乐的主图内容。
  game.py  第三部分
  详细注释,都写在代码里了。大家一定要看一遍,不要跑起来,就不管了哦。
      '''初始化'''
      def reset(self):
          # 随机生成各个块(即初始化游戏地图各个元素)
          while True:
              self.all_pacers = []
              self.pacers_group = pygame.sprite.Group()
              for x in range(self.cfg.NUMGRID):
                  self.all_pacers.append([])
                  for y in range(self.cfg.NUMGRID):
                      pacer = pacerSprite(img_path=random.choice(self.pacer_imgs), size=(self.cfg.GRIDSIZE, self.cfg.GRIDSIZE), position=[self.cfg.XMARGIN+x*self.cfg.GRIDSIZE, self.cfg.YMARGIN+y*self.cfg.GRIDSIZE-self.cfg.NUMGRID*self.cfg.GRIDSIZE], downlen=self.cfg.NUMGRID*self.cfg.GRIDSIZE)
                      self.all_pacers[x].append(pacer)
                      self.pacers_group.add(pacer)
              if self.isMatch()[0] == 0:
                  break
          # 得分
          self.score = 0
          # 拼出一个的奖励
          self.reward = 10
          # 时间
          self.remaining_time = 300
      '''显示剩余时间'''
      def showRemainingTime(self):
          remaining_time_render = self.font.render('CountDown: %ss' % str(self.remaining_time), 1, (85, 65, 0))
          rect = remaining_time_render.get_rect()
          rect.left, rect.top = (self.cfg.SCREENSIZE[0]-201, 6)
          self.screen.blit(remaining_time_render, rect)
      '''显示得分'''
      def drawScore(self):
          score_render = self.font.render('SCORE:'+str(self.score), 1, (85, 65, 0))
          rect = score_render.get_rect()
          rect.left, rect.top = (10, 6)
          self.screen.blit(score_render, rect)
      '''显示加分'''
      def drawAddScore(self, add_score):
          score_render = self.font.render('+'+str(add_score), 1, (255, 100, 100))
          rect = score_render.get_rect()
          rect.left, rect.top = (250, 250)
          self.screen.blit(score_render, rect)
      '''生成新的拼图块'''
      def generateNewpacers(self, res_match):
          if res_match[0] == 1:
              start = res_match[2]
              while start > -2:
                  for each in [res_match[1], res_match[1]+1, res_match[1]+2]:
                      pacer = self.getpacerByPos(*[each, start])
                      if start == res_match[2]:
                          self.pacers_group.remove(pacer)
                          self.all_pacers[each][start] = None
                      elif start >= 0:
                          pacer.target_y += self.cfg.GRIDSIZE
                          pacer.fixed = False
                          pacer.direction = 'down'
                          self.all_pacers[each][start+1] = pacer
                      else:
                          pacer = pacerSprite(img_path=random.choice(self.pacer_imgs), size=(self.cfg.GRIDSIZE, self.cfg.GRIDSIZE), position=[self.cfg.XMARGIN+each*self.cfg.GRIDSIZE, self.cfg.YMARGIN-self.cfg.GRIDSIZE], downlen=self.cfg.GRIDSIZE)
                          self.pacers_group.add(pacer)
                          self.all_pacers[each][start+1] = pacer
                  start -= 1
          elif res_match[0] == 2:
              start = res_match[2]
              while start > -4:
                  if start == res_match[2]:
                      for each in range(0, 3):
                          pacer = self.getpacerByPos(*[res_match[1], start+each])
                          self.pacers_group.remove(pacer)
                          self.all_pacers[res_match[1]][start+each] = None
                  elif start >= 0:
                      pacer = self.getpacerByPos(*[res_match[1], start])
                      pacer.target_y += self.cfg.GRIDSIZE * 3
                      pacer.fixed = False
                      pacer.direction = 'down'
                      self.all_pacers[res_match[1]][start+3] = pacer
                  else:
                      pacer = pacerSprite(img_path=random.choice(self.pacer_imgs), size=(self.cfg.GRIDSIZE, self.cfg.GRIDSIZE), position=[self.cfg.XMARGIN+res_match[1]*self.cfg.GRIDSIZE, self.cfg.YMARGIN+start*self.cfg.GRIDSIZE], downlen=self.cfg.GRIDSIZE*3)
                      self.pacers_group.add(pacer)
                      self.all_pacers[res_match[1]][start+3] = pacer
                  start -= 1
      '''移除匹配的pacer'''
      def removeMatched(self, res_match):
          if res_match[0] > 0:
              self.generateNewpacers(res_match)
              self.score += self.reward
              return self.reward
          return 0
      '''游戏界面的网格绘制'''
      def drawGrids(self):
          for x in range(self.cfg.NUMGRID):
              for y in range(self.cfg.NUMGRID):
                  rect = pygame.Rect((self.cfg.XMARGIN+x*self.cfg.GRIDSIZE, self.cfg.YMARGIN+y*self.cfg.GRIDSIZE, self.cfg.GRIDSIZE, self.cfg.GRIDSIZE))
                  self.drawBlock(rect, color=(0, 0, 255), size=1)
      '''画矩形block框'''
      def drawBlock(self, block, color=(255, 0, 255), size=4):
          pygame.draw.rect(self.screen, color, block, size)
      '''下落特效'''
      def droppacers(self, x, y):
          if not self.getpacerByPos(x, y).fixed:
              self.getpacerByPos(x, y).move()
          if x < self.cfg.NUMGRID - 1:
              x += 1
              return self.droppacers(x, y)
          elif y < self.cfg.NUMGRID - 1:
              x = 0
              y += 1
              return self.droppacers(x, y)
          else:
              return self.isFull()
      '''是否每个位置都有拼图块了'''
      def isFull(self):
          for x in range(self.cfg.NUMGRID):
              for y in range(self.cfg.NUMGRID):
                  if not self.getpacerByPos(x, y).fixed:
                      return False
          return True
      '''检查有无拼图块被选中'''
      def checkSelected(self, position):
          for x in range(self.cfg.NUMGRID):
              for y in range(self.cfg.NUMGRID):
                  if self.getpacerByPos(x, y).rect.collidepoint(*position):
                      return [x, y]
          return None
      '''是否有连续一样的三个块(无--返回0/水平--返回1/竖直--返回2)'''
      def isMatch(self):
          for x in range(self.cfg.NUMGRID):
              for y in range(self.cfg.NUMGRID):
                  if x + 2 < self.cfg.NUMGRID:
                      if self.getpacerByPos(x, y).type == self.getpacerByPos(x+1, y).type == self.getpacerByPos(x+2, y).type:
                          return [1, x, y]
                  if y + 2 < self.cfg.NUMGRID:
                      if self.getpacerByPos(x, y).type == self.getpacerByPos(x, y+1).type == self.getpacerByPos(x, y+2).type:
                          return [2, x, y]
          return [0, x, y]
      '''根据坐标获取对应位置的拼图对象'''
      def getpacerByPos(self, x, y):
          return self.all_pacers[x][y]
      '''交换拼图'''
      def swappacer(self, pacer1_pos, pacer2_pos):
          margin = pacer1_pos[0] - pacer2_pos[0] + pacer1_pos[1] - pacer2_pos[1]
          if abs(margin) != 1:
              return False
          pacer1 = self.getpacerByPos(*pacer1_pos)
          pacer2 = self.getpacerByPos(*pacer2_pos)
          if pacer1_pos[0] - pacer2_pos[0] == 1:
              pacer1.direction = 'left'
              pacer2.direction = 'right'
          elif pacer1_pos[0] - pacer2_pos[0] == -1:
              pacer2.direction = 'left'
              pacer1.direction = 'right'
          elif pacer1_pos[1] - pacer2_pos[1] == 1:
              pacer1.direction = 'up'
              pacer2.direction = 'down'
          elif pacer1_pos[1] - pacer2_pos[1] == -1:
              pacer2.direction = 'up'
              pacer1.direction = 'down'
          pacer1.target_x = pacer2.rect.left
          pacer1.target_y = pacer2.rect.top
          pacer1.fixed = False
          pacer2.target_x = pacer1.rect.left
          pacer2.target_y = pacer1.rect.top
          pacer2.fixed = False
          self.all_pacers[pacer2_pos[0]][pacer2_pos[1]] = pacer1
          self.all_pacers[pacer1_pos[0]][pacer1_pos[1]] = pacer2
          return True
      '''信息显示'''
      def __repr__(self):
          return self.info
  6、资源相关
  包括游戏背景音频、图片和字体设计。
  res主资源目录:
  audios:加载游戏背景音乐。
  fonts:记分牌相关字体。
  imgs:这里存放的是我们的各种小星星的图形,是关键了的哦。如果这个加载不了,我们的消消乐 就没有任何图形了。
  7、启动主程序
  xxls.py
  在主程序中,通过读取配置文件,引入项目资源:包括图片、音频等,并从我们的modules里引入所有我们的模块。
  '''
  Function:
      消消乐
  '''
  import os
  import sys
  import cfg
  import pygame
  from modules import *
   
   
  '''主程序'''
  def main():
      pygame.init()
      screen = pygame.display.set_mode(cfg.SCREENSIZE)
      pygame.display.set_caption('hacklex')
      # 加载背景音乐
      pygame.mixer.init()
      pygame.mixer.music.load(os.path.join(cfg.ROOTDIR, "res/audios/bg.mp3"))
      pygame.mixer.music.set_volume(0.6)
      pygame.mixer.music.play(-1)
      # 加载音效
      sounds = {}
      sounds['mismatch'] = pygame.mixer.Sound(os.path.join(cfg.ROOTDIR, 'res/audios/badswap.wav'))
      sounds['match'] = []
      for i in range(6):
          sounds['match'].append(pygame.mixer.Sound(os.path.join(cfg.ROOTDIR, 'res/audios/match%s.wav' % i)))
   
      # 字体显示
      font = pygame.font.Font(os.path.join(cfg.ROOTDIR, 'res/font/font.TTF'), 25)
      # 星星
      pacer_imgs = []
      for i in range(1, 8):
          pacer_imgs.append(os.path.join(cfg.ROOTDIR, 'res/imgs/pacer%s.png' % i))
      # 循环
      game = pacerGame(screen, sounds, font, pacer_imgs, cfg)
      while True:
          score = game.start()
          flag = False
          # 给出选择,玩家选择重玩或者退出
          while True:
              for event in pygame.event.get():
                  if event.type == pygame.QUIT or (event.type == pygame.KEYUP and event.key == pygame.K_ESCAPE):
                      pygame.quit()
                      sys.exit()
                  elif event.type == pygame.KEYUP and event.key == pygame.K_r:
                      flag = True
              if flag:
                  break
              screen.fill((136, 207, 236))
              text0 = 'Final score: %s' % score
              text1 = 'Press <R> to restart the game.'
              text2 = 'Press <Esc> to quit the game.'
              y = 150
              for idx, text in enumerate([text0, text1, text2]):
                  text_render = font.render(text, 1, (85, 65, 0))
                  rect = text_render.get_rect()
                  if idx == 0:
                      rect.left, rect.top = (223, y)
                  elif idx == 1:
                      rect.left, rect.top = (133.5, y)
                  else:
                      rect.left, rect.top = (126.5, y)
                  y += 99
                  screen.blit(text_render, rect)
              pygame.display.update()
          game.reset()
   
   
  '''游戏运行'''
  if __name__ == '__main__':
      main()
  四、如何启动游戏呢?
  1、使用开发工具IDE启动
  如果的开发工具IDE的环境
  例如:VScode、sublimeText、notepad+pycharm什么的配置了Python环境,可以直接在工具中,运行该游戏。
  2、命令行启动
  如下图所示:

      本文内容不用于商业目的,如涉及知识产权问题,请权利人联系51Testing小编(021-64471599-8017),我们将立即处理

评 论

论坛新帖



建议使用IE 6.0以上浏览器,800×600以上分辨率,法律顾问:上海信义律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2022, 沪ICP备05003035号
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪公网安备 31010102002173号

51Testing官方微信

51Testing官方微博

扫一扫 测试知识全知道