Допустим, у нас есть следующий рабочий процесс Agents.jl + Mak ie .jl:
using Agents, Random, AgentsPlots, Makie, Observables
mutable struct BallAgent <: AbstractAgent
id::Int
pos::Tuple{Float64, Float64}
vel::Tuple{Float64, Float64}
mass::Float64
end
function ball_model(; speed = 0.002)
space2d = ContinuousSpace(2; periodic = true, extend = (1, 1))
model = AgentBasedModel(BallAgent, space2d, properties = Dict(:dt => 1e0, :i => Observable(0)))
Random.seed!(1001)
for ind ∈ 1:500
pos = Tuple(rand(Float64, 2))
vel = (sincos(rand(Float64) * 2π) |> reverse) .* speed
add_agent!(pos, model, vel, 1e0)
end
index!(model)
return model
end
agent_step!(agent::BallAgent, model) = move_agent!(agent, model, model.dt)
function AbstractPlotting.:plot!(scene::AbstractPlotting.Plot(AgentBasedModel))
ab_model = scene[1][]
position = Observable([a.pos for a ∈ allagents(ab_model)])
on(ab_model.i) do i
position[] = [a.pos for a ∈ allagents(ab_model)]
end
scatter!(scene, position, markersize = 0.01)
end
function create_animation()
model = ball_model()
scene = plot(model)
display(AbstractPlotting.PlotDisplay(), scene)
for i ∈ 1:600
Agents.step!(model, agent_step!, 1)
model.i[] = i
sleep(1/60)
end
end
Теперь, так как AgentsPlot.jl не поддерживает Mak ie, я должен сделать рецепт для этого и в настоящее время я обновляю график путем регистрации обратного вызова, который обновляет наблюдаемые позиции, которые передаются в разброс.
Дело в том, что я регистрирую этот обратный вызов в наблюдаемой Int, которая присоединена к AgentBasedModel, которая создана специально для этого. Это просто кажется уродливым способом go об этом.
model = AgentBasedModel(BallAgent, space2d, properties = Dict(:dt => 1e0, :i => Observable(0)))
i - это наблюдаемая вещь, к которой мы прикрепляем обратный вызов, например:
on(ab_model.i) do i
position[] = [a.pos for a ∈ allagents(ab_model)]
end
, и я должен обновить это здесь, поэтому обратный вызов вызывается так:
for i ∈ 1:600
model.i[] = i