资讯详情

资讯详情

猫鼠游戏从零搭建:3步跑通完整示例,告别只会抄代码

猫鼠游戏从零搭建:3步跑通完整示例,告别只会抄代码 是不是觉得看了一堆教程还是不会写项目?别急,很多人卡在“看懂了但手不动”的尴尬期。今天这篇猫鼠游戏完整示例,直接带你从0到1跑通,不讲虚的,只给能跑的代码和踩坑记录。 1. 项目目标与核心逻辑 我们不做那种花里胡哨的图形界面,先搞个命令行版猫鼠游戏。目标很明确:地图生成:随机生成一个有墙壁的迷宫。 角色控制:玩家控制老鼠(用键盘或输入指令),电脑控制猫(AI寻路)。 胜负判定:老鼠吃到所有奶酪算赢,被猫抓到算输。核心难点:猫的寻路算法。如果猫只是乱走,游戏没意思;如果猫太聪明,玩家赢不了。我们要用 BFS(广度优先搜索) 让猫走最短路径追老鼠,但给猫加个“反应延迟”,模拟人类反应,这样才有“猫鼠游戏”的博弈感。 为什么选这个? 因为它涵盖了数据结构(队列)、算法(BFS)、状态机(游戏循环)和IO处理。比“Hello World”有深度,比大型框架易上手。 2. 目录结构规划 工程化思维很重要,别把所有代码堆在 main.py 里。建议结构如下: cat_mouse_game/ ├── main.py # 入口文件,初始化游戏 ├── game_logic.py # 核心逻辑:地图生成、碰撞检测 ├── ai_agent.py # 猫的AI行为:BFS寻路 ├── player.py # 玩家控制:输入处理 ├── config.py # 配置:地图大小、速度等 └── utils.py # 工具函数:地图渲染、消息打印为什么这么分? 以后想换算法(比如A*)只改 ai_agent.py,想改地图规则只改 game_logic.py。解耦是代码可维护性的基石。 3. 核心代码实现 3.1 地图生成与初始化 (game_logic.py) 地图用二维列表表示,0 是空地,1 是墙,2 是奶酪。 import randomdef generate_map(width=10, height=10, wall_density=0.2, cheese_count=3):生成随机地图:param width: 地图宽度:param height: 地图高度:param wall_density: 墙壁密度,0-1之间:param cheese_count: 奶酪数量:return: 二维列表表示的地图# 初始化全为空地map_grid = [[0 for _ in range(width)] for _ in range(height)]# 随机生成墙壁,避免生成在边缘,确保地图连通性(简化处理,实际需更复杂算法)for i in range(1, height - 1):for j in range(1, width - 1):if random.random() wall_density:map_grid[i][j] = 1# 随机放置奶酪cheese_positions = []while len(cheese_positions) cheese_count:x = random.randint(1, height - 2)y = random.randint(1, width - 2)if map_grid[x][y] == 0 and [x, y] not in cheese_positions:map_grid[x][y] = 2cheese_positions.append([x, y])return map_grid逐行解析:random.random() wall_density:概率生成墙,wall_density 越小地图越开阔。 奶酪放置时检查 map_grid[x][y] == 0,避免奶酪生成在墙上。3.2 猫的AI:BFS寻路 (ai_agent.py) 这是灵魂部分。猫要找到离老鼠最近的路径。 from collections import dequeclass Cat:def __init__(self, x, y):self.x = xself.y = ydef bfs_next_move(self, map_grid, mouse_x, mouse_y):使用BFS寻找猫移动到下一个位置的最短路径:param map_grid: 当前地图:param mouse_x: 老鼠x坐标:param mouse_y: 老鼠y坐标:return: 下一个移动的 (x, y) 坐标height = len(map_grid)width = len(map_grid[0])# BFS初始化queue = deque()queue.append((self.x, self.y))visited = [[False] * width for _ in range(height)]visited[self.x][self.y] = True# 方向:上、下、左、右directions = [(-1, 0), (1, 0), (0, -1), (0, 1)]# 记录路径,以便回溯parent = {}parent[(self.x, self.y)] = Nonewhile queue:curr_x, curr_y = queue.popleft()# 如果当前格子是老鼠位置,找到路径if curr_x == mouse_x and curr_y == mouse_y:# 回溯找到第一步step = (curr_x, curr_y)while parent[step] is not None:step = parent[step]return stepfor dx, dy in directions:nx, ny = curr_x + dx, curr_y + dy# 边界检查和墙壁检查if 0 = nx height and 0 = ny width and map_grid[nx][ny] != 1:if not visited[nx][ny]:visited[nx][ny] = Trueparent[(nx, ny)] = (curr_x, curr_y)queue.append((nx, ny))# 如果没找到路径(老鼠被围堵),随机移动return self.random_move(map_grid)def random_move(self, map_grid):随机移动一步,避免死锁directions = [(-1, 0), (1, 0), (0, -1), (0, 1)]valid_moves = []for dx, dy in directions:nx, ny = self.x + dx, self.y + dyif 0 = nx len(map_grid) and 0 = ny len(map_grid[0]) and map_grid[nx][ny] != 1:valid_moves.append((nx, ny))if valid_moves:next_x, next_y = random.choice(valid_moves)self.x, self.y = next_x, next_y# 如果没得走,原地不动关键点:deque 用于BFS,比 list 效率高,因为 list.pop(0) 是 O(n),deque.popleft() 是 O(1)。 parent 字典记录路径,BFS本身只给距离,回溯才能拿到具体走法。 避坑:一定要加 random_move 兜底。如果地图生成时老鼠被墙完全围死,BFS会跑不完,游戏卡死。3.3 游戏主循环 (main.py) 把逻辑串起来。 import os import time from game_logic import generate_map from ai_agent import Cat from player import Mousedef clear_screen():os.system('cls' if os.name == 'nt' else 'clear')def print_map(map_grid, cat_pos, mouse_pos, cheese_left):渲染地图到终端height = len(map_grid)width = len(map_grid[0])print(= * (width * 2 + 1))for i in range(height):row = for j in range(width):if map_grid[i][j] == 1:row += ██ elif (i, j) == cat_pos:row += 🐱 elif (i, j) == mouse_pos:row += 🐭 elif map_grid[i][j] == 2:row += 🧀 else:row += print(row)print(= * (width * 2 + 1))print(f奶酪剩余: {cheese_left} | 猫的位置: {cat_pos} | 鼠的位置: {mouse_pos})def main():# 初始化map_size = 15map_grid = generate_map(width=map_size, height=map_size, wall_density=0.25, cheese_count=5)# 随机初始位置(确保不在墙上)def get_random_empty_pos():while True:x = random.randint(0, map_size - 1)y = random.randint(0, map_size - 1)if map_grid[x][y] == 0:return x, ymouse = Mouse(*get_random_empty_pos())cat = Cat(*get_random_empty_pos())cheese_left = 5game_over = Falseprint(游戏开始!输入方向: w(上) a(左) s(下) d(右), q(退出))while not game_over:clear_screen()print_map(map_grid, (cat.x, cat.y), (mouse.x, mouse.y), cheese_left)# 1. 玩家输入move = input(你的移动: ).lower()if move == 'q':break# 2. 老鼠移动if not mouse.move(move, map_grid):print(撞墙了!原地不动。)# 3. 检查奶酪if map_grid[mouse.x][mouse.y] == 2:map_grid[mouse.x][mouse.y] = 0cheese_left -= 1print(吃到奶酪!)# 4. 检查胜负if cheese_left == 0:print(🎉 你赢了!)breakif (cat.x, cat.y) == (mouse.x, mouse.y):print(💀 被猫抓到了!游戏结束。)break# 5. 猫移动 (AI)time.sleep(0.5) # 模拟反应延迟next_pos = cat.bfs_next_move(map_grid, mouse.x, mouse.y)if next_pos:cat.x, cat.y = next_pos# 6. 再次检查碰撞(猫移动后可能撞上)if (cat.x, cat.y) == (mouse.x, mouse.y):print(💀 被猫抓到了!游戏结束。)breakif __name__ == __main__:main()player.py 补充: class Mouse:def __init__(self, x, y):self.x = xself.y = ydef move(self, direction, map_grid):dx, dy = 0, 0if direction == 'w': dx = -1elif direction == 's': dx = 1elif direction == 'a': dy = -1elif direction == 'd': dy = 1else: return Falsenx, ny = self.x + dx, self.y + dyif 0 = nx len(map_grid) and 0 = ny len(map_grid[0]) and map_grid[nx][ny] != 1:self.x, self.y = nx, nyreturn Truereturn False4. 运行与测试 4.1 环境准备 不需要复杂环境,Python 3.7+ 即可。所有代码只用标准库,零依赖。 pip install -r requirements.txt # 其实这里没东西,纯标准库 python main.py4.2 测试场景正常游玩:地图生成后,观察猫是否总是朝老鼠方向移动。 边界测试:把 wall_density 调到 0.8,地图很堵。看猫是否会卡在角落(random_move 是否生效)。 性能测试:把地图改到 50x50。BFS 在 2500 格内搜索,deque 能保证毫秒级响应。如果用 list 做队列,可能会卡。Stack Overflow 经验: 很多初学者用 list 做 BFS 队列,当地图变大时程序变慢。在 Stack Overflow 上,高赞回答指出 collections.deque 是双端队列,popleft() 是 O(1) 操作,而 list.pop(0) 是 O(n),因为要移动所有元素。这就是为什么我们在 ai_agent.py 里用 deque。 5. 优化与扩展 5.1 让猫更“狡猾” 目前猫每步都重新 BFS,计算量稍大。可以优化:预计算:老鼠不动时,缓存猫的路径,直到老鼠移动才重新计算。 威胁区域:计算老鼠周围 3 步内的区域,如果老鼠进入,猫加速(减少 time.sleep 时间)。5.2 图形化界面 命令行版太素?用 pygame 或 tkinter 替换 print_map。tkinter:Python 自带,轻量,适合快速原型。 pygame:功能强大,适合做真正的游戏,支持音效、动画。5.3 多猫模式 生成 2-3 只猫,各自独立 BFS。这时候老鼠需要判断哪只猫最近,选择安全路径。这引入了博弈论的雏形。 5.4 持久化 用 json 保存最高分和地图布局。每次启动读取 config.json。 6. 小结 从 0 到 1 搭完这个猫鼠游戏,你掌握了:BFS 算法:最短路径搜索的经典应用。 模块化设计:逻辑、AI、UI 分离,方便维护。 状态机:游戏循环中的输入-处理-渲染流程。 边界处理:墙、地图边缘、死锁情况。常见报错排查:IndexError:检查坐标是否越界,BFS 中 nx, ny 是否加了边界检查。 游戏卡死:检查 BFS 是否无限循环,visited 数组是否正确标记。 猫不动:检查 random_move 是否被触发,地图是否全被墙围死。这个完整示例不是终点,而是起点。你可以加音效、加皮肤、加多人模式。编程的乐趣在于折腾,不在于完美。 互动时间: 你在写类似的小游戏时,卡在哪个环节最多?是地图生成不连通,还是 AI 太笨/太聪明?或者你有更好的寻路算法建议?评论区留言,我挨个回。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →