前言
该文章主要讲元宇宙虚拟空间的角色初始化,基本核心技术点,不多说,直接引入正题。
角色初始化
在调用渲染前,打印一下更新的列表
console.log(this.updatables);
this.render(this);;
这里看到有很多要更新的
这里我们来看一下角色Character的更新,首先是在CharacterSpawnPoint载入人物的模型,通过Character类对角色模型进行一个初始化
public spawn(loadingManager: LoadingManager, world: World): void {
loadingManager.loadGLTF('build/assets/boxman.glb', (model) => {
let player = new Character(model);
let worldPos = new THREE.Vector3();
this.object.getWorldPosition(worldPos);
player.setPosition(worldPos.x, worldPos.y, worldPos.z);
let forward = Utils.getForward(this.object);
player.setOrientation(forward, true);
world.add(player);
player.takeControl();
});
}
Character初始化的内容,
constructor(gltf: any)
{
//继承了THREE.Object3D
super();
//根据模型动画数据设置动画
this.readCharacterData(gltf);
this.setAnimations(gltf.animations);
//创建一个组方便管理和控制角色,THREE.Object3D是可以加入一个组的
this.tiltContainer = new THREE.Group();
this.add(this.tiltContainer);
//在嵌套一层模型容器,更好控制动画和角色行为,最后把gltf的模型数据导入进来
this.modelContainer = new THREE.Group();
this.modelContainer.position.y = -0.57;
this.tiltContainer.add(this.modelContainer);
this.modelContainer.add(gltf.scene);
//创建动画混合器
this.mixer = new THREE.AnimationMixer(gltf.scene);
//速度模拟器,选择模拟器
this.velocitySimulator = new VectorSpringSimulator(60, this.defaultVelocitySimulatorMass, this.defaultVelocitySimulatorDamping);
this.rotationSimulator = new RelativeSpringSimulator(60, this.defaultRotationSimulatorMass, this.defaultRotationSimulatorDamping);
//视图向量(人物看哪里)
this.viewVector = new THREE.Vector3();
//人物的动作
this.actions = {
'up': new KeyBinding('KeyW'),
'down': new KeyBinding('KeyS'),
'left': new KeyBinding('KeyA'),
'right': new KeyBinding('KeyD'),
'run': new KeyBinding('ShiftLeft'),
'jump': new KeyBinding('Space'),
'use': new KeyBinding('KeyE'),
'enter': new KeyBinding('KeyF'),
'enter_passenger': new KeyBinding('KeyG'),
'seat_switch': new KeyBinding('KeyX'),
'primary': new KeyBinding('Mouse0'),
'secondary': new KeyBinding('Mouse1'),
};
// 使用CapsuleCollider类,创建物理碰撞的角色胶囊
this.characterCapsule = new CapsuleCollider({
mass: 1,
position: new CANNON.Vec3(),
height: 0.5,
radius: 0.25,
segments: 8,
friction: 0.0
});
// capsulePhysics.physical.collisionFilterMask = ~CollisionGroups.Trimesh;
//设置能够碰撞的碰撞组(匹配)
this.characterCapsule.body.shapes.forEach((shape) => {
// tslint:disable-next-line: no-bitwise
shape.collisionFilterMask = ~CollisionGroups.TrimeshColliders;
});
//允许休眠
this.characterCapsule.body.allowSleep = false;
// 设置碰撞组
this.characterCapsule.body.collisionFilterGroup = 2;
// 是否禁止角色碰撞旋转
this.characterCapsule.body.fixedRotation = true;//固定旋转
this.characterCapsule.body.updateMassProperties();
// debug
const boxGeo = new THREE.BoxGeometry(0.1, 0.1, 0.1);
const boxMat = new THREE.MeshLambertMaterial({
color: 0xff0000
});
this.raycastBox = new THREE.Mesh(boxGeo, boxMat);
this.raycastBox.visible = false;
//物理前/后步骤回调绑定
this.characterCapsule.body.preStep = (body: CANNON.Body) => { this.physicsPreStep(body, this); };
this.characterCapsule.body.postStep = (body: CANNON.Body) => { this.physicsPostStep(body, this); };
// 更新角色状态(如待机)
this.setState(new Idle(this));
}
物体胶囊的形状,在CapsuleCollider类定义了3个球体胶囊叠加
constructor(options: any){
let defaults = {
mass: 0,
position: new CANNON.Vec3(),
height: 0.5,
radius: 0.3,
segments: 8,
friction: 0.3
};
options = Utils.setDefaults(options, defaults);
this.options = options;
//创建物理材质,名字是自己取的
let mat = new CANNON.Material('capsuleMat');
mat.friction = options.friction;
//创建胶囊的物理body
let capsuleBody = new CANNON.Body({
mass: options.mass,
position: options.position
});
// 创建物理的球形
let sphereShape = new CANNON.Sphere(options.radius);
capsuleBody.material = mat;
// sphereShape.material = mat;
//给body设置形状,形状为3个球体叠加
capsuleBody.addShape(sphereShape, new CANNON.Vec3(0, 0, 0));
capsuleBody.addShape(sphereShape, new CANNON.Vec3(0, options.height / 2, 0));
capsuleBody.addShape(sphereShape, new CANNON.Vec3(0, -options.height / 2, 0));
this.body = capsuleBody;
}