51Testing软件测试论坛

标题: 美轮美奂的界面效果---Python消消 [打印本页]

作者: lsekfe    时间: 2022-11-2 11:40
标题: 美轮美奂的界面效果---Python消消
一、环境要求

  1. <font size="3">windows系统,python3.6+  pip21+</font>
复制代码


开发环境搭建地址:

  1. <font size="3">安装游戏依赖模块

  2.   pip install pygame</font>
复制代码


二、游戏简介
  消消乐应该大家都玩过,或者看过。这个花里胡哨的小游戏,用python的pygame来实现,很简单。今天带大家,用Python来实现一下这个花里胡哨的小游戏。
  三、完整开发流程
  1、项目主结构
  首先,先整理一下项目的主结构,其实看一下主结构,基本就清晰了。


  1. <font size="3">modules:相关定义的Python类位置

  2.   ——game.py:主模块

  3.   

  4.   res:存放引用到的图片、音频等等

  5.   ——audios:音频资源

  6.   ——imgs:图片资源

  7.   ——fonts:字体

  8.   

  9.   cfg.py:为主配置文件

  10.   

  11.   xxls.py:主程序文件

  12.   

  13.   requirements.txt:需要引入的python依赖包</font>
复制代码


[attach]144562[/attach]

2、详细配置
  cfg.py
  配置文件中,需要引入os模块,并且配置打开游戏的屏幕大小。


  1. <font size="3">'''主配置文件'''

  2.   import os

  3.   

  4.   '''屏幕设置大小'''

  5.   SCREENSIZE = (700, 700)

  6.   '''元素尺寸'''

  7.   NUMGRID = 8

  8.   GRIDSIZE = 64

  9.   XMARGIN = (SCREENSIZE[0] - GRIDSIZE * NUMGRID) // 2

  10.   YMARGIN = (SCREENSIZE[1] - GRIDSIZE * NUMGRID) // 2

  11.   '''获取根目录'''

  12.   ROOTDIR = os.getcwd()

  13.   '''FPS'''

  14.   FPS = 30</font>
复制代码


3、消消乐所有图形加载
  game.py:第一部分
  把整个项目放在一整个game.py模块下了,把这个代码文件拆开解读一下。
  拼图精灵类:首先通过配置文件中,获取方块精灵的路径,加载到游戏里。
  定义move()移动模块的函数,这个移动比较简单。模块之间,只有相邻的可以相互移动。


  1. <font size="3"> '''

  2.   Function:

  3.       主游戏

  4.   '''

  5.   import sys

  6.   import time

  7.   import random

  8.   import pygame

  9.   

  10.   

  11.   '''拼图精灵类'''

  12.   class pacerSprite(pygame.sprite.Sprite):

  13.       def __init__(self, img_path, size, position, downlen, **kwargs):

  14.           pygame.sprite.Sprite.__init__(self)

  15.           self.image = pygame.image.load(img_path)

  16.           self.image = pygame.transform.smoothscale(self.image, size)

  17.           self.rect = self.image.get_rect()

  18.           self.rect.left, self.rect.top = position

  19.           self.downlen = downlen

  20.           self.target_x = position[0]

  21.           self.target_y = position[1] + downlen

  22.           self.type = img_path.split('/')[-1].split('.')[0]

  23.           self.fixed = False

  24.           self.speed_x = 9

  25.           self.speed_y = 9

  26.           self.direction = 'down'

  27.       def move(self):

  28.                   #下移

  29.           if self.direction == 'down':

  30.               self.rect.top = min(self.target_y, self.rect.top+self.speed_y)

  31.               if self.target_y == self.rect.top:

  32.                   self.fixed = True

  33.                   #上移

  34.           elif self.direction == 'up':

  35.               self.rect.top = max(self.target_y, self.rect.top-self.speed_y)

  36.               if self.target_y == self.rect.top:

  37.                   self.fixed = True

  38.                   #左移

  39.           elif self.direction == 'left':

  40.               self.rect.left = max(self.target_x, self.rect.left-self.speed_x)

  41.               if self.target_x == self.rect.left:

  42.                   self.fixed = True

  43.                   #右移

  44.           elif self.direction == 'right':

  45.               self.rect.left = min(self.target_x, self.rect.left+self.speed_x)

  46.               if self.target_x == self.rect.left:

  47.                   self.fixed = True

  48.       '''获取当前坐标'''

  49.       def getPosition(self):

  50.           return self.rect.left, self.rect.top

  51.       '''设置星星坐标'''

  52.       def setPosition(self, position):

  53.           self.rect.left, self.rect.top = position</font>
复制代码


4、随机生成初始布局、相邻消除、自动下落
  game.py  第二部分
  设置游戏主窗口启动的标题,设置启动游戏的主方法。


  1. <font size="3">'''主游戏类'''

  2.   class pacerGame():

  3.       def __init__(self, screen, sounds, font, pacer_imgs, cfg, **kwargs):

  4.           self.info = 'pacer'

  5.           self.screen = screen

  6.           self.sounds = sounds

  7.           self.font = font

  8.           self.pacer_imgs = pacer_imgs

  9.           self.cfg = cfg

  10.           self.reset()

  11.       '''开始游戏'''

  12.       def start(self):

  13.           clock = pygame.time.Clock()

  14.           # 遍历整个游戏界面更新位置

  15.           overall_moving = True

  16.           # 指定某些对象个体更新位置

  17.           individual_moving = False

  18.           # 定义一些必要的变量

  19.           pacer_selected_xy = None

  20.           pacer_selected_xy2 = None

  21.           swap_again = False

  22.           add_score = 0

  23.           add_score_showtimes = 10

  24.           time_pre = int(time.time())

  25.           # 游戏主循环

  26.           while True:

  27.               for event in pygame.event.get():

  28.                   if event.type == pygame.QUIT or (event.type == pygame.KEYUP and event.key == pygame.K_ESCAPE):

  29.                       pygame.quit()

  30.                       sys.exit()

  31.                   elif event.type == pygame.MOUSEBUTTONUP:

  32.                       if (not overall_moving) and (not individual_moving) and (not add_score):

  33.                           position = pygame.mouse.get_pos()

  34.                           if pacer_selected_xy is None:

  35.                               pacer_selected_xy = self.checkSelected(position)

  36.                           else:

  37.                               pacer_selected_xy2 = self.checkSelected(position)

  38.                               if pacer_selected_xy2:

  39.                                   if self.swappacer(pacer_selected_xy, pacer_selected_xy2):

  40.                                       individual_moving = True

  41.                                       swap_again = False

  42.                                   else:

  43.                                       pacer_selected_xy = None

  44.               if overall_moving:

  45.                   overall_moving = not self.droppacers(0, 0)

  46.                   # 移动一次可能可以拼出多个3连块

  47.                   if not overall_moving:

  48.                       res_match = self.isMatch()

  49.                       add_score = self.removeMatched(res_match)

  50.                       if add_score > 0:

  51.                           overall_moving = True

  52.               if individual_moving:

  53.                   pacer1 = self.getpacerByPos(*pacer_selected_xy)

  54.                   pacer2 = self.getpacerByPos(*pacer_selected_xy2)

  55.                   pacer1.move()

  56.                   pacer2.move()

  57.                   if pacer1.fixed and pacer2.fixed:

  58.                       res_match = self.isMatch()

  59.                       if res_match[0] == 0 and not swap_again:

  60.                           swap_again = True

  61.                           self.swappacer(pacer_selected_xy, pacer_selected_xy2)

  62.                           self.sounds['mismatch'].play()

  63.                       else:

  64.                           add_score = self.removeMatched(res_match)

  65.                           overall_moving = True

  66.                           individual_moving = False

  67.                           pacer_selected_xy = None

  68.                           pacer_selected_xy2 = None

  69.               self.screen.fill((135, 206, 235))

  70.               self.drawGrids()

  71.               self.pacers_group.draw(self.screen)

  72.               if pacer_selected_xy:

  73.                   self.drawBlock(self.getpacerByPos(*pacer_selected_xy).rect)

  74.               if add_score:

  75.                   if add_score_showtimes == 10:

  76.                       random.choice(self.sounds['match']).play()

  77.                   self.drawAddScore(add_score)

  78.                   add_score_showtimes -= 1

  79.                   if add_score_showtimes < 1:

  80.                       add_score_showtimes = 10

  81.                       add_score = 0

  82.               self.remaining_time -= (int(time.time()) - time_pre)

  83.               time_pre = int(time.time())

  84.               self.showRemainingTime()

  85.               self.drawScore()

  86.               if self.remaining_time <= 0:

  87.                   return self.score

  88.               pygame.display.update()

  89.               clock.tick(self.cfg.FPS)</font>
复制代码


5、随机初始化消消乐的主图内容。
  game.py  第三部分
  详细注释,都写在代码里了。大家一定要看一遍,不要跑起来,就不管了哦。


  1. <font size="3">    '''初始化'''

  2.       def reset(self):

  3.           # 随机生成各个块(即初始化游戏地图各个元素)

  4.           while True:

  5.               self.all_pacers = []

  6.               self.pacers_group = pygame.sprite.Group()

  7.               for x in range(self.cfg.NUMGRID):

  8.                   self.all_pacers.append([])

  9.                   for y in range(self.cfg.NUMGRID):

  10.                       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)

  11.                       self.all_pacers[x].append(pacer)

  12.                       self.pacers_group.add(pacer)

  13.               if self.isMatch()[0] == 0:

  14.                   break

  15.           # 得分

  16.           self.score = 0

  17.           # 拼出一个的奖励

  18.           self.reward = 10

  19.           # 时间

  20.           self.remaining_time = 300

  21.       '''显示剩余时间'''

  22.       def showRemainingTime(self):

  23.           remaining_time_render = self.font.render('CountDown: %ss' % str(self.remaining_time), 1, (85, 65, 0))

  24.           rect = remaining_time_render.get_rect()

  25.           rect.left, rect.top = (self.cfg.SCREENSIZE[0]-201, 6)

  26.           self.screen.blit(remaining_time_render, rect)

  27.       '''显示得分'''

  28.       def drawScore(self):

  29.           score_render = self.font.render('SCORE:'+str(self.score), 1, (85, 65, 0))

  30.           rect = score_render.get_rect()

  31.           rect.left, rect.top = (10, 6)

  32.           self.screen.blit(score_render, rect)

  33.       '''显示加分'''

  34.       def drawAddScore(self, add_score):

  35.           score_render = self.font.render('+'+str(add_score), 1, (255, 100, 100))

  36.           rect = score_render.get_rect()

  37.           rect.left, rect.top = (250, 250)

  38.           self.screen.blit(score_render, rect)

  39.       '''生成新的拼图块'''

  40.       def generateNewpacers(self, res_match):

  41.           if res_match[0] == 1:

  42.               start = res_match[2]

  43.               while start > -2:

  44.                   for each in [res_match[1], res_match[1]+1, res_match[1]+2]:

  45.                       pacer = self.getpacerByPos(*[each, start])

  46.                       if start == res_match[2]:

  47.                           self.pacers_group.remove(pacer)

  48.                           self.all_pacers[each][start] = None

  49.                       elif start >= 0:

  50.                           pacer.target_y += self.cfg.GRIDSIZE

  51.                           pacer.fixed = False

  52.                           pacer.direction = 'down'

  53.                           self.all_pacers[each][start+1] = pacer

  54.                       else:

  55.                           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)

  56.                           self.pacers_group.add(pacer)

  57.                           self.all_pacers[each][start+1] = pacer

  58.                   start -= 1

  59.           elif res_match[0] == 2:

  60.               start = res_match[2]

  61.               while start > -4:

  62.                   if start == res_match[2]:

  63.                       for each in range(0, 3):

  64.                           pacer = self.getpacerByPos(*[res_match[1], start+each])

  65.                           self.pacers_group.remove(pacer)

  66.                           self.all_pacers[res_match[1]][start+each] = None

  67.                   elif start >= 0:

  68.                       pacer = self.getpacerByPos(*[res_match[1], start])

  69.                       pacer.target_y += self.cfg.GRIDSIZE * 3

  70.                       pacer.fixed = False

  71.                       pacer.direction = 'down'

  72.                       self.all_pacers[res_match[1]][start+3] = pacer

  73.                   else:

  74.                       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)

  75.                       self.pacers_group.add(pacer)

  76.                       self.all_pacers[res_match[1]][start+3] = pacer

  77.                   start -= 1

  78.       '''移除匹配的pacer'''

  79.       def removeMatched(self, res_match):

  80.           if res_match[0] > 0:

  81.               self.generateNewpacers(res_match)

  82.               self.score += self.reward

  83.               return self.reward

  84.           return 0

  85.       '''游戏界面的网格绘制'''

  86.       def drawGrids(self):

  87.           for x in range(self.cfg.NUMGRID):

  88.               for y in range(self.cfg.NUMGRID):

  89.                   rect = pygame.Rect((self.cfg.XMARGIN+x*self.cfg.GRIDSIZE, self.cfg.YMARGIN+y*self.cfg.GRIDSIZE, self.cfg.GRIDSIZE, self.cfg.GRIDSIZE))

  90.                   self.drawBlock(rect, color=(0, 0, 255), size=1)

  91.       '''画矩形block框'''

  92.       def drawBlock(self, block, color=(255, 0, 255), size=4):

  93.           pygame.draw.rect(self.screen, color, block, size)

  94.       '''下落特效'''

  95.       def droppacers(self, x, y):

  96.           if not self.getpacerByPos(x, y).fixed:

  97.               self.getpacerByPos(x, y).move()

  98.           if x < self.cfg.NUMGRID - 1:

  99.               x += 1

  100.               return self.droppacers(x, y)

  101.           elif y < self.cfg.NUMGRID - 1:

  102.               x = 0

  103.               y += 1

  104.               return self.droppacers(x, y)

  105.           else:

  106.               return self.isFull()

  107.       '''是否每个位置都有拼图块了'''

  108.       def isFull(self):

  109.           for x in range(self.cfg.NUMGRID):

  110.               for y in range(self.cfg.NUMGRID):

  111.                   if not self.getpacerByPos(x, y).fixed:

  112.                       return False

  113.           return True

  114.       '''检查有无拼图块被选中'''

  115.       def checkSelected(self, position):

  116.           for x in range(self.cfg.NUMGRID):

  117.               for y in range(self.cfg.NUMGRID):

  118.                   if self.getpacerByPos(x, y).rect.collidepoint(*position):

  119.                       return [x, y]

  120.           return None

  121.       '''是否有连续一样的三个块(无--返回0/水平--返回1/竖直--返回2)'''

  122.       def isMatch(self):

  123.           for x in range(self.cfg.NUMGRID):

  124.               for y in range(self.cfg.NUMGRID):

  125.                   if x + 2 < self.cfg.NUMGRID:

  126.                       if self.getpacerByPos(x, y).type == self.getpacerByPos(x+1, y).type == self.getpacerByPos(x+2, y).type:

  127.                           return [1, x, y]

  128.                   if y + 2 < self.cfg.NUMGRID:

  129.                       if self.getpacerByPos(x, y).type == self.getpacerByPos(x, y+1).type == self.getpacerByPos(x, y+2).type:

  130.                           return [2, x, y]

  131.           return [0, x, y]

  132.       '''根据坐标获取对应位置的拼图对象'''

  133.       def getpacerByPos(self, x, y):

  134.           return self.all_pacers[x][y]

  135.       '''交换拼图'''

  136.       def swappacer(self, pacer1_pos, pacer2_pos):

  137.           margin = pacer1_pos[0] - pacer2_pos[0] + pacer1_pos[1] - pacer2_pos[1]

  138.           if abs(margin) != 1:

  139.               return False

  140.           pacer1 = self.getpacerByPos(*pacer1_pos)

  141.           pacer2 = self.getpacerByPos(*pacer2_pos)

  142.           if pacer1_pos[0] - pacer2_pos[0] == 1:

  143.               pacer1.direction = 'left'

  144.               pacer2.direction = 'right'

  145.           elif pacer1_pos[0] - pacer2_pos[0] == -1:

  146.               pacer2.direction = 'left'

  147.               pacer1.direction = 'right'

  148.           elif pacer1_pos[1] - pacer2_pos[1] == 1:

  149.               pacer1.direction = 'up'

  150.               pacer2.direction = 'down'

  151.           elif pacer1_pos[1] - pacer2_pos[1] == -1:

  152.               pacer2.direction = 'up'

  153.               pacer1.direction = 'down'

  154.           pacer1.target_x = pacer2.rect.left

  155.           pacer1.target_y = pacer2.rect.top

  156.           pacer1.fixed = False

  157.           pacer2.target_x = pacer1.rect.left

  158.           pacer2.target_y = pacer1.rect.top

  159.           pacer2.fixed = False

  160.           self.all_pacers[pacer2_pos[0]][pacer2_pos[1]] = pacer1

  161.           self.all_pacers[pacer1_pos[0]][pacer1_pos[1]] = pacer2

  162.           return True

  163.       '''信息显示'''

  164.       def __repr__(self):

  165.           return self.info</font>
复制代码


6、资源相关
  包括游戏背景音频、图片和字体设计


  1. <font size="3">res主资源目录

  2.   audios:加载游戏背景音乐

  3.   fonts:记分牌相关字体

  4.   imgs:这里存放的是我们的各种小星星的图形,是关键了的哦。如果这个加载不了,

  5.   我们的消消乐 就没有任何图形了</font>
复制代码


7、启动主程序
  xxls.py
  在主程序中,通过读取配置文件,引入项目资源:包括图片、音频等,并从我们的modules里引入所有我们的模块。


  1. <font size="3">'''

  2.   Function:

  3.       消消乐

  4.   '''

  5.   import os

  6.   import sys

  7.   import cfg

  8.   import pygame

  9.   from modules import *

  10.   

  11.   

  12.   '''主程序'''

  13.   def main():

  14.       pygame.init()

  15.       screen = pygame.display.set_mode(cfg.SCREENSIZE)

  16.       pygame.display.set_caption('hacklex')

  17.       # 加载背景音乐

  18.       pygame.mixer.init()

  19.       pygame.mixer.music.load(os.path.join(cfg.ROOTDIR, "res/audios/bg.mp3"))

  20.       pygame.mixer.music.set_volume(0.6)

  21.       pygame.mixer.music.play(-1)

  22.       # 加载音效

  23.       sounds = {}

  24.       sounds['mismatch'] = pygame.mixer.Sound(os.path.join(cfg.ROOTDIR, 'res/audios/badswap.wav'))

  25.       sounds['match'] = []

  26.       for i in range(6):

  27.           sounds['match'].append(pygame.mixer.Sound(os.path.join(cfg.ROOTDIR, 'res/audios/match%s.wav' % i)))

  28.   

  29.       # 字体显示

  30.       font = pygame.font.Font(os.path.join(cfg.ROOTDIR, 'res/font/font.TTF'), 25)

  31.       # 星星

  32.       pacer_imgs = []

  33.       for i in range(1, 8):

  34.           pacer_imgs.append(os.path.join(cfg.ROOTDIR, 'res/imgs/pacer%s.png' % i))

  35.       # 循环

  36.       game = pacerGame(screen, sounds, font, pacer_imgs, cfg)

  37.       while True:

  38.           score = game.start()

  39.           flag = False

  40.           # 给出选择,玩家选择重玩或者退出

  41.           while True:

  42.               for event in pygame.event.get():

  43.                   if event.type == pygame.QUIT or (event.type == pygame.KEYUP and event.key == pygame.K_ESCAPE):

  44.                       pygame.quit()

  45.                       sys.exit()

  46.                   elif event.type == pygame.KEYUP and event.key == pygame.K_r:

  47.                       flag = True

  48.               if flag:

  49.                   break

  50.               screen.fill((136, 207, 236))

  51.               text0 = 'Final score: %s' % score

  52.               text1 = 'Press <R> to restart the game.'

  53.               text2 = 'Press <Esc> to quit the game.'

  54.               y = 150

  55.               for idx, text in enumerate([text0, text1, text2]):

  56.                   text_render = font.render(text, 1, (85, 65, 0))

  57.                   rect = text_render.get_rect()

  58.                   if idx == 0:

  59.                       rect.left, rect.top = (223, y)

  60.                   elif idx == 1:

  61.                       rect.left, rect.top = (133.5, y)

  62.                   else:

  63.                       rect.left, rect.top = (126.5, y)

  64.                   y += 99

  65.                   screen.blit(text_render, rect)

  66.               pygame.display.update()

  67.           game.reset()

  68.   

  69.   

  70.   '''游戏运行'''

  71.   if __name__ == '__main__':

  72.       main()</font>
复制代码


四、如何启动游戏呢?
  1、使用开发工具IDE启动
  如果的开发工具IDE的环境。
  例如:VScode、sublimeText、notepad+pycharm什么的配置了Python环境,可以直接在工具中,运行该游戏。
  2、命令行启动
  如下图所示:


[attach]144563[/attach]



作者: 清晨一缕阳光    时间: 2022-11-23 10:48
厉害了




欢迎光临 51Testing软件测试论坛 (http://bbs.51testing.com/) Powered by Discuz! X3.2