新闻中心
Python Curses贪吃蛇:食物生成与蛇身增长机制优化指南

本教程旨在解决python `curses`贪吃蛇游戏中,蛇吃掉食物后未能正确增长,并导致`typeerror`的问题。核心在于当蛇头与食物位置重合时,应立即重新生成新的食物,而非简单地将食物变量设为`none`。通过修正食物生成逻辑,确保游戏能够持续进行,并使蛇身在每次成功进食后正确增长。
引言
在开发基于curses库的Python贪吃蛇游戏时,一个常见的挑战是确保游戏逻辑的正确性,特别是关于食物的生成、蛇的进食以及蛇身的增长。本文将深入探讨一个特定问题:当蛇吃到食物后,蛇身未能增长,反而可能导致程序崩溃,并提供详细的解决方案和优化建议。
问题分析
原始代码中,当蛇头与食物位置重合时,食物的处理逻辑如下:
if head == food:
food = None
else:
tail = snake.pop()这段代码的意图是,如果蛇吃到了食物,就将food变量设为None,表示食物已被移除。然而,问题出在随后的渲染阶段:
w.addch(food[0], food[1], curses.ACS_PI)
当food被设为None后,尝试访问food[0]和food[1]会导致TypeError: 'NoneType' object is not subscriptable。这意味着程序在吃掉食物后,试图在一个空值上执行索引操作而崩溃。
立即学习“Python免费学习笔记(深入)”;
此外,将food设为None也未能实现食物的重新生成,导致游戏无法继续提供新的食物供蛇食用,从而无法实现蛇身的增长。蛇身增长的逻辑依赖于在吃到食物时 不 移除蛇尾,而当前代码在food == None时,既没有重新生成食物,也没有跳过snake.pop()(虽然这是在else块中,但food=None本身就是问题)。
GemDesign
AI高保真原型设计工具
652
查看详情
解决方案
解决此问题的关键在于,当蛇头吃到食物后,不应将food设为None,而应该立即调用create_food函数来生成一个新的食物。这样既避免了TypeError,又确保了游戏能够持续进行,并允许蛇身通过不移除尾部来增长。
将原始代码中的食物处理逻辑修改为:
if head == food:
food = create_food(snake, box) # 吃到食物后,立即生成新食物
else:
tail = snake.pop() # 未吃到食物,移除蛇尾
w.addch(tail[0], tail[1], ' ') # 清除旧蛇尾的显示注意: 原始代码中清除蛇尾的w.addch(tail[0], tail[1], ' ')语句位于w.addch(food[0], food[1], curses.ACS_PI)之后,并且在else块之外,这意味着即使蛇吃到了食物,tail变量也可能未定义,或者在food = None之后,tail的清除也可能出错。更合理的做法是,只有在蛇未吃到食物时,才移除蛇尾并清除其显示。
完整代码示例与优化
以下是修正后的main函数核心游戏循环部分,包含了食物生成与蛇身增长的正确逻辑:
import curses
from random import randint
def create_food(snake, box):
"""
在指定边界内生成一个不在蛇身位置的食物。
"""
food = None
while food is None:
# 确保食物生成在边界内
food = [randint(box[0] + 1, box[1] - 1), randint(box[2] + 1, box[3] - 1)]
# 确保食物不生成在蛇身上
if food in snake:
food = None
return food
def main(stdscr):
curses.curs_set(0) # 隐藏光标
stdscr.timeout(100) # 设置刷新间隔(毫秒),控制游戏速度
sh, sw = stdscr.getmaxyx() # 获取屏幕高度和宽度
w = curses.newwin(sh, sw, 0, 0) # 创建一个新的窗口
w.keypad(1) # 启用特殊按键输入(如方向键)
# 定义游戏区域的边界 [y_min, y_max, x_min, x_max]
box = [3, sh - 3, 3, sw - 3]
# 初始化蛇身,由多个坐标组成
snake = [
[sh // 2, sw // 2],
[sh // 2, sw // 2 - 1],
[sh // 2, sw // 2 - 2]
]
food = create_food(snake, box) # 初始生成食物
key = curses.KEY_RIGHT # 初始方向向右
while True:
# 绘制边界和分数(每次循环都重新绘制,因为curses会清屏)
w.border(0)
w.addstr(0, 5, f" Score: {len(snake) - 3} ") # 显示分数
next_key = w.getch() # 获取用户输入
# 如果没有新输入,保持当前方向
key = key if next_key == -1 else next_key
# 计算新蛇头的位置
head = [snake[0][0], snake[0][1]]
if key == curses.KEY_DOWN:
head[0] += 1
elif key == curses.KEY_UP:
head[0] -= 1
elif key == curses.KEY_LEFT:
head[1] -= 1
elif key == curses.KEY_RIGHT:
head[1] += 1
snake.insert(0, head) # 将新蛇头插入蛇身列表的开头
# 检查蛇头是否与食物重合
if head == food:
food =
create_food(snake, box) # 吃到食物,生成新食物
else:
# 未吃到食物,移除蛇尾并清除其显示
tail = snake.pop()
w.addch(tail[0], tail[1], ' ')
# 绘制食物
# create_food函数保证了food在绘制前不会是None
w.addch(food[0], food[1], curses.ACS_PI)
# 绘制新蛇头
w.addch(snake[0][0], snake[0][1], '*')
# 游戏结束条件:撞墙或撞到自己
if (
snake[0][0] in [box[0], box[1]] or # 撞到上下墙
snake[0][1] in [box[2], box[3]] or # 撞到左右墙
snake[0] in snake[1:] # 撞到自己
):
break # 退出游戏循环
w.refresh() # 刷新屏幕显示
# 游戏结束,显示"Game Over"
w.addstr(sh // 2, sw // 2 - 5, "GAME OVER!")
w.refresh()
w.getch() # 等待用户按键后退出
curses.wrapper(main)代码解析
- create_food(snake, box) 函数: 此函数负责在游戏区域box内随机生成食物的坐标,并确保新生成的食物不会出现在蛇身的任何部分上,避免食物被立即“吃掉”或生成在不可达位置。
-
游戏循环 (while True):
- 边界与分数绘制: 每次循环开始时,重新绘制游戏边界和当前分数。这是curses应用的常见做法,以确保屏幕内容正确更新。
- 输入处理: w.getch() 获取用户按键,控制蛇的移动方向。key = key if next_key == -1 else next_key 确保在没有新输入时,蛇继续沿当前方向移动。
- 蛇头移动: 根据当前方向更新蛇头head的坐标。
- 插入新蛇头: snake.insert(0, head) 将新蛇头添加到蛇身列表的最前端。
-
食物交互逻辑:
- if head == food::如果蛇头位置与食物位置相同,说明蛇吃到了食物。此时,调用create_food(snake, box)生成新的食物,并且 不执行 snake.pop()操作,从而使蛇身增长一个单位。
- else::如果蛇没有吃到食物,则执行snake.pop()移除蛇身列表的最后一个元素(即蛇尾),并在屏幕上清除其显示,模拟蛇的移动。
- 绘制: 分别绘制食物(curses.ACS_PI代表一个π符号)和新蛇头(*)。
- 游戏结束条件: 检查蛇头是否撞到边界或撞到自身(snake[0] in snake[1:]),如果满足条件则跳出循环,游戏结束。
- 刷新屏幕: w.refresh() 更新屏幕显示所有绘制的元素。
注意事项
- curses环境: 在不同操作系统上,`
以上就是Python Curses贪吃蛇:食物生成与蛇身增长机制优化指南的详细内容,更多请关注其它相关文章!
# 这是
# 小学综合网站建设方案
# 网络推广自媒体营销模式
# 济南网站建设公司推荐
# seo小白打法
# 售楼处营销推广
# 榆林企业网站优化效果
# 厦门低价网站建设企业
# 专门做小程序推广的网站
# 淮南抖音seo运营系统
# 律师推广网站哪个好
# 多线程
# 重启
# python
# 贪吃蛇
# 蛇尾
# 撞到
# 设为
# 移除
# 吃到
# elif
# win
# ai
# app
# 操作系统
# 前端
相关栏目:
【
科技资讯46185 】
【
网络学院92790 】
相关推荐:
2026春节假期票务安排_2026春节放假购票指南
Flexbox布局实践:实现粘性导航栏与底部固定页脚
手机屏幕碎了但能正常使用怎么办 手机外屏碎裂的修复建议
谷歌邮箱注册显示错误Gmail服务器异常与延迟处理
斑马英语APP如何开启夜间护眼阅读_斑马英语APP夜间模式与低蓝光设置教程
J*aScript:在map操作中高效处理空数组
php源码怎么看淘宝客系统_看php源码淘宝客系统技巧
铁路12306的积分有效期是多久_铁路12306积分有效期说明
漫蛙2在线漫画入口 漫蛙正版漫画网页版直达
12306选座怎么选到临时改签座_12306改签选座策略与步骤
C#使用XPath查询节点时出错? 常见语法错误与调试技巧
正确连接J*aScript到HTML实现可点击图片与自定义事件处理
如何高效处理PHP中的Excel数据导入导出?PortPHP/Spreadsheet助你轻松搞定!
Go与Ruby之间实现AES加密互通:CFB模式下的密钥长度匹配策略
C++ typeid如何获取类型信息_C++ RTTI运行时类型识别用法
深入理解J*a合成构造器:何时以及为何阻止其生成
Gmail邮箱申请注册直达_Gmail邮箱免费注册PC版官网入口2025
12306选座如何查看座位示意图_12306座位示意图解读与使用
TypeScript/J*aScript:高效查找数组中首个唯一ID对象
J*aScript DOM操作:高效清空列表元素的策略与实践
Django模型中自动计算可用余额的实现方法
如何为你的Composer包编写自动化测试_集成PHPUnit到Composer的scripts工作流
CSS布局中意外空白:解决padding-top导致的顶部间距问题
必由学官方网站入口 必由学学生教师共用登录通道
腾讯视频怎么使用多账号家庭管理_腾讯视频家庭多账号统一管理与权限分配教程
Mac怎么使用表情符号_Mac Emoji快捷键面板
将HTML动态表格多行数据保存到Google Sheet的教程
Lar*el 递归关系中排除指定分支的教程
excel如何生成目录 excel一键生成工作表目录超链接
单12V-2×6实现为RTX 5090供电750W!甚至都没敢跑分
TikTok评论显示延迟如何处理 TikTok评论刷新优化方法
Go语言中Map存储的结构体如何调用指针方法:深入解析与实践
必由学官方登录入口 必由学教师学生账号快速访问
J*aScript Promise链中如何正确终止后续.then执行并处理错误
yandex入口引擎手机版 yandex安卓版下载入口
QQ邮箱官方网页版登录 QQ邮箱个人邮箱快速访问
小米14应用无法联网原因分析_小米14网络权限修复
J*a如何使用AtomicInteger控制计数_J*a无锁计数器性能分析
在J*a中如何使用BigDecimal进行高精度计算_BigDecimal类应用指南
蛙漫限时开放最深处链接_蛙漫全站漫画会员同款秒开地址
AI泡沫首次被“刺破”:GPU十年都无法存活!
php源码怎么在电脑上测试_电脑测试php源码方法步骤【教程】
漫蛙网页登录入口 漫蛙漫画官方授权网址
极兔快递快件信息查询系统 极兔快递官网运单号追踪
Linux如何构建多环境配置管理_Linux多环境配置方案
韩小圈电脑版在线入口_网页版免费登录地址
Python实现多节点属性重叠度分析教程
必由学官网入口 必由学教师登录入口
内存检查:在VS Code中调试C++时的内存视图
sublime怎么进行远程开发编辑_配置rsub/rmate实现sublime编辑服务器文件


2025-12-08
浏览次数:次
返回列表
create_food(snake, box) # 吃到食物,生成新食物
else:
# 未吃到食物,移除蛇尾并清除其显示
tail = snake.pop()
w.addch(tail[0], tail[1], ' ')
# 绘制食物
# create_food函数保证了food在绘制前不会是None
w.addch(food[0], food[1], curses.ACS_PI)
# 绘制新蛇头
w.addch(snake[0][0], snake[0][1], '*')
# 游戏结束条件:撞墙或撞到自己
if (
snake[0][0] in [box[0], box[1]] or # 撞到上下墙
snake[0][1] in [box[2], box[3]] or # 撞到左右墙
snake[0] in snake[1:] # 撞到自己
):
break # 退出游戏循环
w.refresh() # 刷新屏幕显示
# 游戏结束,显示"Game Over"
w.addstr(sh // 2, sw // 2 - 5, "GAME OVER!")
w.refresh()
w.getch() # 等待用户按键后退出
curses.wrapper(main)