渲染框架是基于THREE,碰撞检测是基于BVH。本来用的是three自带的octree结构做碰撞发现性能不太好
核心代码:
import * as THREE from 'three'
import { RoundedBoxGeometry } from 'three/examples/jsm/geometries/RoundedBoxGeometry.js';
import { MeshBVH, MeshBVHHelper, StaticGeometryGenerator } from 'three-mesh-bvh';
import CameraControls from 'src/renderers/camera';
import { OrbitControls } from 'src/renderers/controls/OrbitControls'
import { Renderer } from 'src/renderers/Renderer';
class InputControls{
pressKeys=new Set()
releaseKeys=new Set()
constructor() {
this.mountEvents()
}
mountEvents(){
window.addEventListener('keydown',this.handleKey)
window.addEventListener('keyup',this.handleKey)
}
unmountEvents(){
window.removeEventListener('keydown',this.handleKey)
window.removeEventListener('keyup',this.handleKey)
}
isPressedKey(key:string){
return this.pressKeys.has(key)
}
isReleaseKey(key:string){
if(this.pressKeys.has(key)&&!this.releaseKeys.has(key)){
this.releaseKeys.add(key)
return true
}
return false
}
handleKey=(e:KeyboardEvent)=>{
const type=e.type
const key=e.key.toLowerCase()
if(type==='keydown'){
if(!this.pressKeys.has(key)){
this.pressKeys.add(key)
}
}else{
if(this.pressKeys.has(key)){
this.releaseKeys.delete(key)
this.pressKeys.delete(key)
}
}
}
}
export class CharacterPersonCamera{
keys=new Set()
player:THREE.Mesh
collider?:THREE.Mesh
colliderBox2:THREE.Box2=new THREE.Box2()
colliderBox:THREE.Box3=new THREE.Box3()
input:InputControls
speed=100
speedRatio=1 // 速率
gravity=298 // 重力速度
enableGravity=false // 是否启用重力
_enableFirstPerson=false// 是否启用第一视角
// 当前速度和位移
playerVelocity=new THREE.Vector3()
// 累积移动
accumulateMovement=new THREE.Vector3()
deltaPosition=new THREE.Vector3()
tempPlayerPosition=new THREE.Vector2()
tempVector=new THREE.Vector3()
tempVector2=new THREE.Vector3()
tempDirection=new THREE.Vector3()
tempBox=new THREE.Box3()
tempSegment=new THREE.Line3()
tempMat=new THREE.Matrix4()
playerIsOnGround=false // 是否在地面
enable=true // 是否启用
cameraControls?:CameraControls
orbitControls?:OrbitControls
upVector = new THREE.Vector3( 0, 1, 0 );
colliderBoxDistance=Infinity
constructor(public context:Renderer) {
this.input=new InputControls()
this.player=new THREE.Mesh(new RoundedBoxGeometry(0.5,1,0.5,10,1),new THREE.MeshBasicMaterial({
color:0xff0000
}))
// this.player=new THREE.Mesh(new THREE.BoxGeometry(1,1,1),generateCub