Files
grungnet/src/components/map/dice/DiceScene.js

125 lines
3.6 KiB
JavaScript
Raw Normal View History

import React, { useRef, useEffect } from "react";
import * as BABYLON from "babylonjs";
import * as AMMO from "ammo.js";
import "babylonjs-loaders";
2020-05-08 15:09:40 +10:00
function DiceScene({ onSceneMount }) {
const sceneRef = useRef();
const engineRef = useRef();
const canvasRef = useRef();
const containerRef = useRef();
useEffect(() => {
const canvas = canvasRef.current;
const engine = new BABYLON.Engine(canvas, true, {
preserveDrawingBuffer: true,
stencil: true,
});
const scene = new BABYLON.Scene(engine);
scene.clearColor = new BABYLON.Color4(0, 0, 0, 0);
// Enable physics
scene.enablePhysics(
new BABYLON.Vector3(0, -98, 0),
new BABYLON.AmmoJSPlugin(true, AMMO)
);
let camera = new BABYLON.TargetCamera(
"camera",
2020-05-10 16:13:15 +10:00
new BABYLON.Vector3(0, 34, 0),
scene
);
2020-05-10 16:13:15 +10:00
camera.fov = 0.65;
camera.setTarget(BABYLON.Vector3.Zero());
onSceneMount && onSceneMount({ scene, engine, canvas });
engineRef.current = engine;
sceneRef.current = scene;
engine.runRenderLoop(() => {
const scene = sceneRef.current;
const selectedMesh = selectedMeshRef.current;
if (selectedMesh && scene) {
const ray = scene.createPickingRay(
scene.pointerX,
scene.pointerY,
BABYLON.Matrix.Identity(),
camera
);
const currentPosition = selectedMesh.getAbsolutePosition();
let newPosition = ray.origin.scale(camera.globalPosition.y);
newPosition.y = currentPosition.y;
const delta = newPosition.subtract(currentPosition);
selectedMesh.setAbsolutePosition(newPosition);
selectedMeshDeltaPositionRef.current = delta;
}
});
const resizeObserver = new ResizeObserver((entries) => {
engine.resize();
for (let entry of entries) {
canvasRef.current.width = entry.contentRect.width;
canvasRef.current.height = entry.contentRect.height;
}
});
resizeObserver.observe(containerRef.current);
return () => {
resizeObserver.disconnect();
};
}, [onSceneMount]);
const selectedMeshRef = useRef();
const selectedMeshDeltaPositionRef = useRef();
function handlePointerDown() {
const scene = sceneRef.current;
if (scene) {
const pickInfo = scene.pick(scene.pointerX, scene.pointerY);
2020-05-10 16:13:15 +10:00
if (pickInfo.hit && pickInfo.pickedMesh.id !== "tray") {
pickInfo.pickedMesh.physicsImpostor.setLinearVelocity(
new BABYLON.Vector3(0, 0, 0)
);
pickInfo.pickedMesh.physicsImpostor.setAngularVelocity(
new BABYLON.Vector3(0, 0, 0)
);
selectedMeshRef.current = pickInfo.pickedMesh;
}
}
}
function handlePointerUp() {
const selectedMesh = selectedMeshRef.current;
const deltaPosition = selectedMeshDeltaPositionRef.current;
const scene = sceneRef.current;
if (selectedMesh && scene && deltaPosition) {
let impulse = deltaPosition.scale(1000 / scene.deltaTime);
impulse.scale(5);
impulse.y = Math.max(impulse.length() * 0.1, 0.5);
selectedMesh.physicsImpostor.applyImpulse(
impulse,
selectedMesh
.getAbsolutePosition()
.add(new BABYLON.Vector3(0, Math.random() * 0.5 + 0.5, 0))
);
}
selectedMeshRef.current = null;
selectedMeshDeltaPositionRef.current = null;
}
return (
<div
style={{ width: "100%", height: "100%", overflow: "hidden" }}
ref={containerRef}
>
<canvas
onPointerDown={handlePointerDown}
onPointerUp={handlePointerUp}
ref={canvasRef}
/>
</div>
);
}
2020-05-08 15:09:40 +10:00
export default DiceScene;