Day30 小乌龟应用整合篇

今天来一起看看各种小乌龟一起工作吧
Mining Turtle 我已经很熟了,可以挖矿直达地底
那拿钻石斧的 Felling Turtle 呢?
我本以为它只能砍树,实测发现它也能挖矿
而 Mining Turtle 也能砍树
所以我不太确定两者有什麽差异 @@

令我比较讶异的是,拿钻石铲的 Digging Turtle
我本以为它至少能铲土和沙子
实测却发现连铲土都无法,只能铲沙,感觉非常不实用 ><

锄头龟的作业流程

至於拿钻石锄头的 Farming Turtle
可以在其储物箱先备好植物种子和骨粉
整个种植过程的 API 呼叫如下:

  1. turtle.dig() 翻土除草
  2. turtle.place() 撒种子
  3. turtle.select(n) n 是骨粉的位置
  4. turtle.place() 撒骨粉
    这里可以用回圈判断 place 回传值,true 代表可以继续洒骨粉,false 代表作物已经长成、或是不能再用骨粉加速生长了
  5. turtle.dig() 收割作物

接下来我试着把之前学到的东西一起复习并应用

挖出楼梯通道的小乌龟

之前已介绍过,挖矿龟可以掘井挖隧道
但如果玩家想要到达地底,总不能朝着深井跳下去吧 .....
所以必须改写 /rom/programs/turtle/excavate.lua 让这支程序可以挖楼梯出来!
部分程序码如下,因为有点长,我就直接在程序码注解说明每一段的大概

在这之前,我先设置好 GPS 基地台,请参考之前的文章

-- 让玩家指定挖掘的深度,例如 mining 5 那就只会挖出深度 5 的楼梯,然後折返
local depthLimit = tonumber(tArgs[1])
if depthLimit < 1 then
    print("Depth must be positive")
    return
end

-- 目前挖掘的深度
local depth = 0
-- 吐出的东西总数
local unloaded = 0
-- 收集的东西总数
local collected = 0
local protocol = 'mining'   --  这是传讯时让监控中心分辨用的,如果是铲子龟,protocol 就是 digging,砍树龟则是 'felling'

peripheral.find("modem", rednet.open) -- 找到身上的所有 modem 後打开它
rednet.host(protocol, 'yoshi')

-- 印出讯息,同时传送到网路上给监控中心。这里用的是广播,只要有监听 protocol 都可收到
local function printThenSend(message)
    print(message)
    rednet.broadcast(message, protocol)
end

-- 把东西丢出来放到地上,这是挖掘完毕後回到地上的作业
local function unload()
    printThenSend("Unloading")
    for n = 1, 16 do
        local nCount = turtle.getItemCount(n)
        local data = turtle.getItemDetail(n)
        -- 不要把火把丢掉,可能还会再用
        if nCount > 0 and data.name ~= 'minecraft:torch' then
            turtle.select(n)
            turtle.drop()
            unloaded = unloaded + nCount
        end
    end
    collected = 0
    turtle.select(1)
end

local function collect()
    -- 收集物品。略,这部分跟原本 excavate.lua 大同小异
end


-- 从储物箱内寻找火把,然後放置在左方,放完後再转回正前方。这麽做是为了照耀通道,好让主人走下去 XD
local function placeTorch()
    for n = 1, 16 do
        local nCount = turtle.getItemCount(n)
        if nCount > 0 then
            turtle.select(n)
            local data = turtle.getItemDetail()
            if data.name == 'minecraft:torch' then
                turtle.place()
                break
            end
        end
    end
end

-- 因为我已经架设好 GPS 基地台,所以每只小乌龟只要有 Ender Modem 都可以随时取得 GPS 座标并回报
local function reportPosition(currentDepth)
    if math.fmod(currentDepth, 10) == 0 then
        local x, y, z = gps.locate(2, false)
        local msg = string.format("Depth: %s  GPS: %d %d %d", currentDepth, x, y, z)
        printThenSend(msg)
    end
end

-- @tparam boolean dig 是否边移动边挖掘? 如果 dig = false, 小乌龟只会尝试移动,不挖任何东西
local function tryForwards(dig)
    while not turtle.forward() do
        if turtle.detect() then
            if dig and turtle.dig() then
                collect()
            else
                return false
            end
        elseif turtle.attack() then
            collect()
        else
            sleep(0.5)
        end
    end

    if dig then
        -- 往前多挖一格,这样玩家才能走下去
        turtle.dig()
        -- 往左边挖一格,让走道宽一点
        turtle.turnLeft()
        turtle.dig()
        turtle.turnRight()
    else
        turtle.forward()
    end
    
    return true
end

-- @tparam boolean dig 是否边移动边挖掘? 如果 dig = false, 小乌龟只会尝试移动,不挖任何东西
local function tryDown(dig)
    while not turtle.down() do
        if turtle.detectDown() then
            if dig and turtle.digDown() then
                collect()
            else
                return false
            end
        elseif turtle.attackDown() then
            collect()
        else
            sleep(0.5)
        end
    end

    -- 挖宽两格
    if dig then
        turtle.turnLeft()
        turtle.dig()
        -- 深度每 6 格放一支火把
        if dig and (depth % 6 == 0) then
            placeTorch()
        end
        turtle.turnRight()
    end

    depth = depth + 1
    reportPosition(depth)

    return true
end

-- @tparam boolean dig 是否边移动边挖掘? 如果 dig = false, 小乌龟只会尝试移动,不挖任何东西
local function tryUp(dig)
    while not turtle.up() do
        if turtle.detectUp() then
            if dig and turtle.digUp() then
                collect()
            else
                return false
            end
        elseif turtle.attackUp() then
            collect()
        else
            sleep(0.5)
        end
    end

    depth = depth - 1
    reportPosition(depth)

    return true
end


local done = false
-- 先往下开挖,直到指定深度
while not done do
    if not tryForwards(true) or not tryDown(true) then
        done = true
        break
    end
    if depth >= depthLimit then
        break
    end

end

printThenSend("Returning")

-- 挖到指定深度後,开始回程。回转後往上走
turtle.turnLeft()
turtle.turnLeft()
done = false
while not done do
    if not tryUp(false) or not tryForwards(false) then
        done = true
        break
    end
    if depth == 0 then
        break
    end
end

unload()

上述的程序码,大约指定深度 50 ,就可以挖出这样的楼梯通道
虽然形状有点怪,还需要再优化 XD
CC: Tweaked Mining Turtle Stairs

回到地面上後,把东西都一股脑丢出来了
CC: Tweaked Mining Turtle unload

而挖掘过程中,小乌龟的萤幕显示就像这样
CC: Tweaked Mining Turtle monitor

不过,我们不可能就这样跟着小乌龟下去,它挖到哪,我们走到哪
所以这时候就需要 Ender Modem 把小乌龟状态传达给监控中心了!

设置监控小乌龟作业的中心电脑

首先我有一台有 Ender Modem 的电脑,并接上三台大萤幕
分别监控三种 protocol 讯息:mining、digging、felling
也就是挖矿龟、铲沙龟、砍树龟的作业
程序码如下

local centerMonitor = peripheral.wrap("monitor_5")
local leftMonitor = peripheral.wrap("monitor_4")
local rightMonitor = peripheral.wrap("monitor_2")

rednet.open('right')
rednet.host('monitor', 'center')    --  这台电脑的 protocol 是 monitor、名称是 center

parallel.waitForAny(
    function ()
        while true do
            local senderID, message, protocol = rednet.receive('mining')
            term.redirect(centerMonitor)
            print("Turtle ID: " .. senderID)
            print("message: " .. message)
        end
    end,
    function ()
        while true do
            local senderID, message, protocol = rednet.receive('digging')
            term.redirect(leftMonitor)
            print("Turtle ID: " .. senderID)
            print("message: " .. message)
        end
    end,
    function ()
        while true do
            local senderID, message, protocol = rednet.receive('felling')
            term.redirect(rightMonitor)
            print("Turtle ID: " .. senderID)
            print("message: " .. message)
        end
    end
)

rednet.close()

我在三个 function 间持续不断地切断,只要有收到小乌龟讯息,就把 ID 和讯息发送到萤幕上显示
这样一来,监控中心可以根据不同的 protocol 来决定显示方式
例如我把 mining 的讯息显示到正中央大萤幕
digging 讯息显示在左方萤幕,felling 讯息显示在右方萤幕
执行过程大概的画面如下
CC: Tweaked Turtles Monitor and Rednet

以上就是今天的分享了~

30 天铁人赛感言

其实在这 30 天,没办法充分花时间在游戏体验
前期花了许多时间在熟悉 Lua 语言特性和语法
後期则一直在自己探索 CC: Tweaked 模组的使用方式
所以我的程序码和范例应用其实都满简单的XD
我相信 CC: Tweaked 可以应用得非常有趣,让很多事情都全自动化了
(那主人还要干嘛 .....)

在国内几乎没有人把这模组介绍得非常详细(应该是没有)
只知道有些幼童程序语言学习的课程似乎有玩到,但没有玩得很深入
说来说去就是 Turtle,并没有从 Computer 开始的基础介绍
所以只能找国外各种范例和文章,或是自己尝试了~

感谢这三十天有追踪和阅读我文章的网友们
如果你也有玩麦块,试试看,会很有趣~


<<:  DAY 30 好用的套件

>>:  [ 卡卡 DAY 30 ] - React Native codepush iOS 热更新

[Day11] Esp32s用AP mode + LED

1.前言 讲了那麽多天的理论,现在该来让各位多动手实作啦,今天主要是会运用Esp32s内建的WiFi...

Day 28. 测试HTTP Status Code

使用SuperTest 使用SSR时,你要负责回应正确的HTTP Status Code。 因为牵涉...

那些被忽略但很好用的 Web API / MutationObserver

我的改变,你看得见! 在开发网页过程中,我们最常做的事情就是对资料进行修改後运用在 DOM 元素上...

【系统程序】2.1基本组译器功能

2.1基本组译器功能 2.1.1简易SIC组译器 组译器的两阶段处理 1.扫描原始程序中的标记,并计...

Day28 JQuery应用

JQuery的应用有非常多种,概念就是当触发条件达成时,我要做些甚麽,例如:滑鼠单击一下,隐藏的选单...