今天郭先生说一说使用cannon.js的车辆辅助类让我们的汽车模型拥有物理特性。效果图如下,在线案例请点击博客原文

下面我们说一下今天要使用的两个类,并简单的看看他们的物理意义

1. RaycastVehicle类

这是车辆辅助类,将光线从车轮位置投射到地面并施加力。它决定车的位置,角度,质量等信息。下面是它的构造函数

RaycastVehicle ( [options] )

options一共有四个参数,并且比较好理解,

  • chassisBody – 表示车身的刚体
  • indexForwardAxis – 前轴索引0 = x,1 = y,2 = z
  • indexRightAxis – 前轴索引0 = x,1 = y,2 = z
  • indexUpAxis – 前轴索引0 = x,1 = y,2 = z

后面的三个参数要决定了车辆哪个方向是前面,,哪个是右面,哪个是上面。比如说我们在three.js中一般以y轴作为向上的方向,因此我们就要将indexUpAxis设置成1,indexRightAxis设置成2。如果有特别的要求,three.js的视图以z轴作为up的方向,这是我们就要将indexUpAxis设置成2,indexRightAxis设置成1(cannon的默认值就是将z轴的方向作为up的方向的)。RaycastVehicle就先说到这,它的一些属性和方向请查看文档。

2. WheelInfo类

这个是车轮类,里面包含了十分丰富的信息,包括车轮相对于车的位置,车轮半径,滚动影响,转弯滑动等等信息,下面我们看一下构造函数

WheelInfo ( [options] )

这个options就很复杂了,可以在我的例子中手动调试。下面我们还是通过案例代码来学习这两个类。

3. 案例代码

先看看物理引擎的部分

var carBodySize = new THREE.Vector3(4.52, 2.26, 1.08);
var wheelRadius = 0.5;
initCannon() {
//初始物理里世界
world = new CANNON.World();
world.quatNormalizeSkip = 0;
world.quatNormalizeFast = false;
world.gravity.set(0, 0, -9.8);
world.broadphase = new CANNON.NaiveBroadphase();
world.solver.iterations = 10;
world.defaultContactMaterial.friction = 0;
//定义车体形状
var chassisShape;
//车体为一个矩形
chassisShape = new CANNON.Box(new CANNON.Vec3(carBodySize.x/2, carBodySize.y/2, carBodySize.z/2));
//定义车体刚体
var chassisBody = new CANNON.Body({mass: 150, material: new CANNON.Material({friction: 0, restitution: 0})})
//刚体中添加形状
chassisBody.addShape(chassisShape);
//初始化刚体的位置
chassisBody.position.set(0, 0, 5);
//设置一个初始的角速度
chassisBody.angularVelocity.set(0, 0, 0.5);
//初始化车辆引擎
vehicle = new CANNON.RaycastVehicle({
chassisBody: chassisBody, indexForwardAxis: 0, indexRightAxis: 1, indexUpAxis: 2
}); var options = {
radius: wheelRadius,
directionLocal: new CANNON.Vec3(0, 0, -wheelRadius * 2),
suspensionStiffness: 30,
suspensionRestLength: 0.3,
frictionSlip: 5,
dampingRelaxation: 2.3,
dampingCompression: 4.4,
maxSuspensionForce: 100000,
rollInfluence: 0.01,
axleLocal: new CANNON.Vec3(0, 1, 0),
chassisConnectionPointLocal: new CANNON.Vec3(1, 1, 0),
maxSuspensionTravel: 0.3,
customSlidingRotationalSpeed: -30,
useCustomSlidingRotationalSpeed: true
};
//设置第一个轮的位置,并将轮子信息添加到车辆类中
options.chassisConnectionPointLocal.set(1.13, 0.95, -0.1);
vehicle.addWheel(options);
//设置第二个轮的位置,并将轮子信息添加到车辆类中
options.chassisConnectionPointLocal.set(1.13, -0.95, -0.1);
vehicle.addWheel(options);
//设置第三个轮的位置,并将轮子信息添加到车辆类中
options.chassisConnectionPointLocal.set(-1.47, 0.95, -0.05);
vehicle.addWheel(options);
//设置第四个轮的位置,并将轮子信息添加到车辆类中
options.chassisConnectionPointLocal.set(-1.47, -0.95, -0.05);
vehicle.addWheel(options);
//通过addToWorld方法将将车辆及其约束添加到世界上。
vehicle.addToWorld(world);
//高度场的方法,上节已经了解了,不多说
var matrix = [];
for (var i = 0; i < size; i++) {
matrix.push([]);
for (var j = 0; j < size; j++) {
var height = Math.cos(i / size * Math.PI * (size / 10)) * Math.cos(j / size * Math.PI * (size / 10)) / 2;
matrix[i].push(height)
}
}
var hfShape = new CANNON.Heightfield(matrix, {
elementSize: 1
});
var hfBody = new CANNON.Body({ mass: 0, material: new CANNON.Material({friction: 0.5, restitution: 0})});
hfBody.addShape(hfShape, new CANNON.Vec3(-size / 2, - size / 2, 0), new CANNON.Quaternion());
world.addBody(hfBody);
},

接下来是操作小汽车的一些代码

document.onkeydown = this.handler;
document.onkeyup = this.handler;
handler(event) {
var up = (event.type == 'keyup');
if(!up && event.type !== 'keydown'){
return;
} vehicle.setBrake(0, 0);
vehicle.setBrake(0, 1);
vehicle.setBrake(0, 2);
vehicle.setBrake(0, 3); switch(event.keyCode){
case 38: // 按下向前键时,通过applyEngineForce方法,设置车轮力以在每个步骤中施加在后车轮上
vehicle.applyEngineForce(up ? 0 : -params.maxForce, 2);
vehicle.applyEngineForce(up ? 0 : -params.maxForce, 3);
break; case 40: // 同上
vehicle.applyEngineForce(up ? 0 : params.maxForce, 2);
vehicle.applyEngineForce(up ? 0 : params.maxForce, 3);
break; case 66: // 刹车键b,通过setBrake方法,设置四个车轮的制动力
vehicle.setBrake(brakeForce, 0);
vehicle.setBrake(brakeForce, 1);
vehicle.setBrake(brakeForce, 2);
vehicle.setBrake(brakeForce, 3);
break; case 39: // 按下右键,通过setSteeringValue方法,设置前轮转向值
vehicle.setSteeringValue(up ? 0 : -maxSteerVal, 0);
vehicle.setSteeringValue(up ? 0 : -maxSteerVal, 1);
break; case 37: // 同上
vehicle.setSteeringValue(up ? 0 : maxSteerVal, 0);
vehicle.setSteeringValue(up ? 0 : maxSteerVal, 1);
break;
}
},

好的这就是主要代码,小车是在THREE的官方demo上面下载的。

转载请注明地址:郭先生的博客

最新文章

  1. 小tip:关于typeof,instanceof,toString(),valueOf(),toLocaleString(),join(),reverse(),sort(),pop(),push(),shift(),unshift()
  2. Java之HashMap在多线程情况下导致死循环的问题
  3. Activity has leaked window that was originally added -界面退出时未关闭对话框异常 android.view.WindowManager$BadTokenException: Unable to add window -- token null is not valid; is your activity running? -
  4. 2000 Asia shanghai Dance Dance Revolution
  5. (转载)总结一下SQL语句中引号(&#39;)、quotedstr()、(&#39;&#39;)、format()在SQL语句中的用法
  6. 苹果开发证书相关BLOG与Delphi IOS环境安装(超详细)
  7. HDU 3729 二分匹配 反向匹配
  8. 妙用transform
  9. Python进阶——笔记1
  10. C#多条件查出来的多个DataSet,然后循环将数据整合
  11. Java 并发编程:线程间的协作(wait/notify/sleep/yield/join)
  12. bzoj千题计划315:bzoj3172: [Tjoi2013]单词(AC自动机)
  13. Linux 小记 — Ubuntu 自动化配置
  14. 碰到在Windows中访问局域网文件夹, 提示无法访问时的解决办法
  15. AI之路,第二篇:python数学知识2
  16. 三种方法实现java调用Restful接口
  17. PHP操作Redis常用
  18. iOS中CGRectDividede中布局用法
  19. Oracle 中分组排序取值的问题
  20. Explorer : 发布一个key-value存储系统,带有客户端和服务器端

热门文章

  1. 阿里云Ubuntu配置安装MQTT服务器
  2. JavaScript--总结二(流程控制+调试)
  3. 使用纯 CSS 实现滚动阴影效果
  4. swing桌面四子棋程序开发过程中遇到的一些问题记录(二)
  5. Spark MLlib中KMeans聚类算法的解析和应用
  6. reactjs踩坑记
  7. 【Flutter】布局类组件之对齐和相对定位
  8. Docker学习笔记之进入容器Bash
  9. MySQL select 查询的分页和排序
  10. Assuming that agent dropped connection because of access permission