使用cannon.js开发具有物理特性的汽车

cannon.js

cannon.js是一个Web端的轻量级物理引擎,其官方网站提供了大量的例子供我们学习。使用cannon.js搭配three.js或Babylon.js,可以开发出具有物理效果的3D Web应用程序。

RaycastVehicle

RaycastVehicle是cannon.js提供了一个车辆对象。并且官方给我们提供了demo

何为Raycast

为何称为RaycastVehicle呢?这与该对象的物理模拟原理有关系。该对象使用刚体(CANNON.Body)作为车身,从刚体的四个角处向下发射固定长度的射线,射线与地面的交叉点作为车辆与地面的接触点,在该点为车身刚体施加纵向的悬挂弹力与横向的牵引摩擦力。
在这里插入图片描述
其核心计算在updateVehicle方法中。

使用方法

使用方法可以参考官方示例
1、首先构造一个RaycastVehicle对象:

vehicle = new CANNON.RaycastVehicle({
    chassisBody: chassisBody,
    indexRightAxis: 0,
    indexForwardAxis: 2,
    indexUpAxis: 1,
});
vehicle.addToWorld(world);

其中,chassisBody是代表车身的刚体,indexRightAxis、indexForwardAxis、indexUpAxis官方示例中并没有用到,他们分别代表车的右、前、上轴,0、1、2分别代表x、y、z轴。

2、添加逻辑车轮:

vehicle.addWheel(options);

options对象为车轮及悬挂的参数:

chassisConnectionPointLocal: new Vec3(),// 车轮连接点,相对于chassisBody(也是发射射线的起点)
directionLocal: new Vec3(),// 车轮的下方方向(垂直车身向下)
axleLocal: new Vec3(),// 车轴方向
suspensionRestLength: 1,// 悬挂长度(未受任何力)
suspensionMaxLength: 2,// 悬挂最大长度,限制计算出的suspensionLength
suspensionStiffness: 100,// 悬挂刚度
dampingCompression: 10,// 悬挂压缩阻尼
dampingRelaxation: 10,// 悬挂复原阻尼
maxSuspensionForce: Number.MAX_VALUE, // 限制计算出的suspensionForce
maxSuspensionTravel: 1,// 悬挂可伸长或压缩的最大距离
radius: 1,// 车轮半径
frictionSlip: 10000,// 滑动摩檫系数(用于计算车轮所能提供的最大摩檫力)
rollInfluence: 0.01,// 施加侧向力时的位置系数,越小越接近车身,防止侧翻

3、添加车轮碰撞。添加好逻辑车轮后,还要在world中添加刚体以产生碰撞:

for (var i = 0; i < vehicle.wheelInfos.length; i++) {
    var wheel = vehicle.wheelInfos[i];
    var cylinderShape = new CANNON.Cylinder(wheel.radius, wheel.radius, wheel.radius / 2, 20);
    var wheelBody = new CANNON.Body({
        mass: 0
    });
    wheelBody.type = CANNON.Body.KINEMATIC;
    wheelBody.collisionFilterGroup = 0; // turn off collisions
    var q = new CANNON.Quaternion();
    q.setFromAxisAngle(new CANNON.Vec3(1, 0, 0), Math.PI / 2);// 把竖着的圆柱体放倒作为车轮
    wheelBody.addShape(cylinderShape, new CANNON.Vec3(), q);
    wheelBodies.push(wheelBody);
    world.addBody(wheelBody);
}

对于车轮碰撞,还要实时更新其Transom:

world.addEventListener('postStep', function () {
    for (var i = 0; i < vehicle.wheelInfos.length; i++) {
        var t = vehicle.wheelInfos[i].worldTransform;
        var wheelBody = wheelBodies[i];
        wheelBody.position.copy(t.position);
        wheelBody.quaternion.copy(t.quaternion);
        }
});

4、车辆控制。可以使用RaycastVehicle的如下函数控制车辆:

applyEngineForce = function(value, wheelIndex) // 施加牵引力
setSteeringValue = function(value, wheelIndex) // 设置转向角(弧度)
setBrake = function(brake, wheelIndex) // 刹车

5、实现动画。在每帧渲染之前,把车身、车轮的Transom拷贝给three.js或Bayalon.js图形,就实现了动画。
在这里插入图片描述

实现漂移

在赛车游戏中,漂移能够很大程度上增加游戏的娱乐性。要理解漂移,首先要了解汽车的转向。
后轮无滑移转向时,前轮与后轮的瞬心即为转向中心:
在这里插入图片描述
无滑移状态下,转向中心静止不变,车辆将沿转向中心做圆周运动。当漂移时,转向中心也做圆周运动,车辆运动的圆周比无滑移转向时的半径小:
在这里插入图片描述
(漂移轨迹有待验证)
实现漂移,可以在用户按下漂移键后,修改后轮的摩擦系数:

vehicle.wheelInfos[2].frictionSlip= up ? 3.5: 1.5;
vehicle.wheelInfos[3].frictionSlip= up ? 3.5: 1.5;

但是,此时很容易出现漂移过度,车子打一个圈:
在这里插入图片描述
前文中介绍了转向半径,这里再利用一下。设转向半径为r,轴距为l,轮距为w:
在这里插入图片描述
根据阿克曼条件,两轮的转向角为:
δ 0 = arctan ⁡ ( l r + w / 2 ) δ_0=\arctan(\frac{l}{r+w/2}) δ0=arctan(r+w/2l)
δ 1 = arctan ⁡ ( l r − w / 2 ) δ_1=\arctan(\frac{l}{r-w/2}) δ1=arctan(rw/2l)
车子打圈时,就可以通过调整两前轮的转向角度,避免漂移过程中进入一个极小的转向半径。

        r = 6 + Math.abs(vehicle.currentVehicleSpeedKmHour) / 10
        switch (event.keyCode) {
            // 。。。
            case 39: // right
                vehicle.setSteeringValue(up ? 0 : -Math.atan(2 / (r + 1 / 2)), 0);
                vehicle.setSteeringValue(up ? 0 : -Math.atan(2 / (r - 1 / 2)), 1);
                break;

            case 37: // left
                vehicle.setSteeringValue(up ? 0 : Math.atan(2 / (r - 1 / 2)), 0);
                vehicle.setSteeringValue(up ? 0 : Math.atan(2 / (r + 1 / 2)), 1);
                break;

            case 67:
                vehicle.wheelInfos[2].frictionSlip = up ? 3.5 : 1.4;
                vehicle.wheelInfos[3].frictionSlip = up ? 3.5 : 1.4;

在这里插入图片描述

此外,在卡丁车类游戏中,也可以使用参考文献[1]中,给车身施加侧向力的方法让车辆产生更顺滑的漂移。

参考

[1] 人人都是秋名山车神——Unity实现简化版卡丁车漂移
[2] How to make a DRIFT Controler in UNITY(Free Download Script)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值