Created
April 10, 2021 18:03
-
-
Save jcampuza/45b0de8f91608310a877a2b45e9d9099 to your computer and use it in GitHub Desktop.
FirstPersonControls for three.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Camera, Euler } from 'three'; | |
export class FirstPersonControls { | |
constructor(private camera: Camera, private domElement: HTMLElement) { | |
this.connect(); | |
} | |
state = { | |
mousedown: false, | |
enabled: false, | |
previousPointerX: 0, | |
previousPointerY: 0, | |
}; | |
set enabled(value: boolean) { | |
this.state.enabled = value; | |
} | |
connect() { | |
this.domElement.addEventListener('mousedown', this.onPointerdown); | |
this.domElement.addEventListener('mouseup', this.onPointerup); | |
this.domElement.addEventListener('mouseout', this.onPointerup); | |
this.domElement.addEventListener('mousemove', this.onPointerMove); | |
this.domElement.addEventListener('touchstart', this.onPointerdown); | |
this.domElement.addEventListener('touchend', this.onPointerup); | |
this.domElement.addEventListener('touchcancel', this.onPointerup); | |
this.domElement.addEventListener('touchmove', this.onPointerMove); | |
} | |
disconnect() { | |
this.domElement.removeEventListener('mousedown', this.onPointerdown); | |
this.domElement.removeEventListener('mouseout', this.onPointerup); | |
this.domElement.removeEventListener('mouseup', this.onPointerup); | |
this.domElement.removeEventListener('mousemove', this.onPointerMove); | |
this.domElement.removeEventListener('touchstart', this.onPointerdown); | |
this.domElement.removeEventListener('touchend', this.onPointerup); | |
this.domElement.removeEventListener('touchcancel', this.onPointerup); | |
this.domElement.removeEventListener('touchmove', this.onPointerMove); | |
} | |
getPointerClientPosition(e: MouseEvent | TouchEvent) { | |
return { | |
clientX: e instanceof MouseEvent ? e.clientX : e.touches[0].clientX, | |
clientY: e instanceof MouseEvent ? e.clientY : e.touches[0].clientY, | |
}; | |
} | |
onPointerdown = (e: MouseEvent | TouchEvent) => { | |
if (!this.state.enabled) { | |
return; | |
} | |
e.preventDefault(); | |
e.stopPropagation(); | |
this.state.mousedown = true; | |
const { clientX, clientY } = this.getPointerClientPosition(e); | |
this.state.previousPointerX = clientX; | |
this.state.previousPointerY = clientY; | |
}; | |
onPointerup = () => { | |
if (!this.state.enabled) { | |
return; | |
} | |
this.state.mousedown = false; | |
this.state.previousPointerX = 0; | |
this.state.previousPointerY = 0; | |
}; | |
onPointerMove = (e: TouchEvent | MouseEvent) => { | |
if (!this.state.enabled) { | |
return; | |
} | |
if (!this.state.mousedown) { | |
return; | |
} | |
const { clientX, clientY } = this.getPointerClientPosition(e); | |
const delta = { | |
x: clientX - this.state.previousPointerX, | |
y: clientY - this.state.previousPointerY, | |
}; | |
this.state.previousPointerX = clientX; | |
this.state.previousPointerY = clientY; | |
const euler = new Euler(0, 0, 0, 'YXZ'); | |
euler.setFromQuaternion(this.camera.quaternion); | |
euler.y += delta.x * 0.003; | |
euler.x += delta.y * 0.003; | |
const HALF_PI = Math.PI / 2; | |
euler.x = Math.max(-HALF_PI, Math.min(HALF_PI, euler.x)); | |
this.camera.quaternion.setFromEuler(euler); | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment