Skip to content

Commit

Permalink
feat(app)!: 227 Change the keyboardcontrols implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
JaimeTorrealba committed Jan 28, 2024
1 parent f10476e commit fed0f86
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 175 deletions.
39 changes: 39 additions & 0 deletions playground/src/pages/controls/KeyboardControls.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<script setup lang="ts">
import { TresCanvas } from '@tresjs/core'
import { BasicShadowMap, NoToneMapping, Vector3 } from 'three'
import { PointerLockControls, KeyboardControls, StatsGl, Sky, Box } from '@tresjs/cientos'
const gl = {
clearColor: '#82DBC5',
shadows: true,
alpha: false,
shadowMapType: BasicShadowMap,
toneMapping: NoToneMapping,
}
const isActive = (state: boolean) => console.log(state)
const hasChange = (state: any) => console.log('change', state)
</script>

<template>
<TresCanvas v-bind="gl">
<TresPerspectiveCamera :position="[0, 3, 10]" />
<StatsGl />
<Sky />
<KeyboardControls
@change="state => hasChange(state)"
@is-lock="state => isActive(state)"
/>
<Box />
<Box :position="[15, 0, 0]" />
<Box :position="[-15, 0, 0]" />

<TresAxesHelper
:args="[10]"
:position-y="5"
/>
<TresGridHelper :args="[100, 100]" />
<TresAmbientLight :intensity="1" />
</TresCanvas>
</template>

Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script setup lang="ts">
import { TresCanvas } from '@tresjs/core'
import { BasicShadowMap, NoToneMapping } from 'three'
import { PointerLockControls, KeyboardControls, Stats, Sky } from '@tresjs/cientos'
import { PointerLockControls, StatsGl, Sky } from '@tresjs/cientos'
const gl = {
clearColor: '#82DBC5',
Expand All @@ -11,21 +11,20 @@ const gl = {
toneMapping: NoToneMapping,
}
const isActive = (state: boolean) => console.log(state)
const isActive = (state: boolean) => console.log('is-active', state)
const hasChange = (state: any) => console.log('change', state)
</script>

<template>
<TresCanvas v-bind="gl">
<TresPerspectiveCamera :position="[0, 3, 10]" />
<Stats />
<StatsGl />
<Sky />
<PointerLockControls
make-default
@is-lock="state => isActive(state)"
@change="state => hasChange(state)"
/>
<KeyboardControls head-bobbing />

<TresGridHelper :args="[100, 100]" />
<TresAmbientLight :intensity="1" />
Expand Down
11 changes: 8 additions & 3 deletions playground/src/router/routes/controls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,14 @@ export const controlsRoutes = [
component: () => import('../../pages/controls/TransformControlsDemo.vue'),
},
{
path: '/controls/first-person-controls',
name: 'FirstPersonControls',
component: () => import('../../pages/controls/FirstPersonControlsDemo.vue'),
path: '/controls/keyboard-controls',
name: 'KeyboardControls',
component: () => import('../../pages/controls/KeyboardControls.vue'),
},
{
path: '/controls/pointerlock-controls',
name: 'PointerLockControls',
component: () => import('../../pages/controls/PointerLockControls.vue'),
},
{
path: '/controls/scroll-controls',
Expand Down
250 changes: 82 additions & 168 deletions src/core/controls/KeyboardControls.vue
Original file line number Diff line number Diff line change
@@ -1,208 +1,122 @@
<script setup lang="ts">
import { ref, shallowRef, toRefs } from 'vue'
import { ref, toRefs, watchEffect } from 'vue'
import { useRenderLoop, useTresContext } from '@tresjs/core'
import { PointerLockControls } from 'three-stdlib'
import { onKeyStroke } from '@vueuse/core'
import { useMagicKeys } from '@vueuse/core'
import { PointerLockControls as PointerLockControlsType } from 'three-stdlib'
import { Vector3, Quaternion } from 'three'
import type { Camera } from 'three'
import { PointerLockControls } from './index'
export interface KeyboardControlsProps {
/**
* Keys to go forward.
* @type {string[]}
* @default '[w, W]'
* @memberof KeyboardControlsProps
* Whether to make this the default controls.
*
**/
forward?: string[] | string
/**
* Keys to go back.
* @type {string[]}
* @default '[s, S]'
* @default true
* @type {boolean}
* @memberof KeyboardControlsProps
*
**/
back?: string[] | string
* @see https://threejs.org/docs/index.html?q=pointe#examples/en/controls/PointerLockControls
*/
makeDefault?: boolean
/**
* Keys to go left.
* @type {string[]}
* @default '[a, A]'
* @memberof KeyboardControlsProps
* The camera to control.
*
**/
left?: string[] | string
/**
* Keys to go right.
* @type {string[]}
* @default '[d, D]'
* @default false
* @type {boolean}
* @memberof KeyboardControlsProps
*
**/
right?: string[] | string
* @see https://threejs.org/docs/index.html?q=pointe#examples/en/controls/PointerLockControls
*/
camera?: Camera
/**
* Key to jump (only with PointerLockControls).
* @type {string[]}
* @default 'space'
* @memberof KeyboardControlsProps
* The dom element to listen to.
*
**/
jump?: string[] | string
/**
* Default gravity number for jump.
* @type {number}
* @default 9.8
* @type {HTMLElement}
* @memberof KeyboardControlsProps
*
**/
gravity?: number
* @see https://threejs.org/docs/index.html?q=pointe#examples/en/controls/PointerLockControls
*/
domElement?: HTMLElement
/**
* Speed movement.
* Indicates the movement speed.
* @type {number}
* @default 0.1
* @default 0.25
* @memberof KeyboardControlsProps
*
**/
moveSpeed?: number
/**
* Activate/deactivate headBobbing effect (only with PointerLockControls).
* @type {boolean}
* @default false
* @memberof KeyboardControlsProps
* The trigger id.
*
**/
headBobbing?: boolean
/**
* Indicates if the forward movement is in the Z axis or Y axis.
* @type {boolean}
* @default false
* @type {string}
* @memberof KeyboardControlsProps
*
**/
is2D?: boolean
* @see https://threejs.org/docs/index.html?q=pointe#examples/en/controls/PointerLockControls
*/
selector?: string
}
// TODO: remove disable once eslint is updated to support vue 3.3
// eslint-disable-next-line vue/no-setup-props-destructure
const props = withDefaults(defineProps<KeyboardControlsProps>(), {
forward: () => ['w', 'W'],
back: () => ['s', 'S'],
left: () => ['a', 'A'],
right: () => ['d', 'D'],
jump: () => [' '],
gravity: 9.8,
moveSpeed: 0.1,
headBobbing: false,
is2D: false,
moveSpeed: 0.25,
makeDefault: true,
})
const emit = defineEmits(['isLock', 'change'])
const { moveSpeed } = toRefs(props)
const { camera: activeCamera, controls, renderer } = useTresContext()
const sidewardMove = ref(0)
const forwardMove = ref(0)
const { w, s, a, d } = useMagicKeys()
watchEffect(() => {
if (a.value) sidewardMove.value = -moveSpeed.value
else if (d.value) sidewardMove.value = moveSpeed.value
else sidewardMove.value = 0
if (w.value) forwardMove.value = moveSpeed.value
else if (s.value) forwardMove.value = -moveSpeed.value
else forwardMove.value = 0
})
const { forward, back, left, right, jump, gravity, moveSpeed, headBobbing, is2D } = toRefs(props)
const { camera: activeCamera, controls } = useTresContext()
const xMove = ref(0)
const zMove = ref(0)
const isHeadBobbing = ref(false)
const isJumping = ref(false)
const HBSpeed = 5
const jumpSpeed = 6
const HBAmplitude = 0.3
const initJumpTime = ref(0)
const wrapperRef = shallowRef()
const _forward = is2D.value ? 'y' : 'z'
const initCameraPos = activeCamera.value.position?.y || 0
// FORWARD DIRECTION MOVEMENTS
onKeyStroke(
forward.value,
() => {
isHeadBobbing.value = true
zMove.value = moveSpeed.value
},
{ eventName: 'keydown' },
)
onKeyStroke(
back.value,
() => {
isHeadBobbing.value = true
zMove.value = -moveSpeed.value
},
{ eventName: 'keydown' },
)
onKeyStroke(
[...forward.value, ...back.value],
() => {
isHeadBobbing.value = false
zMove.value = 0
},
{ eventName: 'keyup' },
)
// X DIRECTION MOVEMENTS
onKeyStroke(
left.value,
() => {
isHeadBobbing.value = true
xMove.value = -moveSpeed.value
},
{ eventName: 'keydown' },
)
onKeyStroke(
right.value,
() => {
isHeadBobbing.value = true
xMove.value = moveSpeed.value
},
{ eventName: 'keydown' },
)
onKeyStroke(
[...left.value, ...right.value],
() => {
isHeadBobbing.value = false
xMove.value = 0
},
{ eventName: 'keyup' },
)
//JUMP BUTTON
onKeyStroke(jump.value, () => {
if (!isJumping.value) initJumpTime.value = Date.now()
isJumping.value = true
defineExpose({
value: controls,
})
// HEAD BOBBING
const headBobbingMov = (elapsedTime: number) => isHeadBobbing.value
? Math.sin(elapsedTime * HBSpeed) * HBAmplitude + initCameraPos
: initCameraPos
const isActive = (isLock: boolean) => emit('isLock', isLock)
// JUMP
const getJumpTime = () => ((Date.now() - initJumpTime.value) / 1000) * 3
const getJumpDistance = (jumpTime: number) => initCameraPos + jumpSpeed * jumpTime - 0.5 * gravity.value * jumpTime ** 2
const hasChange = (state: any) => emit('change', state)
const getJump = () => {
if (isJumping.value) {
const jumpDistance = getJumpDistance(getJumpTime())
if (jumpDistance <= initCameraPos) isJumping.value = false
return jumpDistance
}
return 0
const moveVector = new Vector3(0, 0, 0)
const rotationVector = new Vector3(0, 0, 0)
const tmpQuaternion = new Quaternion()
const moveForward = (delta: number, movementSpeed: number) => {
if (!activeCamera.value?.position && !moveVector) return
const camera = activeCamera.value
const rotMult = delta * 0.001
camera?.translateZ(-movementSpeed)
tmpQuaternion.set(rotationVector.x * rotMult, rotationVector.y * rotMult, rotationVector.z * rotMult, 1).normalize()
camera?.quaternion.multiply(tmpQuaternion)
if (sidewardMove.value || forwardMove.value) emit('change', controls.value)
}
const { onLoop } = useRenderLoop()
onLoop(({ elapsed }) => {
// has PointerLockControls?
if (controls.value instanceof PointerLockControls && controls.value?.isLocked) {
controls.value.moveForward(zMove.value)
controls.value.moveRight(xMove.value)
if (activeCamera.value.position) {
activeCamera.value.position.y = headBobbing.value ? headBobbingMov(elapsed) : initCameraPos
activeCamera.value.position.y += getJump()
}
}
else if (wrapperRef.value.children.length > 0 && !(controls.value instanceof PointerLockControls)) {
wrapperRef.value.position.x += xMove.value
wrapperRef.value.position[_forward] += is2D.value ? zMove.value : -zMove.value
onLoop(({ delta }) => {
if (controls.value instanceof PointerLockControlsType && controls.value?.isLocked) {
moveForward(delta, forwardMove.value)
controls.value.moveRight(sidewardMove.value)
}
})
</script>

<template>
<TresGroup ref="wrapperRef">
<slot />
</TresGroup>
<PointerLockControls
:selector="selector"
:make-default="makeDefault"
:camera="camera || activeCamera"
:dom-element="domElement || renderer.domElement"
@is-lock="isActive"
@change="hasChange"
/>
</template>

0 comments on commit fed0f86

Please sign in to comment.