The PointerLockControls feature seems to be failing to actually lock my pointer

Uncaught TypeError: THREE.PointerLockControls is not a constructor

I'm facing an issue with using firstperson controls and I can't seem to figure out the reason behind it. It's really throwing me off.

  const THREE = require('THREE');
  var FirstPersonControls = require('first-person-controls');

  const CANNON = require('cannon');
  var keyboard  = new THREEx.KeyboardState();
  var lights = [];
  var camSpeed = 1;
  var world, mass, body, body2, shape, shape2, timeStep=1/60,
     camera, scene, renderer, geometry, material, mesh, textureCube;
  initThree();
  initCannon();
  animate();
  function initCannon() {
      world = new CANNON.World();
      world.gravity.set(0,-9.8,0);
      world.broadphase = new CANNON.NaiveBroadphase();
      world.solver.iterations = 10;
      shape = new CANNON.Box(new CANNON.Vec3(1,1,1));
      shape2 = new CANNON.Box(new CANNON.Vec3(50,1,50));
      mass = 1;
      body = new CANNON.Body({
        mass: 1
      });
      body2 = new CANNON.Body({
        mass: 0
      });
      body.position.set(1,10,1);
      body.addShape(shape);
      body2.addShape(shape2);
      body.angularDamping = 0.5;
      world.addBody(body);
      world.addBody(body2);
  }
  function initThree() {
      scene = new THREE.Scene();
      camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 10000 );
      var controls = new THREE.FirstPersonControls(camera);
        controls.lookSpeed = 0.1;
        controls.movementSpeed = 10;

        var clock = new THREE.Clock(true);
      var prefix = ".png"
      var r = __dirname + "/skyboxes/mp_cliffside/";
            var urls = [
                r + "px" + prefix, r + "nx" + prefix,
                r + "py" + prefix, r + "ny" + prefix,
                r + "pz" + prefix, r + "nz" + prefix
            ];
            textureCube = new THREE.CubeTextureLoader().load( urls );
    var dottedAlphaMap = new THREE.TextureLoader().load( __dirname + "/textures/brickmap.png" );
    var dottedAlphaMap2 = new THREE.TextureLoader().load( __dirname + "/textures/stonemap-wet-texture.jpg" );


            scene.background = textureCube;
      lights[0] = new THREE.PointLight( '#ffffff', 3, 100 );
        lights[0].position.set( 0, 5, 0 );
        scene.add( lights[0] );
      scene.add( camera );
      renderer = new THREE.WebGLRenderer({ alpha:false });
      renderer.setSize( window.innerWidth, window.innerHeight );
      camera.position.y = 40;
      camera.rotation.x = -90 * Math.PI / 180;
      document.body.appendChild( renderer.domElement );


  }
  function animate() {
      requestAnimationFrame( animate );
      updatePhysics();
      render();
  }
  var controllee = camera;
  function updatePhysics() {
      // Step the physics world
      world.step(timeStep);
      // Copy coordinates from Cannon.js to Three.js
      lights[0].position.copy(camera.position)
  }
  function render() {
    requestAnimationFrame(render);

    controls.update(clock.getDelta());
    if(keyboard.pressed("F")){
        camera.fov += 0.1;
            camera.updateProjectionMatrix();
    }
    if(keyboard.pressed("G")){
        camera.fov -= 0.1;
            camera.updateProjectionMatrix();
    }
    if(keyboard.pressed("space")){
        controllee.translateY(camSpeed/10);
    }
    if(keyboard.pressed("shift")){
        controllee.translateY(-camSpeed/10);
    }
    if(keyboard.pressed("W")){
        controllee.translateZ(-camSpeed/10);
    }
    if(keyboard.pressed("S")){
        controllee.translateZ(camSpeed/10);
    }
    if(keyboard.pressed("A")){
        controllee.translateX(-camSpeed/10);
    }
    if(keyboard.pressed("D")){
        controllee.translateX(camSpeed/10);
    }
    if(keyboard.pressed("I")){
        controllee.rotateX(camSpeed/100);
    }
    if(keyboard.pressed("K")){
        controllee.rotateX(-camSpeed/100);
    }
    if(keyboard.pressed("J")){
        controllee.rotateY(camSpeed/100);
    }
    if(keyboard.pressed("L")){
        controllee.rotateY(-camSpeed/100);
    }
    if(keyboard.pressed("U")){
        controllee.rotateZ(camSpeed/100);
    }
    if(keyboard.pressed("O")){
        controllee.rotateZ(-camSpeed/100);
    }
      renderer.render( scene, camera );
  }

I am utilizing three.js and cannon.js imported from the node package manager.

I am attempting to achieve first-person shooter-like controls, but obstacles like this keep arising!

I would greatly appreciate any assistance, as I suspect the issue may lie in the three npm version, in which case, I'm out of luck.

Update: I have adjusted my code to incorporate three.js via a script tag. Similarly, I have included PointerLockControls, but now I am unsure how to lock the pointer.

Answer №1

Remember that in order to lock your mouse to the screen and look around like in an FPS game, you need to use "controls.lock()".

Unfortunately, locking the mouse pointer from code is not possible. You must have a user interaction with a DOM element to achieve this.

The easiest DOM element to use is the "body", as shown below:

// Include document.body in PointerLockControls constructor
let fpsControls = new PointerLockControls( camera ,  document.body );

// Add event listener to document.body
document.body.addEventListener( 'click', function () {
    // Lock the mouse on the screen
    fpsControls.lock();
}, false );

NOTE 1: You do not need to call fpsControls.update() in the animation function;

NOTE 2: Ensure that your body section is in front of the canvas and covers the entire screen. You can set z-index: -1 on the canvas' CSS or z-index: 10 in body's CSS. Example:

body{
  z-index: 10
  margin: 0;
  padding: 0;
  height: 100vh;
  width: 100vh;
  overflow: hidden;
}

This setup allows you to click anywhere on the screen to experience the desired behavior. Press ESC to unlock the controller.

Stay Calm and Happy Coding

Answer №2

However, my current issue lies in my lack of knowledge on how to secure the pointer properly.

One way to achieve this is by following the steps outlined in this reference:

  • Design a splash screen displaying "Click to Begin"
  • Set up a click event listener for the specific DOM element
  • Within the listener's code, utilize
    document.body.requestPointerLock()
    to prompt the browser for pointer lock access

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Having trouble with your Ajax post request?

I am currently working on creating a form that allows users to input information and submit it without the page refreshing. The processing of the form data will occur after the user clicks the submit button. To achieve this, I am utilizing jQuery and Ajax ...

Having trouble removing a cookie in express?

Seems pretty straightforward. In the /user/login route, I set a cookie as shown below: if (rememberMe) { console.log('Login will be remembered.'); res.cookie('user', userObj, { signed: true, httpOnly: true, path: '/' ...

Encountered an issue retrieving audio during recording with Recorder.js

I've come across a scenario where I'm utilizing the Recorder.js Demo for recording audio. Interestingly, it works perfectly on Linux but encounters an issue when used on Windows. A pop-up alert stating "Error getting audio" shows up. Here's ...

AngularJS continues to display an "Invalid Request" message whenever the requested resource is unavailable

When I try to fetch a group of images through AJAX and exhibit them on the page using ng-repeat, an issue arises with the image source tags. These tags send incorrect requests to the server before the collection is retrieved, leading to error messages in t ...

Learn how to utilize the combineLatest/zip operators to only respond to emissions from the second observable while disregarding emissions from the first observable

Here's an example of how I'm initializing a property: this.currentMapObject$ = zip(this.mapObjects$, this.currentMapObjectsIndex$, (mapObjects, index) => mapObjects[index]); I want the value of this.currentMapObject$ to be emitted only ...

Issue with JavaScript ScrollTop

Simply put, I am trying to determine the total scroll size for a text area in a unit that scrollTop can align with. However, I am at a loss on how to do so. I've tried scrollHeight and various other methods without success. Any advice or suggestions ...

Implementing Ajax functionality in MVC 3 to return a partial view

I wanted to express my gratitude for this invaluable site that has taught me so much. Currently, I am working on an MVC3 component where I need to populate a selectlist and upon user selection, load a partial view with the relevant data displayed. Everythi ...

Navigating through the complexities of scoping in JavaScript when integrating Node.js

Currently, I am working on an express.js application without using mongoose. My goal is to create a function that can handle calls to MongoDB, pass parameters to it, and retrieve data from the database. However, I have encountered a problem with the foll ...

Empty Canvas: Google Charts Graph Fails to Populate

I am currently using mysql, php, and javascript to display a curve chart. The issue I am facing is that the chart appears blank. google.load('visualization', '1.0', {'packages':['corechart']}); google.setOnLo ...

Updating individual items in the Redux state while displaying the previous version

I'm facing an issue with updating the reducer for my items (icdCode) in my array (icdCodes) within a React component. The update works only after reloading the entire component, which is not ideal. Initially, I had to deal with a duplicate key problem ...

Having trouble displaying a JSON response on an HTML page with AJAX

I've written an AJAX function that goes like this: function ajx(){ var ajaxRequest; // This variable makes Ajax possible! try{ // Works in Opera 8.0+, Firefox, Safari ajaxRequest = new XMLHttpRequest(); } catch (e){ // For Internet Exp ...

Conceal dynamically generated div elements created with ngIf

I am currently working on initializing this div using ngOnInit in Angular ngOnInit(): void { let optTemp = ''; for (let data of arrOption) { optTemp = optTemp + '<option>' + data.trim() + '</option> ...

Discover the steps to display a user's username following a successful login utilizing Passport.js

I want to display the message "Welcome back "username here" " to a user after they have logged in successfully on the website. The issue is that logging in with passport is not a typical request and response process, as the authentication occurs within th ...

I want to add an LI element to a UL by utilizing jQuery in forms.js

I have several forms on my webpage and I am utilizing jQuery form.js to save each comment that users post. After saving the comment successfully, I want to append it to the UL tag. Although the saving part is functioning properly, I am encountering difficu ...

Sort subcategories based on the selected category from the dropdown menu

I'm feeling a bit stuck at the moment. My goal is to show specific subcategories when a particular category is chosen from the dropdown menu. For example, let's say we have these categories: Cate1 Cate2 Under Cate1, we can find: Sub1 Sub2 an ...

Retrieve the information in a div element from an external website by utilizing AJAX

Exploring the world of AJAX is new to me, and I am eager to fetch content from a div on an external site and display it on my own website. Below is the current code snippet I have: <html> <head> <script src="https://ajax.googleapis.com ...

Tax calculator that combines item prices and applies tax multiplication

Struggling to crack the code for my calculator. Despite consulting my textbook, I can't seem to figure out why it won't calculate properly. Any advice or tips would be greatly appreciated. <html> <head> <title> Total Calculator ...

React.js Component Composition Problem

I am attempting to replicate the following straightforward HTML code within a React environment: Traditional HTML <div> Hello <div>child</div> <div>child</div> <div>child</div> </div> React(working ...

Retrieving Data from Outside Source using AngularJS

Is there a way to retrieve JSON-Text-Stream data from a specific URL (e.g. SOMEURL/ean.php?id=4001513007704)? The returned result typically appears as follows: { "product": { "ean_id": "4001513007704", "title": "Gerolsteiner Mineralw ...

How can jQuery incorporate additional selection criteria for a parent element?

How can I apply a specific criteria to a node that has been selected using jQuery? let objDIV = $("#selindividual").parent(); After retrieving the DIV, I want to target the following: button:contains(\"Submit\") If I had to do this in ...