{
const { shapeType, tileZone, textRotate, textScale } = params;
const words = 'Here is a bunch of words ...';
const sim = new AA.Simulation({
width: 850,
height: 600,
gridStep: 50,
state: { chars: 0 },
beforeTick: () => {
if (AA.random.uniform_01() < 1 / 30 && sim.actors.size < 8) addCar();
if (sim.tickIndex % 10 === 0) {
sim.state.chars = (sim.state.chars + 1) % (words.length + 1);
}
}
}).vis({
background: true,
image: 'road.png',
tile: true,
});
invalidation.then(() => sim.end());
sim.squares.forEach(sq => sq.state = null);
[
[ 8, 2, 'top' ],
[ 12, 2, 'top-right' ],
[ 12, 5, 'right' ],
[ 12, 9, 'bottom-right' ],
[ 8, 9, 'bottom' ],
[ 4, 9, 'bottom-left' ],
[ 4, 5, 'left' ],
[ 4, 2, 'top-left' ]
].forEach(([xIndex, yIndex, textPosition]) => {
const sq = sim.squareAt(xIndex, yIndex);
sq.zIndex = -Infinity;
sq.vis({
tint: shapeType === 'image' ? 0xffffff : AV.colors.pink,
image: shapeType === 'image'
? (() => sim.frame(360, 2) ? 'corn.png' : 'grass-dark.png')
: null,
advanced: shapeType === 'advanced',
fontSize: 12,
textPosition,
textAlign: getAlign(textPosition),
text: textPosition.replace('-', '-\n'),
textTint: () => sim.frame(360, 2) ? 0xffffff : 0x0,
textPadding: 4
});
});
// zones
[
{ indexLimits: [ 7, 9, 5, 6], textPosition: 'center' },
{ indexLimits: [ 7, 9, 0, 0], textPosition: 'top' },
{ indexLimits: [15, 16, 0, 1], textPosition: 'top-right' },
{ indexLimits: [16, 16, 5, 6], textPosition: 'right' },
{ indexLimits: [15, 16, 10, 11], textPosition: 'bottom-right' },
{ indexLimits: [ 7, 9, 11, 11], textPosition: 'bottom' },
{ indexLimits: [ 0, 1, 10, 11], textPosition: 'bottom-left' },
{ indexLimits: [ 0, 0, 5, 6], textPosition: 'left' },
{ indexLimits: [ 0, 1, 0, 1], textPosition: 'top-left' }
].forEach(({indexLimits, textPosition}) => {
new AA.Zone({indexLimits})
.vis({
tint: shapeType === 'image' ? 0xffffff : AV.colors.kiwi,
image: shapeType === 'image'
? (() => sim.frame(360, 2) ? 'pumpkin.png' : 'grass-light.png')
: null,
advanced: shapeType === 'advanced',
tile: tileZone,
textPosition,
textAlign: getAlign(textPosition),
fontSize: 14,
text: () => words.slice(0, sim.state.chars) + '|',
textTint: () => sim.frame(360, 2) ? 0xffffff : 0x0,
textPadding: 4
})
.addTo(sim);
});
// paths to goal
const goal = [...sim.zones][4];
const obstacles =
sim.zones
.difference([goal])
.union(sim.squares.filter(sq => !Number.isNaN(sq.zIndex)));
const paths = sim.paths([['goal', goal]], [[obstacles, Infinity]]).get('goal');
// cars
const carColors = ['aqua', 'green', 'purple', 'blue', 'orange', 'pink', 'red', 'olive'];
function addCar() {
sim.populate({
n: 1,
radius: 12,
random: true,
padding: 10,
exclude: [...obstacles, goal, ...sim.actors],
setup: ac => {
ac.maxSpeed = 3;
ac.maxForce = 0.15;
ac.updateRadius = function() { return this.radius + 0.05 };
ac.steer.set(goal, { behavior: 'go', target: goal, paths });
ac.updateState = function() {
if (this.isOverlapping(goal)) this.remove();
};
ac.vis({
tint: shapeType === 'image' ? 0xffffff : AV.colors.orange,
image: shapeType === 'image'
? `bubble-car-${carColors[AA.random.int(8)()]}.png`
: null,
advanced: shapeType === 'advanced',
textTint: 0xffffff,
fontSize: textScale ? 12 : () => 12,
text: ac => Math.round(ac.radius),
textRotate
});
}
});
}
addCar();
// obstacles repel cars, cars also avoid obstacles
sim.interaction.set('obstacles-repel-cars', {
group1: obstacles,
group2: sim.actors,
behavior: 'repel',
strength: 7,
off: 10
});
sim.interaction.set('cars-avoid-obstacles', {
group1: obstacles,
group2: sim.actors,
behavior: 'avoid',
strength: 3,
off: 20,
});
// cars repel each other
sim.interaction.set('cars-repel-cars', {
group1: sim.actors,
behavior: 'repel',
strength: 3,
off: 30,
});
// vis
function getAlign(textPosition) {
if (textPosition.includes('left')) return 'left';
if (textPosition.includes('right')) return 'right';
return 'center';
}
let otherText;
return AV.visObs(sim, {
images: [
'https://cdn.jsdelivr.net/gh/gjmcn/sprites/bitmap-fonts-96/swansea.xml',
'https://cdn.jsdelivr.net/gh/gjmcn/sprites/sprite-sheets/outside.json',
'https://cdn.jsdelivr.net/gh/gjmcn/sprites/sprite-sheets/bubble-cars.json'
],
fontName: 'Swansea',
afterSetup: (sim, app) => {
otherText = AV.text('', 225, 15, {
fontName: 'Swansea',
fontSize: 14,
tint: 0xffffff,
yAnchor: 0,
maxWidth: 150
});
app.stage.addChild(otherText);
},
afterTick: () => otherText.text = sim.frame(360, 2)
? '... that does not belong to an agent.'
: 'Some other text ...'
});
}