PlayCanvas First Person Character sample code

This tutorial explains how to create solid ground/floor for your character to walk around on as well as how to create a first person character controller to explore your game’s world.

Steps for creating solid ground for a character to walk on:

We need to create a ground or floor that the first person character can walk around on without falling through the ground. To do this we need an entity that has a rigid body, a collider, and a box model.

  1. Click on Add Entity > Entity (to create an empty entity.
  2. Select the entity and rename it “Ground”.
  3. In the Inspector Panel, click on Add Component > Collision. Change the Collision type to Box.
  4. Click on Add Component > Model and then change the model type to Box.
  5. Change the properties of the Ground entity, its Collision component, and Model component to match the following (you can add a material to the Box model if you have one):
    ground
  6. Click on Add Component and select Rigid Body. It’s type will be Static and the Friction set to 0.3 and Restitution set to 0. The settings should look like this:
    rigidbody

You can change the position/scale/rotation size of the ground and it’s rigid body and collider if you want to make the ground bigger or smaller.

Steps for using the first person character controller:

Now we will add the first person character and the script to control it.

  1. Click on Add Entity > Entity (create an empty entity).
  2. Rename the entity “Character”.
  3. Change the Character’s Y position so that it is above the ground when the game launches (eg. Y = 3).
  4. Click on Add Component and add a Collision.
  5. Click on Add Component and add a Rigid Body.
  6. Change the Rigid Body and Collision’s settings to match those shown in the image below. The Character should have a Dynamic Rigid Body and the Collision type should be Capsule.
    components
  7. Click on the Character entity in the hierarchy and click Add Entity > Camera so that the new camera is a child of the Character entity.
    camera
  8. Change the Camera properties to match those shown below.
    camera_settings
  9. In the Assets panel click on on Add Asset and then select Script to create a new script. Name it first_person_movement.js and hit Enter/Return on your keyboard.
  10. Click on your Character entity in the hierarchy (not the camera), select Add Component and then click on Script.
  11. Drag the first_person_movement.js script file on to the script component for the Character.
  12. Double-click the script file in the Assets panel to edit the script. Replace the existing code with the code below and then save the script. Run your game to test it out.

Code for first_person_movement.js script:

pc.script.attribute("camera", "entity", null); // optional, assign a camera entity, otherwise one is created
pc.script.attribute("power", "number", 5000);
pc.script.attribute("lookSpeed", "number", 0.5);

pc.script.create('first_person_movement', function (app) {
    var force = new pc.Vec3();
    
    
    // Creates a new First_person-movement instance
    var First_person_movement = function (entity) {
        this.entity = entity;
        
        this.camera = null;
        this.eulers = new pc.Vec3();
    };

    First_person_movement.prototype = {
        // Called once after all resources are loaded and before the first update
        initialize: function () {
            // Listen for mouse move events
            app.mouse.on("mousemove", this._onMouseMove, this);
            
            // when the mouse is clicked hide the cursor
            app.mouse.on("mousedown", function () {
                app.mouse.enablePointerLock();
            }, this);            
            
            // Check for required components
            if (!this.entity.collision) {
                console.error("First Person Movement script needs to have a 'collision' component");
            }
            
            if (!this.entity.rigidbody || this.entity.rigidbody.type !== pc.BODYTYPE_DYNAMIC) {
                console.error("First Person Movement script needs to have a DYNAMIC 'rigidbody' component");
            }
        },

        // Called every frame, dt is time in seconds since last update
        update: function (dt) {
            // If a camera isn't assigned from the Editor, create one
            if (!this.camera) {
                this._createCamera();
            }
            
            // Get camera directions to determine movement directions
            var forward = this.camera.forward;
            var right = this.camera.right;
            
            // movement
            var x = 0;
            var z = 0;

            // Use W-A-S-D keys to move player
            // Check for key presses
            if (app.keyboard.isPressed(pc.KEY_A) || app.keyboard.isPressed(pc.KEY_Q)) {
                x -= right.x;
                z -= right.z;
            }
            
            if (app.keyboard.isPressed(pc.KEY_D)) {
                x += right.x;
                z += right.z;
            }
            
            if (app.keyboard.isPressed(pc.KEY_W)) {
                x += forward.x;
                z += forward.z;
            }
            
            if (app.keyboard.isPressed(pc.KEY_S)) {
                x -= forward.x;
                z -= forward.z;
            }
            
            // use direction from keypresses to apply a force to the character
            if (x !== 0 && z !== 0) {
                force.set(x, 0, z).normalize().scale(this.power);
                this.entity.rigidbody.applyForce(force);
            }

            // update camera angle from mouse events
            this.camera.setLocalEulerAngles(this.eulers.y, this.eulers.x, 0);
        },
        
        _onMouseMove: function (e) {
            // If pointer is disabled
            // If the left mouse button is down update the camera from mouse movement
            if (pc.Mouse.isPointerLocked() || e.buttons[0]) {
                this.eulers.x -= this.lookSpeed * e.dx;
                this.eulers.y -= this.lookSpeed * e.dy;
            }            
        },
        
        _createCamera: function () {
            // If user hasn't assigned a camera, create a new one
            this.camera = new pc.Entity();
            this.camera.setName("First Person Camera");
            this.camera.addComponent("camera");
            this.entity.addChild(this.camera);
            this.camera.translateLocal(0, 0.5, 0);
        }
    };

    return First_person_movement;
});