vis = {
const sim = new AA.Simulation({
width: 800,
height: 400,
gridStep: 20,
state: {eaten: [0, 0, 0]},
beforeTick: () => {
for (let food of predator.overlapping('actor')) {
sim.state.eaten[food.state.kind]++;
food.remove();
}
tp.update(plot, null);
sim.pause(sim.actors.size === 1);
}
}).vis({baseColor: 0xcfebf7});
invalidation.then(() => sim.end());
const predator = new AA.Actor({
x: 400,
y: 200,
radius: 24,
maxSpeed: 2.5,
maxForce: 0.1
}).vis({
image: 'fish.png',
tint: 0x333333
})
.addTo(sim);
predator.steer.set('seek-prey', {
target: () => predator.nearest(1, null, 'actor')[0],
behavior: 'seek'
});
const nPrey = 120;
sim.populate({
n: nPrey,
radius: 9,
random: true,
exclude: [predator],
setup: (ac, i) => {
ac.maxSpeed = 1 + (i % 3) * 0.4;
ac.wrap = true;
ac.state.kind = i % 3;
ac.label('prey', true);
ac.steer.set('flee-predator', {
target: predator,
behavior: 'flee',
off: 40
});
ac.steer.set('wander', {
behavior: 'wander',
wanderStrength: 0.03,
wanderRate: 0.003
});
ac.vis({
image: 'fish.png',
tint: AV.colors[ac.state.kind]
})
}
});
// boundary repels predator
sim.interaction.set('boundary-repel', {
group1: sim,
group2: [predator],
behavior: 'repel',
strength: 3
});
// prey avoid each other
sim.interaction.set('prey-avoid', {
group1: sim.withLabel('prey'),
behavior: 'avoid',
});
// visualise simulation
const visDiv = AV.visObs(sim, {
images: ['https://cdn.jsdelivr.net/gh/gjmcn/sprites/sprite-sheets/shapes.json'],
});
// bar chart
const plot = tp.hBar({
data: [0, 0, 0],
x: (d, i, s) => sim.state.eaten[i],
y: (d, i) => i,
fillScheme: tp.cat,
fill: (d, i) => i,
duration: 200
})
.option({
width: 800,
height: 90,
limits: [0, 40, -0.6, 2.6],
yClean: true
})
.plot(visDiv);
return visDiv;
}