用Python做一个开心消消乐小游戏

Crossin的编程教室

共 6835字,需浏览 14分钟

 · 2021-02-26

作者:野客
来源:Python小二(pythonXE)


大家好,欢迎来到 Crossin的编程教室 !

提到开心消消乐这款小游戏,相信大家都不陌生,其曾在 2015 年获得过玩家最喜爱的移动单机游戏奖,受欢迎程度可见一斑,本文我们使用 Python 来做个简单的消消乐小游戏。

准备

本游戏基于 Python 的 pygame 库进行开发。所以在动手之前,你需要安装 pygame 库。

pip install pygame

如果你的版本比较特殊无法自动下载安装,可以从这里下载离线包安装:

http://www.lfd.uci.edu/~gohlke/pythonlibs/#pygame

注意:假如遇上游戏启动后空白不显示的情况,请更新pygame到2.0以上版本尝试。

对pygame基本操作还不了解的,可以在公众号(Crossin的编程教室)对话页回复关键字 pygame,查看我们之前写过的 pygame 教程。

实现

消消乐的构成主要包括三部分:游戏主体、计分器、计时器,下面来看一下具体实现。

定义一些常量,比如:窗口宽高、网格行列数等,代码如下:

WIDTH = 400HEIGHT = 400NUMGRID = 8GRIDSIZE = 36XMARGIN = (WIDTH - GRIDSIZE * NUMGRID) // 2YMARGIN = (HEIGHT - GRIDSIZE * NUMGRID) // 2ROOTDIR = os.getcwd()FPS = 30

接着创建一个主窗口,代码如下:

pygame.init()screen = pygame.display.set_mode((WIDTH, HEIGHT))pygame.display.set_caption('消消乐')

看一下效果:

再接着在窗口中画一个 8 x 8 的网格,代码如下:

screen.fill((255, 255, 220))# 游戏界面的网格绘制def drawGrids(self):  for x in range(NUMGRID):      for y in range(NUMGRID):          rect = pygame.Rect((XMARGIN+x*GRIDSIZE, YMARGIN+y*GRIDSIZE, GRIDSIZE, GRIDSIZE))          self.drawBlock(rect, color=(255, 165, 0), size=1)# 画矩形 block 框def drawBlock(self, block, color=(255, 0, 0), size=2):    pygame.draw.rect(self.screen, color, block, size)

看一下效果:

再接着在网格中随机放入各种拼图块,代码如下:

# 随机生成各个块while True:    self.all_gems = []    self.gems_group = pygame.sprite.Group()    for x in range(NUMGRID):        self.all_gems.append([])        for y in range(NUMGRID):            gem = Puzzle(img_path=random.choice(self.gem_imgs), size=(GRIDSIZE, GRIDSIZE), position=[XMARGIN+x*GRIDSIZE, YMARGIN+y*GRIDSIZE-NUMGRID*GRIDSIZE], downlen=NUMGRID*GRIDSIZE)            self.all_gems[x].append(gem)            self.gems_group.add(gem)    if self.isMatch()[0] == 0:        break

看一下效果:

再接着加入计分器和计时器,代码如下:

# 显示剩余时间def showRemainingTime(self):    remaining_time_render = self.font.render('倒计时: %ss' % str(self.remaining_time), 1, (85, 65, 0))    rect = remaining_time_render.get_rect()    rect.left, rect.top = (WIDTH-190, 15)    self.screen.blit(remaining_time_render, rect)# 显示得分def drawScore(self):    score_render = self.font.render('分数:'+str(self.score), 1, (85, 65, 0))    rect = score_render.get_rect()    rect.left, rect.top = (55, 15)    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)

看一下效果:

当设置的游戏时间用尽时,我们可以生成一些提示信息,代码如下:

while True:for event in pygame.event.get():    if event.type == pygame.QUIT:        pygame.quit()        sys.exit()    if event.type == pygame.KEYUP and event.key == pygame.K_r:        flag = Trueif flag:    breakscreen.fill((255, 255, 220))text0 = '最终得分: %s' % scoretext1 = '按 R 键重新开始'y = 140for idx, text in enumerate([text0, text1]):    text_render = font.render(text, 1, (85, 65, 0))    rect = text_render.get_rect()    if idx == 0:        rect.left, rect.top = (100, y)    elif idx == 1:        rect.left, rect.top = (100, y)    y += 60    screen.blit(text_render, rect)pygame.display.update()

看一下效果:

说完了游戏图形化界面相关的部分,我们再看一下游戏的主要处理逻辑。

我们通过鼠标来操纵拼图块,因此程序需要检查有无拼图块被选中,代码实现如下:

# 检查有无拼图块被选中def checkSelected(self, position):    for x in range(NUMGRID):        for y in range(NUMGRID):            if self.getGemByPos(x, y).rect.collidepoint(*position):                return [x, y]    return None

我们需要将鼠标连续选择的拼图块进行位置交换,代码实现如下:

# 交换拼图def swapGem(self, gem1_pos, gem2_pos):  margin = gem1_pos[0] - gem2_pos[0] + gem1_pos[1] - gem2_pos[1]  if abs(margin) != 1:    return False  gem1 = self.getGemByPos(*gem1_pos)  gem2 = self.getGemByPos(*gem2_pos)  if gem1_pos[0] - gem2_pos[0] == 1:    gem1.direction = 'left'    gem2.direction = 'right'  elif gem1_pos[0] - gem2_pos[0] == -1:    gem2.direction = 'left'    gem1.direction = 'right'  elif gem1_pos[1] - gem2_pos[1] == 1:    gem1.direction = 'up'    gem2.direction = 'down'  elif gem1_pos[1] - gem2_pos[1] == -1:    gem2.direction = 'up'    gem1.direction = 'down'  gem1.target_x = gem2.rect.left  gem1.target_y = gem2.rect.top  gem1.fixed = False  gem2.target_x = gem1.rect.left  gem2.target_y = gem1.rect.top  gem2.fixed = False  self.all_gems[gem2_pos[0]][gem2_pos[1]] = gem1  self.all_gems[gem1_pos[0]][gem1_pos[1]] = gem2  return True

每一次交换拼图块时,我们需要判断是否有连续一样的三个及以上拼图块,代码实现如下:

# 是否有连续一样的三个块def isMatch(self):  for x in range(NUMGRID):    for y in range(NUMGRID):      if x + 2 < NUMGRID:        if self.getGemByPos(x, y).type == self.getGemByPos(x+1, y).type == self.getGemByPos(x+2, y).type:          return [1, x, y]      if y + 2 < NUMGRID:        if self.getGemByPos(x, y).type == self.getGemByPos(x, y+1).type == self.getGemByPos(x, y+2).type:          return [2, x, y]  return [0, x, y]

当出现三个及以上拼图块时,需要将这些拼图块消除,代码实现如下:

# 移除匹配的元素def removeMatched(self, res_match):  if res_match[0] > 0:    self.generateNewGems(res_match)    self.score += self.reward    return self.reward  return 0

将匹配的拼图块消除之后,我们还需要随机生成新的拼图块,代码实现如下:

# 生成新的拼图块def generateNewGems(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]:        gem = self.getGemByPos(*[each, start])        if start == res_match[2]:          self.gems_group.remove(gem)          self.all_gems[each][start] = None        elif start >= 0:          gem.target_y += GRIDSIZE          gem.fixed = False          gem.direction = 'down'          self.all_gems[each][start+1] = gem        else:          gem = Puzzle(img_path=random.choice(self.gem_imgs), size=(GRIDSIZE, GRIDSIZE), position=[XMARGIN+each*GRIDSIZE, YMARGIN-GRIDSIZE], downlen=GRIDSIZE)          self.gems_group.add(gem)          self.all_gems[each][start+1] = gem      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):          gem = self.getGemByPos(*[res_match[1], start+each])          self.gems_group.remove(gem)          self.all_gems[res_match[1]][start+each] = None      elif start >= 0:        gem = self.getGemByPos(*[res_match[1], start])        gem.target_y += GRIDSIZE * 3        gem.fixed = False        gem.direction = 'down'        self.all_gems[res_match[1]][start+3] = gem      else:        gem = Puzzle(img_path=random.choice(self.gem_imgs), size=(GRIDSIZE, GRIDSIZE), position=[XMARGIN+res_match[1]*GRIDSIZE, YMARGIN+start*GRIDSIZE], downlen=GRIDSIZE*3)        self.gems_group.add(gem)        self.all_gems[res_match[1]][start+3] = gem      start -= 1

之后反复执行这个过程,直至耗尽游戏时间,游戏结束。

最后,我们动态看一下游戏效果。

总结

本文我们使用 Python 实现了一个简单的消消乐游戏,有兴趣的可以对游戏做进一步扩展,比如增加关卡等。

如果文章对你有帮助,欢迎转发/点赞/收藏~

后台回复 消消乐 获取游戏源码



_往期文章推荐_

用python写一个简单的贪吃蛇游戏




浏览 42
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报