当前位置: 首页 > news >正文

CS课程项目设计7:基于Canvas交互友好的五子棋游戏

本专栏的第二篇和第四篇文章分别介绍了交互友好的五子棋游戏、支持AI人机对战的五子棋游戏,具体内容可以参考以下两篇帖子:

CS课程项目设计2:交互友好的五子棋游戏-CSDN博客https://blog.csdn.net/weixin_36431280/article/details/149415017?spm=1001.2014.3001.5501CS课程项目设计4:支持AI人机对战的五子棋游戏-CSDN博客https://blog.csdn.net/weixin_36431280/article/details/149432389?spm=1001.2014.3001.5501

这两个项目实现的五子棋棋盘都太简陋了,不太美观。因此,和本专栏的第五篇和第六篇文章一样:

CS课程项目设计5:基于Canvas交互友好的井字棋游戏-CSDN博客https://blog.csdn.net/weixin_36431280/article/details/149664504?spm=1001.2014.3001.5501

CS课程项目设计6:基于Canvas支持人机对战的井字棋游戏-CSDN博客https://blog.csdn.net/weixin_36431280/article/details/149668934我们使用Canvas组件进一步改进这两个项目,提高页面布局的美观度。

原始交互友好的五子棋游戏棋盘和现有基于Canvas交互友好的五子棋游戏棋盘的对比图如下所示:


1. 研究目的

这个项目重新设计了棋盘、按键、设置玩家昵称页面、赢局和平局显示页面,并且对照本专栏第二篇文章来介绍这个基于Canvas交互友好的五子棋游戏。

具体而言,为了让五子棋棋盘更加美观,我们可以使用 tkinter 的 Canvas 组件来绘制棋盘,并用 Canvas 上的图形表示棋子,同时可以调整颜色和线条样式来提升视觉效果。

主要修改点:

  • 使用Canvas绘制棋盘:通过Canvas的create_line方法绘制棋盘的横线和竖线,使用burlywood作为棋盘背景色,让棋盘看起来更美观。
  • 用圆形表示棋子:使用Canvas的create_oval方法绘制圆形棋子,黑棋用黑色填充,白棋用白色填充。
  • 处理画布点击事件:通过绑定Canvas的<Button-1>事件,处理用户的点击操作,计算点击位置对应的棋盘格子。
  • 更新悔棋和加载游戏逻辑:在悔棋和加载游戏时,需要更新Canvas上的棋子显示。

同时,对按钮和文字窗口进行了美化,使用了更现代的设计风格和交互效果。主要改进包括:

  • 为按钮添加了圆角、阴影和悬停效果
  • 使用更现代的字体和颜色方案
  • 为文字窗口添加了边框和背景色
  • 优化了整体布局,增加了间距和对齐
  • 为玩家状态添加了颜色标记
  • 添加了棋盘边框和分隔线样式

最后,对设置用户昵称和显示玩家胜利的布局进行了美化,使用了更现代的设计风格和交互效果。主要改进包括:

  • 为设置用户昵称创建了自定义对话框
  • 使用更现代的字体和颜色方案
  • 为胜利消息添加了动画效果和视觉反馈
  • 优化了整体布局,增加了间距和对齐
  • 为玩家状态添加了颜色标记
  • 添加了平滑过渡效果

2. 技术方案

本项目采用 Python 语言结合 tkinter 库实现,具体技术方案如下:

  1. 开发语言:Python 3.8
  2. GUI 库:tkinter(Python 内置库,无需额外安装)
  3. 数据存储:JSON 格式文件用于保存和加载游戏进度
  4. 多线程处理:使用 threading 模块处理音效播放和复杂动画,避免阻塞 UI 线程
  5. 动画实现:通过 tkinter 的 update () 方法和延时函数实现简单动画效果
  6. 本地化支持:通过字体设置和文本配置确保中文显示正常

系统架构采用面向对象设计,主要类包括:

  • Gomoku:游戏主类,负责管理游戏状态、处理用户输入和更新界面
  • 界面组件:包括棋盘按钮、状态标签、控制按钮等,通过 tkinter 实现

3. 实现流程

明确游戏的基本功能和交互逻辑,设计数据结构和类的关系。确定需要实现的核心功能包括:棋盘显示、玩家轮流落子、胜负判定、悔棋、保存 / 加载游戏等。

首先实现游戏的核心逻辑,包括:

  • 初始化 15×15 棋盘和游戏状态
  • 处理玩家点击事件,更新棋盘状态
  • 判断胜负条件(五子连珠)
  • 实现玩家轮流机制

其中,处理玩家点击事件,更新棋盘状态的代码如下所示:

def make_move(self, row, col):"""处理玩家移动"""if self.board[row][col] == ' ' and self.game_active:# 记录当前移动到历史self.move_history.append((row, col, self.current_player))self.undo_button.config(state=tk.NORMAL)  # 启用悔棋按钮# 播放放置音效self.play_sound('place')# 添加放置动画self.animate_cell(row, col)# 更新棋盘数据self.board[row][col] = self.current_player# 更新按钮显示(使用●表示黑棋,○表示白棋)symbol = '●' if self.current_player == 'X' else '○'self.buttons[row][col].config(text=symbol)# 记录上一步self.last_move = (row, col)self.last_move_label.config(text=f"上一步: {self.player_names[self.current_player]} 在位置 {row + 1},{col + 1}")# 检查游戏状态if self.check_winner(self.current_player):self.status_label.config(text=f"{self.player_names[self.current_player]} 获胜!")self.game_active = Falseself.undo_button.config(state=tk.DISABLED)  # 禁用悔棋按钮# 播放胜利音效和动画self.play_sound('win')self.animate_winning_cells()messagebox.showinfo("游戏结束", f"{self.player_names[self.current_player]} 获胜!")elif self.is_board_full():self.status_label.config(text="游戏平局!")self.game_active = Falseself.undo_button.config(state=tk.DISABLED)  # 禁用悔棋按钮# 播放平局音效self.play_sound('draw')messagebox.showinfo("游戏结束", "游戏平局!")else:# 切换玩家self.current_player = 'O' if self.current_player == 'X' else 'X'self.status_label.config(text=f"当前玩家: {self.player_names[self.current_player]}")

当前玩家可以看到上一位玩家的下子坐标位置,可视化界面如下所示:

判断胜负和平局条件的代码如下所示:

def check_winner(self, player):"""检查玩家是否获胜,并记录获胜的格子"""directions = [(0, 1), (1, 0), (1, 1), (1, -1)]  # 水平、垂直、对角线、反对角线for row in range(self.board_size):for col in range(self.board_size):if self.board[row][col] == player:for dx, dy in directions:# 检查当前方向上是否有连续五个相同的棋子line = []for i in range(5):r = row + i * dxc = col + i * dyif 0 <= r < self.board_size and 0 <= c < self.board_size and self.board[r][c] == player:line.append((r, c))else:breakif len(line) == 5:self.winning_cells = linereturn Truereturn False

赢局的可视化界面如下所示:

此外,该项目使用 tkinter 创建用户界面,包括:

  • 设计 15×15 棋盘布局和样式
  • 添加状态显示区域,显示当前玩家和游戏状态
  • 实现控制按钮(悔棋、保存 / 加载、重新开始等)
  • 支持玩家自定义名称

其中,支持玩家自定义名称的代码如下所示:

def set_player_names(self):"""使用自定义对话框设置玩家名称"""dialog = tk.Toplevel(self.root)dialog.title("设置玩家名称")dialog.geometry("400x200")dialog.configure(bg=self.colors['background'])dialog.transient(self.root)dialog.grab_set()# 创建对话框内容title_label = tk.Label(dialog,text="请设置玩家名称",font=('Arial', 16, 'bold'),bg=self.colors['background'],fg=self.colors['text'])title_label.pack(pady=10)# 玩家X名称输入x_frame = tk.Frame(dialog, bg=self.colors['background'])x_frame.pack(pady=5, padx=20, fill=tk.X)x_label = tk.Label(x_frame,text="黑棋玩家:",font=('Arial', 12),bg=self.colors['background'],fg=self.colors['text'])x_label.pack(side=tk.LEFT, padx=5)self.x_entry = tk.Entry(x_frame,font=('Arial', 12),bg='white',fg=self.colors['text'],relief=tk.FLAT,bd=2)self.x_entry.insert(0, self.player_names['X'])self.x_entry.pack(side=tk.LEFT, fill=tk.X, expand=True)# 玩家O名称输入o_frame = tk.Frame(dialog, bg=self.colors['background'])o_frame.pack(pady=5, padx=20, fill=tk.X)o_label = tk.Label(o_frame,text="白棋玩家:",font=('Arial', 12),bg=self.colors['background'],fg=self.colors['text'])o_label.pack(side=tk.LEFT, padx=5)self.o_entry = tk.Entry(o_frame,font=('Arial', 12),bg='white',fg=self.colors['text'],relief=tk.FLAT,bd=2)self.o_entry.insert(0, self.player_names['O'])self.o_entry.pack(side=tk.LEFT, fill=tk.X, expand=True)# 按钮框架button_frame = tk.Frame(dialog, bg=self.colors['background'])button_frame.pack(pady=10, padx=20, fill=tk.X)ok_button = tk.Button(button_frame,text="确定",font=('Arial', 12, 'bold'),bg=self.colors['button'],fg='white',relief=tk.FLAT,padx=20,pady=8,command=lambda: self.on_name_dialog_ok(dialog))ok_button.pack(side=tk.RIGHT, padx=5)ok_button.bind("<Enter>", lambda e: ok_button.config(bg=self.colors['button_hover']))ok_button.bind("<Leave>", lambda e: ok_button.config(bg=self.colors['button']))# 将 wait_window 移到对话框内容构建完成后self.root.wait_window(dialog)

支持玩家自定义名称的可视化界面如下所示:

我们逐步添加附加功能:

  • 悔棋功能:记录历史操作,支持撤销上一步
  • 保存 / 加载功能:使用 JSON 格式保存游戏状态到文件
  • 音效系统:使用 playsound 库播放操作音效
  • 动画效果:为棋子放置和获胜状态添加视觉动画
  • 本地化支持:确保中文显示正常

其中,悔棋功能的代码如下所示:

def undo_move(self):"""悔棋功能"""if not self.move_history:return  # 没有历史记录# 播放悔棋音效self.play_sound('undo')# 恢复上一步row, col, player = self.move_history.pop()self.board[row][col] = ' 'self.buttons[row][col].config(text='', bg='SystemButtonFace')  # 恢复默认背景# 清除获胜高亮if self.winning_cells:for r, c in self.winning_cells:self.buttons[r][c].config(bg='SystemButtonFace')self.winning_cells = []# 更新上一步信息if self.move_history:last_row, last_col, last_player = self.move_history[-1]self.last_move = (last_row, last_col)self.last_move_label.config(text=f"上一步: {self.player_names[last_player]} 在位置 {last_row + 1},{last_col + 1}")else:self.last_move = Noneself.last_move_label.config(text="上一步: 无")# 切换回上一个玩家self.current_player = playerself.status_label.config(text=f"当前玩家: {self.player_names[self.current_player]}")# 重新激活游戏(如果之前结束了)self.game_active = True# 如果没有历史记录了,禁用悔棋按钮if not self.move_history:self.undo_button.config(state=tk.DISABLED)

悔棋功能的可视化界面如下所示:

加载游戏的可视化界面如下所示:

最后,我们还对游戏进行全面测试,包括:

  • 基本游戏流程测试
  • 边界条件测试(如各种方向的五子连珠、棋盘填满平局等)
  • 保存 / 加载功能测试
  • 异常处理测试(如文件不存在、格式错误等)

根据测试结果进行代码优化和 Bug 修复。

4. 总结

本项目成功实现了一款功能完整、交互友好的五子棋游戏,通过以下特点提升了用户体验:

  1. 丰富的功能:支持自定义玩家名称、悔棋、保存 / 加载游戏进度等功能,满足用户多样化需求。
  2. 良好的视觉体验:通过动画效果和高亮显示,增强游戏的视觉反馈,使游戏过程更加直观。
  3. 音效系统:为关键操作添加音效,提升游戏的沉浸感。
  4. 模块化设计:代码结构清晰,各个功能模块独立封装,便于后续扩展和维护。
  5. 本地化支持:优化中文显示,适应中文用户的使用习惯。

未来可以进一步扩展的方向包括:

  1. 添加人机对战功能,实现 AI 对手,支持不同难度级别
  2. 设计更精美的 UI 界面,使用现代设计元素和布局
  3. 支持多人在线对战功能,实现玩家之间的远程对战
  4. 添加游戏统计和历史记录功能,记录玩家胜率和对战历史
  5. 实现多语言支持,扩大用户群体

5. 项目展示

最后上传个该项目的简要演示视频,供大家了解。

基于Canvas交互友好的五子棋游戏

http://www.lryc.cn/news/608052.html

相关文章:

  • 从AI智能体出发,重构数据中台:迈向Agentic时代的数据能力体系
  • Docker容器中文PDF生成解决方案
  • Oracle 11gR2 Clusterware应知应会
  • 分布式事务----spring操作多个数据库,事务以及事务回滚还有用吗
  • Oracle 11g RAC集群部署手册(二)
  • Token系列 - 再谈稳定币
  • mac 安装pytho3 和pipx
  • 讲一讲Spring核心三大组件IOC、Bean、AOP
  • 我的世界模组开发教程——物品item(1)
  • Vuex 4.0:Vue.js 应用的状态管理新篇章
  • 深度学习核心:神经网络-激活函数 - 原理、实现及在医学影像领域的应用
  • K8S部署ELK(一):部署Filebeat日志收集器
  • SCI 绘图实用 RGB 配色方案:多组比较
  • [Windows] 微软.Net运行库离线合集包 Microsoft .Net Packages AIO v13.05.25
  • Vue3+ts自定义指令
  • 从毫秒到真义:构建工业级RAG系统的向量检索优化指南
  • 入门MicroPython+ESP32:ESP32烧录MicroPython固件
  • Python进阶(5):类与继承
  • Unity_数据持久化_XML存储相关
  • 探索:Uniapp 安卓热更新
  • 智能合约漏洞导致的损失,法律责任应如何分配
  • 医疗后台管理系统开发实践
  • 分类任务当中常见指标 F1分数、recall、准确率分别是什么含义
  • 通过解决docker network connect实现同一个宿主机不同网络的容器间通信
  • 【stm32】点灯及蜂鸣器
  • 深度学习·mmsegmentation基础教程
  • 前端开发(HTML,CSS,VUE,JS)从入门到精通!第三天(JavaScript)
  • ospf作业
  • 关于Web前端安全防御之点击劫持的原理及防御措施
  • winscp 连openwrt 返回127错误码