跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI 生图工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
Python算法

Python 实现消消乐小游戏

使用 Python 和 Pygame 库开发消消乐小游戏的完整过程。内容涵盖环境搭建、游戏窗口初始化、8x8 网格绘制、随机拼图块生成、鼠标交互逻辑、相邻方块交换机制、匹配检测算法以及消除后的方块下落与补充逻辑。文章提供了详细的代码示例,解释了计分器、计时器及游戏结束界面的实现方式,适合希望学习游戏开发基础逻辑的开发者参考。

DockerOne发布于 2025/2/6更新于 2026/9/1063 浏览
Python 实现消消乐小游戏

Python 实现消消乐小游戏

简介

消消乐(Match-3)是一款经典的益智游戏,核心玩法是通过交换相邻的方块,使三个或更多相同颜色的方块连成一线从而消除得分。本文使用 Python 和 Pygame 库实现一个基础的消消乐游戏,涵盖游戏界面绘制、网格管理、方块交换、匹配检测及消除逻辑。

环境准备

在开始之前,请确保已安装 Python 环境并安装 Pygame 库:

pip install pygame

项目结构与常量定义

游戏主体主要由窗口设置、网格系统、计分器和计时器组成。首先定义全局常量和必要的导入模块。

导入依赖

import os
import sys
import time
import pygame
import random

常量配置

设定窗口大小、网格行列数及边距等参数,便于后续调整。

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

游戏主窗口初始化

使用 Pygame 初始化显示模式并设置窗口标题。

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

网格与方块绘制

绘制网格背景

在主循环中填充背景色,并调用绘制函数画出 8x8 的网格线。

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=(, , ), size=)

 ():
    pygame.draw.rect(.screen, color, block, size)
255
165
0
1
def
drawBlock
self, block, color=(255, 0, 0), size=2
self

随机生成拼图块

初始化时,在网格中随机放置不同颜色的拼图块(Gems)。为了避免初始状态直接存在可消除的组合,需进行预检查。

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

显示倒计时

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)

游戏结束处理

当时间耗尽,显示最终得分并提供重新开始选项。

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 = True
    if flag:
        break
    screen.fill((255, 255, 220))
    text0 = '最终得分:%s' % score
    text1 = '按 R 键重新开始'
    y = 140
    for 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

方块交换

允许玩家交换相邻的两个方块。代码需验证交换位置是否相邻(距离为 1),并更新方向和目标坐标。

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 和 Pygame 构建消消乐游戏的核心流程,包括界面渲染、事件监听、数据交换及消除算法。通过模块化设计,可以进一步扩展关卡系统、道具功能或音效支持。开发者可根据实际需求调整网格大小、颜色种类及游戏规则。


注:以上代码片段展示了关键逻辑,实际运行需结合完整的类结构定义及资源文件加载。

目录

  1. Python 实现消消乐小游戏
  2. 简介
  3. 环境准备
  4. 项目结构与常量定义
  5. 导入依赖
  6. 常量配置
  7. 游戏主窗口初始化
  8. 网格与方块绘制
  9. 绘制网格背景
  10. 随机生成拼图块
  11. 计分与计时系统
  12. 显示分数
  13. 显示加分动画
  14. 显示倒计时
  15. 游戏结束处理
  16. 核心交互逻辑
  17. 鼠标选中检测
  18. 方块交换
  19. 匹配检测
  20. 消除与生成新方块
  21. 总结

更多推荐文章

查看全部
  • 大型语言模型(LLMs)关键技术指南
  • 30 行 Python 实现公开接口数据抓取与本地存储
  • 大模型应用的 5 种核心架构模式
  • Python 基础语法与数据结构常用代码示例
  • AI 入门:常见术语解释与误区澄清
  • 从零构建可扩展 Flutter 应用:v1.0 到 v2.0 全代码详解
  • Ubuntu 20.04 系统无声问题排查与解决方案
  • Nginx 配置 HTTPS 实战教程:前后端集成
  • 前端核心面试题与实战指南
  • 2026 年 3 月 18 日人工智能前沿动态与产业观察
  • 无人机避障:Mid360+Fast-lio 感知建图与 Ego-planner 运动规划
  • AI Skills:前端开发新效率工具
  • AI 编程 Spec Coding 标准化工作流详解
  • 数据库 SQL 防火墙:内核级主动防御 SQL 注入方案
  • 2026 无人机 AI 算法全景图:7 大场景 50+ 算法详解
  • 论文解读:大语言模型的代理推理架构与演进
  • C++26 标准更新:std::execution on 函数深度解析
  • C++ 类型转换与 IO 流详解
  • go2rtc 开源视频流媒体协议转换工具
  • STM32 上运行 AI 模型的四种方案及案例解析

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • curl 转代码

    解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online