I tried to make a dice roller solver for D8, D10, D12, D20

Hello! I’m making a dice roller for playing with my friends. Until now I have physics and I can get the results for D4 dice and D6 dice. I want to get the result for other dices. I tried to code for D8 but I messed up. I did some search in this forum and other forums to get what I have now.

How do I get the dice face upwards for that other dices, please?
I want to make it works for D8, D10, D12 and D20.

Thanks in advance.

Here is my code:

// These functions I got in a topic.
public static Vector3f getRight(final Quaternion rotation, Vector3f store) {
	if(store == null){
		store = new Vector3f(1,0,0);
	}
	return rotation.mult(store);
}

public static Vector3f getUp(final Quaternion rotation, Vector3f store) {
	if(store == null){
		store = new Vector3f(0,1,0);
	}
	return rotation.mult(store);
}

public static Vector3f getForward(final Quaternion rotation, Vector3f store) {
	if(store == null){
		store = new Vector3f(0,0,1);
	}
	return rotation.mult(store);
}

// Here is my code for D4 and D6 (I got some parts in a topic)
int getResultD4(RigidBodyControl rbc) {
        			
	Vector3f up         = getUp(rbc.getPhysicsRotation(), null);
	Vector3f right      = getRight(rbc.getPhysicsRotation(), null);
	Vector3f forward    = getForward(rbc.getPhysicsRotation(), null);

	Vector3f negUp      = up.clone().negate();
	Vector3f negRight   = right.clone().negate();
	Vector3f negForward = forward.clone().negate();
	
	Vector3f[] values_d4 = {
			forward.clone(),
			right.clone(),
			negRight.clone(),
			up.clone()
	};
	
	int result = checkDiceValuesMaxRange(values_d4);
	
	return result;
}

// D6 dice
public int getResultD6(RigidBodyControl rbc) {
  	
	Vector3f up         = getUp(rbc.getPhysicsRotation(), null);
	Vector3f right      = getRight(rbc.getPhysicsRotation(), null);
	Vector3f forward    = getForward(rbc.getPhysicsRotation(), null);

	Vector3f negUp      = up.clone().negate();
	Vector3f negRight   = right.clone().negate();
	Vector3f negForward = forward.clone().negate();
	
	Vector3f[] values_d6 = {
		up.clone(),
		negRight.clone(),
		forward.clone(),
		negForward.clone(),
		right.clone(),
		negUp.clone()
	};
	
	int result = checkDiceValuesMaxRange(values_d6);
	
	return result;
}

private int checkDiceValuesMaxRange(Vector3f[] values) {
			
	int result = -1;
	
	float max = 0;
	for(int i = 0; i < values.length; i++){
		float dotProduct = Vector3f.UNIT_Y.clone().dot(values[i].clone());
		
		if(dotProduct > max) {  
			max = dotProduct;
			result = i + 1;
		}            
	}
	
	return result;
}

For the D8 dice I tried to use Vector3f.angleBetween but I didn’t know what I was doing and obviously the result was not right. I don’t know how to make the directions array for dices with more than six sides. I tried to change the array with more directions but I don’t know the math for it.

1 Like

I did it for D6 for a game, few years ago, and used the same technique as yours. However I never had to go further because with stuck with the D6.

Today I would use a different approach though. I would use physics to roll, with a random initial impulsion and direction (as you may do yourself) but, to know the upward face, I would do a ray cast from right above the dice and get the first hit of the dice geometry. This would give you the upward face of the geometry, and from there you could resolve the result.
This has the advantage to work for any kind of dice except for D4 (though for D4 you just have to take the second hit…).

3 Likes

Thank you very much! :grinning: I did it and it works perfectly. I just needed to change the triangle indexes.

Here is the new code:

int getD8ResultRaycast(Spatial dice) {
        
        int result = -1;
        
        CollisionResults results = new CollisionResults();
        
        Vector3f diceRayPos = dice.getWorldTranslation().clone();
        
        diceRayPos.set(diceRayPos.x - -0.03f, diceRayPos.y + 2f, diceRayPos.z);
                
        Ray ray = new Ray(diceRayPos, Vector3f.UNIT_Y.clone().negate());
        
        dice.collideWith(ray, results);
        
        int[] d8_values = { 5, 7, 6, 8, 3, 1, 4, 2 };
        
        for (int i = 0; i < results.size(); i++) {
                        
            int t = results.getCollision(i).getTriangleIndex();
            
            Mesh m = results.getCollision(i).getGeometry().getMesh();
            
            for (int j = 0; j < m.getTriangleCount(); j++) {
                if(t == j) {
                    result = d8_values[j];
                    break;
                }
            }
        }
        return result;
    }
3 Likes