import { constructors } from '../core/library.js';
import { mergeOver, pushUnique, λnull, isa_fn } from '../core/utilities.js';
import { requestVector, releaseVector } from './vector.js';
import baseMix from '../mixin/base.js';The Scrawl-canvas particle physics engine is a simple system designed to allow developers a way to add particle-based effects to their canvas animation scenes. The physics engine is built on top of the following components:
We do not have to handle particle generation and manipulation ourselves. Instead, Scrawl-canvas gives us three dedicated entitys which we use to add particle animation effects to the canvas scene. These entitys are:
The Scrawl-canvas particle physics engine system is based on a fairly classical understanding of particle kinetics (applying forces and constraints to a small, spherical object in 3D space) and kinematics (the movement of the small object in response to the forces and constraints applied to it).
A Scrawl-canvas Force object is, essentially, a wrapper around an action function which calculates a force operating on a particle. The force object must have a unique name. Also …
The action function must accept three arguments, in the following order:
The function must add the result of its calculation to the Particle object’s load Vector.
… See the gravity force, below, for an example of how to construct a Force object.
The Force factory uses the Base mixin, thus Force objects can be cloned and killed like other Scrawl-canvas objects. Force objects are stored in the scrawl.library.force section of the Scrawl-canvas library object.
import { constructors } from '../core/library.js';
import { mergeOver, pushUnique, λnull, isa_fn } from '../core/utilities.js';
import { requestVector, releaseVector } from './vector.js';
import baseMix from '../mixin/base.js';const Force = function (items = {}) {
this.makeName(items.name);
this.register();
this.set(this.defs);
this.set(items);
if (!this.action) this.action = λnull;
return this;
};let P = Force.prototype = Object.create(Object.prototype);
P.type = 'Force';
P.lib = 'force';
P.isArtefact = false;
P.isAsset = false;P = baseMix(P);let defaultAttributes = {
action: null,
};
P.defs = mergeOver(P.defs, defaultAttributes);P.packetFunctions = pushUnique(P.packetFunctions, ['action']);P.kill = function () {
this.deregister();
return true;
};let S = P.setters;
S.action = function (item) {
if (isa_fn(item)) this.action = item;
else this.action = λnull;
}let myRepellorBall = scrawl.makeWheel({
name: 'big-ball',
radius: 30,
});
scrawl.makeForce({
name: 'example-repellor',
action: (particle, world, host) => {
let {load, position} = particle;
let ballPosition = myRepellorBall.get('position');
let tempVector = scrawl.requestVector(ballPosition).vectorSubtract(position);
let magnitude = tempVector.getMagnitude();
if (magnitude && magnitude < myRepellorBall.get('radius')) {
tempVector.scalarMultiply(1 / (magnitude / 1000));
load.vectorSubtract(tempVector)
}
scrawl.releaseVector(tempVector);
},
});
const makeForce = function (items) {
return new Force(items);
};
constructors.Force = Force;
makeForce({
name: 'gravity',
action: (particle, world, host) => {
let {mass, load} = particle;
let c = requestVector();
c.setFromVector(world.gravity).scalarMultiply(mass);
load.vectorAdd(c);
releaseVector(c);
},
});export {
makeForce,
};