« Back to Main Page

GameDev2:Physics/First Person Example

From Bold Idea Knowledgebase

This example demonstrates the following:

  • How to create a first-person POV player object that responds to physics and can interact w/ real-world objects
  • How to control a physics player using pointer-lock and typical WASD movement

Click here for a copy of PointerLockControls.js

<html><head><link rel="stylesheet" type="text/css" href="css/style.css"></head>
<body>
	
<!-- Include other libraries here (keep three.js at the top): -->
<script src="js/Three.js"></script>
<script src="js/physi.js"></script>
<script src="js/PointerLockControls.js"></script>
<script src="js/Door.js"></script>

<script>

// Add variables that are defined in other libraries below to avoid warnings:
/* global THREE, Scoreboard, Physijs */


Physijs.scripts.worker = 'js/physijs_worker.js';
Physijs.scripts.ammo = 'ammo.js';

// ****** START CODING HERE! ****** 
// Set our width and height
var width = window.innerWidth, height = window.innerHeight;
// Create your scene.
var scene = new Physijs.Scene();

// Set up the camera
var camera = new THREE.PerspectiveCamera(70, width/height);

// Set up the renderer
var renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setSize(width, height);
renderer.shadowMap.enabled = true;
document.body.appendChild(renderer.domElement);

/**
 * Basic pointer-lock controls
 * 
 * See https://threejs.org/examples/misc_controls_pointerlock.html for a more 
 * complete example of pointer-lock 
 * 
 * Note: don't copy WASD control from that example as it doesn't work w/ physics
 */
var controls = new THREE.PointerLockControls(camera);
document.body.addEventListener('click', function() {
  document.body.requestPointerLock();
  controls.enabled = true;
});

// *** ADD 3D OBJECTS TO YOUR SCENE HERE ***

/**
 * Player object setup
 */
var playerHeight = 6;

// We use a capsueMesh so that the player can move over un-even terrain
var player = new Physijs.CapsuleMesh(
 new THREE.CylinderGeometry(1, 1, playerHeight),
 new THREE.MeshNormalMaterial()
);
player.position.set(-10, -20, 0);
player.visible = false;

// Use the controls object as the player's POV
var pov = controls.getObject();
player.add(pov);
pov.position.set(0, (playerHeight / 10), 0);
scene.add(player);

/**
 * Player WASD Controls
 */
// Keep track of W, A, S, D keypresses
var keyW = false;
var keyA = false;
var keyS = false;
var keyD = false;

document.addEventListener('keydown', function(event) {
  if (event.keyCode == 87) keyW = true;
  if (event.keyCode == 65) keyA = true;
  if (event.keyCode == 83) keyS = true;
  if (event.keyCode == 68) keyD = true;
});

document.addEventListener('keyup', function(event) {
  if (event.keyCode == 87) keyW = false;
  if (event.keyCode == 65) keyA = false;
  if (event.keyCode == 83) keyS = false;
  if (event.keyCode == 68) keyD = false;
});

// Note: this function should be called during animate()
function controlPlayer() {
  // Change this to the speed you want your player to move
  var speed = 10;
    
  // Our player is a pill shape, so this keeps our player from accidentally tipping over
  player.setAngularFactor({ x: 0, y: 0, z: 0 });
    
  // We want to rotate our vector around the Y axis
  var rotateAxis = new THREE.Vector3(0, 1, 0);
  
  if (keyW || keyA || keyS || keyD) {
    // Get a vector based on our direction
    
    // create vectors for each direction
    var vectorFwd = controls.getDirection();
    var vectorLeft = controls.getDirection();
    var vectorRight = controls.getDirection();
    var vectorBack = controls.getDirection();
    vectorLeft.applyAxisAngle(rotateAxis, Math.PI / 2);
    vectorRight.applyAxisAngle(rotateAxis,-Math.PI / 2);
    vectorBack.applyAxisAngle(rotateAxis, Math.PI);
    
    var vector = new THREE.Vector3();
    
    if (keyW) vector.add(vectorFwd);
    if (keyA) vector.add(vectorLeft);
    if (keyS) vector.add(vectorBack);
    if (keyD) vector.add(vectorRight);
    
    // apply speed to our vector
    vector.normalize();
    vector.multiplyScalar(speed);
    
    // If you don't want to allow the player to "fly", set to current Y velocity 
    vector.y = player.getLinearVelocity().y;
    
    // now we just set the velocity to that vector
    player.setLinearVelocity(vector);
    
    // set a flag to indicate that our player is moving
    player.isMoving = true;
  } else {
    // if no keys are , but player is still moving, slow the player down to a halt.
    if (player.isMoving) {
      var vector = player.getLinearVelocity();
      vector.normalize();
      player.setLinearVelocity(vector);
      player.isMoving = false;
    }
  }
}


/**
 * Scene objects
 */
// Our floor has mass of 0 so it doesn't fall w/ gravity
var floor = new Physijs.BoxMesh(
  new THREE.BoxGeometry(50, 1, 50), 
  new THREE.MeshBasicMaterial({color: 0xCCCCCC}),
  0
);
floor.position.set(0, -26, 0);
scene.add(floor);

// Add a ball
var ball = new Physijs.SphereMesh(
  new THREE.SphereGeometry(2, 10, 10),
  new THREE.MeshNormalMaterial()
);
ball.position.set(0, -20, -10);
scene.add(ball);

// Add a fixed box to demonstrate how you can walk over it 
// (because our player uses CapsuleMesh)
var box = new Physijs.BoxMesh(
  new THREE.BoxGeometry(5, .25, 5),
  new THREE.MeshNormalMaterial(),
  0
)
box.position.set(0, -25, 0);
scene.add(box);

function animate() {
 // Use this function to animate your objects.
 // This function runs over 60 times per second!
 // *** ANIMATE YOUR 3D OBJECTS HERE ****
 renderer.render(scene, camera);
 requestAnimationFrame(animate);
 scene.simulate();
 
 controlPlayer();
}


animate();
</script>
</body></html>