chore: 添加第三方依赖库
This commit is contained in:
3
thirdparty/rapier.js/testbed2d/.npmignore
vendored
Normal file
3
thirdparty/rapier.js/testbed2d/.npmignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
webpack.config2d.js
|
||||
src
|
||||
*.tgz
|
||||
32
thirdparty/rapier.js/testbed2d/package.json
vendored
Normal file
32
thirdparty/rapier.js/testbed2d/package.json
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"author": "sebcrozet <developer@crozet.re>",
|
||||
"name": "rapier-testbed2d",
|
||||
"version": "0.1.0",
|
||||
"description": "JavaScript testbed for rapier.",
|
||||
"license": "Apache-2.0",
|
||||
"main": "dist/rapier-testbed2d.js",
|
||||
"scripts": {
|
||||
"build": "rimraf dist pkg && webpack",
|
||||
"start": "rimraf dist pkg && webpack serve --open --node-env development"
|
||||
},
|
||||
"dependencies": {
|
||||
"@dimforge/rapier2d": "file:../builds/rapier2d",
|
||||
"hash-wasm": "^4.12.0",
|
||||
"lil-gui": "^0.17.0",
|
||||
"pixi-viewport": "^4.37.0",
|
||||
"pixi.js": "^6.3.2",
|
||||
"seedrandom": "^3.0.5",
|
||||
"stats.js": "^0.17.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/seedrandom": "^3.0.2",
|
||||
"@types/stats.js": "^0.17.0",
|
||||
"copy-webpack-plugin": "^11.0.0",
|
||||
"rimraf": "^3.0.2",
|
||||
"ts-loader": "^9.4.1",
|
||||
"typescript": "^4.8.4",
|
||||
"webpack": "^5.74.0",
|
||||
"webpack-cli": "^4.10.0",
|
||||
"webpack-dev-server": "^4.11.1"
|
||||
}
|
||||
}
|
||||
5
thirdparty/rapier.js/testbed2d/publish.sh
vendored
Normal file
5
thirdparty/rapier.js/testbed2d/publish.sh
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
#!/bin/bash
|
||||
|
||||
npm run build
|
||||
rsync -av dist/ crozet@ssh.cluster003.hosting.ovh.net:/home/crozet/rapier/demos2d
|
||||
# rsync -av dist/Box2D_v2.3.1_min.wasm.wasm crozet@ssh.cluster003.hosting.ovh.net:/home/crozet/rapier/Box2D_v2.3.1_min.wasm.wasm
|
||||
269
thirdparty/rapier.js/testbed2d/src/Graphics.ts
vendored
Normal file
269
thirdparty/rapier.js/testbed2d/src/Graphics.ts
vendored
Normal file
@@ -0,0 +1,269 @@
|
||||
import * as PIXI from "pixi.js";
|
||||
import {Viewport} from "pixi-viewport";
|
||||
import type * as RAPIER from "@dimforge/rapier2d";
|
||||
|
||||
type RAPIER_API = typeof import("@dimforge/rapier2d");
|
||||
|
||||
const BOX_INSTANCE_INDEX = 0;
|
||||
const BALL_INSTANCE_INDEX = 1;
|
||||
|
||||
var kk = 0;
|
||||
|
||||
export class Graphics {
|
||||
coll2gfx: Map<number, PIXI.Graphics>;
|
||||
colorIndex: number;
|
||||
colorPalette: Array<number>;
|
||||
renderer: PIXI.Renderer;
|
||||
scene: PIXI.Container;
|
||||
viewport: Viewport;
|
||||
instanceGroups: Array<Array<PIXI.Graphics>>;
|
||||
lines: PIXI.Graphics;
|
||||
|
||||
constructor() {
|
||||
// High pixel Ratio make the rendering extremely slow, so we cap it.
|
||||
// const pixelRatio = window.devicePixelRatio ? Math.min(window.devicePixelRatio, 1.5) : 1;
|
||||
|
||||
this.coll2gfx = new Map();
|
||||
this.colorIndex = 0;
|
||||
this.colorPalette = [0xf3d9b1, 0x98c1d9, 0x053c5e, 0x1f7a8c];
|
||||
this.renderer = new PIXI.Renderer({
|
||||
backgroundColor: 0x292929,
|
||||
antialias: true,
|
||||
// resolution: pixelRatio,
|
||||
width: window.innerWidth,
|
||||
height: window.innerHeight,
|
||||
});
|
||||
|
||||
this.scene = new PIXI.Container();
|
||||
document.body.appendChild(this.renderer.view);
|
||||
|
||||
this.viewport = new Viewport({
|
||||
screenWidth: window.innerWidth,
|
||||
screenHeight: window.innerHeight,
|
||||
worldWidth: 1000,
|
||||
worldHeight: 1000,
|
||||
interaction: this.renderer.plugins.interaction,
|
||||
});
|
||||
|
||||
this.scene.addChild(this.viewport);
|
||||
this.viewport.drag().pinch().wheel().decelerate();
|
||||
|
||||
let me = this;
|
||||
|
||||
function onWindowResize() {
|
||||
me.renderer.resize(window.innerWidth, window.innerHeight);
|
||||
}
|
||||
|
||||
function onContextMenu(event: UIEvent) {
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
document.oncontextmenu = onContextMenu;
|
||||
document.body.oncontextmenu = onContextMenu;
|
||||
|
||||
window.addEventListener("resize", onWindowResize, false);
|
||||
|
||||
this.initInstances();
|
||||
}
|
||||
|
||||
initInstances() {
|
||||
this.instanceGroups = [];
|
||||
this.instanceGroups.push(
|
||||
this.colorPalette.map((color) => {
|
||||
let graphics = new PIXI.Graphics();
|
||||
graphics.beginFill(color);
|
||||
graphics.drawRect(-1.0, 1.0, 2.0, -2.0);
|
||||
graphics.endFill();
|
||||
return graphics;
|
||||
}),
|
||||
);
|
||||
|
||||
this.instanceGroups.push(
|
||||
this.colorPalette.map((color) => {
|
||||
let graphics = new PIXI.Graphics();
|
||||
graphics.beginFill(color);
|
||||
graphics.drawCircle(0.0, 0.0, 1.0);
|
||||
graphics.endFill();
|
||||
return graphics;
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
render(world: RAPIER.World, debugRender: Boolean) {
|
||||
kk += 1;
|
||||
|
||||
if (!this.lines) {
|
||||
this.lines = new PIXI.Graphics();
|
||||
this.viewport.addChild(this.lines);
|
||||
}
|
||||
|
||||
if (debugRender) {
|
||||
let buffers = world.debugRender();
|
||||
let vtx = buffers.vertices;
|
||||
let cls = buffers.colors;
|
||||
|
||||
this.lines.clear();
|
||||
|
||||
for (let i = 0; i < vtx.length / 4; i += 1) {
|
||||
let color = PIXI.utils.rgb2hex([
|
||||
cls[i * 8],
|
||||
cls[i * 8 + 1],
|
||||
cls[i * 8 + 2],
|
||||
]);
|
||||
this.lines.lineStyle(1.0, color, cls[i * 8 + 3], 0.5, true);
|
||||
this.lines.moveTo(vtx[i * 4], -vtx[i * 4 + 1]);
|
||||
this.lines.lineTo(vtx[i * 4 + 2], -vtx[i * 4 + 3]);
|
||||
}
|
||||
} else {
|
||||
this.lines.clear();
|
||||
}
|
||||
|
||||
this.updatePositions(world);
|
||||
this.renderer.render(this.scene);
|
||||
}
|
||||
|
||||
lookAt(pos: {zoom: number; target: {x: number; y: number}}) {
|
||||
this.viewport.setZoom(pos.zoom);
|
||||
this.viewport.moveCenter(pos.target.x, pos.target.y);
|
||||
}
|
||||
|
||||
updatePositions(world: RAPIER.World) {
|
||||
world.forEachCollider((elt) => {
|
||||
let gfx = this.coll2gfx.get(elt.handle);
|
||||
let translation = elt.translation();
|
||||
let rotation = elt.rotation();
|
||||
|
||||
if (!!gfx) {
|
||||
gfx.position.x = translation.x;
|
||||
gfx.position.y = -translation.y;
|
||||
gfx.rotation = -rotation;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.coll2gfx.forEach((gfx) => {
|
||||
this.viewport.removeChild(gfx);
|
||||
gfx.destroy();
|
||||
});
|
||||
this.coll2gfx = new Map();
|
||||
this.colorIndex = 0;
|
||||
}
|
||||
|
||||
addCollider(
|
||||
RAPIER: RAPIER_API,
|
||||
world: RAPIER.World,
|
||||
collider: RAPIER.Collider,
|
||||
) {
|
||||
let i;
|
||||
let parent = collider.parent();
|
||||
let instance;
|
||||
let graphics;
|
||||
let vertices;
|
||||
let instanceId = parent.isFixed() ? 0 : this.colorIndex + 1;
|
||||
|
||||
switch (collider.shapeType()) {
|
||||
case RAPIER.ShapeType.Cuboid:
|
||||
let hext = collider.halfExtents();
|
||||
instance = this.instanceGroups[BOX_INSTANCE_INDEX][instanceId];
|
||||
graphics = instance.clone();
|
||||
graphics.scale.x = hext.x;
|
||||
graphics.scale.y = hext.y;
|
||||
this.viewport.addChild(graphics);
|
||||
break;
|
||||
case RAPIER.ShapeType.Ball:
|
||||
let rad = collider.radius();
|
||||
instance = this.instanceGroups[BALL_INSTANCE_INDEX][instanceId];
|
||||
graphics = instance.clone();
|
||||
graphics.scale.x = rad;
|
||||
graphics.scale.y = rad;
|
||||
this.viewport.addChild(graphics);
|
||||
break;
|
||||
case RAPIER.ShapeType.Polyline:
|
||||
vertices = Array.from(collider.vertices());
|
||||
graphics = new PIXI.Graphics();
|
||||
graphics
|
||||
.lineStyle(0.2, this.colorPalette[instanceId])
|
||||
.moveTo(vertices[0], -vertices[1]);
|
||||
|
||||
for (i = 2; i < vertices.length; i += 2) {
|
||||
graphics.lineTo(vertices[i], -vertices[i + 1]);
|
||||
}
|
||||
|
||||
this.viewport.addChild(graphics);
|
||||
break;
|
||||
case RAPIER.ShapeType.HeightField:
|
||||
let heights = Array.from(collider.heightfieldHeights());
|
||||
let scale = collider.heightfieldScale();
|
||||
let step = scale.x / (heights.length - 1);
|
||||
|
||||
graphics = new PIXI.Graphics();
|
||||
graphics
|
||||
.lineStyle(0.2, this.colorPalette[instanceId])
|
||||
.moveTo(-scale.x / 2.0, -heights[0] * scale.y);
|
||||
|
||||
for (i = 1; i < heights.length; i += 1) {
|
||||
graphics.lineTo(
|
||||
-scale.x / 2.0 + i * step,
|
||||
-heights[i] * scale.y,
|
||||
);
|
||||
}
|
||||
|
||||
this.viewport.addChild(graphics);
|
||||
break;
|
||||
case RAPIER.ShapeType.ConvexPolygon:
|
||||
vertices = Array.from(collider.vertices());
|
||||
graphics = new PIXI.Graphics();
|
||||
graphics.beginFill(this.colorPalette[instanceId], 1.0);
|
||||
graphics.moveTo(vertices[0], -vertices[1]);
|
||||
|
||||
for (i = 2; i < vertices.length; i += 2) {
|
||||
graphics.lineTo(vertices[i], -vertices[i + 1]);
|
||||
}
|
||||
|
||||
this.viewport.addChild(graphics);
|
||||
break;
|
||||
case RAPIER.ShapeType.Voxels:
|
||||
graphics = new PIXI.Graphics();
|
||||
graphics.beginFill(this.colorPalette[instanceId], 1.0);
|
||||
collider.clearShapeCache();
|
||||
let shape = collider.shape as RAPIER.Voxels;
|
||||
let gridCoords = shape.data;
|
||||
let sz = shape.voxelSize;
|
||||
|
||||
for (i = 0; i < gridCoords.length; i += 2) {
|
||||
let minx = gridCoords[i] * sz.x;
|
||||
let miny = gridCoords[i + 1] * sz.y;
|
||||
let maxx = minx + sz.x;
|
||||
let maxy = miny + sz.y;
|
||||
|
||||
graphics.moveTo(minx, -miny);
|
||||
graphics.lineTo(maxx, -miny);
|
||||
graphics.lineTo(maxx, -maxy);
|
||||
graphics.lineTo(minx, -maxy);
|
||||
}
|
||||
|
||||
this.viewport.addChild(graphics);
|
||||
break;
|
||||
default:
|
||||
console.log("Unknown shape to render: ", collider.shapeType());
|
||||
return;
|
||||
}
|
||||
|
||||
let t = collider.translation();
|
||||
let r = collider.rotation();
|
||||
// dummy.position.set(t.x, t.y, t.z);
|
||||
// dummy.quaternion.set(r.x, r.y, r.z, r.w);
|
||||
// dummy.scale.set(instanceDesc.scale.x, instanceDesc.scale.y, instanceDesc.scale.z);
|
||||
// dummy.updateMatrix();
|
||||
// instance.setMatrixAt(instanceDesc.elementId, dummy.matrix);
|
||||
// instance.instanceMatrix.needsUpdate = true;
|
||||
graphics.position.x = t.x;
|
||||
graphics.position.y = -t.y;
|
||||
graphics.rotation = r;
|
||||
|
||||
this.coll2gfx.set(collider.handle, graphics);
|
||||
this.colorIndex =
|
||||
(this.colorIndex + 1) % (this.colorPalette.length - 1);
|
||||
}
|
||||
}
|
||||
113
thirdparty/rapier.js/testbed2d/src/Gui.ts
vendored
Normal file
113
thirdparty/rapier.js/testbed2d/src/Gui.ts
vendored
Normal file
@@ -0,0 +1,113 @@
|
||||
import GUI from "lil-gui";
|
||||
import * as Stats from "stats.js";
|
||||
import type {Testbed} from "./Testbed";
|
||||
|
||||
export interface DebugInfos {
|
||||
token: number;
|
||||
stepId: number;
|
||||
worldHash: string;
|
||||
worldHashTime: number;
|
||||
snapshotTime: number;
|
||||
}
|
||||
|
||||
export class Gui {
|
||||
stats: Stats;
|
||||
rapierVersion: string;
|
||||
maxTimePanelValue: number;
|
||||
stepTimePanel: Stats.Panel;
|
||||
gui: GUI;
|
||||
debugText: HTMLDivElement;
|
||||
|
||||
constructor(testbed: Testbed, simulationParameters: Testbed["parameters"]) {
|
||||
// Timings
|
||||
this.stats = new Stats();
|
||||
this.rapierVersion = testbed.RAPIER.version();
|
||||
this.maxTimePanelValue = 16.0;
|
||||
this.stepTimePanel = this.stats.addPanel(
|
||||
new Stats.Panel("ms (step)", "#ff8", "#221"),
|
||||
);
|
||||
this.stats.showPanel(this.stats.dom.children.length - 1);
|
||||
document.body.appendChild(this.stats.dom);
|
||||
|
||||
var backends = simulationParameters.backends;
|
||||
var demos = Array.from(simulationParameters.builders.keys());
|
||||
var me = this;
|
||||
|
||||
// For configuring simulation parameters.
|
||||
this.gui = new GUI({
|
||||
title: "Rapier JS demos",
|
||||
});
|
||||
var currDemo = this.gui
|
||||
.add(simulationParameters, "demo", demos)
|
||||
.onChange((demo: string) => {
|
||||
testbed.switchToDemo(demo);
|
||||
});
|
||||
this.gui
|
||||
.add(simulationParameters, "numSolverIters", 0, 20)
|
||||
.step(1)
|
||||
.listen();
|
||||
this.gui
|
||||
.add(simulationParameters, "debugInfos")
|
||||
.listen()
|
||||
.onChange((value: boolean) => {
|
||||
me.debugText.style.visibility = value ? "visible" : "hidden";
|
||||
});
|
||||
this.gui.add(simulationParameters, "debugRender").listen();
|
||||
this.gui.add(simulationParameters, "running").listen();
|
||||
this.gui.add(simulationParameters, "step");
|
||||
simulationParameters.step = () => {
|
||||
simulationParameters.stepping = true;
|
||||
};
|
||||
this.gui.add(simulationParameters, "takeSnapshot");
|
||||
simulationParameters.takeSnapshot = () => {
|
||||
testbed.takeSnapshot();
|
||||
};
|
||||
this.gui.add(simulationParameters, "restoreSnapshot");
|
||||
simulationParameters.restoreSnapshot = () => {
|
||||
testbed.restoreSnapshot();
|
||||
};
|
||||
this.gui.add(simulationParameters, "restart");
|
||||
simulationParameters.restart = () => {
|
||||
testbed.switchToDemo(currDemo.getValue());
|
||||
};
|
||||
|
||||
/*
|
||||
* Block of text for debug infos.
|
||||
*/
|
||||
this.debugText = document.createElement("div");
|
||||
this.debugText.style.position = "absolute";
|
||||
this.debugText.innerHTML = "";
|
||||
this.debugText.style.top = 50 + "px";
|
||||
this.debugText.style.visibility = "visible";
|
||||
this.debugText.style.color = "#fff";
|
||||
document.body.appendChild(this.debugText);
|
||||
}
|
||||
|
||||
setDebugInfos(infos: DebugInfos) {
|
||||
let text = "Version " + this.rapierVersion;
|
||||
text += "<br/>[Step " + infos.stepId + "]";
|
||||
|
||||
if (infos.worldHash) {
|
||||
text +=
|
||||
"<br/>World hash (xxHash128): " + infos.worldHash.toString();
|
||||
text +=
|
||||
"<br/>World hash time (xxHash128): " +
|
||||
infos.worldHashTime +
|
||||
"ms";
|
||||
text += "<br/>Snapshot time: " + infos.snapshotTime + "ms";
|
||||
}
|
||||
this.debugText.innerHTML = text;
|
||||
}
|
||||
|
||||
setTiming(timing: number) {
|
||||
if (!!timing) {
|
||||
this.maxTimePanelValue = Math.max(this.maxTimePanelValue, timing);
|
||||
this.stepTimePanel.update(timing, this.maxTimePanelValue);
|
||||
}
|
||||
}
|
||||
|
||||
resetTiming() {
|
||||
this.maxTimePanelValue = 1.0;
|
||||
this.stepTimePanel.update(0.0, 16.0);
|
||||
}
|
||||
}
|
||||
189
thirdparty/rapier.js/testbed2d/src/Testbed.ts
vendored
Normal file
189
thirdparty/rapier.js/testbed2d/src/Testbed.ts
vendored
Normal file
@@ -0,0 +1,189 @@
|
||||
import {Graphics} from "./Graphics";
|
||||
import {Gui} from "./Gui";
|
||||
import type {DebugInfos} from "./Gui";
|
||||
import {xxhash128} from "hash-wasm";
|
||||
import type * as RAPIER from "@dimforge/rapier2d";
|
||||
|
||||
type RAPIER_API = typeof import("@dimforge/rapier2d");
|
||||
|
||||
type Builders = Map<string, (RAPIER: RAPIER_API, testbed: Testbed) => void>;
|
||||
|
||||
class SimulationParameters {
|
||||
backend: string;
|
||||
prevBackend: string;
|
||||
demo: string;
|
||||
numSolverIters: number;
|
||||
running: boolean;
|
||||
stepping: boolean;
|
||||
debugRender: boolean;
|
||||
step: () => void;
|
||||
restart: () => void;
|
||||
takeSnapshot: () => void;
|
||||
restoreSnapshot: () => void;
|
||||
backends: Array<string>;
|
||||
builders: Builders;
|
||||
debugInfos: boolean;
|
||||
|
||||
constructor(backends: Array<string>, builders: Builders) {
|
||||
this.backend = "rapier";
|
||||
this.prevBackend = "rapier";
|
||||
this.demo = "collision groups";
|
||||
this.numSolverIters = 4;
|
||||
this.running = true;
|
||||
this.stepping = false;
|
||||
this.debugRender = false;
|
||||
this.step = function () {};
|
||||
this.restart = function () {};
|
||||
this.takeSnapshot = function () {};
|
||||
this.restoreSnapshot = function () {};
|
||||
this.backends = backends;
|
||||
this.builders = builders;
|
||||
this.debugInfos = false;
|
||||
}
|
||||
}
|
||||
|
||||
export class Testbed {
|
||||
RAPIER: RAPIER_API;
|
||||
gui: Gui;
|
||||
graphics: Graphics;
|
||||
inhibitLookAt: boolean;
|
||||
parameters: SimulationParameters;
|
||||
demoToken: number;
|
||||
mouse: {x: number; y: number};
|
||||
events: RAPIER.EventQueue;
|
||||
world: RAPIER.World;
|
||||
preTimestepAction?: (gfx: Graphics) => void;
|
||||
stepId: number;
|
||||
prevDemo: string;
|
||||
lastMessageTime: number;
|
||||
snap: Uint8Array;
|
||||
snapStepId: number;
|
||||
|
||||
constructor(RAPIER: RAPIER_API, builders: Builders) {
|
||||
let backends = ["rapier"];
|
||||
this.RAPIER = RAPIER;
|
||||
let parameters = new SimulationParameters(backends, builders);
|
||||
this.gui = new Gui(this, parameters);
|
||||
this.graphics = new Graphics();
|
||||
this.inhibitLookAt = false;
|
||||
this.parameters = parameters;
|
||||
this.demoToken = 0;
|
||||
this.mouse = {x: 0, y: 0};
|
||||
this.events = new RAPIER.EventQueue(true);
|
||||
this.switchToDemo(builders.keys().next().value);
|
||||
|
||||
window.addEventListener("mousemove", (event) => {
|
||||
this.mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
|
||||
this.mouse.y = 1 - (event.clientY / window.innerHeight) * 2;
|
||||
});
|
||||
}
|
||||
|
||||
setpreTimestepAction(action: (gfx: Graphics) => void) {
|
||||
this.preTimestepAction = action;
|
||||
}
|
||||
|
||||
setWorld(world: RAPIER.World) {
|
||||
document.onkeyup = null;
|
||||
document.onkeydown = null;
|
||||
this.preTimestepAction = null;
|
||||
this.world = world;
|
||||
this.world.numSolverIterations = this.parameters.numSolverIters;
|
||||
this.demoToken += 1;
|
||||
this.stepId = 0;
|
||||
this.gui.resetTiming();
|
||||
|
||||
world.forEachCollider((coll) => {
|
||||
this.graphics.addCollider(this.RAPIER, world, coll);
|
||||
});
|
||||
|
||||
this.lastMessageTime = new Date().getTime();
|
||||
}
|
||||
|
||||
lookAt(pos: Parameters<Graphics["lookAt"]>[0]) {
|
||||
if (!this.inhibitLookAt) {
|
||||
this.graphics.lookAt(pos);
|
||||
}
|
||||
|
||||
this.inhibitLookAt = false;
|
||||
}
|
||||
|
||||
switchToDemo(demo: string) {
|
||||
if (demo == this.prevDemo) {
|
||||
this.inhibitLookAt = true;
|
||||
}
|
||||
|
||||
this.prevDemo = demo;
|
||||
this.graphics.reset();
|
||||
this.stepId = 0;
|
||||
|
||||
this.parameters.prevBackend = this.parameters.backend;
|
||||
this.parameters.builders.get(demo)(this.RAPIER, this);
|
||||
}
|
||||
|
||||
switchToBackend(backend: string) {
|
||||
this.switchToDemo(this.parameters.demo);
|
||||
}
|
||||
|
||||
takeSnapshot() {
|
||||
this.snap = this.world.takeSnapshot();
|
||||
this.snapStepId = this.stepId;
|
||||
}
|
||||
|
||||
restoreSnapshot() {
|
||||
if (!!this.snap) {
|
||||
this.world.free();
|
||||
this.world = this.RAPIER.World.restoreSnapshot(this.snap);
|
||||
this.stepId = this.snapStepId;
|
||||
}
|
||||
}
|
||||
|
||||
run() {
|
||||
if (this.parameters.running || this.parameters.stepping) {
|
||||
this.world.numSolverIterations = this.parameters.numSolverIters;
|
||||
|
||||
if (!!this.preTimestepAction) {
|
||||
this.preTimestepAction(this.graphics);
|
||||
}
|
||||
|
||||
let t0 = new Date().getTime();
|
||||
this.world.step(this.events);
|
||||
this.gui.setTiming(new Date().getTime() - t0);
|
||||
this.stepId += 1;
|
||||
|
||||
if (!!this.parameters.debugInfos) {
|
||||
let t0 = performance.now();
|
||||
let snapshot = this.world.takeSnapshot();
|
||||
let t1 = performance.now();
|
||||
let snapshotTime = t1 - t0;
|
||||
|
||||
let debugInfos: DebugInfos = {
|
||||
token: this.demoToken,
|
||||
stepId: this.stepId,
|
||||
worldHash: "",
|
||||
worldHashTime: 0,
|
||||
snapshotTime: 0,
|
||||
};
|
||||
t0 = performance.now();
|
||||
xxhash128(snapshot).then((hash) => {
|
||||
debugInfos.worldHash = hash;
|
||||
t1 = performance.now();
|
||||
let worldHashTime = t1 - t0;
|
||||
debugInfos.worldHashTime = worldHashTime;
|
||||
debugInfos.snapshotTime = snapshotTime;
|
||||
this.gui.setDebugInfos(debugInfos);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (this.parameters.stepping) {
|
||||
this.parameters.running = false;
|
||||
this.parameters.stepping = false;
|
||||
}
|
||||
|
||||
this.gui.stats.begin();
|
||||
this.graphics.render(this.world, this.parameters.debugRender);
|
||||
this.gui.stats.end();
|
||||
|
||||
requestAnimationFrame(() => this.run());
|
||||
}
|
||||
}
|
||||
89
thirdparty/rapier.js/testbed2d/src/demos/characterController.ts
vendored
Normal file
89
thirdparty/rapier.js/testbed2d/src/demos/characterController.ts
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
import type {Testbed} from "../Testbed";
|
||||
|
||||
type RAPIER_API = typeof import("@dimforge/rapier2d");
|
||||
|
||||
export function initWorld(RAPIER: RAPIER_API, testbed: Testbed) {
|
||||
let gravity = new RAPIER.Vector2(0.0, -9.81);
|
||||
let world = new RAPIER.World(gravity);
|
||||
|
||||
// Create Ground.
|
||||
let bodyDesc = RAPIER.RigidBodyDesc.fixed();
|
||||
let body = world.createRigidBody(bodyDesc);
|
||||
let colliderDesc = RAPIER.ColliderDesc.cuboid(15.0, 0.1);
|
||||
world.createCollider(colliderDesc, body);
|
||||
|
||||
// Dynamic cubes.
|
||||
let rad = 0.5;
|
||||
let num = 5;
|
||||
let i, j, k;
|
||||
let shift = rad * 2.5;
|
||||
let center = num * rad;
|
||||
let height = 5.0;
|
||||
|
||||
for (i = 0; i < num; ++i) {
|
||||
for (k = i; k < num; ++k) {
|
||||
let x = (i * shift) / 2.0 + (k - i) * shift - center;
|
||||
let y = (i * shift) / 2.0 + height;
|
||||
|
||||
// Create dynamic cube.
|
||||
let bodyDesc = RAPIER.RigidBodyDesc.dynamic().setTranslation(x, y);
|
||||
let body = world.createRigidBody(bodyDesc);
|
||||
let colliderDesc = RAPIER.ColliderDesc.cuboid(rad, rad / 2.0);
|
||||
world.createCollider(colliderDesc, body);
|
||||
}
|
||||
}
|
||||
|
||||
// Character.
|
||||
let characterDesc =
|
||||
RAPIER.RigidBodyDesc.kinematicPositionBased().setTranslation(
|
||||
-10.0,
|
||||
4.0,
|
||||
);
|
||||
let character = world.createRigidBody(characterDesc);
|
||||
let characterColliderDesc = RAPIER.ColliderDesc.cuboid(0.6, 1.2);
|
||||
let characterCollider = world.createCollider(
|
||||
characterColliderDesc,
|
||||
character,
|
||||
);
|
||||
|
||||
let characterController = world.createCharacterController(0.1);
|
||||
characterController.enableAutostep(0.7, 0.3, true);
|
||||
characterController.enableSnapToGround(0.7);
|
||||
|
||||
let speed = 0.2;
|
||||
let movementDirection = {x: 0.0, y: -speed};
|
||||
|
||||
let updateCharacter = () => {
|
||||
characterController.computeColliderMovement(
|
||||
characterCollider,
|
||||
movementDirection,
|
||||
);
|
||||
|
||||
let movement = characterController.computedMovement();
|
||||
let newPos = character.translation();
|
||||
newPos.x += movement.x;
|
||||
newPos.y += movement.y;
|
||||
character.setNextKinematicTranslation(newPos);
|
||||
console.log("here");
|
||||
};
|
||||
|
||||
testbed.setWorld(world);
|
||||
testbed.setpreTimestepAction(updateCharacter);
|
||||
|
||||
document.onkeydown = function (event: KeyboardEvent) {
|
||||
if (event.key == "ArrowLeft") movementDirection.x = -speed;
|
||||
if (event.key == "ArrowRight") movementDirection.x = speed;
|
||||
if (event.key == " ") movementDirection.y = speed;
|
||||
};
|
||||
|
||||
document.onkeyup = function (event: KeyboardEvent) {
|
||||
if (event.key == "ArrowLeft") movementDirection.x = 0.0;
|
||||
if (event.key == "ArrowRight") movementDirection.x = 0.0;
|
||||
if (event.key == " ") movementDirection.y = -speed; // Gravity
|
||||
};
|
||||
|
||||
testbed.lookAt({
|
||||
target: {x: 0.0, y: -1.0},
|
||||
zoom: 50.0,
|
||||
});
|
||||
}
|
||||
79
thirdparty/rapier.js/testbed2d/src/demos/collisionGroups.ts
vendored
Normal file
79
thirdparty/rapier.js/testbed2d/src/demos/collisionGroups.ts
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
import type {Testbed} from "../Testbed";
|
||||
|
||||
type RAPIER_API = typeof import("@dimforge/rapier2d");
|
||||
|
||||
export function initWorld(RAPIER: RAPIER_API, testbed: Testbed) {
|
||||
let gravity = new RAPIER.Vector2(0.0, -9.81);
|
||||
let world = new RAPIER.World(gravity);
|
||||
|
||||
/*
|
||||
* Ground
|
||||
*/
|
||||
let ground_size = 5.0;
|
||||
let ground_height = 0.1;
|
||||
|
||||
let groundBodyDesc = RAPIER.RigidBodyDesc.fixed().setTranslation(
|
||||
0.0,
|
||||
-ground_height,
|
||||
);
|
||||
let groundBody = world.createRigidBody(groundBodyDesc);
|
||||
let colliderDesc = RAPIER.ColliderDesc.cuboid(ground_size, ground_height);
|
||||
world.createCollider(colliderDesc, groundBody);
|
||||
|
||||
/*
|
||||
* Setup groups
|
||||
*/
|
||||
let group1 = 0x00010001;
|
||||
let group2 = 0x00020002;
|
||||
|
||||
/*
|
||||
* A green floor that will collide with the first group only.
|
||||
*/
|
||||
colliderDesc = RAPIER.ColliderDesc.cuboid(1.0, 0.1)
|
||||
.setTranslation(0.0, 1.0)
|
||||
.setCollisionGroups(group1);
|
||||
world.createCollider(colliderDesc, groundBody);
|
||||
|
||||
/*
|
||||
* A blue floor that will collide with the second group only.
|
||||
*/
|
||||
colliderDesc = RAPIER.ColliderDesc.cuboid(1.0, 0.1)
|
||||
.setTranslation(0.0, 2.0)
|
||||
.setCollisionGroups(group2);
|
||||
world.createCollider(colliderDesc, groundBody);
|
||||
|
||||
/*
|
||||
* Create the cubes
|
||||
*/
|
||||
let num = 8;
|
||||
let rad = 0.1;
|
||||
|
||||
let shift = rad * 2.0;
|
||||
let centerx = shift * (num / 2);
|
||||
let centery = 2.5;
|
||||
let i, j;
|
||||
|
||||
for (j = 0; j < 4; ++j) {
|
||||
for (i = 0; i < num; ++i) {
|
||||
let x = i * shift - centerx;
|
||||
let y = j * shift + centery;
|
||||
|
||||
// Alternate between the green and blue groups.
|
||||
let group = i % 2 == 0 ? group1 : group2;
|
||||
|
||||
let bodyDesc = RAPIER.RigidBodyDesc.dynamic().setTranslation(x, y);
|
||||
let body = world.createRigidBody(bodyDesc);
|
||||
let colliderDesc = RAPIER.ColliderDesc.cuboid(
|
||||
rad,
|
||||
rad,
|
||||
).setCollisionGroups(group);
|
||||
world.createCollider(colliderDesc, body);
|
||||
}
|
||||
}
|
||||
|
||||
testbed.setWorld(world);
|
||||
testbed.lookAt({
|
||||
target: {x: 0.0, y: -1.0},
|
||||
zoom: 100.0,
|
||||
});
|
||||
}
|
||||
68
thirdparty/rapier.js/testbed2d/src/demos/convexPolygons.ts
vendored
Normal file
68
thirdparty/rapier.js/testbed2d/src/demos/convexPolygons.ts
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
import seedrandom from "seedrandom";
|
||||
import type {Testbed} from "../Testbed";
|
||||
|
||||
type RAPIER_API = typeof import("@dimforge/rapier2d");
|
||||
|
||||
export function initWorld(RAPIER: RAPIER_API, testbed: Testbed) {
|
||||
let gravity = new RAPIER.Vector2(0.0, -9.81);
|
||||
let world = new RAPIER.World(gravity);
|
||||
|
||||
/*
|
||||
* Ground
|
||||
*/
|
||||
// Create Ground.
|
||||
let groundSize = 30.0;
|
||||
let grounds = [
|
||||
{x: 0.0, y: 0.0, hx: groundSize, hy: 1.2},
|
||||
{x: -groundSize, y: groundSize, hx: 1.2, hy: groundSize},
|
||||
{x: groundSize, y: groundSize, hx: 1.2, hy: groundSize},
|
||||
];
|
||||
|
||||
grounds.forEach((ground) => {
|
||||
let bodyDesc = RAPIER.RigidBodyDesc.fixed().setTranslation(
|
||||
ground.x,
|
||||
ground.y,
|
||||
);
|
||||
let body = world.createRigidBody(bodyDesc);
|
||||
let colliderDesc = RAPIER.ColliderDesc.cuboid(ground.hx, ground.hy);
|
||||
world.createCollider(colliderDesc, body);
|
||||
});
|
||||
|
||||
/*
|
||||
* Create the convex polygons
|
||||
*/
|
||||
let num = 14;
|
||||
let scale = 4.0;
|
||||
|
||||
let shift = scale;
|
||||
let centerx = (shift * num) / 2.0;
|
||||
let centery = shift / 2.0;
|
||||
|
||||
let i, j, k;
|
||||
let rng = seedrandom("convexPolygon");
|
||||
|
||||
for (i = 0; i < num; ++i) {
|
||||
for (j = 0; j < num * 2; ++j) {
|
||||
let x = i * shift - centerx;
|
||||
let y = j * shift * 2.0 + centery + 2.0;
|
||||
|
||||
let bodyDesc = RAPIER.RigidBodyDesc.dynamic().setTranslation(x, y);
|
||||
let body = world.createRigidBody(bodyDesc);
|
||||
|
||||
let points = [];
|
||||
for (k = 0; k < 10; ++k) {
|
||||
points.push(rng() * scale, rng() * scale);
|
||||
}
|
||||
let colliderDesc = RAPIER.ColliderDesc.convexHull(
|
||||
new Float32Array(points),
|
||||
);
|
||||
world.createCollider(colliderDesc, body);
|
||||
}
|
||||
}
|
||||
|
||||
testbed.setWorld(world);
|
||||
testbed.lookAt({
|
||||
target: {x: -10.0, y: -30.0},
|
||||
zoom: 7.0,
|
||||
});
|
||||
}
|
||||
56
thirdparty/rapier.js/testbed2d/src/demos/cubes.ts
vendored
Normal file
56
thirdparty/rapier.js/testbed2d/src/demos/cubes.ts
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
import type {Testbed} from "../Testbed";
|
||||
|
||||
type RAPIER_API = typeof import("@dimforge/rapier2d");
|
||||
|
||||
export function initWorld(RAPIER: RAPIER_API, testbed: Testbed) {
|
||||
let gravity = new RAPIER.Vector2(0.0, -9.81);
|
||||
let world = new RAPIER.World(gravity);
|
||||
|
||||
// Create Ground.
|
||||
let groundSize = 40.0;
|
||||
let grounds = [
|
||||
{x: 0.0, y: 0.0, hx: groundSize, hy: 0.1},
|
||||
{x: -groundSize, y: groundSize, hx: 0.1, hy: groundSize},
|
||||
{x: groundSize, y: groundSize, hx: 0.1, hy: groundSize},
|
||||
];
|
||||
|
||||
grounds.forEach((ground) => {
|
||||
let bodyDesc = RAPIER.RigidBodyDesc.fixed().setTranslation(
|
||||
ground.x,
|
||||
ground.y,
|
||||
);
|
||||
let body = world.createRigidBody(bodyDesc);
|
||||
let colliderDesc = RAPIER.ColliderDesc.cuboid(ground.hx, ground.hy);
|
||||
world.createCollider(colliderDesc, body);
|
||||
});
|
||||
|
||||
// Dynamic cubes.
|
||||
let num = 20;
|
||||
let numy = 50;
|
||||
let rad = 1.0;
|
||||
|
||||
let shift = rad * 2.0 + rad;
|
||||
let centerx = shift * (num / 2);
|
||||
let centery = shift / 2.0;
|
||||
|
||||
let i, j;
|
||||
|
||||
for (j = 0; j < numy; ++j) {
|
||||
for (i = 0; i < num; ++i) {
|
||||
let x = i * shift - centerx;
|
||||
let y = j * shift + centery + 3.0;
|
||||
|
||||
// Create dynamic cube.
|
||||
let bodyDesc = RAPIER.RigidBodyDesc.dynamic().setTranslation(x, y);
|
||||
let body = world.createRigidBody(bodyDesc);
|
||||
let colliderDesc = RAPIER.ColliderDesc.cuboid(rad, rad);
|
||||
world.createCollider(colliderDesc, body);
|
||||
}
|
||||
}
|
||||
|
||||
testbed.setWorld(world);
|
||||
testbed.lookAt({
|
||||
target: {x: -10.0, y: -30.0},
|
||||
zoom: 7.0,
|
||||
});
|
||||
}
|
||||
65
thirdparty/rapier.js/testbed2d/src/demos/heightfield.ts
vendored
Normal file
65
thirdparty/rapier.js/testbed2d/src/demos/heightfield.ts
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
import type {Testbed} from "../Testbed";
|
||||
|
||||
type RAPIER_API = typeof import("@dimforge/rapier2d");
|
||||
|
||||
export function initWorld(RAPIER: RAPIER_API, testbed: Testbed) {
|
||||
let gravity = new RAPIER.Vector2(0.0, -9.81);
|
||||
let world = new RAPIER.World(gravity);
|
||||
let i, j;
|
||||
|
||||
/*
|
||||
* Ground
|
||||
*/
|
||||
let ground_size = {x: 50.0, y: 1.0};
|
||||
let nsubdivs = 100;
|
||||
let heights = [];
|
||||
|
||||
heights.push(40.0);
|
||||
for (i = 1; i < nsubdivs; ++i) {
|
||||
heights.push(Math.cos((i * ground_size.x) / nsubdivs) * 2.0);
|
||||
}
|
||||
heights.push(40.0);
|
||||
|
||||
let bodyDesc = RAPIER.RigidBodyDesc.fixed();
|
||||
let body = world.createRigidBody(bodyDesc);
|
||||
let colliderDesc = RAPIER.ColliderDesc.heightfield(
|
||||
new Float32Array(heights),
|
||||
ground_size,
|
||||
);
|
||||
world.createCollider(colliderDesc, body);
|
||||
|
||||
/*
|
||||
* Create the cubes
|
||||
*/
|
||||
let num = 15;
|
||||
let rad = 0.5;
|
||||
|
||||
let shift = rad * 2.0;
|
||||
let centerx = shift * (num / 2);
|
||||
let centery = shift / 2.0;
|
||||
|
||||
for (i = 0; i < num; ++i) {
|
||||
for (j = 0; j < num * 5; ++j) {
|
||||
let x = i * shift - centerx;
|
||||
let y = j * shift + centery + 3.0;
|
||||
|
||||
// Build the rigid body.
|
||||
let bodyDesc = RAPIER.RigidBodyDesc.dynamic().setTranslation(x, y);
|
||||
let body = world.createRigidBody(bodyDesc);
|
||||
|
||||
if (j % 2 == 0) {
|
||||
let colliderDesc = RAPIER.ColliderDesc.cuboid(rad, rad);
|
||||
world.createCollider(colliderDesc, body);
|
||||
} else {
|
||||
let colliderDesc = RAPIER.ColliderDesc.ball(rad);
|
||||
world.createCollider(colliderDesc, body);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
testbed.setWorld(world);
|
||||
testbed.lookAt({
|
||||
target: {x: -10.0, y: -15.0},
|
||||
zoom: 10.0,
|
||||
});
|
||||
}
|
||||
92
thirdparty/rapier.js/testbed2d/src/demos/keva.ts
vendored
Normal file
92
thirdparty/rapier.js/testbed2d/src/demos/keva.ts
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
import type * as RAPIER from "@dimforge/rapier2d";
|
||||
import type {Testbed} from "../Testbed";
|
||||
|
||||
type RAPIER_API = typeof import("@dimforge/rapier2d");
|
||||
|
||||
function buildBlock(
|
||||
RAPIER: RAPIER_API,
|
||||
world: RAPIER.World,
|
||||
halfExtents: RAPIER.Vector,
|
||||
shift: RAPIER.Vector,
|
||||
numx: number,
|
||||
numy: number,
|
||||
numz: number,
|
||||
) {
|
||||
let halfExtents_yx = {x: halfExtents.y, y: halfExtents.x};
|
||||
let dimensions = [halfExtents, halfExtents_yx];
|
||||
let spacing = (halfExtents.y * numx - halfExtents.x) / (numz - 1.0);
|
||||
|
||||
let i;
|
||||
let j;
|
||||
let y = 0.0;
|
||||
|
||||
for (i = 0; i <= numy; ++i) {
|
||||
let dim = dimensions[i % 2];
|
||||
[numx, numz] = [numz, numx];
|
||||
|
||||
for (j = 0; j < numx; ++j) {
|
||||
let x = i % 2 == 0 ? spacing * j * 2.0 : dim.x * j * 2.0;
|
||||
|
||||
// Build the rigid body.
|
||||
let bodyDesc = RAPIER.RigidBodyDesc.dynamic().setTranslation(
|
||||
x + dim.x + shift.x,
|
||||
y + dim.y + shift.y,
|
||||
);
|
||||
let body = world.createRigidBody(bodyDesc);
|
||||
let colliderDesc = RAPIER.ColliderDesc.cuboid(dim.x, dim.y);
|
||||
world.createCollider(colliderDesc, body);
|
||||
}
|
||||
|
||||
y += dim.y * 2.0;
|
||||
}
|
||||
}
|
||||
|
||||
export function initWorld(RAPIER: RAPIER_API, testbed: Testbed) {
|
||||
let gravity = new RAPIER.Vector2(0.0, -9.81);
|
||||
let world = new RAPIER.World(gravity);
|
||||
|
||||
// Create Ground.
|
||||
let groundSize = 150.0;
|
||||
let groundHeight = 0.1;
|
||||
let bodyDesc = RAPIER.RigidBodyDesc.fixed().setTranslation(
|
||||
0.0,
|
||||
-groundHeight,
|
||||
);
|
||||
let body = world.createRigidBody(bodyDesc);
|
||||
let colliderDesc = RAPIER.ColliderDesc.cuboid(groundSize, groundHeight);
|
||||
world.createCollider(colliderDesc, body);
|
||||
|
||||
// Keva tower.
|
||||
let halfExtents = new RAPIER.Vector2(0.5, 2.0);
|
||||
let blockHeight = 0.0;
|
||||
// These should only be set to odd values otherwise
|
||||
// the blocks won't align in the nicest way.
|
||||
let numyArr = [0, 3, 5, 5, 7, 9];
|
||||
let numBlocksBuilt = 0;
|
||||
let i;
|
||||
|
||||
for (i = 5; i >= 1; --i) {
|
||||
let numx = i * 15;
|
||||
let numy = numyArr[i];
|
||||
let numz = numx * 2 + 1;
|
||||
let blockWidth = numx * halfExtents.y * 2.0;
|
||||
buildBlock(
|
||||
RAPIER,
|
||||
world,
|
||||
halfExtents,
|
||||
new RAPIER.Vector2(-blockWidth / 2.0, blockHeight),
|
||||
numx,
|
||||
numy,
|
||||
numz,
|
||||
);
|
||||
blockHeight += (numy + 1) * (halfExtents.x + halfExtents.y);
|
||||
numBlocksBuilt += numx * numy;
|
||||
}
|
||||
|
||||
testbed.setWorld(world);
|
||||
|
||||
testbed.lookAt({
|
||||
target: {x: -10.0, y: -5.0},
|
||||
zoom: 4.0,
|
||||
});
|
||||
}
|
||||
51
thirdparty/rapier.js/testbed2d/src/demos/lockedRotations.ts
vendored
Normal file
51
thirdparty/rapier.js/testbed2d/src/demos/lockedRotations.ts
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
import type {Testbed} from "../Testbed";
|
||||
|
||||
type RAPIER_API = typeof import("@dimforge/rapier2d");
|
||||
|
||||
export function initWorld(RAPIER: RAPIER_API, testbed: Testbed) {
|
||||
let gravity = new RAPIER.Vector2(0.0, -9.81);
|
||||
let world = new RAPIER.World(gravity);
|
||||
|
||||
/*
|
||||
* The ground
|
||||
*/
|
||||
let ground_size = 1.8;
|
||||
let ground_height = 1.0;
|
||||
|
||||
let bodyDesc = RAPIER.RigidBodyDesc.fixed().setTranslation(
|
||||
0.0,
|
||||
-ground_height,
|
||||
);
|
||||
let body = world.createRigidBody(bodyDesc);
|
||||
let colliderDesc = RAPIER.ColliderDesc.cuboid(ground_size, ground_height);
|
||||
world.createCollider(colliderDesc, body);
|
||||
|
||||
/*
|
||||
* A rectangle that only rotates along the `x` axis.
|
||||
*/
|
||||
bodyDesc = RAPIER.RigidBodyDesc.dynamic()
|
||||
.setTranslation(0.0, 3.0)
|
||||
.lockTranslations();
|
||||
body = world.createRigidBody(bodyDesc);
|
||||
colliderDesc = RAPIER.ColliderDesc.cuboid(2.0, 0.6);
|
||||
world.createCollider(colliderDesc, body);
|
||||
|
||||
/*
|
||||
* A cuboid that cannot rotate.
|
||||
*/
|
||||
bodyDesc = RAPIER.RigidBodyDesc.dynamic()
|
||||
.setTranslation(0.4, 5.0)
|
||||
.lockRotations();
|
||||
body = world.createRigidBody(bodyDesc);
|
||||
colliderDesc = RAPIER.ColliderDesc.cuboid(0.4, 0.6);
|
||||
world.createCollider(colliderDesc, body);
|
||||
|
||||
/*
|
||||
* Setup the testbed.
|
||||
*/
|
||||
testbed.setWorld(world);
|
||||
testbed.lookAt({
|
||||
target: {x: 0.0, y: -2.0},
|
||||
zoom: 50.0,
|
||||
});
|
||||
}
|
||||
100
thirdparty/rapier.js/testbed2d/src/demos/pidController.ts
vendored
Normal file
100
thirdparty/rapier.js/testbed2d/src/demos/pidController.ts
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
import type {Testbed} from "../Testbed";
|
||||
|
||||
type RAPIER_API = typeof import("@dimforge/rapier2d");
|
||||
|
||||
export function initWorld(RAPIER: RAPIER_API, testbed: Testbed) {
|
||||
let gravity = new RAPIER.Vector2(0.0, -9.81);
|
||||
let world = new RAPIER.World(gravity);
|
||||
|
||||
// Create Ground.
|
||||
let bodyDesc = RAPIER.RigidBodyDesc.fixed();
|
||||
let body = world.createRigidBody(bodyDesc);
|
||||
let colliderDesc = RAPIER.ColliderDesc.cuboid(15.0, 0.1);
|
||||
world.createCollider(colliderDesc, body);
|
||||
|
||||
// Dynamic cubes.
|
||||
let rad = 0.5;
|
||||
let num = 5;
|
||||
let i, j, k;
|
||||
let shift = rad * 2.5;
|
||||
let center = num * rad;
|
||||
let height = 5.0;
|
||||
|
||||
for (i = 0; i < num; ++i) {
|
||||
for (k = i; k < num; ++k) {
|
||||
let x = (i * shift) / 2.0 + (k - i) * shift - center;
|
||||
let y = (i * shift) / 2.0 + height;
|
||||
|
||||
// Create dynamic cube.
|
||||
let bodyDesc = RAPIER.RigidBodyDesc.dynamic().setTranslation(x, y);
|
||||
let body = world.createRigidBody(bodyDesc);
|
||||
let colliderDesc = RAPIER.ColliderDesc.cuboid(rad, rad / 2.0);
|
||||
world.createCollider(colliderDesc, body);
|
||||
}
|
||||
}
|
||||
|
||||
// Character.
|
||||
let characterDesc = RAPIER.RigidBodyDesc.dynamic()
|
||||
.setTranslation(-10.0, 4.0)
|
||||
.setGravityScale(10.0)
|
||||
.setSoftCcdPrediction(10.0);
|
||||
let character = world.createRigidBody(characterDesc);
|
||||
let characterColliderDesc = RAPIER.ColliderDesc.cuboid(0.6, 1.2);
|
||||
world.createCollider(characterColliderDesc, character);
|
||||
|
||||
let pidController = world.createPidController(
|
||||
60.0,
|
||||
0.0,
|
||||
1.0,
|
||||
RAPIER.PidAxesMask.AllAng,
|
||||
);
|
||||
let speed = 0.2;
|
||||
let movementDirection = {x: 0.0, y: 0.0};
|
||||
let targetVelocity = {x: 0.0, y: 0.0};
|
||||
let targetRotation = 0.0;
|
||||
|
||||
let updateCharacter = () => {
|
||||
if (movementDirection.x == 0.0 && movementDirection.y == 0.0) {
|
||||
// Only adjust the rotation, but let translation.
|
||||
pidController.setAxes(RAPIER.PidAxesMask.AllAng);
|
||||
} else if (movementDirection.y == 0.0) {
|
||||
// Don’t control the linear Y axis so the player can fall down due to gravity.
|
||||
pidController.setAxes(
|
||||
RAPIER.PidAxesMask.AllAng | RAPIER.PidAxesMask.LinX,
|
||||
);
|
||||
} else {
|
||||
pidController.setAxes(RAPIER.PidAxesMask.All);
|
||||
}
|
||||
|
||||
let targetPoint = character.translation();
|
||||
targetPoint.x += movementDirection.x;
|
||||
targetPoint.y += movementDirection.y;
|
||||
|
||||
pidController.applyLinearCorrection(
|
||||
character,
|
||||
targetPoint,
|
||||
targetVelocity,
|
||||
);
|
||||
pidController.applyAngularCorrection(character, 0.0, 0.0);
|
||||
};
|
||||
|
||||
testbed.setWorld(world);
|
||||
testbed.setpreTimestepAction(updateCharacter);
|
||||
|
||||
document.onkeydown = function (event: KeyboardEvent) {
|
||||
if (event.key == "ArrowLeft") movementDirection.x = -speed;
|
||||
if (event.key == "ArrowRight") movementDirection.x = speed;
|
||||
if (event.key == " ") movementDirection.y = speed;
|
||||
};
|
||||
|
||||
document.onkeyup = function (event: KeyboardEvent) {
|
||||
if (event.key == "ArrowLeft") movementDirection.x = 0.0;
|
||||
if (event.key == "ArrowRight") movementDirection.x = 0.0;
|
||||
if (event.key == " ") movementDirection.y = 0.0;
|
||||
};
|
||||
|
||||
testbed.lookAt({
|
||||
target: {x: 0.0, y: -1.0},
|
||||
zoom: 50.0,
|
||||
});
|
||||
}
|
||||
64
thirdparty/rapier.js/testbed2d/src/demos/polyline.ts
vendored
Normal file
64
thirdparty/rapier.js/testbed2d/src/demos/polyline.ts
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
import type {Testbed} from "../Testbed";
|
||||
|
||||
type RAPIER_API = typeof import("@dimforge/rapier2d");
|
||||
|
||||
export function initWorld(RAPIER: RAPIER_API, testbed: Testbed) {
|
||||
let gravity = new RAPIER.Vector2(0.0, -9.81);
|
||||
let world = new RAPIER.World(gravity);
|
||||
let i, j;
|
||||
|
||||
/*
|
||||
* Ground
|
||||
*/
|
||||
let nsubdivs = 100;
|
||||
let points = [];
|
||||
let groundSize = 30.0;
|
||||
let stepSize = groundSize / nsubdivs;
|
||||
|
||||
points.push(-groundSize / 2.0, 25.0);
|
||||
for (i = 1; i < nsubdivs; ++i) {
|
||||
let x = -groundSize / 2.0 + i * stepSize;
|
||||
let y = Math.cos(i * stepSize) * 2.0;
|
||||
points.push(x, y);
|
||||
}
|
||||
points.push(groundSize / 2.0, 25.0);
|
||||
let bodyDesc = RAPIER.RigidBodyDesc.fixed();
|
||||
let body = world.createRigidBody(bodyDesc);
|
||||
let colliderDesc = RAPIER.ColliderDesc.polyline(new Float32Array(points));
|
||||
world.createCollider(colliderDesc, body);
|
||||
|
||||
/*
|
||||
* Create the cubes
|
||||
*/
|
||||
let num = 10;
|
||||
let rad = 0.5;
|
||||
|
||||
let shift = rad * 2.0;
|
||||
let centerx = shift * (num / 2);
|
||||
let centery = shift / 2.0;
|
||||
|
||||
for (i = 0; i < num; ++i) {
|
||||
for (j = 0; j < num * 5; ++j) {
|
||||
let x = i * shift - centerx;
|
||||
let y = j * shift + centery + 3.0;
|
||||
|
||||
// Build the rigid body.
|
||||
let bodyDesc = RAPIER.RigidBodyDesc.dynamic().setTranslation(x, y);
|
||||
let body = world.createRigidBody(bodyDesc);
|
||||
|
||||
if (j % 2 == 0) {
|
||||
let colliderDesc = RAPIER.ColliderDesc.cuboid(rad, rad);
|
||||
world.createCollider(colliderDesc, body);
|
||||
} else {
|
||||
let colliderDesc = RAPIER.ColliderDesc.ball(rad);
|
||||
world.createCollider(colliderDesc, body);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
testbed.setWorld(world);
|
||||
testbed.lookAt({
|
||||
target: {x: -10.0, y: -15.0},
|
||||
zoom: 10.0,
|
||||
});
|
||||
}
|
||||
59
thirdparty/rapier.js/testbed2d/src/demos/revoluteJoints.ts
vendored
Normal file
59
thirdparty/rapier.js/testbed2d/src/demos/revoluteJoints.ts
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
import type {Testbed} from "../Testbed";
|
||||
|
||||
type RAPIER_API = typeof import("@dimforge/rapier2d");
|
||||
|
||||
export function initWorld(RAPIER: RAPIER_API, testbed: Testbed) {
|
||||
let gravity = new RAPIER.Vector2(0.0, -9.81);
|
||||
let world = new RAPIER.World(gravity);
|
||||
let bodies = [];
|
||||
|
||||
let rad = 0.4;
|
||||
let numi = 30; // Num vertical nodes.
|
||||
let numk = 30; // Num horizontal nodes.
|
||||
let shift = 1.0;
|
||||
let i, k;
|
||||
|
||||
for (k = 0; k < numk; ++k) {
|
||||
for (i = 0; i < numi; ++i) {
|
||||
let status =
|
||||
k >= numk / 2 - 3 && k <= numk / 2 + 3 && i == 0
|
||||
? RAPIER.RigidBodyType.Fixed
|
||||
: RAPIER.RigidBodyType.Dynamic;
|
||||
|
||||
let bodyDesc = new RAPIER.RigidBodyDesc(status).setTranslation(
|
||||
k * shift,
|
||||
-i * shift,
|
||||
);
|
||||
let child = world.createRigidBody(bodyDesc);
|
||||
let colliderDesc = RAPIER.ColliderDesc.ball(rad);
|
||||
world.createCollider(colliderDesc, child);
|
||||
|
||||
// Vertical joint.
|
||||
if (i > 0) {
|
||||
let parent = bodies[bodies.length - 1];
|
||||
let anchor1 = new RAPIER.Vector2(0.0, 0.0);
|
||||
let anchor2 = new RAPIER.Vector2(0.0, shift);
|
||||
let JointData = RAPIER.JointData.revolute(anchor1, anchor2);
|
||||
world.createImpulseJoint(JointData, parent, child, true);
|
||||
}
|
||||
|
||||
// Horizontal joint.
|
||||
if (k > 0) {
|
||||
let parentIndex = bodies.length - numi;
|
||||
let parent = bodies[parentIndex];
|
||||
let anchor1 = new RAPIER.Vector2(0.0, 0.0);
|
||||
let anchor2 = new RAPIER.Vector2(-shift, 0.0);
|
||||
let JointData = RAPIER.JointData.revolute(anchor1, anchor2);
|
||||
world.createImpulseJoint(JointData, parent, child, true);
|
||||
}
|
||||
|
||||
bodies.push(child);
|
||||
}
|
||||
}
|
||||
|
||||
testbed.setWorld(world);
|
||||
testbed.lookAt({
|
||||
target: {x: 30.0, y: 30.0},
|
||||
zoom: 10.0,
|
||||
});
|
||||
}
|
||||
90
thirdparty/rapier.js/testbed2d/src/demos/voxels.ts
vendored
Normal file
90
thirdparty/rapier.js/testbed2d/src/demos/voxels.ts
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
import type {Testbed} from "../Testbed";
|
||||
|
||||
type RAPIER_API = typeof import("@dimforge/rapier2d");
|
||||
|
||||
function generateVoxels(n: number) {
|
||||
let points = [];
|
||||
|
||||
let i;
|
||||
for (i = 0; i <= n; ++i) {
|
||||
let y = Math.max(-0.8, Math.min(Math.sin((i / n) * 10.0), 0.8)) * 8.0;
|
||||
points.push(i - n / 2.0, y);
|
||||
}
|
||||
return {
|
||||
points: new Float32Array(points),
|
||||
voxelSize: {x: 1.0, y: 1.2},
|
||||
};
|
||||
}
|
||||
|
||||
export function initWorld(RAPIER: RAPIER_API, testbed: Testbed) {
|
||||
let gravity = new RAPIER.Vector2(0.0, -9.81);
|
||||
let world = new RAPIER.World(gravity);
|
||||
|
||||
// Create Ground.
|
||||
let bodyDesc = RAPIER.RigidBodyDesc.fixed();
|
||||
let body = world.createRigidBody(bodyDesc);
|
||||
let voxels = generateVoxels(100);
|
||||
let colliderDesc = RAPIER.ColliderDesc.voxels(
|
||||
voxels.points,
|
||||
voxels.voxelSize,
|
||||
);
|
||||
world.createCollider(colliderDesc, body);
|
||||
|
||||
// Dynamic cubes.
|
||||
let num = 10;
|
||||
let numy = 4;
|
||||
let rad = 1.0;
|
||||
|
||||
let shift = rad * 2.0 + rad;
|
||||
let centery = shift / 2.0;
|
||||
|
||||
let offset = -num * (rad * 2.0 + rad) * 0.5;
|
||||
let i, j;
|
||||
|
||||
for (j = 0; j < numy; ++j) {
|
||||
for (i = 0; i < num; ++i) {
|
||||
let x = i * shift + offset;
|
||||
let y = j * shift + centery + 10.0;
|
||||
|
||||
// Create dynamic cube.
|
||||
let bodyDesc = RAPIER.RigidBodyDesc.dynamic().setTranslation(x, y);
|
||||
let body = world.createRigidBody(bodyDesc);
|
||||
let colliderDesc;
|
||||
|
||||
switch (j % 3) {
|
||||
case 0:
|
||||
colliderDesc = RAPIER.ColliderDesc.cuboid(rad, rad);
|
||||
break;
|
||||
case 1:
|
||||
colliderDesc = RAPIER.ColliderDesc.ball(rad);
|
||||
break;
|
||||
case 2:
|
||||
colliderDesc = RAPIER.ColliderDesc.cuboid(
|
||||
rad / 2.0,
|
||||
rad / 2.0,
|
||||
);
|
||||
world.createCollider(colliderDesc, body);
|
||||
colliderDesc = RAPIER.ColliderDesc.cuboid(
|
||||
rad / 2.0,
|
||||
rad,
|
||||
).setTranslation(rad, 0.0);
|
||||
world.createCollider(colliderDesc, body);
|
||||
colliderDesc = RAPIER.ColliderDesc.cuboid(
|
||||
rad / 2.0,
|
||||
rad,
|
||||
).setTranslation(-rad, 0.0);
|
||||
break;
|
||||
}
|
||||
|
||||
world.createCollider(colliderDesc, body);
|
||||
}
|
||||
|
||||
offset -= 0.05 * rad * (num - 1.0);
|
||||
}
|
||||
|
||||
testbed.setWorld(world);
|
||||
testbed.lookAt({
|
||||
target: {x: 0.0, y: 0.0},
|
||||
zoom: 20.0,
|
||||
});
|
||||
}
|
||||
30
thirdparty/rapier.js/testbed2d/src/index.ts
vendored
Normal file
30
thirdparty/rapier.js/testbed2d/src/index.ts
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
import {Testbed} from "./Testbed";
|
||||
import * as CollisionGroups from "./demos/collisionGroups";
|
||||
import * as Cubes from "./demos/cubes";
|
||||
import * as Keva from "./demos/keva";
|
||||
import * as Heightfield from "./demos/heightfield";
|
||||
import * as Polyline from "./demos/polyline";
|
||||
import * as RevoluteJoints from "./demos/revoluteJoints";
|
||||
import * as LockedRotations from "./demos/lockedRotations";
|
||||
import * as ConvexPolygons from "./demos/convexPolygons";
|
||||
import * as CharacterController from "./demos/characterController";
|
||||
import * as PidController from "./demos/pidController";
|
||||
import * as Voxels from "./demos/voxels";
|
||||
|
||||
import("@dimforge/rapier2d").then((RAPIER) => {
|
||||
let builders = new Map([
|
||||
["collision groups", CollisionGroups.initWorld],
|
||||
["character controller", CharacterController.initWorld],
|
||||
["convex polygons", ConvexPolygons.initWorld],
|
||||
["cubes", Cubes.initWorld],
|
||||
["heightfield", Heightfield.initWorld],
|
||||
["joints: revolute", RevoluteJoints.initWorld],
|
||||
["keva tower", Keva.initWorld],
|
||||
["locked rotations", LockedRotations.initWorld],
|
||||
["pid controller", PidController.initWorld],
|
||||
["polyline", Polyline.initWorld],
|
||||
["voxels", Voxels.initWorld],
|
||||
]);
|
||||
let testbed = new Testbed(RAPIER, builders);
|
||||
testbed.run();
|
||||
});
|
||||
3
thirdparty/rapier.js/testbed2d/static/.htaccess
vendored
Normal file
3
thirdparty/rapier.js/testbed2d/static/.htaccess
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
RewriteEngine On
|
||||
RewriteCond %{SERVER_PORT} 80
|
||||
RewriteRule ^(.*)$ https://www.rapier.rs/$1 [R,L]
|
||||
18
thirdparty/rapier.js/testbed2d/static/index.html
vendored
Normal file
18
thirdparty/rapier.js/testbed2d/static/index.html
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Rapier2D JS bindings demo</title>
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
canvas {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<script src="index.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
11
thirdparty/rapier.js/testbed2d/tsconfig.json
vendored
Normal file
11
thirdparty/rapier.js/testbed2d/tsconfig.json
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"outDir": "./dist/",
|
||||
"noImplicitAny": true,
|
||||
"module": "es2022",
|
||||
"target": "es2022",
|
||||
"allowJs": true,
|
||||
"moduleResolution": "node",
|
||||
"allowSyntheticDefaultImports": true
|
||||
}
|
||||
}
|
||||
55
thirdparty/rapier.js/testbed2d/webpack.config.js
vendored
Normal file
55
thirdparty/rapier.js/testbed2d/webpack.config.js
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
const webpack = require("webpack");
|
||||
const path = require("path");
|
||||
const CopyPlugin = require("copy-webpack-plugin");
|
||||
|
||||
const isDev = process.env.NODE_ENV === "development";
|
||||
const dist = path.resolve(__dirname, "dist");
|
||||
|
||||
/**
|
||||
* @type {import('webpack-dev-server').Configuration}
|
||||
*/
|
||||
const devServer = {
|
||||
static: {
|
||||
directory: dist,
|
||||
},
|
||||
allowedHosts: "all",
|
||||
compress: true,
|
||||
};
|
||||
|
||||
/**
|
||||
* @type {import('webpack').Configuration}
|
||||
*/
|
||||
const webpackConfig = {
|
||||
mode: isDev ? "development" : "production",
|
||||
entry: "./src/index.ts",
|
||||
devtool: "inline-source-map",
|
||||
output: {
|
||||
path: dist,
|
||||
filename: "index.js",
|
||||
},
|
||||
resolve: {
|
||||
extensions: [".ts", ".js"],
|
||||
},
|
||||
devServer,
|
||||
performance: false,
|
||||
experiments: {
|
||||
asyncWebAssembly: true,
|
||||
syncWebAssembly: true,
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.tsx?$/,
|
||||
use: "ts-loader",
|
||||
exclude: /node_modules/,
|
||||
},
|
||||
],
|
||||
},
|
||||
plugins: [
|
||||
new CopyPlugin({
|
||||
patterns: [{from: "static", to: dist}],
|
||||
}),
|
||||
],
|
||||
};
|
||||
|
||||
module.exports = webpackConfig;
|
||||
Reference in New Issue
Block a user