ct

Agent

Agent 定义了一个智能体的工作流程和基本属性,支持智能体的行为控制和任务执行。Agent 作为基类主要起到模板作用,方便用户添加其他类型的智能体。

local agent = Agent()

属性

agent 中定义的属性并非所有智能体都会用到(如 speedmodel),用户可以根据自己的需求进行扩展。

函数

Agent 中的函数主要是管理智能体任务和状态的函数。

原生函数

原生函数是指 Microcity 三维模型中直接可用的函数。这里只列出了其中的一部分。

由于 Agent 已经将三维模型存储在 model 变量中,因此对 agent 直接调用 agent:setpos() 和 agent:delete() 等函数不会起作用。假设 agent.model 中存储了一个三维模型,则需要调用 agent.model:setpos() 和 agent.model:delete() 才能达到预期的效果。

考虑到 Agent 作为基类,子类模型可能更加复杂(例如,可能存在多个部分,此时 agent.model 可能为一个列表)。在这种情况下,如果想要直接对 agent 调用这些函数(例如 agent:setpos() 和 agent:delete()),需要在子类中根据具体的结构重写这些函数。

setpos

设置智能体三维模型的位置。

agent:setpos(x, y, z)

delete

删除智能体的模型

agent:delete()

任务相关函数

addtask

将任务添加到任务队列。成功添加后将智能体的状态设为 running。

agent:addtask(name, params)

添加任务流程

graph
addtask(添加任务 addtask)
not_idle(检查状态)
invoke(协程立即唤醒 agent.execute)
running(state == 'running')
execute(执行任务...)

addtask-->not_idle-->|state=='idle'|running-->|coroutine.queue|invoke-->execute
not_idle-->|state!='idle'|execute

deltask

删除任务队列中的首个任务。 成功删除后根据任务队列是否为空,将智能体的状态设为 idle 或 running。

agent:deltask()

删除任务流程

graph
deltask(删除任务)
invoke(协程立即唤醒 agent.execute)
execute_next(执行下一个任务...)
idle(agent.state=='idle')
has_task(判断是否还有任务)

deltask-->has_task-->|没有其他任务|idle
has_task-->|还有任务|invoke-->execute_next

execute

执行智能体的当前任务(任务队列中的首个任务)。一般不需要手动调用。

agent:execute()

agent:execute() 函数定期被协程唤醒调用,用于执行 agent 的任务。当被调用时,execute() 会根据任务开始时间和当前时间得到一个时间差 dt,然后将 dt 输入到任务的 execute 函数中,以更新 agent 的状态。

当任务被执行时,agent:execute() 会检查任务是否初始化,如果没有初始化则调用任务的 init 函数进行初始化。初始化完成后,agent:execute() 会调用任务的 execute 函数,将 dt 传入任务中,以推进任务的执行。

一般来说,任务的 init 部分会计算当前任务需要花费的时间,并通过协程在结束时间唤醒 agent.execute() 函数;任务的 execute 部分会根据 dt 更新 agent 的状态,并判断当前时间点任务是否完成。如果任务完成,则调用 agent:deltask() 删除任务.

执行任务流程

graph
invoke(协程唤醒agent.execute)
get_task(获取任务)
init(任务初始化检查)
execute(执行task.execute)
verify_dt(推进时间验证)
exit(退出)

subgraph agent.init
  init_params(初始化参数)
  nail(预定结束时刻唤醒)
end

invoke-->|有任务|get_task-->init-->|已初始化|execute-->verify_dt-->exit
invoke-->|无任务|exit
init-->|未初始化|init_params-->nail-->execute

任务

任务相关变量

任务推进

任务相关变量

tasks 表结构

属性

agent.state: 标记 agent 的状态,有 idlerunning 两种状态。用于检测 agent 是否正在执行任务。

任务管理流程

graph
addtask(添加任务 addtask)
execute(执行任务...)
deltask(删除任务 deltask)
invoke(协程唤醒 agent.execute)
running(设为运行状态 running)
idle(设为空闲状态 idle)

addtask-->running-->|等待刷新|invoke
invoke-->execute -->deltask
deltask-->|有任务|invoke
deltask-->|无任务|idle

任务示例

agent 默认添加了一个 move2 任务,带有 init 和 execute 部分,可以作为添加其他任务的参考。

agent.lua 中的 move2 任务:

-- params = {x, y, z, ...}
agent.tasks.move2 = {
    init = function(params)
        print('init move2 at', coroutine.qtime())
        local px, py, pz = agent.model:getpos()
        agent.lastpos = {px, py, pz}
        params.est, params.delta, params.vecE = {}, {}, {}

        -- 计算坐标
        for i = 1, 3 do
            params.delta[i] = params[i] - agent.lastpos[i]
            params.vecE[i] = params.delta[i] == 0 and 0 or params.delta[i] / math.abs(params.delta[i])
            params.est[i] = params.delta[i] == 0 and 0 or math.abs(params.delta[i]) / agent.speed[i]
        end
        params.dt = math.max(table.unpack(params.est)) -- 任务所需时间

        params.init = true -- 标记完成初始化
        coroutine.queue(params.dt, agent.execute, agent) -- 结束时间唤醒execute
    end,
    execute = function(dt, params)
        -- 计算坐标
        local position = {table.unpack(agent.lastpos)}
        for i = 1, 3 do
            position[i] = dt <= params.est[i] and agent.lastpos[i] + agent.speed[i] * dt * params.vecE[i] or
                              params[i]
        end

        -- 设置位置
        agent.model:setpos(table.unpack(position))

        if dt == params.dt then
            agent.pos = position -- 更新位置
            agent:deltask() -- 删除任务
        end
    end
}