import * as scrawl from '../source/scrawl.js';import * as scrawl from '../source/scrawl.js';@ts-expect-error
import rapier from "https://cdn.skypack.dev/@dimforge/rapier2d-compat";
import { reportSpeed } from './utilities.js';We are using a 600px x 600px canvas
const unit = 60,
halfUnit = unit / 2,
thirdUnit = unit / 3,
sixthUnit = unit / 6,
rows = 10,
cols = 10,
width = 600,
height = 600;const artefacts = scrawl.library.artefact;
const canvas = artefacts.mycanvas;Keep the dynamic boxes in their own group (for drag-and-drop functionality later)
let boxesGroup = scrawl.makeGroup({
name: "boxes-group",
host: canvas.base.name
});let ground = scrawl.makeBlock({
name: "my-ground",
dimensions: [600, 40],
start: [300, 580],
handle: ["center", "center"],
fillStyle: "green",
method: "fill"
});A color generator to make our dynamic boxes look pretty
let colorMaker = scrawl.makeColor({
name: "box-color-fill-generator",
maximumColor: "orange",
minimumColor: "brown"
});Build dynamic boxes
for (let y = 0; y < rows; y++) {
for (let x = 0; x < cols; x++) {
scrawl.makeBlock({
name: `block-${y}-${x}`,
group: "boxes-group",
startX: halfUnit + x * unit,
startY: -sixthUnit + y * unit,
handle: ["center", "center"],
width: thirdUnit + Math.ceil(Math.random() * halfUnit),
height: thirdUnit + Math.ceil(Math.random() * halfUnit),
fillStyle: colorMaker.getRangeColor(Math.random()),
method: "fillThenDraw"
});
}
}const boxes = [],
boxnames = [...boxesGroup.artefacts],
rad = scrawl.library.radian;Function to automate rigid body generation from Scrawl-canvas Block entitys
const createBodyFromBlock = function (world, block, density = 1, isStatic = false ) {
let tempx = block.get("startX") / unit,
tempy = (height - block.get("startY")) / unit,
tempw = block.get("width") / unit,
temph = block.get("height") / unit;
let rbDesc, colDesc, rigidBody;
let bodyType = isStatic
? rapier.RigidBodyType.Static
: rapier.RigidBodyType.Dynamic;
rbDesc = new rapier.RigidBodyDesc(bodyType);
rbDesc.setTranslation(tempx, tempy);
rigidBody = world.createRigidBody(rbDesc);
colDesc = rapier.ColliderDesc.cuboid(tempw / 2, temph / 2);
world.createCollider(colDesc, rigidBody.handle);
return rigidBody;
};Function to update Scrawl-canvas entitys with Rapier rigid body position/rotation data
const updatePosition = function (box) {
let { entity, body } = box;
let { x, y } = body.translation();
let r = -body.rotation() / rad;
let sx = x * unit,
sy = y * unit;
sy = height - sy;
entity.set({
startX: sx,
startY: sy,
roll: r
});
};Flag to run/halt the physics simulation
let isRunning = false;Initialize Rapier (involves web assembly, thus asynchronous)
rapier.init()
.then(() => {
let tempx, tempy, tempw, temph;Create the world, with added gravity
let gravity = new rapier.Vector2(0.0, -9.8),
world = new rapier.World(gravity);Create rigid body for static ground entity
createBodyFromBlock(world, ground, null, true);Create dynamic rigid-bodies for the other boxes
boxnames.forEach((name) => {
let ent = artefacts[name];
if (ent) {
boxes.push({
entity: ent,
body: createBodyFromBlock(world, ent, 2)
});
}
});Simulation loop
const physicsLoop = () => {
if (isRunning) {
world.step();
boxes.forEach(b => updatePosition(b));
}
};Add the simulation loop to our Scrawl-canvas animation object
animation.set({
commence: physicsLoop,
});
})
.catch(e => console.log(e));Function to display frames-per-second data, and other information relevant to the demo
const report = reportSpeed('#reportmessage');Create the Display cycle animation
const animation = scrawl.makeRender({
name: "demo-animation",
target: canvas,
afterShow: report
});const runButton = document.querySelector("#run"),
haltButton = document.querySelector("#halt");
scrawl.addNativeListener("click", e => {
runButton.setAttribute("disabled", "disabled");
haltButton.removeAttribute("disabled");
isRunning = true;
}, runButton);
scrawl.addNativeListener("click", e => {
runButton.removeAttribute("disabled");
haltButton.setAttribute("disabled", "disabled");
isRunning = false;
}, haltButton);console.log(scrawl.library);