question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

How would I identify when all the dice have settled when calling prepareValues?

See original GitHub issue

Hello,

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:open
  • Created 6 years ago
  • Comments:5 (1 by maintainers)

github_iconTop GitHub Comments

2reactions
rin3scommented, May 21, 2018

@byWulf The check in prepareValues seems return allStable as true right at the start, compared to Teal’s version, where he displays the results label at the end when the visuals have played out.

0reactions
byWulfcommented, Apr 6, 2018

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.

DiceManager.prepareValues({dice: 0, value: 1});

Will throw dice 0 so it lands on side 1.

let randomValue = Math.floor(Math.random * 6) + 1;
DiceManager.prepareValues({dice: 0, value: randomValue});

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!

Read more comments on GitHub >

github_iconTop Results From Across the Web

1.2 Combinations and permutations
Suppose we roll two dice, say a red die and a green die. ... Why do we know, without listing them all, that...
Read more >
Dice - Wikipedia
Dice (singular die or dice) are small, throwable objects with marked sides that can rest in multiple positions. They are used for generating...
Read more >
Dice -- from Wolfram MathWorld
A die (plural "dice") is a solid with markings on each of its faces. The faces are usually all the same shape, making...
Read more >
Im a little stuck in a dice rolling program in python, am very ...
There's a few improvements: you typically don't want to repeat code, so it would be better to only have the input statement in...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found