agentscape
Version:
Agentscape is a library for creating agent-based simulations. It provides a simple API for defining agents and their behavior, and for defining the environment in which the agents interact. Agentscape is designed to be flexible and extensible, allowing
79 lines • 3.2 kB
JavaScript
import Vector2 from '../numbers/Vector2';
import Agent from './Agent';
export default class Particle extends Agent {
constructor(opts) {
super(opts);
this.metabolism = 0;
this.acceleration = new Vector2([0, 0]);
this.velocity = new Vector2(opts.initialVelocity);
this.mass = opts.mass || 1;
}
get kineticEnergy() {
return 0.5 * this.mass * this.velocity.magnitude ** 2;
}
get momentum() {
return this.velocity.scale(this.mass);
}
/**
* Applies an acceleration to the particle proportionate to the net gravitational attraction of all other particles in the given set.
*/
resolveGravitation(world, particles) {
this.acceleration = new Vector2([0, 0]);
particles.forEach((other) => {
this.resolveGravitationPair(world, other);
});
}
resolveCollisions(world, particles, options = { particle: true }) {
if (world.boundaryCondition === 'finite') {
this.resolveBoundaryCollision(world);
}
if (options.particle) {
particles.forEach((neighbor) => {
this.resolveParticleCollision(neighbor);
});
}
}
resolveParticleCollision(other) {
if (this.id === other.id) {
return;
}
const nextPosition = this.position.add(this.velocity);
const otherNextPosition = other.position.add(other.velocity);
const distance = nextPosition.subtract(otherNextPosition).magnitude;
if (distance < (this.radius / 2) + (other.radius / 2)) {
const normal = this.position.subtract(other.position).normal;
const relativeVelocity = this.velocity.subtract(other.velocity);
const impulse = (2 * this.mass * other.mass) / (this.mass + other.mass) * relativeVelocity.dot(normal);
this.velocity = this.velocity.subtract(normal.scale(impulse / this.mass));
other.velocity = other.velocity.add(normal.scale(impulse / other.mass));
}
}
resolveBoundaryCollision(world) {
if (this.position.x - this.radius < 0) {
this.position.x = this.radius;
this.velocity.x *= -1;
}
else if (this.position.x + this.radius >= world.width) {
this.position.x = world.width - this.radius;
this.velocity.x *= -1;
}
if (this.position.y - this.radius < 0) {
this.position.y = this.radius;
this.velocity.y *= -1;
}
else if (this.position.y + this.radius >= world.height) {
this.position.y = world.height - this.radius;
this.velocity.y *= -1;
}
}
resolveGravitationPair(world, other) {
if (this.id === other.id) {
return;
}
const dxy = this.position.subtract(other.position);
const force = dxy.scale(-1e-4 * this.mass * other.mass / this.distanceTo(world, other) ** 2);
this.acceleration = this.acceleration.add(force.scale(1 / this.mass));
other.acceleration = other.acceleration.subtract(force.scale(1 / other.mass).scale(-1));
}
}
//# sourceMappingURL=Particle.js.map