你玩过第一人称的射击游戏吗?大作CF,CS类型的。本教程,我们将模拟相同的相机运动:摄像机在地面,将和地面产生碰撞效果,并可以与场景中的任何其他模型也会发生碰撞。
如何实现碰撞
为了实现这种效果,我们必须要做三个步骤:
定义并应用重力
首先要做的是定义重力矢量,定义重力。在地球这样的世界中,重力的方向是沿Y轴向下,我们可以随意改变它
scene.gravity = new BABYLON.Vector3(0, -9.81, 0);
重力可以应用于你在代码中定义的相机:
camera.applyGravity = true;
定义椭圆体
下一个重要的步骤是在我们的相机周围定义椭球体。这个椭球代表我们玩家的尺寸:当一个模型与这个椭球体接触时会发生碰撞事件,防止我们的相机太靠近这个模型:
Babylon.js的相机上的椭球的默认值为(0.5,1,0.5),但你可以同过自己的修改默认值。在下面的例子中,我们将相机的椭球修改的比默认的大一些:
camera.ellipsoid = new BABYLON.Vector3(1, 1, 1);
注意,相机的椭球体是偏移的,以将相机视点设置到椭球体的顶部。你可以通过更新camera.ellipsoidOffset属性来控制此行为。
相机的最终位置计算:
finalPosition = position - vec3(0,ellipsoid.y,0)+ ellipsoidOffset
应用碰撞
完成之前的配置以后,最后一步是设置开启场景中的碰撞检测:
// 开启碰撞
scene.collisionsEnabled = true;
camera.checkCollisions = true;
并开启哪些模型可以与相机产生碰撞:
ground.checkCollisions = true;
box.checkCollisions = true;
是不是很简单,你可以访问官方案例查看案例:官方案例
此案例中,相机将于地面发生碰撞,离开地面会一直坠落。并且靠近箱子,也会产生碰撞,无法穿过。
模型与模型的碰撞
你还可以使用mesh.ellipsoid属性和mesh.moveWithCollisions(velocity)函数对模型执行相同的操作。此函数将尝试根据给定的速度移动网格,并检查当前模型与激活了checkCollisions的所有模型之间是否产生了碰撞。
你还可以使用mesh.ellipsoidOffset在模型上移动椭球体(默认情况下,椭球体在网格上居中)
var speedCharacter = 8;
var gravity = 0.15;
var character = "你的模型";
character.ellipsoid = new BABYLON.Vector3(0.5, 1.0, 0.5);
character.ellipsoidOffset = new BABYLON.Vector3(0, 1.0, 0);
var forwards = new BABYLON.Vector3(parseFloat(Math.sin(character.rotation.y)) / speedCharacter, gravity, parseFloat(Math.cos(character.rotation.y)) / speedCharacter);
forwards.negate();
character.moveWithCollisions(forwards);
//或者
var backwards = new BABYLON.Vector3(parseFloat(Math.sin(character.rotation.y)) / speedCharacter, -gravity, parseFloat(Math.cos(character.rotation.y)) / speedCharacter);
character.moveWithCollisions(backwards);
下面,查看一下官方案例演示:点击此处
弧形旋转相机
ArcRotateCamera也可以实现碰撞检测,但不会和自由相机一样沿着障碍物旋转,当产生碰撞时,相机不会移动。
开启碰撞,只需要设置camera.checkCollisions = true,你可以使用以下代码设置相机的碰撞半径:
camera.collisionRadius = new BABYLON.Vector3(0.5, 0.5, 0.5)