How would I identify when all the dice have settled when calling prepareValues?
See original GitHub issueHello,
I’ve gotten your library to work in an Angular 5 application while following this example: https://github.com/byWulf/threejs-dice/blob/master/examples/rolling.html.
How would I go about identifying when the dice have all settled and then get the number that is on the upper face?
This is my code:
import { Component, ElementRef, OnInit, ViewChild } from '@angular/core';
import * as CANNON from 'cannon';
import * as THREE from 'three';
import { Stats } from 'three-stats';
import { DiceD6, DiceManager } from 'threejs-dice';
declare const require: (moduleId: string) => any;
const OrbitControls = require('three-orbit-controls')(THREE);
@Component({
selector: 'app-roll',
templateUrl: './roll.component.html',
styleUrls: ['./roll.component.scss']
})
export class RollComponent implements OnInit {
@ViewChild('canvasWrapper') canvasWrapper: ElementRef;
private _world: CANNON.World;
private _dice: DiceD6[] = [];
private _scene: THREE.Scene;
private _renderer: THREE.WebGLRenderer;
private _camera: THREE.PerspectiveCamera;
private _controls: any;
private _stats: any;
private _throwRunning: boolean;
private readonly WIDTH = window.innerWidth - 48;
private readonly HEIGHT = window.innerHeight - 10;
private readonly VIEW_ANGLE = 45;
private readonly NEAR = 0.01;
private readonly FAR = 20000;
private readonly ASPECT = this.WIDTH / this.HEIGHT;
constructor(private _self: ElementRef) { }
ngOnInit() {
this._scene = new THREE.Scene();
// CAMERA
this._camera = new THREE.PerspectiveCamera(this.VIEW_ANGLE, this.ASPECT, this.NEAR, this.FAR);
this._scene.add(this._camera);
this._camera.position.set(0, 30, 30);
// RENDERER
this._renderer = new THREE.WebGLRenderer({ antialias: true });
this._renderer.setSize(this.WIDTH, this.HEIGHT);
this._renderer.shadowMap.enabled = true;
this._renderer.shadowMap.type = THREE.PCFSoftShadowMap;
// CONTAINER
const container = this.canvasWrapper.nativeElement;
container.appendChild(this._renderer.domElement);
// CONTROLS
this._controls = new OrbitControls(this._camera, this._renderer.domElement);
// STATS
this._stats = new Stats();
this._stats.domElement.style.position = 'absolute';
this._stats.domElement.style.top = '84px';
this._stats.domElement.style.left = '24px';
this._stats.domElement.style.zIndex = 100;
container.appendChild(this._stats.domElement);
const ambient = new THREE.AmbientLight('#ffffff', 0.3);
this._scene.add(ambient);
const directionalLight = new THREE.DirectionalLight('#ffffff', 0.5);
directionalLight.position.x = -1000;
directionalLight.position.y = 1000;
directionalLight.position.z = 1000;
this._scene.add(directionalLight);
const light = new THREE.SpotLight(0xefdfd5, 1.3);
light.position.y = 100;
light.castShadow = true;
light.shadow.camera.near = 50;
light.shadow.camera.far = 110;
light.shadow.mapSize.width = 1024;
light.shadow.mapSize.height = 1024;
this._scene.add(light);
// FLOOR
const floorMaterial = new THREE.MeshPhongMaterial({ color: '#222222', side: THREE.DoubleSide });
const floorGeometry = new THREE.PlaneGeometry(30, 30, 10, 10);
const floor = new THREE.Mesh(floorGeometry, floorMaterial);
floor.receiveShadow = true;
floor.rotation.x = Math.PI / 2;
this._scene.add(floor);
// SKYBOX/FOG
const skyBoxGeometry = new THREE.BoxGeometry(10000, 10000, 10000);
const skyBoxMaterial = new THREE.MeshPhongMaterial({ color: 0x9999ff, side: THREE.BackSide });
const skyBox = new THREE.Mesh(skyBoxGeometry, skyBoxMaterial);
// scene.add(skyBox);
this._scene.fog = new THREE.FogExp2(0x9999ff, 0.00025);
////////////
// CUSTOM //
////////////
this._world = new CANNON.World();
this._world.gravity.set(0, -9.82 * 20, 0);
this._world.broadphase = new CANNON.NaiveBroadphase();
this._world.solver.iterations = 16;
DiceManager.setWorld(this._world);
// Floor
const floorBody = new CANNON.Body({ mass: 0, material: DiceManager.floorBodyMaterial });
floorBody.addShape(new CANNON.Plane());
floorBody.quaternion.setFromAxisAngle(new CANNON.Vec3(1, 0, 0), -Math.PI / 2);
this._world.addBody(floorBody);
// Walls
const colors = ['#ff0000', '#ffff00', '#00ff00', '#0000ff', '#ff00ff'];
for (let i = 0; i < 5; i++) {
const die = new DiceD6({ size: 1.5, backColor: colors[i] });
this._scene.add(die.getObject());
this._dice.push(die);
}
setInterval(() => this.randomDiceThrow(), 10000);
this.randomDiceThrow();
requestAnimationFrame(() => this.animate());
}
private randomDiceThrow() {
const diceValues = [];
for (let i = 0; i < this._dice.length; i++) {
const yRand = Math.random() * 20;
this._dice[i].getObject().position.x = -15 - (i % 3) * 1.5;
this._dice[i].getObject().position.y = 2 + Math.floor(i / 3) * 1.5;
this._dice[i].getObject().position.z = -15 + (i % 3) * 1.5;
this._dice[i].getObject().quaternion.x = (Math.random() * 90 - 45) * Math.PI / 180;
this._dice[i].getObject().quaternion.z = (Math.random() * 90 - 45) * Math.PI / 180;
this._dice[i].updateBodyFromMesh();
const rand = Math.random() * 5;
this._dice[i].getObject().body.velocity.set(25 + rand, 40 + yRand, 15 + rand);
this._dice[i].getObject().body.angularVelocity.set(20 * Math.random() - 10, 20 * Math.random() - 10, 20 * Math.random() - 10);
diceValues.push({ dice: this._dice[i], value: i + 1 });
}
DiceManager.prepareValues(diceValues);
// this._world.addEventListener('postStep', () => {
// if (this._dice[0].isFinished) {
// console.log('First dice is finished and its value is' + this._dice[0].getUpsideValue());
// }
// });
}
private wait(condition: () => boolean, ready: () => any, checkInterval: number) {
if (condition()) {
ready();
} else {
console.log('hello?');
setTimeout(this.wait(condition, ready, checkInterval), checkInterval);
}
}
private animate() {
this.updatePhysics();
this.render();
this.update();
requestAnimationFrame(() => this.animate());
}
private updatePhysics() {
this._world.step(1.0 / 60.0);
// tslint:disable-next-line:prefer-const
for (let i in this._dice) {
if (this._dice.hasOwnProperty(i)) {
this._dice[i].updateMeshFromBody();
}
}
}
private update() {
this._controls.update();
this._stats.update();
}
private render() {
this._renderer.render(this._scene, this._camera);
}
}
If I add an event listener to the world’s postStep method and do my checks there, like in the commented out section of the randomDiceThrow
method, then my whole scene goes black and nothing is happening. I’d like to know when they are all stable by using isFinished()
on all of them and then get their upside value (using getUpsideValue
). I tried using emulateThrow
that has the callback, but then there is no animation.
I’m sorry if these are noob questions. Thanks!
Issue Analytics
- State:
- Created 6 years ago
- Comments:5 (1 by maintainers)
@byWulf The
check
inprepareValues
seems returnallStable
astrue
right at the start, compared to Teal’s version, where he displays the results label at the end when the visuals have played out.Hey 😃 Sorry for the late response. I’m currently moving to a new city so time is short.
The purpose of this lib is to have random throws but with fixed upper sides. You define the side, which should be up after the throw, before the throw in the DiceManager.prepareValues() method.
Will throw dice 0 so it lands on side 1.
Will throw dice 0 so it lands on the random generated side. You will have the upside value before the throw in
randomValue
.Internally the system first “simulates” the throw and looks, what side is up. And then for the real throw it replaces all sides (and the simulated upper side with the wished value) and then executes the real throw. As the physics don’t change, the switched upper side after the throw will be your defined side.
Hope I could help you!