Lua表格单选逻辑异常:ComputerCraft商店NPC仅首个选项生效
问题:ComputerCraft商店NPC选项选择逻辑异常
我在Minecraft的ComputerCraft模组里开发商店NPC功能,当前函数传入三个选项,但只有第一个选项能正确终止循环。我需要实现两次选择同一选项才确认的防误触逻辑,但目前仅有第一个选项能正常更新状态。
原代码如下:
function UTOptions(opt) local FR = 0 local max = 14 local w,h = term.getSize() local check = {} while true do for i,v in ipairs(opt) do if(string.len(v)>max) then error("Option is too long.") end if (FR == 0) then check[i] = 0 end term.setCursorPos(w-15,i+2) if (check[i]== 1) then term.setTextColor(colors.red) write("*") term.setTextColor(colors.white) write(v) else write("*"..v) end end local event, side, mx, my = os.pullEvent("monitor_touch") if (check[my-2] == 0) then check[my-2] = 1 for i,v in ipairs(check) do if (v ~= my-2) then check[i] = 0 end end elseif (check[my-2]==1) then return my-2 end FR = 1 end end
我尝试修改触摸事件中的my偏移值(比如改成my-3或my-4),但只能改变生效的选项,其余选项仍无法更新。我怀疑问题出在这段代码:
for i,v in ipairs(check) do if (v ~= my-2) then check[i] = 0 end end
问题分析与修复
你找的问题点完全正确:这段循环的逻辑错误。check数组存储的是每个选项的选中状态(0未选中,1已选中),但你把数组的值v和选项索引my-2做对比,这逻辑完全不成立——v是0或1,而my-2是1、2、3这类索引值,所以条件判断完全错位,根本没起到重置其他选项的作用。
正确的逻辑是:遍历每个选项索引i,如果i不等于当前选中的选项索引my-2,就把check[i]设为0。另外还要补充清屏重绘的逻辑,否则旧的显示内容会残留,导致视觉上状态没更新。
修正后的代码:
function UTOptions(opt) local max = 14 local w,h = term.getSize() local check = {} -- 初始化所有选项为未选中状态 for i in ipairs(opt) do check[i] = 0 end while true do -- 清除选项区域的旧内容,避免残留 term.setCursorPos(w-15, 3) for _ in ipairs(opt) do write(string.rep(" ", 15)) -- 覆盖原位置内容 term.setCursorPos(w-15, term.getCursorY() + 1) end -- 重绘所有选项 for i,v in ipairs(opt) do if(string.len(v)>max) then error("Option is too long.") end term.setCursorPos(w-15, i+2) if check[i] == 1 then term.setTextColor(colors.red) write("*") term.setTextColor(colors.white) write(v) else write("*"..v) end end local event, side, mx, my = os.pullEvent("monitor_touch") local selectedIdx = my - 2 -- 检查索引是否在有效范围内 if selectedIdx < 1 or selectedIdx > #opt then goto continue -- 点击了选项外的区域,跳过处理 end if check[selectedIdx] == 0 then -- 第一次选择,标记为选中,重置其他选项 check[selectedIdx] = 1 for i in ipairs(check) do if i ~= selectedIdx then check[i] = 0 end end else -- 第二次选择同一选项,确认并返回索引 return selectedIdx end ::continue:: end end
关键修改点
- 提前初始化
check数组,去掉不必要的FR变量 - 每次循环先清除选项区域的旧内容,避免显示残留
- 修正重置其他选项的循环逻辑:对比索引
i而非数组值v - 添加索引有效性检查,防止点击选项外区域导致报错
- 使用
goto跳过无效点击的处理逻辑,代码更清晰
内容的提问来源于stack exchange,提问作者CrimboJimbo
相关产品推荐
相关产品推荐

