diff --git a/src/components/map/MapDice.js b/src/components/map/MapDice.js
index 98c0653..fb7b7ae 100644
--- a/src/components/map/MapDice.js
+++ b/src/components/map/MapDice.js
@@ -2,7 +2,7 @@ import React, { useState } from "react";
import { Flex, IconButton } from "theme-ui";
import ExpandMoreDiceIcon from "../../icons/ExpandMoreDiceIcon";
-import DiceTray from "./dice/DiceTray";
+import DiceTrayOverlay from "./dice/DiceTrayOverlay";
function MapDice() {
const [isExpanded, setIsExpanded] = useState(false);
@@ -32,7 +32,7 @@ function MapDice() {
>
-
+
);
}
diff --git a/src/components/map/dice/DiceButtons.js b/src/components/map/dice/DiceButtons.js
index 4c611e9..84e9301 100644
--- a/src/components/map/dice/DiceButtons.js
+++ b/src/components/map/dice/DiceButtons.js
@@ -1,5 +1,5 @@
import React, { useState } from "react";
-import { Flex } from "theme-ui";
+import { Flex, IconButton } from "theme-ui";
import D20Icon from "../../../icons/D20Icon";
import D12Icon from "../../../icons/D12Icon";
@@ -8,6 +8,7 @@ import D8Icon from "../../../icons/D8Icon";
import D6Icon from "../../../icons/D6Icon";
import D4Icon from "../../../icons/D4Icon";
import D100Icon from "../../../icons/D100Icon";
+import ExpandMoreDiceTrayIcon from "../../../icons/ExpandMoreDiceTrayIcon";
import DiceButton from "./DiceButton";
import SelectDiceButton from "./SelectDiceButton";
@@ -16,7 +17,12 @@ import Divider from "../../Divider";
import { dice } from "../../../dice";
-function DiceButtons({ diceRolls, onDiceAdd }) {
+function DiceButtons({
+ diceRolls,
+ onDiceAdd,
+ diceTraySize,
+ onDiceTraySizeChange,
+}) {
const [currentDice, setCurrentDice] = useState(dice[0]);
const diceCounts = {};
@@ -91,6 +97,23 @@ function DiceButtons({ diceRolls, onDiceAdd }) {
>
+
+
+ onDiceTraySizeChange(diceTraySize === "single" ? "double" : "single")
+ }
+ >
+
+
);
}
diff --git a/src/components/map/dice/DiceControls.js b/src/components/map/dice/DiceControls.js
index 189422c..df5ee28 100644
--- a/src/components/map/dice/DiceControls.js
+++ b/src/components/map/dice/DiceControls.js
@@ -10,6 +10,8 @@ function DiceControls({
onDiceAdd,
onDiceClear,
onDiceReroll,
+ diceTraySize,
+ onDiceTraySizeChange,
}) {
const [diceRolls, setDiceRolls] = useState([]);
@@ -114,6 +116,8 @@ function DiceControls({
{ type, roll: "unknown" },
]);
}}
+ onDiceTraySizeChange={onDiceTraySizeChange}
+ diceTraySize={diceTraySize}
/>
>
diff --git a/src/components/map/dice/DiceScene.js b/src/components/map/dice/DiceScene.js
index c7c62e3..9e90f9d 100644
--- a/src/components/map/dice/DiceScene.js
+++ b/src/components/map/dice/DiceScene.js
@@ -74,7 +74,7 @@ function DiceScene({ onSceneMount, onPointerDown, onPointerUp }) {
const scene = sceneRef.current;
if (scene) {
const pickInfo = scene.pick(scene.pointerX, scene.pointerY);
- if (pickInfo.hit && pickInfo.pickedMesh.id !== "tray") {
+ if (pickInfo.hit && pickInfo.pickedMesh.name !== "dice_tray") {
pickInfo.pickedMesh.physicsImpostor.setLinearVelocity(
BABYLON.Vector3.Zero()
);
diff --git a/src/components/map/dice/DiceTray.js b/src/components/map/dice/DiceTrayOverlay.js
similarity index 80%
rename from src/components/map/dice/DiceTray.js
rename to src/components/map/dice/DiceTrayOverlay.js
index f76a5cb..5a56592 100644
--- a/src/components/map/dice/DiceTray.js
+++ b/src/components/map/dice/DiceTrayOverlay.js
@@ -1,4 +1,10 @@
-import React, { useRef, useCallback, useEffect, useContext } from "react";
+import React, {
+ useRef,
+ useCallback,
+ useEffect,
+ useContext,
+ useState,
+} from "react";
import * as BABYLON from "babylonjs";
import { Box } from "theme-ui";
@@ -8,13 +14,11 @@ import Scene from "./DiceScene";
import DiceControls from "./DiceControls";
import Dice from "../../../dice/Dice";
-import createDiceTray, {
- diceTraySize,
-} from "../../../dice/diceTray/DiceTrayMesh";
+import DiceTray from "../../../dice/diceTray/DiceTray";
import MapInteractionContext from "../../../contexts/MapInteractionContext";
-function DiceTray({ isOpen }) {
+function DiceTrayOverlay({ isOpen }) {
const sceneRef = useRef();
const shadowGeneratorRef = useRef();
const diceRefs = useRef([]);
@@ -22,6 +26,26 @@ function DiceTray({ isOpen }) {
const sceneInteractionRef = useRef(false);
// Set to true to ignore scene sleep and visible values
const forceSceneRenderRef = useRef(false);
+ const diceTrayRef = useRef();
+
+ const [diceTraySize, setDiceTraySize] = useState("single");
+ useEffect(() => {
+ const diceTray = diceTrayRef.current;
+ let resizeTimout;
+ if (diceTray) {
+ diceTray.size = diceTraySize;
+ // Force rerender
+ forceSceneRenderRef.current = true;
+ resizeTimout = setTimeout(() => {
+ forceSceneRenderRef.current = false;
+ }, 1000);
+ }
+ return () => {
+ if (resizeTimout) {
+ clearTimeout(resizeTimout);
+ }
+ };
+ }, [diceTraySize]);
useEffect(() => {
let openTimeout;
@@ -49,7 +73,7 @@ function DiceTray({ isOpen }) {
}, []);
async function initializeScene(scene) {
- var light = new BABYLON.DirectionalLight(
+ let light = new BABYLON.DirectionalLight(
"DirectionalLight",
new BABYLON.Vector3(-0.5, -1, -0.5),
scene
@@ -62,7 +86,7 @@ function DiceTray({ isOpen }) {
shadowGenerator.darkness = 0.7;
shadowGeneratorRef.current = shadowGenerator;
- var ground = BABYLON.Mesh.CreateGround("ground", 100, 100, 2, scene);
+ let ground = BABYLON.Mesh.CreateGround("ground", 100, 100, 2, scene);
ground.physicsImpostor = new BABYLON.PhysicsImpostor(
ground,
BABYLON.PhysicsImpostor.BoxImpostor,
@@ -72,36 +96,7 @@ function DiceTray({ isOpen }) {
ground.isVisible = false;
ground.position.y = 0.2;
- const wallSize = 50;
-
- function createWall(name, x, z, yaw) {
- let wall = BABYLON.Mesh.CreateBox(
- name,
- wallSize,
- scene,
- true,
- BABYLON.Mesh.DOUBLESIDE
- );
- wall.rotation = new BABYLON.Vector3(0, yaw, 0);
- wall.position.z = z;
- wall.position.x = x;
- wall.physicsImpostor = new BABYLON.PhysicsImpostor(
- wall,
- BABYLON.PhysicsImpostor.BoxImpostor,
- { mass: 0, friction: 10.0 },
- scene
- );
- wall.isVisible = false;
- }
-
- const wallOffsetWidth = wallSize / 2 + diceTraySize.width / 2 - 0.5;
- const wallOffsetHeight = wallSize / 2 + diceTraySize.height / 2 - 0.5;
- createWall("wallTop", 0, -wallOffsetHeight, 0);
- createWall("wallRight", -wallOffsetWidth, 0, Math.PI / 2);
- createWall("wallBottom", 0, wallOffsetHeight, Math.PI);
- createWall("wallLeft", wallOffsetWidth, 0, -Math.PI / 2);
-
- var roof = BABYLON.Mesh.CreateGround("roof", 100, 100, 2, scene);
+ let roof = BABYLON.Mesh.CreateGround("roof", 100, 100, 2, scene);
roof.physicsImpostor = new BABYLON.PhysicsImpostor(
roof,
BABYLON.PhysicsImpostor.BoxImpostor,
@@ -117,7 +112,9 @@ function DiceTray({ isOpen }) {
);
scene.environmentIntensity = 1.0;
- createDiceTray(scene, shadowGenerator);
+ let diceTray = new DiceTray("single", scene, shadowGenerator);
+ await diceTray.load();
+ diceTrayRef.current = diceTray;
}
function update(scene) {
@@ -222,9 +219,12 @@ function DiceTray({ isOpen }) {
return (
);
}
-export default DiceTray;
+export default DiceTrayOverlay;
diff --git a/src/components/map/dice/SelectDiceButton.js b/src/components/map/dice/SelectDiceButton.js
index 8550667..7f470ec 100644
--- a/src/components/map/dice/SelectDiceButton.js
+++ b/src/components/map/dice/SelectDiceButton.js
@@ -26,7 +26,12 @@ function SelectDiceButton({ onDiceChange, currentDice }) {
return (
<>
-
+
0.5 ? trayOffsetHeight : -trayOffsetHeight
+ Math.random() > 0.5
+ ? trayBounds.maximumWorld.z
+ : trayBounds.minimumWorld.z
);
instance.position = position;
instance.addRotation(
diff --git a/src/dice/diceTray/DiceTray.js b/src/dice/diceTray/DiceTray.js
new file mode 100644
index 0000000..8fd90c2
--- /dev/null
+++ b/src/dice/diceTray/DiceTray.js
@@ -0,0 +1,156 @@
+import * as BABYLON from "babylonjs";
+
+import singleMeshSource from "../meshes/diceTraySingle.glb";
+import doubleMeshSource from "../meshes/diceTrayDouble.glb";
+
+import singleAlbedo from "./singleAlbedo.jpg";
+import singleMetalRoughness from "./singleMetalRoughness.jpg";
+import singleNormal from "./singleNormal.jpg";
+
+import doubleAlbedo from "./doubleAlbedo.jpg";
+import doubleMetalRoughness from "./doubleMetalRoughness.jpg";
+import doubleNormal from "./doubleNormal.jpg";
+
+class DiceTray {
+ _size;
+ get size() {
+ return this._size;
+ }
+ set size(newSize) {
+ this._size = newSize;
+ const wallOffsetWidth = this.wallSize / 2 + this.width / 2 - 0.5;
+ const wallOffsetHeight = this.wallSize / 2 + this.height / 2 - 0.5;
+ this.wallTop.position.z = -wallOffsetHeight;
+ this.wallRight.position.x = -wallOffsetWidth;
+ this.wallBottom.position.z = wallOffsetHeight;
+ this.wallLeft.position.x = wallOffsetWidth;
+ this.singleMesh.isVisible = newSize === "single";
+ this.doubleMesh.isVisible = newSize === "double";
+ }
+ scene;
+ shadowGenerator;
+ get width() {
+ return this.size === "single" ? 10 : 20;
+ }
+ height = 20;
+ wallSize = 50;
+ wallTop;
+ wallRight;
+ wallBottom;
+ wallLeft;
+ singleMesh;
+ doubleMesh;
+
+ constructor(initialSize, scene, shadowGenerator) {
+ this._size = initialSize;
+ this.scene = scene;
+ this.shadowGenerator = shadowGenerator;
+ }
+
+ async load() {
+ this.loadWalls();
+ await this.loadMeshes();
+ }
+
+ createWall(name, x, z, yaw) {
+ let wall = BABYLON.Mesh.CreateBox(
+ name,
+ this.wallSize,
+ this.scene,
+ true,
+ BABYLON.Mesh.DOUBLESIDE
+ );
+ wall.rotation = new BABYLON.Vector3(0, yaw, 0);
+ wall.position.z = z;
+ wall.position.x = x;
+ wall.physicsImpostor = new BABYLON.PhysicsImpostor(
+ wall,
+ BABYLON.PhysicsImpostor.BoxImpostor,
+ { mass: 0, friction: 10.0 },
+ this.scene
+ );
+ wall.isVisible = false;
+
+ return wall;
+ }
+
+ loadWalls() {
+ const wallOffsetWidth = this.wallSize / 2 + this.width / 2 - 0.5;
+ const wallOffsetHeight = this.wallSize / 2 + this.height / 2 - 0.5;
+ this.wallTop = this.createWall("wallTop", 0, -wallOffsetHeight, 0);
+ this.wallRight = this.createWall(
+ "wallRight",
+ -wallOffsetWidth,
+ 0,
+ Math.PI / 2
+ );
+ this.wallBottom = this.createWall(
+ "wallBottom",
+ 0,
+ wallOffsetHeight,
+ Math.PI
+ );
+ this.wallLeft = this.createWall(
+ "wallLeft",
+ wallOffsetWidth,
+ 0,
+ -Math.PI / 2
+ );
+ }
+
+ async loadMeshes() {
+ this.singleMesh = (
+ await BABYLON.SceneLoader.ImportMeshAsync(
+ "",
+ singleMeshSource,
+ "",
+ this.scene
+ )
+ ).meshes[1];
+ this.singleMesh.id = "dice_tray_single";
+ this.singleMesh.name = "dice_tray";
+ let singleMaterial = new BABYLON.PBRMaterial(
+ "dice_tray_mat_single",
+ this.scene
+ );
+ singleMaterial.albedoTexture = new BABYLON.Texture(singleAlbedo);
+ singleMaterial.normalTexture = new BABYLON.Texture(singleNormal);
+ singleMaterial.metallicTexture = new BABYLON.Texture(singleMetalRoughness);
+ singleMaterial.useRoughnessFromMetallicTextureAlpha = false;
+ singleMaterial.useRoughnessFromMetallicTextureGreen = true;
+ singleMaterial.useMetallnessFromMetallicTextureBlue = true;
+ this.singleMesh.material = singleMaterial;
+
+ this.singleMesh.receiveShadows = true;
+ this.shadowGenerator.addShadowCaster(this.singleMesh);
+ this.singleMesh.isVisible = this.size === "single";
+
+ this.doubleMesh = (
+ await BABYLON.SceneLoader.ImportMeshAsync(
+ "",
+ doubleMeshSource,
+ "",
+ this.scene
+ )
+ ).meshes[1];
+ this.doubleMesh.id = "dice_tray_double";
+ this.doubleMesh.name = "dice_tray";
+ let doubleMaterial = new BABYLON.PBRMaterial(
+ "dice_tray_mat_double",
+ this.scene
+ );
+ doubleMaterial.albedoTexture = new BABYLON.Texture(doubleAlbedo);
+ doubleMaterial.normalTexture = new BABYLON.Texture(doubleNormal);
+ doubleMaterial.metallicTexture = new BABYLON.Texture(doubleMetalRoughness);
+ doubleMaterial.useRoughnessFromMetallicTextureAlpha = false;
+ doubleMaterial.useRoughnessFromMetallicTextureGreen = true;
+ doubleMaterial.useMetallnessFromMetallicTextureBlue = true;
+ this.doubleMesh.material = doubleMaterial;
+
+ this.doubleMesh.receiveShadows = true;
+ this.shadowGenerator.addShadowCaster(this.doubleMesh);
+ this.doubleMesh.isVisible = this.size === "double";
+ }
+}
+
+export default DiceTray;
diff --git a/src/dice/diceTray/DiceTrayMesh.js b/src/dice/diceTray/DiceTrayMesh.js
deleted file mode 100644
index 5938f5a..0000000
--- a/src/dice/diceTray/DiceTrayMesh.js
+++ /dev/null
@@ -1,28 +0,0 @@
-import * as BABYLON from "babylonjs";
-
-import meshSource from "../meshes/diceTraySingle.glb";
-
-import albedo from "./albedo.jpg";
-import metalRoughness from "./metalRoughness.jpg";
-import normal from "./normal.jpg";
-
-export const diceTraySize = { width: 10, height: 20 };
-
-export default async function createDiceTray(scene, shadowGenerator) {
- let mesh = (
- await BABYLON.SceneLoader.ImportMeshAsync("", meshSource, "", scene)
- ).meshes[1];
- mesh.id = "tray";
- let material = new BABYLON.PBRMaterial("dice_tray_mat", scene);
- material.albedoTexture = new BABYLON.Texture(albedo);
- material.normalTexture = new BABYLON.Texture(normal);
- material.metallicTexture = new BABYLON.Texture(metalRoughness);
- material.useRoughnessFromMetallicTextureAlpha = false;
- material.useRoughnessFromMetallicTextureGreen = true;
- material.useMetallnessFromMetallicTextureBlue = true;
- mesh.material = material;
-
- mesh.receiveShadows = true;
-
- shadowGenerator.addShadowCaster(mesh);
-}
diff --git a/src/dice/diceTray/doubleAlbedo.jpg b/src/dice/diceTray/doubleAlbedo.jpg
new file mode 100644
index 0000000..1df822b
Binary files /dev/null and b/src/dice/diceTray/doubleAlbedo.jpg differ
diff --git a/src/dice/diceTray/doubleMetalRoughness.jpg b/src/dice/diceTray/doubleMetalRoughness.jpg
new file mode 100644
index 0000000..efa575d
Binary files /dev/null and b/src/dice/diceTray/doubleMetalRoughness.jpg differ
diff --git a/src/dice/diceTray/doubleNormal.jpg b/src/dice/diceTray/doubleNormal.jpg
new file mode 100644
index 0000000..00ea0a0
Binary files /dev/null and b/src/dice/diceTray/doubleNormal.jpg differ
diff --git a/src/dice/diceTray/albedo.jpg b/src/dice/diceTray/singleAlbedo.jpg
similarity index 100%
rename from src/dice/diceTray/albedo.jpg
rename to src/dice/diceTray/singleAlbedo.jpg
diff --git a/src/dice/diceTray/metalRoughness.jpg b/src/dice/diceTray/singleMetalRoughness.jpg
similarity index 100%
rename from src/dice/diceTray/metalRoughness.jpg
rename to src/dice/diceTray/singleMetalRoughness.jpg
diff --git a/src/dice/diceTray/normal.jpg b/src/dice/diceTray/singleNormal.jpg
similarity index 100%
rename from src/dice/diceTray/normal.jpg
rename to src/dice/diceTray/singleNormal.jpg
diff --git a/src/dice/meshes/diceTrayDouble.glb b/src/dice/meshes/diceTrayDouble.glb
new file mode 100644
index 0000000..0eb752b
Binary files /dev/null and b/src/dice/meshes/diceTrayDouble.glb differ
diff --git a/src/icons/ExpandMoreDiceTrayIcon.js b/src/icons/ExpandMoreDiceTrayIcon.js
new file mode 100644
index 0000000..2b860d9
--- /dev/null
+++ b/src/icons/ExpandMoreDiceTrayIcon.js
@@ -0,0 +1,19 @@
+import React from "react";
+
+function ExpandMoreDotIcon() {
+ return (
+
+ );
+}
+
+export default ExpandMoreDotIcon;