Files
grungnet/src/dice/Dice.js
2020-05-28 11:48:18 +10:00

154 lines
4.5 KiB
JavaScript

import * as BABYLON from "babylonjs";
import d4Source from "./shared/d4.glb";
import d6Source from "./shared/d6.glb";
import d8Source from "./shared/d8.glb";
import d10Source from "./shared/d10.glb";
import d12Source from "./shared/d12.glb";
import d20Source from "./shared/d20.glb";
import d100Source from "./shared/d100.glb";
import { lerp } from "../helpers/shared";
const minDiceRollSpeed = 600;
const maxDiceRollSpeed = 800;
class Dice {
static instanceCount = 0;
static async loadMeshes(material, scene, sourceOverrides) {
let meshes = {};
const addToMeshes = async (type, defaultSource) => {
let source = sourceOverrides ? sourceOverrides[type] : defaultSource;
const mesh = await this.loadMesh(source, material, scene);
meshes[type] = mesh;
};
await addToMeshes("d4", d4Source);
await addToMeshes("d6", d6Source);
await addToMeshes("d8", d8Source);
await addToMeshes("d10", d10Source);
await addToMeshes("d12", d12Source);
await addToMeshes("d20", d20Source);
await addToMeshes("d100", d100Source);
return meshes;
}
static async loadMesh(source, material, scene) {
let mesh = (
await BABYLON.SceneLoader.ImportMeshAsync("", source, "", scene)
).meshes[1];
mesh.setParent(null);
mesh.material = material;
mesh.receiveShadows = true;
mesh.isVisible = false;
return mesh;
}
static loadMaterial(materialName, textures, scene) {
let pbr = new BABYLON.PBRMaterial(materialName, scene);
pbr.albedoTexture = new BABYLON.Texture(textures.albedo);
pbr.normalTexture = new BABYLON.Texture(textures.normal);
pbr.metallicTexture = new BABYLON.Texture(textures.metalRoughness);
pbr.useRoughnessFromMetallicTextureAlpha = false;
pbr.useRoughnessFromMetallicTextureGreen = true;
pbr.useMetallnessFromMetallicTextureBlue = true;
return pbr;
}
static createInstanceFromMesh(mesh, name, physicalProperties, scene) {
let instance = mesh.createInstance(name);
instance.position = mesh.position;
for (let child of mesh.getChildTransformNodes()) {
const locator = child.clone();
locator.setAbsolutePosition(child.getAbsolutePosition());
locator.name = child.name;
instance.addChild(locator);
}
instance.physicsImpostor = new BABYLON.PhysicsImpostor(
instance,
BABYLON.PhysicsImpostor.ConvexHullImpostor,
physicalProperties,
scene
);
return instance;
}
static getDicePhysicalProperties(diceType) {
switch (diceType) {
case "d4":
return { mass: 4, friction: 4 };
case "d6":
return { mass: 6, friction: 4 };
case "d8":
return { mass: 6.2, friction: 4 };
case "d10":
case "d100":
return { mass: 7, friction: 4 };
case "d12":
return { mass: 8, friction: 4 };
case "20":
return { mass: 10, friction: 4 };
default:
return { mass: 10, friction: 4 };
}
}
static roll(instance) {
instance.physicsImpostor.setLinearVelocity(BABYLON.Vector3.Zero());
instance.physicsImpostor.setAngularVelocity(BABYLON.Vector3.Zero());
const scene = instance.getScene();
const diceTraySingle = scene.getNodeByID("dice_tray_single");
const diceTrayDouble = scene.getNodeByID("dice_tray_double");
const visibleDiceTray = diceTraySingle.isVisible
? diceTraySingle
: diceTrayDouble;
const trayBounds = visibleDiceTray.getBoundingInfo().boundingBox;
const position = new BABYLON.Vector3(
trayBounds.center.x + (Math.random() * 2 - 1),
8,
trayBounds.center.z + (Math.random() * 2 - 1)
);
instance.position = position;
instance.addRotation(
Math.random() * Math.PI * 2,
Math.random() * Math.PI * 2,
Math.random() * Math.PI * 2
);
const throwTarget = new BABYLON.Vector3(
lerp(trayBounds.minimumWorld.x, trayBounds.maximumWorld.x, Math.random()),
5,
lerp(trayBounds.minimumWorld.z, trayBounds.maximumWorld.z, Math.random())
);
const impulse = new BABYLON.Vector3(0, 0, 0)
.subtract(throwTarget)
.normalizeToNew()
.scale(lerp(minDiceRollSpeed, maxDiceRollSpeed, Math.random()));
instance.physicsImpostor.applyImpulse(
impulse,
instance.physicsImpostor.getObjectCenter()
);
}
static async createInstance(mesh, physicalProperties, scene) {
this.instanceCount++;
return this.createInstanceFromMesh(
mesh,
`dice_instance_${this.instanceCount}`,
physicalProperties,
scene
);
}
}
export default Dice;