summaryrefslogtreecommitdiff
path: root/src/client/scripts/physics.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/scripts/physics.ts')
-rw-r--r--src/client/scripts/physics.ts168
1 files changed, 168 insertions, 0 deletions
diff --git a/src/client/scripts/physics.ts b/src/client/scripts/physics.ts
new file mode 100644
index 0000000000..c7f6b44a9f
--- /dev/null
+++ b/src/client/scripts/physics.ts
@@ -0,0 +1,168 @@
+import Matter from 'matter-js';
+
+export function physics(container: HTMLElement) {
+ const containerWidth = container.offsetWidth;
+ const containerHeight = container.offsetHeight;
+ const containerCenterX = containerWidth / 2;
+
+ // サイズ固定化(要らないかも?)
+ container.style.position = 'relative';
+ container.style.boxSizing = 'border-box';
+ container.style.width = `${containerWidth}px`;
+ container.style.height = `${containerHeight}px`;
+
+ // create engine
+ const engine = Matter.Engine.create();
+ const world = engine.world;
+
+ // create renderer
+ const render = Matter.Render.create({
+ engine: engine,
+ //element: document.getElementById('debug'),
+ options: {
+ width: containerWidth,
+ height: containerHeight,
+ background: 'transparent', // transparent to hide
+ wireframeBackground: 'transparent', // transparent to hide
+ hasBounds: false,
+ enabled: true,
+ wireframes: false,
+ showSleeping: true,
+ showDebug: false,
+ showBroadphase: false,
+ showBounds: false,
+ showVelocity: false,
+ showCollisions: false,
+ showAxes: false,
+ showPositions: false,
+ showAngleIndicator: false,
+ showIds: false,
+ showShadows: false
+ }
+ });
+
+ // Disable to hide debug
+ Matter.Render.run(render);
+
+ // create runner
+ const runner = Matter.Runner.create();
+ Matter.Runner.run(runner, engine);
+
+ // add walls
+ const wallopts = {
+ isStatic: true,
+ restitution: 0.2,
+ friction: 1
+ };
+ const groundopts = {
+ isStatic: true,
+ restitution: 0.1,
+ friction: 2
+ };
+
+ const groundThickness = 100;
+ const ground = Matter.Bodies.rectangle(containerCenterX, containerHeight + (groundThickness / 2), containerWidth, groundThickness, groundopts);
+ //const wallRight = Matter.Bodies.rectangle(window.innerWidth+50, window.innerHeight/2, 100, window.innerHeight, wallopts);
+ //const wallLeft = Matter.Bodies.rectangle(-50, window.innerHeight/2, 100, window.innerHeight, wallopts);
+
+ Matter.World.add(world, [
+ ground,
+ //wallRight,
+ //wallLeft,
+ ]);
+
+ const objEls = Array.from(container.children);
+ const objs = [];
+ for (const objEl of objEls) {
+ let obj;
+ if (objEl.classList.contains('_physics_circle_')) {
+ obj = Matter.Bodies.circle(
+ objEl.offsetLeft + (objEl.offsetWidth / 2),
+ objEl.offsetTop + (objEl.offsetHeight / 2),
+ Math.max(objEl.offsetWidth, objEl.offsetHeight) / 2,
+ {
+ restitution: 0.1,
+ friction: 4,
+ frictionAir: 0,
+ frictionStatic: 50,
+ density: 100,
+ }
+ );
+ } else {
+ const style = window.getComputedStyle(objEl);
+ obj = Matter.Bodies.rectangle(
+ objEl.offsetLeft + (objEl.offsetWidth / 2),
+ objEl.offsetTop + (objEl.offsetHeight / 2),
+ objEl.offsetWidth,
+ objEl.offsetHeight,
+ {
+ restitution: 0.1,
+ friction: 4,
+ frictionAir: 0,
+ frictionStatic: 50,
+ density: 100,
+ chamfer: { radius: parseInt(style.borderRadius, 10) },
+ }
+ );
+ }
+ objEl.id = obj.id;
+ objs.push(obj);
+ }
+
+ Matter.World.add(engine.world, objs);
+
+ // Add mouse control
+
+ const mouse = Matter.Mouse.create(container);
+ const mouseConstraint = Matter.MouseConstraint.create(engine, {
+ mouse: mouse,
+ constraint: {
+ stiffness: 1,
+ render: {
+ visible: false
+ }
+ }
+ });
+
+ Matter.World.add(engine.world, mouseConstraint);
+
+ // keep the mouse in sync with rendering
+ render.mouse = mouse;
+
+ for (const objEl of objEls) {
+ objEl.style.position = `absolute`;
+ objEl.style.top = 0;
+ objEl.style.left = 0;
+ objEl.style.margin = 0;
+ objEl.style.userSelect = 'none';
+ objEl.style.willChange = 'transform';
+ }
+
+ window.requestAnimationFrame(update);
+
+ let stop = false;
+
+ function update() {
+ for (const objEl of objEls) {
+ const obj = objs.find(obj => obj.id.toString() === objEl.id.toString());
+ if (obj == null) continue;
+
+ const x = (obj.position.x - objEl.offsetWidth / 2);
+ const y = (obj.position.y - objEl.offsetHeight / 2);
+ const angle = obj.angle;
+
+ objEl.style.transform = `translate(${x}px, ${y}px) rotate(${angle}rad)`;
+ }
+
+ if (!stop) {
+ window.requestAnimationFrame(update);
+ }
+ }
+
+ return {
+ stop: () => {
+ stop = true;
+ Matter.Runner.stop(runner);
+ }
+ };
+}