1.19.2 Fabric版ComputerCraft协程无法控制海龟移动问题
问题分析与解决
核心问题
你的代码存在两个关键问题,导致turtle.turnLeft()执行后程序卡住:
- 主循环被阻塞:
listen()里的rednet.receive()是无超时的阻塞调用,会一直等待消息,协程启动后,主循环无法继续调度协程完成后续操作。 - 协程未主动让出控制权:
round()函数一次性执行所有海龟操作,没有插入coroutine.yield()让协程暂停并返回主循环,哪怕主循环不阻塞,协程也会一直占用执行权,无法响应新指令。
另外还有个细节问题:downCo和upCo里的local status = 'Done'是局部变量,会覆盖全局的status,导致外部无法获取正确的任务状态。
修复方案
1. 让消息接收非阻塞
给rednet.receive()添加超时参数,比如rednet.receive(0.1),这样主循环会每隔0.1秒检查一次消息,不会一直卡住。
2. 协程主动让出执行权
在round()的每个海龟操作后(或关键节点)加入coroutine.yield(),让协程执行一步就暂停,返回主循环处理消息,下次循环再继续执行剩余步骤。
3. 调整主循环逻辑
主循环需要同时处理消息和推进协程,而不是只有收到消息才恢复协程。
修改后的完整代码
rednet.open('right') local status = 'None' io.output(io.stdout) io.input(io.stdin) io.write('Control Panel ID: ') local baseId = tonumber(io.read()) io.write('Blocks: ') local blcks = tonumber(io.read()) function round() turtle.dig() coroutine.yield() -- 让出控制权,返回主循环 turtle.turnLeft() coroutine.yield() turtle.dig() coroutine.yield() turtle.forward() coroutine.yield() turtle.turnRight() coroutine.yield() turtle.dig() coroutine.yield() turtle.digDown() coroutine.yield() turtle.down() coroutine.yield() turtle.dig() coroutine.yield() turtle.turnRight() coroutine.yield() turtle.dig() coroutine.yield() turtle.forward() coroutine.yield() turtle.turnLeft() coroutine.yield() turtle.dig() coroutine.yield() sleep(0.2) end function listen() -- 带超时的非阻塞消息接收 local id, message = rednet.receive(0.1) if id and message then if message == 'down' then print('Down!') -- 仅当协程未结束时恢复执行 if coroutine.status(downCo) ~= 'dead' then coroutine.resume(downCo, blcks) end elseif message == 'up' then print('Up!') if coroutine.status(upCo) ~= 'dead' then coroutine.resume(upCo, blcks) end elseif message == 'refuel' then turtle.refuel() elseif message == 'status' then rednet.send(baseId, status) elseif message == 'stop' then print('Stopping!') -- 重置协程,支持下次重新启动任务 downCo = coroutine.create(function(blcks) local a = 0 print('Going down! '..blcks) status = 'Going down' while a <= blcks do a = a + 1 round() end status = 'Done' end) upCo = coroutine.create(function(blcks) status = 'Going up' for i = blcks,1,-1 do turtle.digUp() coroutine.yield() turtle.up() coroutine.yield() end status = 'Done' end) elseif message == 'fuel' then rednet.send(baseId, turtle.getFuelLevel()) end end end downCo = coroutine.create(function(blcks) local a = 0 print('Going down! '..blcks) status = 'Going down' while a <= blcks do a = a + 1 round() end status = 'Done' -- 去掉local,修改全局状态变量 end) upCo = coroutine.create(function(blcks) status = 'Going up' for i = blcks,1,-1 do turtle.digUp() coroutine.yield() turtle.up() coroutine.yield() end status = 'Done' -- 去掉local end) while true do listen() -- 推进采矿协程(如果处于暂停状态) if coroutine.status(downCo) == 'suspended' then local success, err = coroutine.resume(downCo) if not success then print('Down coroutine error: '..err) end end -- 推进上升协程(如果处于暂停状态) if coroutine.status(upCo) == 'suspended' then local success, err = coroutine.resume(upCo) if not success then print('Up coroutine error: '..err) end end end
额外说明
- 加入了协程错误捕获:
coroutine.resume()返回的第一个值表示执行是否成功,第二个值是错误信息,方便排查问题。 stop指令里重置了协程,确保下次可以重新启动采矿任务。- 每个海龟操作后都加入了
coroutine.yield(),既保证主循环能及时处理新指令,也让协程可以逐步完成采矿流程。
内容的提问来源于stack exchange,提问作者MDdiamond
相关产品推荐
相关产品推荐

