创建物理世界类
class Physics{
constructor(
planeGroup,
scene,
camera
){
this.octreeWrold = new Octree()
this.octreeWrold.fromGraphNode(planeGroup)
console.log('planeGroup',planeGroup)
this.playerCollider = new Capsule(
new THREE.Vector3(0,0.35,0),
new THREE.Vector3(0,1.35,0),
0.35
)
this.playerCollider.start.set(0, 2.35, 0);
this.playerCollider.end.set(0, 3.35, 0);
const gltfLoader = new GLTFLoader()
this.capsule = new THREE.Object3D()
this.capsule.position.set(0,0,0)
this.mixer = null
this.actions = []
this.activeAction = null
gltfLoader.load('path', glb => {
this.robot = glb.scene
this.robot.scale.set(0.5,0.5,0.5)
this.robot.position.set(0,-0.88,0)
this.capsule.add(this.robot)
this.mixer = new THREE.AnimationMixer(this.robot)
glb.animations.forEach((animation) => {
let name = animation.name
this.actions[name] = this.mixer.clipAction(animation)
if(name == 'Idle' || name == 'Walking' || name == 'Running'){
animation.clampWhenFinished = false
animation.loop = THREE.LoopRepeat
}else{
animation.clampWhenFinished = true
animation.loop = THREE.LoopOnce
}
})
this.activeAction = this.actions['Idle']
this.activeAction.play()
scene.add(this.capsule)
})
const backCamera = new THREE.PerspectiveCamera(
70,
window.innerWidth / window.innerHeight,
0.001,
1000
)
this.cameraControl = new THREE.Object3D()
camera.position.set(0,2,-5)
camera.lookAt(this.capsule.position)
backCamera.position.set(0,2,5)
backCamera.lookAt(this.capsule.position)
this.cameraControl.add(camera)
this.cameraControl.add(backCamera)
this.capsule.add(this.cameraControl)
document.addEventListener('mousemove',(e)=>{
this.capsule.rotation.y -= e.movementX * 0.003
this.cameraControl.rotation.x += e.movementY * 0.003
if(this.cameraControl.rotation.x > Math.PI / 8){
this.cameraControl.rotation.x = Math.PI / 8
}else if(
this.cameraControl.rotation.x < - Math.PI / 8
){
this.cameraControl.rotation.x = -Math.PI / 8
}
})
document.addEventListener('mousedown', e => {
document.body.requestPointerLock()
} )
this.gravity = -9.8
this.playerVelocity = new THREE.Vector3(0,0,0)
this.playerDerection = new THREE.Vector3(0,0,0)
this.playerOnFloor = false
this.keyStates = {
KeyW : false,
KeyA : false,
KeyS : false,
KeyD : false,
Space : false,
isDown : false,
}
document.addEventListener('keydown', e=> {
this.keyStates[e.code] = true
this.keyStates.isDown = true
})
document.addEventListener('keyup',e => {
this.keyStates[e.code] = false
this.keyStates.isDown = false
})
}
}
更新用户位置的方法
upDataPlayer(deltaTime){
let damping = -0.25
if(this.playerOnFloor){
this.playerVelocity.y = 0
this.keyStates.isDown ||
this.playerVelocity.addScaledVector(this.playerVelocity,damping)
}else{
this.playerVelocity.y += this.gravity * deltaTime
}
const playerMoveDistance = this.playerVelocity.clone().
multiplyScalar(deltaTime)
this.playerCollider.translate(playerMoveDistance)
this.playerCollider.getCenter(this.capsule.position)
this.playerCollisions()
if (
Math.abs(this.playerVelocity.x) + Math.abs(this.playerVelocity.z) > 0.1 &&
Math.abs(this.playerVelocity.x) + Math.abs(this.playerVelocity.z) <= 3
) {
this.fadeToAction("Walking");
} else if (
Math.abs(this.playerVelocity.x) + Math.abs(this.playerVelocity.z) >
3
) {
this.fadeToAction("Running");
} else {
this.fadeToAction("Idle");
}
}
检测用户物理碰撞
playerCollisions(){
const result = this.octreeWrold.capsuleIntersect(this.playerCollider)
this.playerOnFloor = false
if(result){
this.playerOnFloor = result.normal.y > 0
if(result.depth > 0.1){
this.playerCollider.translate(result.normal.multiplyScalar(result.depth))
}
}
}
监听键盘状态,更新用户速度向量的方法
updataPlayerVelocity(deltaTime){
if(this.keyStates['KeyW']){
this.playerDerection.z = 1
const playerFront = new THREE.Vector3(0,0,0)
this.capsule.getWorldDirection(playerFront)
if (
this.playerVelocity.x * this.playerVelocity.x +
this.playerVelocity.z * this.playerVelocity.z <=
200
){
this.playerVelocity.add(playerFront.multiplyScalar(deltaTime * 5))
}
}
if(this.keyStates['KeyS']){
const playerFront = new THREE.Vector3(0,0,0)
this.capsule.getWorldDirection(playerFront)
this.playerVelocity.add(playerFront.multiplyScalar(-deltaTime))
}
if(this.keyStates['KeyA']){
const playerFront = new THREE.Vector3(0,0,0)
this.capsule.getWorldDirection(playerFront)
playerFront.cross(this.capsule.up);
this.playerVelocity.add(playerFront.multiplyScalar(-deltaTime))
}
if(this.keyStates['KeyD']){
const playerFront = new THREE.Vector3(0,0,0)
this.capsule.getWorldDirection(playerFront)
playerFront.cross(this.capsule.up)
this.playerVelocity.add(playerFront.multiplyScalar(deltaTime))
}
if(this.keyStates['Space']
&& this.playerOnFloor
){
this.playerVelocity.y = 5
}
}
重置用户的位置方法
resetPlayer() {
if (this.capsule.position.y < -20) {
this.playerCollider.start.set(0, 2.35, 0);
this.playerCollider.end.set(0, 3.35, 0);
this.playerCollider.radius = 0.35;
this.playerVelocity.set(0, 0, 0);
}
}
更新用户动作方法
fadeToAction(actionName) {
this.prevAction = this.activeAction;
this.activeAction = this.actions[actionName];
if (this.prevAction != this.activeAction) {
this.prevAction.fadeOut(0.3);
this.activeAction
.reset()
.setEffectiveTimeScale(1)
.setEffectiveWeight(1)
.fadeIn(0.3)
.play();
this.mixer.addEventListener("finished", (e) => {
this.prevAction = activeAction;
this.activeAction = this.actions["Idle"];
this.prevAction.fadeOut(0.3);
this.activeAction
.reset()
.setEffectiveTimeScale(1)
.setEffectiveWeight(1)
.fadeIn(0.3)
.play();
});
}
}