The base flocc.Environment
class (from here on, just Environment
) stores agents and runs the simulation over time.
An empty environment can be instantiated by calling: const environment = new Environment();
When instantiating an Environment
, you can pass a number of configuration options.
The torus
option specifies whether 2-dimensional spatial environments should wrap or not. If torus
is set to true
, then an agent whose x
value is set to the environment’s width + 1
will wrap around and reappear at 1
. This pattern is very common, see for example the Flocking model.
torus
defaults to true
; you have to set it to false
to override this behavior.
Passing numbers for width
and height
will set the dimensions of the environment. This is most useful for toroidal environments where agents should reappear at the opposite side when they go out of bounds.
When an environment is instantiated, the time
property is set to 0. Then, with each tick
, time
is incremented by 1.
environment.time; // = 0
environment.tick();
environment.time; // now 1
environment.tick();
environment.tick();
environment.time; // now 3
Environments are actually an extension of Agents, so they inherit all the methods that Agents have, such as .set
, .get
, .getData
, .increment
, and .decrement
. Setting data on the Environment can be a handy way of setting global-ish variables that all Agents can access.
Add an agent to the environment. Since most of the time you will want to add many agents to an environment, doing it within a for loop is most useful:
for (let i = 0; i < 100; i++) {
environment.addAgent(new Agent());
}
Remove a previously referenced agent from the environment.
const agent = new Agent();
environment.addAgent(agent);
// the environment now has 101 agents
environment.removeAgent(agent);
// the environment now has 100 agents
Returns a JavaScript array of all the agents in the environment, in the order they were added.
When .tick
is called, each agent’s rule function(s) is/are invoked. If an agent has multiple rule functions, they are all run before moving on to the next agent. After all agents’ rule functions have been invoked, any enqueued functions are run.
environment.tick(); // ticks once
An environment may tick more than once (i.e. loop through all agents and execute rules multiple times) by passing a number greater than 1.
environment.tick(10); // ticks 10 times
.tick
may also be called with a configuration object that can have keys count
(number, the same as if passing a number as the parameter), and randomizeOrder
(a boolean). If randomizeOrder
is set to true
, then the environment will loop over agents in a (pseudo-) random order, instead of the order they were added to the environment. Any enqueued rules will also be executed in a random order. If the environment uses a Terrain, then all of the terrain’s cells will also be looped over in a random order.
environment.tick({
count: 20,
randomizeOrder: true
}); // ticks 20 times in a randomized order
Pass an instance of an environment helper to provide more structure and functionality for the environment and the agents. The two current Environment
helpers are the Network and KDTree.
Returns an array of data associated with agent.get(key)
across all agents in the environment. This is a shorthand for calling environment.getAgents().map(a => a.get(key))
. It defaults to caching the result and using it for future calls within the same environment tick. However, this behavior can be turned off (for example, if agents are updating synchronously and the data should reflect this) by passing false
as a second parameter: environment.stat('synchronousKey', false)
Calling environment.memo(function() { return 'someExpensiveValue' })
will return 'someExpensiveValue'
and then cache and use that result for future calls within the same environment tick. The function that is passed as the only parameter is called only the first time .memo
is used within an environment tick, and then its return value is used for future calls, until the next environment tick.