Love2D中Ended状态出现Attempt to index a nil value错误的原因排查
问题成因分析
你遇到的“Attempt to index a nil value”错误,核心原因是状态切换时循环未中断,导致后续循环步骤访问已被清空的按钮数组,具体拆解如下:
1. 错误触发的完整流程
当你在ended状态点击按钮(i=1或i=2)时:
- 执行
_stateMachine:change(gstates.run/menu),进入状态机的change方法 - 状态机先调用当前状态(
ended)的exit方法,而ended:exit()里执行了self.buttons = {},直接清空了按钮数组 - 但此时
ended:update的循环还没走完:比如原来self.buttons有2个元素,循环i=1时触发状态切换,清空数组后,循环会继续执行i=2,此时self.buttons[2]已经是nil,调用:detect(dt)自然会报错“索引nil值”
2. 为什么run状态没报错?
看run的代码:
- i=1时只是修改
self.buttons[i].waitAnimEnded = false,没有触发状态切换,循环正常走完 - i=2时触发
change(gstates.ended),此时run:exit()清空self.buttons,但这已经是循环的最后一次迭代(i=2),清空后没有后续循环步骤要访问按钮数组,所以不会触发错误
3. 你加的判断为什么能解决问题?
你加的if not(#self.buttons == 0)其实是利用了“状态切换后按钮数组被清空,长度变为0”的特性:
当循环走到i=2时,#self.buttons已经是0,判断条件不成立,跳过了访问self.buttons[i]的代码,避免了nil索引错误。不过这个写法其实有点冗余——如果数组真的是空的,外层的for i=1, #self.buttons根本不会执行循环。真正起作用的是,状态切换后数组长度变为0,后续循环迭代里的判断会跳过危险代码。
更合理的修复方式
相比加这个判断,更直接的做法是触发状态切换后立刻中断循环,避免继续执行后续迭代:
function m:update(dt, _stateMachine) for i = 1, #self.buttons do self.buttons[i]:detect(dt) if self.buttons[i].waitAnimEnded == true then if i == 1 then _stateMachine:change(gstates.run) elseif i == 2 then _stateMachine:change(gstates.menu) end break -- 触发状态切换后直接跳出循环,不再执行后续迭代 end end end
这样状态切换后循环立刻停止,不会再去访问已经被清空的按钮数组,从根源上避免错误。
内容的提问来源于stack exchange,提问作者SpinRoleDevelop
相关产品推荐
相关产品推荐

