I am participating in the Mid-Autumn Festival Creative Submission contest, please see: Mid-Autumn Festival Creative Submission Contest for details

Bo cake (Ba cake), is originated in Xiamen, Fujian Province Mid-Autumn festival traditional activities, then spread to the southern Fujian region. Began in the early Qing Dynasty, zheng Chenggong cantonment soldiers in order to solve the Mid-Autumn Festival lovesickness, encourage morale and invention. Thus, passed down from generation to generation, it has become a unique folk custom in southern Fujian

The annual Mid-Autumn Festival is coming again. In southern Fujian, the most anticipated program of the Festival should be bo cake. After all, the paper towel, toothpaste and toothbrush that Bo received last year have almost been used up, and they are in urgent need of a wave of supplies. However, the epidemic is not over yet, many friends at home also want to experience the fun of bo Cake.

But what if there are no dice at home? What if there are dice without a big red bowl? What if there’s a bowl and dice and friends can’t get together?

Brave niuniu is not afraid of suffering, no boat we build, today to share with you how to quickly develop a 3D bo pie game in half an hour.

Step.1 Preparation

The development tools

For DEMO development, we used CocosCreator, an excellent domestic game development engine that has just released version 3.3. Download the latest version of CocosCreator from CocosCreator3.3

Download and open a new EMPTY 3D project:

Material resources

We need a 3D model of Dice and bowl. You can search Dice and bowl on Sketchfab to find a free model you like

You can download CocosCreator in either GLTF or FBX format

Sound resources

We need a soundtrack, a die roll, and a win/lose cue. Here is a very good foreign music/sound website www.epidemicsound.com/. Although most sound effects are charged, we can request to catch the file address through network (this website is more conscientious, without encryption).

Step.2 Build a scenario

With the resources in place, we can start building the scenario. First, drag the downloaded bowl model into the scene

Find the material option in the right property panel and adjust the color, metal strength, roughness of the material to make the model more textured

To make the material look more realistic, we added a sky box and checked the useIBL option, so the material has the effect of reflecting the environment:

Skybox resources:

Now that the model is ready, but does not have physical properties, we need to add physical components to the model, a static rigid body component and a grid collider to make it have physical collision effects:

MeshCollider is a MeshCollider that is automatically generated from the vertices of the model due to the unique shape of the bowl. It is recommended to use a combination of square colliders and spherical colliders for better performance

Next, pull the dice into the scene and adjust the material properties to give the model a stronger texture

Add a rigidbody and collider to the die as well (the die is Dynamic and the rigidbody type is Dynamic)

Now that the scene is built, run it and see what it looks like:

Step.3 Game logic

The next part of the game logic is to create a new script and mount it on any node of the scene (you can create an empty node to mount it).

Open main. ts, add simple interactive operations, click the screen to fix the dice over the bowl, drag the screen to move the dice, and release the dice:

@property(Node)
public dices: Node = null;
start () {
        this.dice = this.dices.children; // Save the obtained 6 dice nodes
        systemEvent.on(SystemEvent.EventType.TOUCH_START, this.onTouchStart, this);
        systemEvent.on(SystemEvent.EventType.TOUCH_MOVE, this.onTouchMove, this);
        systemEvent.on(SystemEvent.EventType.TOUCH_END, this.onTouchEnd, this);
}
onTouchStart (e) {
    for (let i = 0; i < this.dice.length; i++) {
        let dice = this.dice[i];
        let rb = dice.getComponent(RigidBody); // Walk through the dice node to get the rigid body components on the node
        rb.setLinearVelocity(new Vec3(0.0.0)); // Set the rigidbody speed to 0
        setTimeout(() = > {
            rb.type = ERigidBodyType.KINEMATIC; 
            // Set the rigidbody type to KINEMATIC rigidbody. Dynamic rigidbody cannot interfere with motion mode through script. When controlling dice, the rigidbody type should be set to KINEMATIC first
        }, 0);
        // The rigidbody type change does not take effect in the current frame, so setTimeout is added to force execution in the next frame
        dice.setPosition(dice.position.x, 3, dice.position.z); // Just change the Y value, and the dice is positioned straight up
    }
}
onTouchMove (e) {
    // Drag the dice
    var delta = e.getDelta();
    for (var i = 0; i < this.dice.length; i++) {
        let dice = this.dice[i];
        dice.setPosition(dice.position.x - delta.y / 200.3, dice.position.z - delta.x / 200);
    }
}
onTouchEnd () {
    // Release the dice and add a random velocity and angular velocity impulse
    for (var i = 0; i < this.dice.length; i++) {
        let dice = this.dice[i];
        let rb = dice.getComponent(RigidBody);
        setTimeout(() = > {
            let r = (Math.random() - 0.5) * this.power;
            let ry = -(Math.random() + 0.2) * this.power;
            let rt = (Math.random() - 0.5) * this.power * 20;
            rb.type = ERigidBodyType.DYNAMIC;  // Set RigidBody back to dynamic
            rb.applyImpulse(new Vec3(r, ry, r), new Vec3(0.0.0));
            rb.applyTorque(new Vec3(rt, rt, rt));
        }, 0); }}Copy the code

Run to see the effect:

If it is only used as a tool, it is finished at this stage. If you want the application to judge the result, you need to add the judgment of the poppie rule. We need to know which side comes up when the die stops moving, and we can tell by the Angle between the normal lines, but here I’m using a more understandable way:

Add six empty child nodes to the model, each positioned in the center of each face, so that after the roll is over, we only need to determine which node has the highest Y value, the one facing up

Step.4 Details are perfect

There is a little detail here. The volume of the sound should be adjusted dynamically according to the intensity of the impact. At the same time, the sound of the continuous impact time of the same node should be filtered, otherwise a pile of dice will collide at high speed, and the sound will be mixed. Key code:

start () {
    this.rb = this.getComponent(RigidBody);
    this.vel = new Vec3(0.0.0);
    let Cld = this.getComponent(Collider);
    Cld.on('onCollisionEnter'.this.onCollision, this); // Collision event listener
}
private onCollision (event: ICollisionEvent) {
    let curTime = new Date().getTime();
    if (curTime - this.lastTime > 50) {
        // Transition to 50ms continuous collision
        this.rb.getLinearVelocity(this.vel); // Get the relative velocity of the rigid body at the time of the collision
        this.audioSource.volume = Math.pow(Vec3.len(this.vel), 2) / 100; // Set the volume based on the relative speed
        this.audioSource.play();
    }
    this.lastTime = curTime;
}
Copy the code

Finally, we will complete the DEMO with some instructions

The final DEMO presentation

Desktop version: Mid-Autumn Festival bo cake 3D

The H5 version:

Have fun!