65.9K
CodeProject 正在变化。 阅读更多。
Home

Box 2d 车辆 - 第 1 部分

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.89/5 (12投票s)

2012年8月23日

BSD

4分钟阅读

viewsIcon

30525

downloadIcon

1472

如何使用 box2d 创建漂亮的汽车?

引言

本文展示了如何制作一款汽车游戏;这款游戏的概念非常受欢迎,并被用于许多游戏中。为了制作具有逼真物理行为的游戏,我们使用了box2d物理引擎。本文中的最终代码可以在您自己的完整游戏中使用。此代码是用面向对象的 JavaScript 编写的,用于跨平台开发,称为 Moscrif,但 box2d 已被移植到许多其他编程语言,其用法非常相似。此项目的视频也可在 youtube上观看。

Box2d 引擎 

box2d 物理引擎提供逼真的物理模拟。它在许多设备上都表现出色,例如任天堂 Wii、DS 和一些手机(包括 Android 和 iPhone)以及大多数主要操作系统。

Box2d 关节

所有物理元素都创建为 box2d 刚体,它们在 box2d 世界中相互作用,并通过关节连接在一起。支持多种类型的关节:距离、摩擦、齿轮、鼠标、棱柱、旋转、焊接等... 

每个关节连接两个刚体,并允许某种类型的运动。在这个示例中,我们使用棱柱、旋转和鼠标关节。

  • 棱柱关节允许两个刚体沿指定轴的相对平移。棱柱关节防止刚体之间的相对旋转。
  • 旋转关节允许两个刚体围绕一个锚点进行相对旋转。
  • 鼠标关节仅用于连接车轮和底盘,以阻止这些刚体之间的接触。

图片:棱柱和旋转关节 


有时,不允许关节在整个范围内移动是不希望的。为了限制关节的运动,我们可以使用关节的限制。此外,可以将马达应用于关节,以根据关节的自由度来驱动连接刚体的运动。

Car

汽车由五个刚体组成,即底盘、车轮和减震器(悬架)。所有刚体都是部分动态的,这意味着它们与其他静态或动态刚体相互作用,并被完全模拟——在力作用和速度下移动。减震器只是小刚体,不可见。它们仅提供棱柱关节和旋转关节之间的连接。减震器通过棱柱关节上下移动,车轮通过旋转关节连接到减震器,这使它们可以围绕中心旋转。车轮是汽车与地面接触的部分。它们的摩擦力(连同地面的摩擦力)影响汽车的附着力。 

在我们的示例中,所有汽车的功能都由 Car 类提供。create 函数创建新车。

示例:创建所有汽车的刚体

function create(scene, x, y)
{
    var damperHeight = 8*this._images.wheel.width * this._scale/10;
    var wheelDistance = 7 * this._images.body.width*this._scale / 10;
 
    // create bodies:
    this._body = scene.addPolygonBody(this._images.body, #dynamic, 0.1, 0.0, 0.0, this._images.body.width*this._scale, this._images.body.height*this._scale);
    this._body.z = 2;
    this._body.scale = this._scale;
    this._body.setPosition(x, y);
    // FRONT
    this._frontDamper = scene.addPolygonBody(null, #dynamic, 10.0, 0.0, 0.0, 2, this._images.wheel.width / 2 * this._scale);
    this._frontDamper.setPosition(x + wheelDistance / 2, y + damperHeight - this._images.wheel.width / 4 * this._scale);
 
    this._frontWheel = scene.addCircleBody(this._images.wheel, #dynamic, 0.1, 0.4, 0.0, this._images.wheel.width / 2 * this._scale);
    this._frontWheel.scale = this._scale;
    this._frontWheel.setPosition(x + wheelDistance / 2, y + damperHeight);
 
    // BACK
    this._backDamper = scene.addPolygonBody(null, #dynamic, 10.0, 0.0, 0.0, 2, this._images.wheel.width / 2 * this._scale);
    this._backDamper.setPosition(x - wheelDistance / 2, y + damperHeight - this._images.wheel.width / 4 * this._scale);
 
    this._backWheel = scene.addCircleBody(this._images.wheel, #dynamic, 0.1, 0.4, 0.0, this._images.wheel.width / 2 * this._scale);
    this._backWheel.scale = this._scale;;
    this._backWheel.setPosition(x - wheelDistance / 2, y + damperHeight);
    ...  JOINTS ....

所有刚体都通过关节连接在一起。减震器通过棱柱关节与底盘连接。 限制和马达应用于棱柱关节。限制限制关节的上下过渡。上过渡是车轮在完全伸展悬架时的最低位置,而下过渡代表相反的位置。

棱柱关节还使用马达来驱动悬架的垂直运动。马达的最大力小于作用于车轮的力(当它们撞到障碍物时),但大于作用于一个车轮的重力,这导致车轮很好地通过所有障碍物。

旋转关节用于使车轮围绕中心旋转。马达应用于旋转关节,其力足以移动汽车。稍后会根据用户事件更改马达速度。

图片:关节


示例:创建关节

    // JOINTS
    // prismatic joins
    var jointDef = {
        lowerTranslation    : -3 * (damperHeight / scene.scale) / 10, //(damperHeight / 5) / scene.scale,  /*meters*/
        upperTranslation    : 0.0,  /*meters*/
        enableLimit         : true,
        enableMotor         : true,
        motorSpeed          : 2.5,
        maxMotorForce       : this._body.getMass() * 8.5,
    }
    this._joints.push(scene.createPrismaticJoint(this._frontDamper, this._body, x + wheelDistance / 2, y, 0.0, 1.0, 0.0, jointDef, false));
    this._joints.push(scene.createPrismaticJoint(this._backDamper, this._body, x - wheelDistance / 2, y, 0.0, 1.0, 0.0, jointDef, false));
 
    // revolute joints
    jointDef = {
        enableMotor     : true,         // enable motor
        maxMotorTorque  : 1500000,         // maximum torque
        motorSpeed      : 0.0,         // it is changed latery*/
    }
   this._motorJoint = scene.createRevoluteJoint(this._frontDamper, this._frontWheel, x + wheelDistance / 2, y + damperHeight, jointDef, false);
   this._motorJointB = scene.createRevoluteJoint(this._backDamper, this._backWheel, x - wheelDistance / 2, y + damperHeight, jointDef, false);
 
   this._joints.push(this._motorJoint);
   this._joints.push(this._motorJointB);
   this._joints.push(scene.createMouseJoint(this._body, this._frontWheel, null, false));
   this._joints.push(scene.createMouseJoint(this._body, this._backWheel, null, false));
}

可以通过更改旋转关节上马达的速度来加速或减速汽车。

示例:加速

function speedUp()
{
    // check if motors does not have maximum speed
    if (this._motorJoint.motorSpeed > -12*Math.PI) {
        // speed motors up
        this._motorJoint.motorSpeed -= this._speedStep;
        this._motorJointB.motorSpeed -= this._speedStep;
    }
}

场景

汽车场景包含许多小障碍,以显示悬架的工作方式。障碍物是小矩形,随机分布在整个场景中。场景中还有三个跳跃点。汽车移动的场景通常大于设备的屏幕。这意味着我们需要水平或垂直滚动场景。为了滚动场景,我们可以在其上绘制画布。画布在 draw 方法中滚动。

示例:在滚动的画布上绘制场景

function draw(canvas)
{
    // draw background
    canvas.drawRect(0, 0, System.width, System.height, this._bg);
    // save default canvas state (without translation)
    canvas.save();
    // translate canvas
    canvas.translate(this._translateX, this._translateY);
    this._x += this._translateX;
    this._translateX = 0;
    // draw all scene elements
    super.draw(canvas);
     // restore default canvas state (without translation)
    canvas.restore();
}
变量 ._translateX 和 ._translateY 在 process 函数中更新,该函数每隔 25 毫秒左右调用一次。此函数检查汽车的当前位置并更新转换变量。

示例:更新转换变量

// reaction to onproces event (repeates about every 25 miliseconds)
function process()
{
   var (x, y) = this._car.getPosition();
 
    if (true) {
        this._translateX = -1*((x) - (4*System.width / 10));
        this.menu.translateX = this._translateX;
    }
    if (y < 2*System.height / 10) {
        this._translateY = -1*(y - 2*System.height / 10);
        this.menu.translateY = this._translateY;
    }
    if (y > 8*System.height / 10) {
        this._translateY = 1*(y - 8*System.height / 10);
        this.menu.translateY = this._translateY;
    }
    // create step in physics world
    this.step(1.0/40.0);
}

改进

本文是第一部分,展示了如何制作基本的 box2d 汽车。通过使用矢量图形而不是位图,外观可以更好。矢量图形可确保在所有分辨率下都能获得平滑的图形,因为它即使在调整大小后也能保留细节。

摘要

本文展示了如何基于物理引擎 box2d 创建汽车卡车游戏。结果是一个免费的游戏草稿,您可以免费下载并在您的项目中使用。box2d 被移植到许多编程语言,如:C++、Java、Adobe Flash、C#、JavaScript 等。使用这些语言您可以创建此游戏,但对于三个平台创建此游戏并且只使用一个代码的最佳方法可能是使用 Moscrif。

© . All rights reserved.