-
Notifications
You must be signed in to change notification settings - Fork 13
Add pointers for mouse look component , Improve pointer lock. #64
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,13 +2,15 @@ import {Component} from '@wonderlandengine/api'; | |
import {property} from '@wonderlandengine/api/decorators.js'; | ||
import {vec3} from 'gl-matrix'; | ||
|
||
const preventDefault = (e: Event) => { e.preventDefault(); }; | ||
const preventDefault = (e: Event) => { | ||
e.preventDefault(); | ||
}; | ||
|
||
/** | ||
* Controls the camera orientation through mouse movement. | ||
* Controls the camera orientation through mouse and touch movement. | ||
* | ||
* Efficiently implemented to affect object orientation only | ||
* when the mouse moves. | ||
* when the mouse or touch moves. | ||
*/ | ||
export class MouseLookComponent extends Component { | ||
static TypeName = 'mouse-look'; | ||
|
@@ -17,8 +19,8 @@ export class MouseLookComponent extends Component { | |
@property.float(0.25) | ||
sensitity = 0.25; | ||
|
||
/** Require a mouse button to be pressed to control view. | ||
* Otherwise view will allways follow mouse movement */ | ||
/** Require a mouse button or touch to be pressed to control view. | ||
* Otherwise view will always follow mouse or touch movement */ | ||
@property.bool(true) | ||
requireMouseDown = true; | ||
|
||
|
@@ -38,70 +40,104 @@ export class MouseLookComponent extends Component { | |
private rotationX = 0; | ||
private rotationY = 0; | ||
private mouseDown = false; | ||
/** Pointerlock spec prevents calling pointerlock right after user exiting it via esc for ~1 second */ | ||
private pointerLockCooldown = false; | ||
|
||
onActivate() { | ||
document.addEventListener('mousemove', this.onMouseMove); | ||
|
||
const canvas = this.engine.canvas; | ||
if (this.mouseButtonIndex === 2) { | ||
canvas.addEventListener('contextmenu', preventDefault, false); | ||
} | ||
canvas.addEventListener('pointermove', this.onPointerMove); | ||
if (this.pointerLockOnClick) { | ||
canvas.addEventListener('mousedown', this.requestPointerLock); | ||
canvas.addEventListener('pointerdown', this.onPointerDown); | ||
document.addEventListener('pointerlockchange', this.onPointerLockChange); | ||
} | ||
|
||
if (this.requireMouseDown) { | ||
if (this.mouseButtonIndex === 2) { | ||
canvas.addEventListener('contextmenu', preventDefault, false); | ||
} | ||
canvas.addEventListener('mousedown', this.onMouseDown); | ||
canvas.addEventListener('mouseup', this.onMouseUp); | ||
if (this.requireMouseDown && !this.pointerLockOnClick) { | ||
canvas.addEventListener('pointerdown', this.onPointerDown); | ||
canvas.addEventListener('pointerup', this.onPointerUp); | ||
} | ||
} | ||
|
||
onDeactivate() { | ||
document.removeEventListener('mousemove', this.onMouseMove); | ||
|
||
const canvas = this.engine.canvas; | ||
canvas.removeEventListener('pointermove', this.onPointerMove); | ||
|
||
if (this.pointerLockOnClick) { | ||
canvas.removeEventListener('mousedown', this.requestPointerLock); | ||
canvas.removeEventListener('pointerdown', this.onPointerDown); | ||
Comment on lines
-64
to
+68
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Pointerlock only really makes sense in a mouse on desktop context, though, right? Then having touch input request pointer lock isn't really desired. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @Squareys How do you suggest we filter it out on mobile devies ? maybe a isMobile check ? |
||
document.removeEventListener('pointerlockchange', this.onPointerLockChange); | ||
} | ||
|
||
if (this.requireMouseDown) { | ||
if (this.requireMouseDown && !this.pointerLockOnClick) { | ||
if (this.mouseButtonIndex === 2) { | ||
canvas.removeEventListener('contextmenu', preventDefault, false); | ||
} | ||
canvas.removeEventListener('mousedown', this.onMouseDown); | ||
canvas.removeEventListener('mouseup', this.onMouseUp); | ||
canvas.removeEventListener('pointerdown', this.onPointerDown); | ||
canvas.removeEventListener('pointerup', this.onPointerUp); | ||
} | ||
} | ||
|
||
requestPointerLock = () => { | ||
async requestPointerLock() { | ||
const canvas = this.engine.canvas; | ||
canvas.requestPointerLock = | ||
canvas.requestPointerLock || | ||
(canvas as any).mozRequestPointerLock || | ||
(canvas as any).webkitRequestPointerLock; | ||
canvas.requestPointerLock(); | ||
} | ||
|
||
onMouseDown = (e: MouseEvent) => { | ||
if (e.button === this.mouseButtonIndex) { | ||
this.mouseDown = true; | ||
document.body.style.cursor = 'grabbing'; | ||
if (e.button === 1) { | ||
e.preventDefault(); | ||
/* Prevent scrolling */ | ||
return false; | ||
} | ||
try { | ||
await navigator.locks.request('pointer-lock', async (lock) => { | ||
if (!document.pointerLockElement) { | ||
await canvas.requestPointerLock(); | ||
} | ||
}); | ||
} catch (error) { | ||
console.error('Pointer lock request failed:', error); | ||
} | ||
} | ||
|
||
onMouseUp = (e: MouseEvent) => { | ||
if (e.button === this.mouseButtonIndex) { | ||
onPointerLockChange = () => { | ||
const canvas = this.engine.canvas; | ||
if (document.pointerLockElement === canvas) return; | ||
this.mouseDown = false; | ||
this.pointerLockCooldown = true; | ||
document.body.style.cursor = 'initial'; | ||
|
||
setTimeout(() => { | ||
this.pointerLockCooldown = false; | ||
}, 1500); | ||
}; | ||
|
||
onPointerDown = (e: PointerEvent) => { | ||
if ( | ||
this.pointerLockCooldown || | ||
!(e.button === this.mouseButtonIndex || e.pointerType === 'touch') | ||
) | ||
return; | ||
this.mouseDown = true; | ||
document.body.style.cursor = 'grabbing'; | ||
if (e.button === 2) { | ||
e.preventDefault(); | ||
} | ||
|
||
if (this.pointerLockOnClick && document.pointerLockElement !== this.engine.canvas) { | ||
this.requestPointerLock(); | ||
} | ||
if (e.button === 1) { | ||
e.preventDefault(); | ||
/* Prevent scrolling */ | ||
return false; | ||
} | ||
}; | ||
|
||
onPointerUp = (e: PointerEvent) => { | ||
if (e.button === this.mouseButtonIndex || e.pointerType === 'touch') { | ||
this.mouseDown = false; | ||
document.body.style.cursor = 'initial'; | ||
} | ||
} | ||
}; | ||
|
||
onMouseMove = (e: MouseEvent) => { | ||
onPointerMove = (e: PointerEvent) => { | ||
if (this.active && (this.mouseDown || !this.requireMouseDown)) { | ||
this.rotationY = (-this.sensitity * e.movementX) / 100; | ||
this.rotationX = (-this.sensitity * e.movementY) / 100; | ||
|
@@ -126,5 +162,5 @@ export class MouseLookComponent extends Component { | |
this.object.rotateAxisAngleRadLocal([0, 1, 0], this.currentRotationY); | ||
this.object.translateLocal(this.origin); | ||
} | ||
} | ||
}; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you have a link for that? Better would be to know the exact moment a next pointer lock is possible. I would bet it's after flushing the task queue, rather than a delay?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@DavidPeicho I learned about it in a quora discussion , was not able to find its official documentation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@DavidPeicho https://discourse.threejs.org/t/how-to-avoid-pointerlockcontrols-error/33017/2#:~:text=Sorry%2C%20no%20way%20to%20avoid%20it.%20As%20per%20the%20spec%3A