threejs用octree实现房间内第三人称漫游并且添加了碰撞,人物在碰撞到墙壁的时候不停的弹回,应该怎么修改才能不会疯狂的弹回
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Three.js Scene</title>
<style>
body { margin: 0; }
canvas { width: 100%; height: 100% }
</style>
</head>
<body>
<script type="importmap">
{
"imports": {
"three": "./three172/build/three.module.js",
"three/addons/": "./three172/examples/jsm/"
}
}
</script>
<script type="module">
import * as THREE from 'three';
import {OrbitControls} from 'three/addons/controls/OrbitControls.js'
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'
import { RGBELoader } from 'three/addons/loaders/RGBELoader.js'
import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js'
let scene,camera,renderer,controls,npc,npcMixer
const keyStates = {
W: false,
A: false,
S: false,
D: false,
};
const initScene = () => {
// 创建场景
scene = new THREE.Scene();
// 创建相机
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 10000);
// camera.position.z = 5;
window.camera = camera
// 创建渲染器
renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// 鼠标控制相机
// controls = new OrbitControls(camera, renderer.domElement);
// 创建蓝色网格
const gridHelper = new THREE.GridHelper(100, 100, 0x0000ff, 0x0000ff);
scene.add(gridHelper);
const light = new THREE.AmbientLight(0xffffff);
scene.add(light);
}
let v = new THREE.Vector3(0, 0, 0);//初始速度设置为0
const a = 12;//加速度:调节按键加速快慢
const damping = -0.04;//阻尼 当没有WASD加速的时候,人、车等玩家角色慢慢减速停下来
const vMax = 5;//限制玩家角色最大速度
let deltaPos
let front
const clock = new THREE.Clock();
function animate() {
let deltaTime = clock.getDelta();
if(v.length()<vMax){
if(keyStates.W){
console.log('w');
// front = new THREE.Vector3(0, 0, 1);
const front = new THREE.Vector3();
//获取玩家角色(相机)正前方
npc.getWorldDirection(front);
v.add(front.multiplyScalar(a * deltaTime));
}
if(keyStates.S){
console.log('S');
// front = new THREE.Vector3(0, 0, -1);
const front = new THREE.Vector3();
//获取玩家角色(相机)正前方
npc.getWorldDirection(front);
v.add(front.multiplyScalar(-a * deltaTime));
}
if (keyStates.A) {//向左运动
const front = new THREE.Vector3();
npc.getWorldDirection(front);
const up = new THREE.Vector3(0, 1, 0);//y方向
const left = up.clone().cross(front);
v.add(left.multiplyScalar(a * deltaTime));
}
if (keyStates.D) {//向右运动
const front = new THREE.Vector3();
npc.getWorldDirection(front);
const up = new THREE.Vector3(0, 1, 0);//y方向
//叉乘获得垂直于向量up和front的向量 左右与叉乘顺序有关,可以用右手螺旋定则判断,也可以代码测试结合3D场景观察验证
const right = front.clone().cross(up);
v.add(right.multiplyScalar(a * deltaTime));
}
}
v.addScaledVector(v, damping);//阻尼减速
deltaPos = v.clone().multiplyScalar(deltaTime);
npc&&npc.position.add(deltaPos);//更新玩家角色的位置
renderer.render(scene, camera);
npcMixer&&npcMixer.update(deltaTime);//这里给动画设置更新速度,因为默认是一秒钟渲染60次,所以这里设置为1/60的值,
requestAnimationFrame(animate);
scene.backgroundRotation.y +=0.0001
}
const loadHRd = () => {
//地址https://polyhaven.com/a/kloofendal_48d_partly_cloudy_puresky
const rgbeLoader = new RGBELoader();
rgbeLoader.load('./assets/day.hdr', (texture) => {
// 设置纹理的格式和包围盒
texture.mapping = THREE.EquirectangularReflectionMapping;
scene.background = texture; // 设置为场景背景
scene.environment = texture; // 设置为环境光照
});
}
function addModels(path){
const loader = new GLTFLoader()
const dracoLoader = new DRACOLoader()
dracoLoader.setDecoderPath('./three172/examples/jsm/libs/draco/')
loader.setDRACOLoader(dracoLoader)
loader.load(path, (gltf) => {
gltf.scene.position.set(0, 0, 0);
gltf.scene.children[0].position.set(0, 0, 0);
scene.add(gltf.scene)
})
}
const listener = () => {
let leftButtonBool = false;//记录鼠标左键状态
document.addEventListener('mousedown', () => {
leftButtonBool = true;
});
document.addEventListener('mouseup', () => {
leftButtonBool = false;
});
document.addEventListener('mousemove', (event) => {
if(leftButtonBool){
npc.rotation.y -= event.movementX / 300;
camera.rotation.x -= event.movementY / 1200;
}
});
document.addEventListener('keydown', (event) => {
if (event.code === 'KeyW') keyStates.W = true;
if (event.code === 'KeyA') keyStates.A = true;
if (event.code === 'KeyS') keyStates.S = true;
if (event.code === 'KeyD') keyStates.D = true;
});
document.addEventListener('keyup', (event) => {
if (event.code === 'KeyW') keyStates.W = false;
if (event.code === 'KeyA') keyStates.A = false;
if (event.code === 'KeyS') keyStates.S = false;
if (event.code === 'KeyD') keyStates.D = false;
});
}
const addNpc = () => {
const loader = new GLTFLoader();
const dracoLoader = new DRACOLoader()
dracoLoader.setDecoderPath('./three172/examples/jsm/libs/draco/')
loader.setDRACOLoader(dracoLoader)
// 加载NPC模型
loader.load('./assets/Jackie.glb', (obj) => {
npc = obj.scene;
npc.name = 'npc';
npc.position.set(0, 0, 0);
// 将NPC模型添加到场景
scene.add(npc);
npcMixer = new THREE.AnimationMixer(npc);
let runAction = npcMixer.clipAction(obj.animations[0]);
runAction.setLoop(THREE.LoopRepeat)
runAction.play()
npc.add(camera)
camera.position.y = 2;
camera.position.z = -3;
camera.rotateY(Math.PI/1);
});
}
listener()
initScene()
animate();
loadHRd()
addModels('./assets/jifang.glb')
addNpc()
</script>
</body>
</html>
视频地址
https://tc.qdqqd.com/OUW9Hw.mp4
尝试过改变碰撞后位移的值
capsule&&capsule.translate(result.normal.multiplyScalar( result.depth));