Physics in Cocos Creator

Introduction

In this tutorial, we are going to look at the basics of using the physics system built into Cocos Creator. The underlying physics engine used is the Box2D physics library. By using a physics engine, you can use simulation and mathematics to calculate the movement in your game world based on gravity, collisions and more

Physics in Cocos Creator

Just like in the previous tutorial, we define collision nodes that define the shapes of our various objects to the physics engine. We are going to create the following simple simulation:

Bowling Physics - Simple Simulation - Physics in Cocos Creator

Let’s start things off with creating the bowling ball. It’s a sprite I downloaded off the internet and created as a sprite node. I think attached a Rigid Body to it. Rigid Bodies are the heart of the physics simulation. These are the entities that the physics engine operates on.

Physics in Cocos Creator - Rigid Bodies

There are a few relevant settings here. Most important is type. In this case, Dynamic, which means that this object is part of the physics simulation and in fact should be moved by the results of the physics calculations. Enabled Contact Listener is important to be selected if you want the collision callback to be called on this object’s script when a collision occurs.

We also need to define the physics shape of our object. This is nearly identical to the Collider Object we used earlier, but instead using special physics versions:

Special Physics

Be sure to use the Physics Component->Collider shapes and not the ones we used in the Collision tutorial. This is a painful mistake to make, trust me!

For our bowling ball, a Circle shape is a no-brainer. In addition to shapes, there are some important physical properties you can define as part of the shape.

const {ccclass, property} = cc._decorator; @ccclass export default class NewClass extends cc.Component { onLoad () { cc.director.getPhysicsManager().enabled = true; } }

Now let’s add some logic to our bowling ball. Attach the following script to your bowling ball object:

const {ccclass, property} = cc._decorator;

@ccclass
export default class BowlingBallController extends cc.Component {
    onLoad () {
        //this.getComponent(cc.RigidBody).enabledContactListener = true;
        this.node.on(cc.Node.EventType.MOUSE_DOWN,(event:cc.Event.EventCustom)=>{
            this.getComponent(cc.RigidBody).gravityScale = 0.8;          
            console.log("click");
        },this);
    }

    onBeginContact(contact, self, other) {
        this.getComponent(cc.AudioSource).play();
    }
    start () {
    }
}

This code listens for a mouse to be clicked on the bowling ball. In the properties for our ball, we set the gravityScale to 0, so it was unaffected by gravity. In this code, we turn the gravity back on, which then causes our ball to start falling. I also have attached an audio source to the ball, that plays a sound when a collision occurs. Notice the callback onBeginContact()? This is called when a collision between objects occurs. In this case, we simply play our hit noise when a collision occurs. Once again you are passed in details of the object you collided with, as well as details of where the contact occurred in case you wanted to do additional calculations.

The rest of our scene is pretty straight forward, just giving us some objects to collide with:

Clipboard-Image_8

The pins are each just rigid bodies, but using Physics Polygon Colliders instead of circle colliders. Finally, there is the floor, which is a simple node with a scaled Physics Box Collider attached. The biggest difference with this node is it’s stationary. We want it to be part of the physics simulation, but not affected by it. In other words, we want our ball and pins to hit the floor, but we don’t want the floor to move when hit. It is still created as a Rigid Body, but in this case, Type is defined as Static:

Rigid Body

The other two types of Rigid Body are Kinematic and Animated. Animated is set up to work with the built-in animation system, while Kinematic is for objects the user is meant to control directly. So instead of the physics simulation determining where the Kinematic object should move, code is instead used, and the physics engine responds to the changes. A Kinematic body is generally used for your character controller, where player input determines how the object should be moved.

With a Kinematic object, you can just move it around the scene normally, such as with the following code:

export default class KinematicController extends cc.Component {
    onKeyDown(e:cc.Event.EventCustom){
        switch(e.keyCode){
            case cc.KEY.right:
                this.node.x += 25;
                break;
                case cc.KEY.left:
                this.node.x -= 25;
                break;       
                case cc.KEY.up:
                this.node.y += 25;
                break;       
                case cc.KEY.down:
                this.node.y -= 25;
                break;                                                
        }
    }

    onLoad () {
        cc.systemEvent.on(cc.SystemEvent.EventType.KEY_DOWN,
            this.onKeyDown,this);
    }
}

When you run into other physics objects, they will respond accordingly. So a kinematic body is one whose position you control directly, but that will influence other physics objects in the simulation.

You can also move around Rigid Body objects, but you don’t do it by manipulating their position directly. Instead, you can apply force and impulses to them and let the simulation engine do the work. So if you are working with a dynamic object, you can move it like this:

  case cc.KEY.right:
        this.getComponent(cc.RigidBody).applyForceToCenter(new cc.Vec2(10000,0),true);
        break;
        case cc.KEY.left:
        this.getComponent(cc.RigidBody).applyForceToCenter(new cc.Vec2(-10000,0),true);
        break;       
        case cc.KEY.up:
        this.getComponent(cc.RigidBody).applyLinearImpulse(new cc.Vec2(0,1000),new cc.Vec2(0.5,0.5),true);
        break;       
        case cc.KEY.down:
        this.getComponent(cc.RigidBody).applyLinearImpulse(new cc.Vec2(0,-1000),new cc.Vec2(0.5,0.5),true);
        break;

Scroll to Top