UNPKG

cannon-es-control

Version:

A lightweight 3D physics engine written in JavaScript with control system tools

232 lines (182 loc) 6.14 kB
import * as THREE from 'https://unpkg.com/three@0.122.0/build/three.module.js' import * as CANNON from '../../dist/cannon-es-control.js' /** * @author mrdoob / http://mrdoob.com/ * @author schteppe / https://github.com/schteppe */ class PointerLockControlsCannon extends THREE.EventDispatcher { constructor(camera, cannonBody) { super() this.enabled = false this.cannonBody = cannonBody // var eyeYPos = 2 // eyes are 2 meters above the ground this.velocityFactor = 0.2 this.jumpVelocity = 20 this.pitchObject = new THREE.Object3D() this.pitchObject.add(camera) this.yawObject = new THREE.Object3D() this.yawObject.position.y = 2 this.yawObject.add(this.pitchObject) this.quaternion = new THREE.Quaternion() this.moveForward = false this.moveBackward = false this.moveLeft = false this.moveRight = false this.canJump = false const contactNormal = new CANNON.Vec3() // Normal in the contact, pointing *out* of whatever the player touched const upAxis = new CANNON.Vec3(0, 1, 0) this.cannonBody.addEventListener('collide', (event) => { const { contact } = event // contact.bi and contact.bj are the colliding bodies, and contact.ni is the collision normal. // We do not yet know which one is which! Let's check. if (contact.bi.id === this.cannonBody.id) { // bi is the player body, flip the contact normal contact.ni.negate(contactNormal) } else { // bi is something else. Keep the normal as it is contactNormal.copy(contact.ni) } // If contactNormal.dot(upAxis) is between 0 and 1, we know that the contact normal is somewhat in the up direction. if (contactNormal.dot(upAxis) > 0.5) { // Use a "good" threshold value between 0 and 1 here! this.canJump = true } }) this.velocity = this.cannonBody.velocity // Moves the camera to the cannon.js object position and adds velocity to the object if the run key is down this.inputVelocity = new THREE.Vector3() this.euler = new THREE.Euler() this.lockEvent = { type: 'lock' } this.unlockEvent = { type: 'unlock' } this.connect() } connect() { document.addEventListener('mousemove', this.onMouseMove) document.addEventListener('pointerlockchange', this.onPointerlockChange) document.addEventListener('pointerlockerror', this.onPointerlockError) document.addEventListener('keydown', this.onKeyDown) document.addEventListener('keyup', this.onKeyUp) } disconnect() { document.removeEventListener('mousemove', this.onMouseMove) document.removeEventListener('pointerlockchange', this.onPointerlockChange) document.removeEventListener('pointerlockerror', this.onPointerlockError) document.removeEventListener('keydown', this.onKeyDown) document.removeEventListener('keyup', this.onKeyUp) } dispose() { this.disconnect() } lock() { document.body.requestPointerLock() } unlock() { document.exitPointerLock() } onPointerlockChange = () => { if (document.pointerLockElement) { this.dispatchEvent(this.lockEvent) this.isLocked = true } else { this.dispatchEvent(this.unlockEvent) this.isLocked = false } } onPointerlockError = () => { console.error('PointerLockControlsCannon: Unable to use Pointer Lock API') } onMouseMove = (event) => { if (!this.enabled) { return } const { movementX, movementY } = event this.yawObject.rotation.y -= movementX * 0.002 this.pitchObject.rotation.x -= movementY * 0.002 this.pitchObject.rotation.x = Math.max(-Math.PI / 2, Math.min(Math.PI / 2, this.pitchObject.rotation.x)) } onKeyDown = (event) => { switch (event.code) { case 'KeyW': case 'ArrowUp': this.moveForward = true break case 'KeyA': case 'ArrowLeft': this.moveLeft = true break case 'KeyS': case 'ArrowDown': this.moveBackward = true break case 'KeyD': case 'ArrowRight': this.moveRight = true break case 'Space': if (this.canJump) { this.velocity.y = this.jumpVelocity } this.canJump = false break } } onKeyUp = (event) => { switch (event.code) { case 'KeyW': case 'ArrowUp': this.moveForward = false break case 'KeyA': case 'ArrowLeft': this.moveLeft = false break case 'KeyS': case 'ArrowDown': this.moveBackward = false break case 'KeyD': case 'ArrowRight': this.moveRight = false break } } getObject() { return this.yawObject } getDirection() { const vector = new CANNON.Vec3(0, 0, -1) vector.applyQuaternion(this.quaternion) return vector } update(delta) { if (this.enabled === false) { return } delta *= 1000 delta *= 0.1 this.inputVelocity.set(0, 0, 0) if (this.moveForward) { this.inputVelocity.z = -this.velocityFactor * delta } if (this.moveBackward) { this.inputVelocity.z = this.velocityFactor * delta } if (this.moveLeft) { this.inputVelocity.x = -this.velocityFactor * delta } if (this.moveRight) { this.inputVelocity.x = this.velocityFactor * delta } // Convert velocity to world coordinates this.euler.x = this.pitchObject.rotation.x this.euler.y = this.yawObject.rotation.y this.euler.order = 'XYZ' this.quaternion.setFromEuler(this.euler) this.inputVelocity.applyQuaternion(this.quaternion) // Add to the object this.velocity.x += this.inputVelocity.x this.velocity.z += this.inputVelocity.z this.yawObject.position.copy(this.cannonBody.position) } } export { PointerLockControlsCannon }