Thursday, September 15, 2022
HomeGame DevelopmentTutorial: First Person Camera and Controls - Cocos Creator

Tutorial: First Person Camera and Controls – Cocos Creator


Hi All,

I believed I’d create slightly tutorial on making a primary individual digital camera and controls. First individual digital camera and controls will open up many door methods in making many various video games so having the ability to do that shortly and easily is essential. So this tutorial goals to be that. Something you should utilize time and time once more and edit nevertheless you want. I’m not going to get into too many specifics.

So to begin create a brand new empty(3D) mission. I’m at the moment utilizing Editor model 3.5.0, though hopefully every thing ought to work in newer variations too.

Once created add a brand new “Scene” within the Assets panel:

I then add a brand new Folder and name it “Scripts” I then proper click on on the folder and create new TypeScript → NewComponent. I make three of those known as cameraScript, globalVars and playerScript.
2

I then create a brand new terrain within the belongings panel known as “Terrain”.
3

Ok now which means our belongings are all arrange. Now we will make the adjustments to the scene. I first drag the terrain over to the editor window. Then create a brand new Capsule.

I then identify the Capsule “Player” and place it above the terrain.

I then drag the “playerScript” from the Assets panel over to the item inspector. Then add two new physics elements known as RigidBody and SphereCollider. The rigidbody provides the character it’s physics. I’ve set mass to 70, Linear and Angular damping each to 0.2, Linear Factor (1,1,1) and Angular Factor to (0,0,0). The SphereCollider provides the item its physics form. I set the Radius to 2.

I then choose the Terrain object. I give it 2 physics elements. RigidBody and TerrainCollider. I set the Rigidbody sort to static as this terrain received’t be shifting anyplace. The TerrainCollider makes use of the terrain mesh for the physics. I additionally needed to take away the terrain urgent the x subsequent to it and choosing the Terrain.terrain.

Last factor we have to do is choose the Main Camera that ought to already be in your scene. Drag the “cameraScript” from the belongings panel over to the item inspector. I additionally modified the FOV to 60.

You can then edit your terrain and make it look nevertheless you need.

So now for the script. I’ve stored it so simple as attainable to observe however to make issues simpler I’ll clarify that the globalVars is the place you may add extra international variables if you want. I put the digital camera node and participant node within the character and digital camera international variables. Which permits for these to be known as from anyplace.

cameraScript

import { _decorator, Component, Input, Vec3, enter,  sport, Node } from 'cc';
import { globalVars } from './globalVars';
const { ccclass, property } = _decorator;

@ccclass('cameraScript')
export class cameraScript extends Component {

    /* Local Variables */

        non-public mouseXSensitvity: quantity = 8;
        non-public mouseYSensitvity: quantity = 5;
        non-public mousePos = new Vec3(0, 0, 0);

    /* End Local Variables */

    begin() {
        globalVars.begin = 0;
        globalVars.digital camera = this;
        doc.addEventListener('pointerlockchange', this.lockChange, false);
        enter.on(Input.EventType.MOUSE_MOVE, this.onMouseMove, this);
        enter.on(Input.EventType.MOUSE_UP, this.onMouseUp, this);
    }

    replace(deltaTime: quantity) {
        this.node.setPosition(globalVars.character.node.getPosition());
        if(globalVars.begin == 1){
            if(this.mousePos.x >= 300 && this.mousePos.x <= 500){
                this.node.setRotationFromEuler(this.mousePos);
            } else if(this.mousePos.x < 300){
                this.node.setRotationFromEuler(300, this.mousePos.y,0);
            } else if(this.mousePos.x > 500){
                this.node.setRotationFromEuler(500, this.mousePos.y,0);
            }
            globalVars.character.node.setRotationFromEuler(new Vec3(0, this.mousePos.y, 0));
        }
    }

    onMouseUp(occasion:EventMouse){
        if(globalVars.begin == 0){
            if (sport.canvas.requestPointerLock) {
                sport.canvas.requestPointerLock();
            }
        }
    }

    lockChange() {
        if (doc.pointerLockElement === sport.canvas ) {
          globalVars.begin = 1;
        } else {
          globalVars.begin = 3;
          setTimeout( () => { globalVars.begin = 0; }, 1800 );
        }
    }

    onMouseMove(occasion:EventMouse){
        this.mousePos.x = 330 + occasion.getLocation().y/this.mouseXSensitvity;
        this.mousePos.y = -event.getLocation().x/this.mouseYSensitvity;
    }
}

globalVars

import { _decorator, Component } from 'cc';
const { ccclass, property } = _decorator;

@ccclass('globalVars')
export class globalVars extends Component {
    
    /* Global Variables */

        public character;
        public digital camera;
        public begin = 0;

    /* End Global Variables */ 
}

playerScript

import { _decorator, Component, Node, sport, enter, Input, KeyCode, EventKeyboard, Vec3, SphereCollider, ICollisionEvent, RigidBody } from 'cc';
import { globalVars } from './globalVars';
const { ccclass, property } = _decorator;

@ccclass('PlayerScript')
export class PlayerScript extends Component {

    /* Local Variables */

        non-public movementSpeed = 3;
        non-public jumpStrength = 300;
        non-public crouch = 0;
        non-public moveForward = 0;
        non-public moveBackward = 0;
        non-public moveLeft = 0;
        non-public moveRight = 0;
        non-public setSpeed = 0.12;
        non-public maxSpeed = 0;
        non-public pace = 1;
        non-public grounded = false;
        non-public collider: SphereCollider = null!;
        non-public playerHeight = 2;

    /* End Local Variables */
    
    begin() {
        globalVars.character = this;
        enter.on(Input.EventType.KEY_DOWN, this.onKeyDown, this);
        enter.on(Input.EventType.KEY_UP, this.onKeyUp, this)
        this.node.getComponent(SphereCollider).on('onCollisionStay', this.OnCollisionStay, this);
        this.node.getComponent(SphereCollider).on('onCollisionExit', this.OnCollisionExit, this);
        this.node.getComponent(SphereCollider).radius = this.playerHeight;
        this.maxSpeed = this.setSpeed;
    }

    OnCollisionStay(occasion: ICollisionEvent) {
        occasion.contacts.forEach(contact => {
            let loose: Vec3 = new Vec3();
            contact.getWorldNormalOnB(out);
            if (Vec3.angle(out, Vec3.UP) < 60) {
                this.grounded = true;
            }
        });
    }

    OnCollisionExit() {
        this.grounded = false;
    }

    onKeyDown(occasion: EventKeyboard){
        swap(occasion.keyCode) {
            case KeyCode.KEY_A: {
                this.moveLeft = 1;
            break;}

            case KeyCode.KEY_W: {
                this.moveForward = 1;
            break;}

            case KeyCode.KEY_D: {
                this.moveRight = 1;
            break;}

            case KeyCode.KEY_S: {
                this.moveBackward = 1;
            break;}

            case KeyCode.SHIFT_LEFT: {
                this.pace = 1.1;
            break;}

            case KeyCode.KEY_C: {
                if(this.crouch == 0){
                    this.crouch = 1;
                    this.node.getComponent(RigidBody).clearForces();
                    this.node.getComponent(SphereCollider).radius = this.playerHeight/1.4;
                    this.maxSpeed = this.setSpeed/1.4;
                } else if(this.crouch == 1){
                    this.crouch = 0;
                    this.node.getComponent(SphereCollider).radius = this.playerHeight;
                    this.maxSpeed = this.setSpeed;
                }
            break;}

            case KeyCode.SPACE: {
                if(this.grounded && this.crouch == 0){
                    this.node.getComponent(RigidBody).applyLocalPower(new Vec3(0,this.jumpStrength*this.node.getComponent(RigidBody).mass,0), new Vec3(0,10,0));
                }
            break;}
        }
    }

    onKeyUp(occasion: EventKeyboard){
        swap(occasion.keyCode) {
            case KeyCode.KEY_A: {
                this.moveLeft = 0;
            break;}

            case KeyCode.KEY_W: {
                this.moveForward = 0;
            break;}

            case KeyCode.KEY_D: {
                this.moveRight = 0;
            break;}

            case KeyCode.KEY_S: {
                this.moveBackward = 0;
            break;}

            case KeyCode.SHIFT_LEFT: {
                this.pace = 1;
            break;}
        }
    }

    replace(deltaTime: quantity) {
            if(this.moveForward && this.moveLeft){
                this.node.getComponent(RigidBody).applyLocalImpulse(new Vec3(-((this.maxSpeed/2)*this.node.getComponent(RigidBody).mass)*this.pace,0,-((this.maxSpeed/2)*this.node.getComponent(RigidBody).mass)*this.pace));
            } else if(this.moveForward && this.moveRight){
                this.node.getComponent(RigidBody).applyLocalImpulse(new Vec3(((this.maxSpeed/2)*this.node.getComponent(RigidBody).mass)*this.pace,0,-((this.maxSpeed/2)*this.node.getComponent(RigidBody).mass)*this.pace));
            } else if(this.moveBackward && this.moveLeft){
                this.node.getComponent(RigidBody).applyLocalImpulse(new Vec3(-((this.maxSpeed/2)*this.node.getComponent(RigidBody).mass)*this.pace,0,((this.maxSpeed/4)*this.node.getComponent(RigidBody).mass)*this.pace));
            } else if(this.moveBackward && this.moveRight){
                this.node.getComponent(RigidBody).applyLocalImpulse(new Vec3(((this.maxSpeed/2)*this.node.getComponent(RigidBody).mass)*this.pace,0,((this.maxSpeed/4)*this.node.getComponent(RigidBody).mass)*this.pace));
            } else if(this.moveForward){
                this.node.getComponent(RigidBody).applyLocalImpulse(new Vec3(0,0,-(this.maxSpeed*this.node.getComponent(RigidBody).mass)*this.pace));
            } else if(this.moveBackward){
                this.node.getComponent(RigidBody).applyLocalImpulse(new Vec3(0,0,((this.maxSpeed/2)*this.node.getComponent(RigidBody).mass)*this.pace));
            } else if(this.moveLeft){
                this.node.getComponent(RigidBody).applyLocalImpulse(new Vec3(-(this.maxSpeed*this.node.getComponent(RigidBody).mass)*this.pace,0,0));
            } else if(this.moveRight){
                this.node.getComponent(RigidBody).applyLocalImpulse(new Vec3((this.maxSpeed*this.node.getComponent(RigidBody).mass)*this.pace,0,0));
            }
    }
}

Once you substitute your scripts with the above. Save the scripts and save the scene within the editor. Then take a look at the mission and it’s best to now have first individual controls with AWSD motion, crouch (c key), dash (Hold left shift) and soar (spacebar). When you click on on the window the mouse will disappear. Press the escape key to see the mouse once more.

Any questions or additions and so forth. Please let me know.

Thanks,
-iDev



RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments