尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

Python Pygame实战:从零开发经典华容道游戏

Python Pygame实战:从零开发经典华容道游戏 1. 项目概述为什么用Pygame做华容道如果你对Python编程有点兴趣又恰好想找个项目练手把经典的华容道游戏做出来绝对是个能让你成就感爆棚的选择。这项目听起来有点“复古”但它的技术含量一点也不低。它不像贪吃蛇那样逻辑简单也不像Flappy Bird那样依赖物理引擎华容道的核心在于状态管理、路径搜索和交互逻辑恰好能覆盖游戏开发里几个非常关键的思维训练点。我选择Pygame来做原因很直接它足够轻量也足够强大。对于这种2D棋盘类游戏Pygame提供的精灵Sprite、事件循环、矩形碰撞检测和图像渲染功能完全是“专业对口”。你不用去折腾复杂的3D坐标系也不用被Unity或Godot那种重型引擎的学习曲线吓到。用Pygame从零开始你能清晰地看到每一行代码是如何驱动屏幕上那个小方块移动的这种掌控感对理解游戏底层逻辑至关重要。这个项目适合谁呢首先当然是Python初学者你已经掌握了列表、循环、函数这些基础语法正愁没地方施展其次是想入门游戏开发的朋友Pygame是公认的优秀起点最后哪怕你是个有经验的开发者想重温一下算法比如A*寻路在华容道里的应用或者给简历增加一个有趣的个人项目它也同样合适。整个过程你会亲手实现从界面绘制、鼠标键盘交互、游戏规则判定到胜利条件检测的完整链条相当于自己当了一回游戏策划加程序员。2. 核心思路与游戏架构设计2.1 游戏规则与数据抽象华容道的核心规则很简单一个N x N的棋盘经典是4x4有N*N-1个带编号的方块和一个空格。玩家通过移动与空格相邻的方块最终将所有方块按顺序比如1到15排列整齐。但要把这个规则变成代码第一步是抽象。最直接的数据结构就是二维列表。例如一个初始被打乱的4x4棋盘可以表示为board [ [1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 0] # 0代表空格 ]这里的“0”代表空格。游戏的所有状态本质上就是这个二维列表的无数种排列组合。我们的核心任务就是响应用户操作改变这个列表并实时将列表的视觉状态渲染到屏幕上。注意空格用0表示是个常见技巧因为0在判断是否为空、进行数值比较时都很方便。你也可以用None但在后续的移动逻辑和胜利判断中用数字会更简洁。2.2 Pygame项目结构规划在动手写代码前花几分钟规划一下文件结构能让你后期维护时感谢自己。一个清晰的Pygame华容道项目可以这样组织klotski_game/ ├── main.py # 程序入口初始化Pygame主游戏循环 ├── game.py # 核心游戏逻辑类管理棋盘状态、移动规则、胜负判断 ├── board.py # 棋盘绘制与方块精灵管理 ├── solver.py # 可选自动求解器模块实现算法解谜 ├── config.py # 配置文件存放颜色、尺寸、关卡等常量 └── assets/ └── images/ # 存放方块图片、背景图等资源main.py负责Pygame窗口的创建、事件分发和主循环调度。game.py是大脑它持有当前的board状态并对外提供move_tile(x, y)、is_solved()等方法。board.py是美工它根据game.py提供的状态调用Pygame的draw方法把棋盘画出来。这种“逻辑与渲染分离”的设计是游戏开发中的好习惯能让代码更清晰也方便你未来增加新功能比如动画效果或者不同的皮肤。3. 开发环境搭建与核心依赖详解3.1 Python与Pygame安装避坑指南首先确保你安装了Python 3.7或以上版本。打开命令行输入python --version或python3 --version确认。接下来安装Pygame。最推荐的方式是使用pip并指定国内镜像源以加速下载pip install pygame -i https://pypi.tuna.tsinghua.edu.cn/simple安装完成后可以写一个几行代码的测试脚本验证import pygame pygame.init() screen pygame.display.set_mode((800, 600)) print(Pygame 安装成功窗口已创建。) pygame.quit()运行这个脚本如果弹出一个黑色窗口并在控制台打印成功信息说明环境就绪。实操心得很多人会在安装Pygame时遇到问题尤其是Windows用户。常见错误是提示缺少VC运行库。一个一劳永逸的解决方法是安装Microsoft Visual C Redistributable。更简单的办法是直接使用Anaconda或Miniconda这类科学计算发行版它们通常已经集成了必要的依赖。命令是conda install pygame。3.2 初始化游戏窗口与参数配置在config.py里我们把所有可配置的项集中管理这比把数字硬编码在代码里要好得多。# config.py SCREEN_WIDTH 800 SCREEN_HEIGHT 600 BOARD_SIZE 4 # 4x4的经典华容道 TILE_SIZE 100 # 每个方块的像素大小 MARGIN 5 # 方块之间的间隙 BACKGROUND_COLOR (50, 50, 80) # 深蓝色背景 TILE_COLOR (220, 220, 100) # 方块颜色 TEXT_COLOR (0, 0, 0) # 方块上数字的颜色 FPS 60 # 帧率控制游戏刷新速度然后在main.py中初始化Pygame并创建窗口import pygame from config import SCREEN_WIDTH, SCREEN_HEIGHT, FPS def main(): pygame.init() screen pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) pygame.display.set_caption(Python华容道 - 经典益智游戏) clock pygame.time.Clock() running True while running: for event in pygame.event.get(): if event.type pygame.QUIT: running False # 填充背景色 screen.fill(BACKGROUND_COLOR) # 这里后续会调用board.py的绘制函数 pygame.display.flip() # 更新整个屏幕 clock.tick(FPS) # 控制帧率 pygame.quit() if __name__ __main__: main()这段代码搭建了游戏的基本骨架一个窗口、一个事件循环、一个渲染流程。clock.tick(FPS)确保了游戏不会在性能好的电脑上跑得太快。4. 游戏核心逻辑实现4.1 棋盘状态管理与方块移动算法现在我们来构建游戏的大脑——Game类。它位于game.py中。import random from config import BOARD_SIZE class Game: def __init__(self): self.size BOARD_SIZE self.board [] self.empty_pos (self.size-1, self.size-1) # 空格初始在右下角 self._create_board() self.shuffle() # 游戏开始前打乱棋盘 def _create_board(self): 创建已解决的初始棋盘状态 self.board [] num 1 for r in range(self.size): row [] for c in range(self.size): if r self.size-1 and c self.size-1: row.append(0) # 最后一个位置是空格 else: row.append(num) num 1 self.board.append(row) def shuffle(self, moves1000): 通过随机移动来打乱棋盘确保游戏有解 # 从已解决状态开始随机移动空格1000次 directions [(0, 1), (0, -1), (1, 0), (-1, 0)] # 右左下上 empty_r, empty_c self.empty_pos for _ in range(moves): # 随机选择一个方向 dr, dc random.choice(directions) new_r, new_c empty_r dr, empty_c dc # 检查新位置是否在棋盘内 if 0 new_r self.size and 0 new_c self.size: # 交换空格和目标位置 self.board[empty_r][empty_c], self.board[new_r][new_c] \ self.board[new_r][new_c], self.board[empty_r][empty_c] empty_r, empty_c new_r, new_c self.empty_pos (empty_r, empty_c) def move_tile(self, row, col): 尝试移动指定位置(row, col)的方块 # 检查点击位置是否就是空格 if self.board[row][col] 0: return False # 点击的是空格无事发生 # 检查点击的方块是否与空格相邻 empty_r, empty_c self.empty_pos if (abs(row - empty_r) 1 and col empty_c) or \ (abs(col - empty_c) 1 and row empty_r): # 交换方块和空格 self.board[empty_r][empty_c], self.board[row][col] \ self.board[row][col], self.board[empty_r][empty_c] self.empty_pos (row, col) # 更新空格位置 return True # 移动成功 return False # 移动失败 def is_solved(self): 检查当前棋盘是否已解决按顺序排列 num 1 for r in range(self.size): for c in range(self.size): # 最后一个位置应该是空格(0) if r self.size-1 and c self.size-1: if self.board[r][c] ! 0: return False else: if self.board[r][c] ! num: return False num 1 return Trueshuffle方法的设计有个关键点它必须保证打乱后的棋盘有解。华容道并非所有随机排列都是可解的。通过从已解决状态开始只进行合法的移动模拟空格移动来打乱可以100%保证生成的状态是可解的。这是实现中的一个重要细节。4.2 鼠标与键盘交互事件处理游戏需要响应用户输入。在Pygame主循环中我们处理两种主要事件鼠标点击和键盘按键。 在main.py的主循环中补充事件处理# 在main.py的while running循环内 for event in pygame.event.get(): if event.type pygame.QUIT: running False elif event.type pygame.MOUSEBUTTONDOWN: # 鼠标点击事件 if event.button 1: # 左键点击 # 获取鼠标位置 mouse_x, mouse_y pygame.mouse.get_pos() # 调用一个函数将屏幕坐标转换为棋盘网格坐标 tile_clicked board.get_tile_at_pos(mouse_x, mouse_y) if tile_clicked: row, col tile_clicked # 尝试移动方块 if game.move_tile(row, col): print(f移动了方块 ({row}, {col})) # 移动成功后检查是否获胜 if game.is_solved(): print(恭喜你解开了华容道) elif event.type pygame.KEYDOWN: # 键盘事件用方向键移动空格周围的方块另一种操作方式 if event.key pygame.K_r: # 按R键重新开始游戏 game.shuffle() print(游戏已重置) elif event.key pygame.K_ESCAPE: running False这里我们提供了两种交互鼠标直接点击方块移动以及键盘R键重置游戏。board.get_tile_at_pos函数将在下一节实现负责将屏幕上的像素坐标(mouse_x, mouse_y)转换为棋盘上的行列索引(row, col)。5. 图形界面绘制与动画效果5.1 方块精灵绘制与坐标计算现在我们来创建Board类负责将所有数据可视化。在board.py中import pygame from config import * class Board: def __init__(self, game): self.game game # 持有Game实例以获取棋盘状态 self.size game.size self.tile_size TILE_SIZE self.margin MARGIN # 计算棋盘在屏幕上的起始位置使其居中 board_pixel_width self.size * (self.tile_size self.margin) - self.margin board_pixel_height board_pixel_width # 棋盘是正方形 self.start_x (SCREEN_WIDTH - board_pixel_width) // 2 self.start_y (SCREEN_HEIGHT - board_pixel_height) // 2 # 加载字体用于在方块上绘制数字 self.font pygame.font.SysFont(None, 48) # None使用系统默认字体 def get_tile_at_pos(self, pixel_x, pixel_y): 将屏幕像素坐标转换为棋盘网格坐标(row, col) # 先判断点击是否在棋盘区域内 board_width self.size * (self.tile_size self.margin) - self.margin if not (self.start_x pixel_x self.start_x board_width and self.start_y pixel_y self.start_y board_width): return None # 点击在棋盘外 # 计算网格坐标 rel_x pixel_x - self.start_x rel_y pixel_y - self.start_y # 考虑方块之间的间隙 col rel_x // (self.tile_size self.margin) row rel_y // (self.tile_size self.margin) # 检查是否点击在了间隙上而不是方块本身 if (rel_x % (self.tile_size self.margin) self.tile_size or rel_y % (self.tile_size self.margin) self.tile_size): return None # 确保坐标在有效范围内 if 0 row self.size and 0 col self.size: return (row, col) return None def draw(self, screen): 在给定的screen上绘制整个棋盘和方块 for row in range(self.size): for col in range(self.size): # 计算当前方块在屏幕上的位置矩形左上角坐标 tile_x self.start_x col * (self.tile_size self.margin) tile_y self.start_y row * (self.tile_size self.margin) tile_value self.game.board[row][col] # 绘制方块背景如果是空格0则不绘制背景色显示为“洞” if tile_value ! 0: # 绘制带圆角的方块 rect pygame.Rect(tile_x, tile_y, self.tile_size, self.tile_size) pygame.draw.rect(screen, TILE_COLOR, rect, border_radius8) # 绘制方块边框增加立体感 pygame.draw.rect(screen, (180, 180, 60), rect, width3, border_radius8) # 绘制方块上的数字 text_surface self.font.render(str(tile_value), True, TEXT_COLOR) text_rect text_surface.get_rect(center(tile_x self.tile_size//2, tile_y self.tile_size//2)) screen.blit(text_surface, text_rect) else: # 绘制空格可以画一个不同颜色的框或者留空 # 这里我们画一个半透明的深色矩形表示空格 s pygame.Surface((self.tile_size, self.tile_size), pygame.SRCALPHA) s.fill((0, 0, 0, 30)) # 黑色30透明度 screen.blit(s, (tile_x, tile_y))get_tile_at_pos函数是交互的关键它精确地将鼠标点击映射到具体的方块上。计算时需要考虑方块之间的间隙margin否则点击间隙也会被误判为点击了方块。5.2 添加简单的移动动画效果目前方块的移动是“瞬间闪现”的体验不够平滑。我们可以增加一个简单的动画让方块滑动到空格位置。这需要修改我们的逻辑从“瞬间交换”变为“记录动画状态并逐步渲染”。首先在Game类中增加动画状态跟踪# 在game.py的Game类中增加 class Game: def __init__(self): # ... 其他初始化代码 ... self.animating False self.animation_progress 0.0 # 0到1之间 self.animation_from None # 动画起始位置像素 self.animation_to None # 动画目标位置像素 self.animation_tile_value 0 # 正在移动的方块的值然后修改move_tile方法不直接交换数据而是触发动画def move_tile(self, row, col): if self.board[row][col] 0: return False empty_r, empty_c self.empty_pos if (abs(row - empty_r) 1 and col empty_c) or \ (abs(col - empty_c) 1 and row empty_r): # 1. 记录动画信息 self.animating True self.animation_progress 0.0 # 计算起始和目标像素位置这里需要board实例的坐标转换信息可以稍后传递 # 假设我们通过某种方式获得了这些坐标... # self.animation_from (tile_x, tile_y) # self.animation_to (empty_x, empty_y) self.animation_tile_value self.board[row][col] # 2. 立即更新逻辑状态但视觉上通过动画表现 self.board[empty_r][empty_c], self.board[row][col] \ self.board[row][col], self.board[empty_r][empty_c] self.empty_pos (row, col) return True return False最后在Board.draw方法中根据动画状态来绘制方块。如果正在动画中就根据animation_progress在from和to位置之间插值来绘制移动的方块。同时在主循环中每帧增加animation_progress直到达到1.0然后结束动画状态。注意事项添加动画会显著增加代码复杂度尤其是坐标转换和状态管理。对于第一个版本我建议先实现无动画的稳定版本确保核心逻辑无误后再考虑加入动画作为增强功能。贪多嚼不烂分步迭代是项目成功的关键。6. 游戏功能增强与扩展6.1 胜利判定与游戏状态反馈当玩家完成拼图时我们需要给出明确的反馈。除了在控制台打印信息更友好的方式是在游戏窗口上显示。我们可以在Board.draw方法的最后检查游戏状态并绘制胜利信息。# 在board.py的draw方法末尾添加 def draw(self, screen): # ... 绘制棋盘的代码 ... # 检查游戏是否胜利 if self.game.is_solved(): # 创建一个半透明的覆盖层 overlay pygame.Surface((SCREEN_WIDTH, SCREEN_HEIGHT), pygame.SRCALPHA) overlay.fill((0, 0, 0, 128)) # 半透明黑色 screen.blit(overlay, (0, 0)) # 创建胜利文本 win_font pygame.font.SysFont(None, 72) win_text win_font.render(恭喜通关, True, (255, 215, 0)) # 金色 text_rect win_text.get_rect(center(SCREEN_WIDTH//2, SCREEN_HEIGHT//2 - 50)) screen.blit(win_text, text_rect) # 创建提示文本 hint_font pygame.font.SysFont(None, 36) hint_text hint_font.render(按 R 键重新开始ESC 键退出, True, (200, 200, 200)) hint_rect hint_text.get_rect(center(SCREEN_WIDTH//2, SCREEN_HEIGHT//2 30)) screen.blit(hint_text, hint_rect)这样当拼图完成时屏幕会变暗并显示醒目的胜利提示用户体验会好很多。6.2 计步器与计时器功能一个完整的游戏通常会有计步和计时功能增加挑战性和可玩性。我们可以在Game类中增加相关属性并在main.py中显示它们。 首先在Game.__init__中初始化def __init__(self): # ... 原有代码 ... self.moves_count 0 self.start_time pygame.time.get_ticks() # 获取当前时间毫秒 self.elapsed_time 0在move_tile方法成功移动后增加步数def move_tile(self, row, col): # ... 移动逻辑判断 ... if 移动成功: self.moves_count 1 return True在Board.draw中在棋盘上方绘制步数和时间def draw(self, screen): # 绘制步数 moves_text f步数: {self.game.moves_count} moves_surface self.font.render(moves_text, True, (255, 255, 255)) screen.blit(moves_surface, (20, 20)) # 计算并绘制时间格式分:秒 if not self.game.is_solved(): self.game.elapsed_time (pygame.time.get_ticks() - self.game.start_time) // 1000 minutes self.game.elapsed_time // 60 seconds self.game.elapsed_time % 60 time_text f时间: {minutes:02d}:{seconds:02d} time_surface self.font.render(time_text, True, (255, 255, 255)) screen.blit(time_surface, (SCREEN_WIDTH - 150, 20))当游戏重置按R键时别忘了重置moves_count和start_time。6.3 实现自动求解器A*算法进阶这是给学有余力、想挑战算法朋友的进阶内容。华容道本质上是一个状态搜索问题我们可以用A*算法来寻找最优解最少步数。这需要定义状态表示、启发式函数和搜索算法。首先我们需要一种方式来表示和比较棋盘状态。一个简单的方法是将二维列表扁平化为元组因为元组是可哈希的可以放入集合或作为字典的键。def state_to_tuple(board): 将棋盘状态转换为可哈希的元组 return tuple(tuple(row) for row in board)A*算法需要一个启发式函数来评估当前状态到目标状态的距离。对于华容道一个常用的启发函数是“曼哈顿距离和”即每个数字方块当前位置到其目标位置的曼哈顿距离行差列差之和。空格0通常不计入。def manhattan_distance(state, size4): 计算给定状态的曼哈顿距离启发值 distance 0 goal_positions {} # 数字-目标位置(行, 列)的映射 num 1 for r in range(size): for c in range(size): if not (r size-1 and c size-1): # 最后一个位置是空格的目标 goal_positions[num] (r, c) num 1 goal_positions[0] (size-1, size-1) # 空格的目标位置 # 计算当前状态每个数字的曼哈顿距离 for r in range(size): for c in range(size): tile state[r][c] if tile ! 0: goal_r, goal_c goal_positions[tile] distance abs(r - goal_r) abs(c - goal_c) return distance然后实现A搜索的核心。由于完整的A实现代码较长这里概述关键步骤将初始状态加入优先队列heapq优先级为f g h其中g是已走步数h是启发值。从队列中取出f值最小的状态。如果该状态是目标状态则回溯路径。否则生成该状态的所有合法后继状态即移动空格上下左右得到的新状态。对于每个后继状态计算其g当前g1和h曼哈顿距离。如果该状态未被访问过或找到了到达该状态更短的路径g更小则更新并加入优先队列。实操心得A算法求解4x4华容道通常很快但对于更复杂的布局或更大的棋盘如5x5搜索空间会爆炸式增长可能需要更复杂的启发函数如线性冲突或IDA迭代加深A*算法。对于游戏中的“提示”功能不必每次求完整最优解可以只搜索几步给玩家一个近期的移动建议。7. 项目打包与性能优化7.1 使用PyInstaller打包为可执行文件当你完成开发并测试无误后可能想分享给不会安装Python的朋友。PyInstaller可以将你的脚本打包成独立的.exeWindows或可执行文件macOS/Linux。首先安装PyInstallerpip install pyinstaller然后在你的项目根目录main.py所在目录下运行pyinstaller --onefile --windowed --name 华容道 main.py--onefile将所有依赖打包成一个单独的可执行文件。--windowed对于GUI程序不显示控制台窗口如果你需要看打印信息调试可以先不加这个参数。--name指定生成的可执行文件的名字。打包完成后在dist文件夹里就能找到可执行文件。你可以把它复制到任何没有Python环境的电脑上运行。踩坑记录打包时最常见的错误是资源文件如图片、字体找不到。因为打包后程序运行在一个临时目录不是你的项目目录。解决方法有两种1) 使用sys._MEIPASSPyInstaller运行时设置的属性来获取资源路径2) 将资源文件作为“数据文件”添加到打包命令中--add-data assets;assetsWindows分号Linux/macOS用冒号。对于我们的华容道如果用了自定义字体或图片就需要处理这个问题。7.2 代码优化与性能考量虽然华容道对性能要求不高但养成好习惯很重要。表面绘制在Pygame中反复绘制整个屏幕screen.fill()是常规操作。但要避免在每一帧都创建新的Surface对象比如文字Surface。对于不变的文字如标题可以在初始化时创建一次并缓存起来。事件处理Pygame的event.get()会清空事件队列。确保在主循环中只调用一次并将结果存下来供所有逻辑使用而不是多次调用。矩形碰撞检测我们用的get_tile_at_pos是手动计算对于小网格没问题。如果网格很大Pygame内置的Rect.collidepoint()函数可能更高效你可以为每个方块创建一个pygame.Rect对象并缓存起来检测时遍历矩形列表即可。状态检查优化is_solved()函数在每一步移动后都被调用。对于4x4棋盘遍历16个元素完全没问题。但如果棋盘变大这个函数可能成为瓶颈。一个优化思路是维护一个“错位方块计数”每次移动只更新受影响的两个位置移动的方块和空格的检查状态而不是每次都全盘遍历。8. 常见问题排查与调试技巧即使按照步骤操作你也可能会遇到一些奇怪的问题。这里记录几个我开发时踩过的坑和解决方法。问题1点击方块没反应或者点击间隙方块移动了。原因get_tile_at_pos函数中的坐标转换逻辑有误特别是对间隙margin的处理。排查在get_tile_at_pos函数中添加打印语句输出计算出的rel_x, rel_y, row, col对比鼠标实际点击位置和你的预期。确保if (rel_x % (self.tile_size self.margin) self.tile_size)这个条件判断能正确过滤掉点击间隙的情况。技巧可以在Board.draw中临时绘制每个方块的网格线和坐标直观地看到每个方块的区域范围便于调试。问题2游戏可以玩但某些打乱的局面永远无法解开。原因shuffle函数可能产生了无解的状态。虽然我们采用了“从已解决状态随机移动”的方法但如果moves参数太小或者随机方向选择导致棋盘“卡在”某个局部可能打乱不充分。更严重的是如果你直接随机生成一个排列而不是通过合法移动大约有一半的概率是无解的。解决确保shuffle函数中的moves足够大比如1000。一个更严谨的方法是在shuffle之后计算棋盘状态的“逆序数”对于数字华容道来判断是否有解。但我们的移动模拟法在理论上是保真的。问题3游戏窗口卡顿或者移动方块有拖影。原因可能是每帧绘制的内容太多或者没有正确清屏。排查确保在主循环中每次绘制新帧前都调用了screen.fill(BACKGROUND_COLOR)来清除上一帧的内容。检查是否有不必要的、每帧都在创建的重型对象比如大字体。技巧使用pygame.time.Clock().tick(FPS)控制帧率。如果FPS设得太高比如120而你的绘制逻辑很重电脑可能会吃力。60FPS对于这类游戏完全足够且流畅。问题4打包后的exe文件运行时闪退或者找不到模块。原因PyInstaller没有正确打包所有依赖或者代码中有基于当前工作目录的路径引用。排查首先尝试不加--windowed参数打包运行exe时弹出的控制台窗口会显示错误信息。常见错误是ModuleNotFoundError。解决对于隐藏导入的模块需要在打包时指定。例如如果你用了pygame.font以外的字体模块可能需要--hidden-import参数。更根本的方法是在代码中所有文件路径操作前使用以下方式获取正确的资源路径import sys import os def resource_path(relative_path): 获取资源的绝对路径。在开发环境和PyInstaller打包后都有效 try: # PyInstaller创建临时文件夹将路径存储在_MEIPASS中 base_path sys._MEIPASS except Exception: base_path os.path.abspath(.) return os.path.join(base_path, relative_path) # 使用示例 font_path resource_path(assets/fonts/myfont.ttf)开发这类项目调试器和打印语句是你最好的朋友。不要怕在代码里加print来输出关键变量的状态。Pygame社区也很活跃遇到复杂问题去Stack Overflow或相关论坛搜索通常都能找到解决方案。最重要的是保持耐心从最简单的能运行版本开始每增加一个功能就充分测试步步为营。当你最终看到自己亲手实现的华容道游戏流畅运行那种满足感绝对是看再多教程也换不来的。
返回列表