Box2D C++ 教程 第五节:物体(Bodies)

2023-11-06

Box2D C++ 教程 第五节:物体(Bodies)

声明:本教程翻译自:Box2D C++ tutorials-Bodies,仅供学习参考

物体(Bodies)

物体是物理场景中的基本对象,但是这里的物体并不是你看到的实际互相弹跳碰撞的实物。听起来很费解吗?挺住!马上做解释!

你可以把物体想象成是一种看不见摸不着的实物的属性。这些不可见的属性是:

  • 质量(mass)-实物到底有多重
  • 速度(velocity)-某方向上实物到底运动多快
  • 转动惯量(rotational inertia)-开始或停止转动需要多大的力
  • 角速度(angular velocity)-某方向实物转动的速度有多快
  • 位置(location)-实物在哪
  • 角度(angle)-实物面向哪个方向

即便你知道一个对象的所有这些特性,你仍然不清楚这到底意味着什么或者它们之间产生碰撞的时候,它们会有什么样的反应。我们需要使用定制器(fixtures)来定义物体的形状和大小,关于定制器我们会在本教程的下一个话题进行讲解。目前我们还是使用一个简单的盒子来代替随后出现的定制器(fixture)的一些细节。让我们创建一个物体并为它设置一些基本属性,来看看是如何工作的吧。

有三种类型的物体:静态物体(static),动态物体(dynamic)以及运动学物体(kinematic)。前两个顾名思义看起来更好理解一些。最后一个看起来理解起来并不是那么的直观。目前先忽略一些细节,随后再进行解释。首先我们将创建一个动态物体,我们可以在场景中的地面上看到它可以移动,然后试图设置速度,等等。开始吧。

创建物体

首先为物体的创建做一个定义,用它来创建物体自身。如果你想创建多个相同或相似的物体,这么做会很方便(译者注:这里所说的创建物体的定义就是下面代码中的b2BodyDef结构体的定义,以后所创建的物体都可以根据这个结构体做快速初始化)。在Footest类的构造方法里,添加如下代码,来创建物体定义:

?
1
2
3
4
b2BodyDef myBodyDef;
myBodyDef.type = b2_dynamicBody; //this will be a dynamic body
myBodyDef.position.Set(0, 20); //set the starting position
myBodyDef.angle = 0; //set the starting angle

这对创建一个基本的物体就足够了。记住这里的物体没有大小、形状,所以这里不会对这些进行定义。你可能会想为什么这里还没有质量-通常为物体设置质量的方式是通过为物体添加定制器(fixtrues)来完成的,下面会进行这一步骤。现在,使用这个定义创建一个活生生的对象吧:

?
1
b2Body* dynamicBody = m_world->CreateBody(&myBodyDef);

这里,我们用到了父类Test中类型为b2World类型的成员变量m_world。world类型的对象就像是Box2D中的老大,它掌管着创建和销毁物理对象。稍后的教程里我们会看到关于world类型更多的细节。好吧,现在我们有了一个物体,但是就像开始提到那样,目前物体是不可见的,现在如果你运行程序,什么都不会看到(如果你选中右侧控制面板中“质心(Center of Masses)”选项,最多你可以看到物体下落的位置)。

为物体设置大小,形状以及其它明确的性质,我们通过添加定制器(fixtures)实现。此外,即便为物体添加默认的定制器也会影响物体的质量。物体可以附加多个定制器,附加的每一个定制器都会影响物体的总质量。目前,我们只为物体添加一个简单的定制器,一个四方形,定制器本来是下一次教程的话题,现在细说有点超前。

?
1
2
3
4
5
6
7
b2PolygonShape boxShape;
boxShape.SetAsBox(1,1);
 
b2FixtureDef boxFixtureDef;
boxFixtureDef.shape = &boxShape;
boxFixtureDef.density = 1;
dynamicBody->CreateFixture(&boxFixtureDef);

虽然上面这段大部分的代码现在你都可以忽略,但是注意一下密度设置这行代码。定制器的面积(area)是通过定制器之间密度的相乘来计算自身质量的,最终会成为物体的质量。

现在,当你运行程序,会看到一个下落的小盒子。如果你足够快,你可以用鼠标捕捉它,然后随意拖拽,如果小盒子丢出屏幕范围可以按restart按钮(R键)重新开始。既然这是个动态物体,那么它可以移动并且旋转,还会受到重力的影响。

设置物体属性

现在,我们设置一些文章开始提到的属性,看看会发生什么。比如说,改变初始位置和角度:

?
1
dynamicBody->SetTransform( b2Vec2( 10, 20 ), 1 );

这将会使物体的初始位置向右移动10个单位,向上移动20个单位,并且逆时针旋转1弧度。Box2D使用弧度作为角度值的单位,如果你像我一样想使用角度值,那么需要多做一些工作,或许会像下面这样:

?
1
2
3
4
#define DEGTORAD 0.0174532925199432957f
#define RADTODEG 57.295779513082320876f
 
dynamicBody->SetTransform(b2Vec2(10, 20), 45 * DEGTORAD ); //45 degrees counter-clockwise

我们也可以设置物体的线速度和角速度:

?
1
2
dynamicBody->SetLinearVelocity(b2Vec2( -5, 5 )); //moving up and left 5 units per second
dynamicBody->SetAngularVelocity(-90 * DEGTORAD); //90 degrees per second clockwise

静态物体(Static bodies)

现在让我们看看什么是静态物体。既然我们已经自定义了物体定义和定制器,那我们就重用它们,只修改一些必须的特性:

?
1
2
3
4
myBodyDef.type = b2_staticBody; //this will be a static body
myBodyDef.position.Set(0, 10); //slightly lower position
b2Body* staticBody = m_world->CreateBody(&myBodyDef); //add body to world
staticBody->CreateFixture(&boxFixtureDef); //add fixture to body

注意这里我们根本不需要改变正方形定制器。运行程序,这时你可以在场景中看到另外一个盒子,但是这次它将不会移动。而且你还会发现即便你像上面那样成功使用setTransform方法改变静态物体的位置,设置静态物体的速度属性,也不会有任何效果。

运动学物体(Kinematic bodies)

最后,让我们来看看所有关于运动学物体的部分。正如我们之前看到的动态物体可以移动,但静态物体不能移动。当一个静态物体和动态物体发生碰撞的时候,静态物体总能“获胜”并且把持住自己,并且被弹回,两个物体不会发生重叠。运动学物体非常像静态物体,当它与动态物体相撞之后,总能保持自己不动,把动态物体反弹回去,与静态物体唯一不同的是,运动学物体可以被移动。

可以像下面这样创建一个运动学物体:

?
1
2
3
4
5
6
7
myBodyDef.type = b2_kinematicBody; //this will be a kinematic body
myBodyDef.position.Set(-18, 11); //start from left side,slightly above the static body
b2Body* kinematicBody = m_world->CreateBody(&myBodyDef); //add body to world
kinematicBody->CreateFixture(&boxFixtureDef); //add fixture to body
 
kinematicBody->SetLinearVelocity( b2Vec2( 1, 0 ) ); //move right 1 unit per second
kinematicBody->SetAngularVelocity( 360 * DEGTORAD ); //1 turn per second counter-clockwise

新创建的物体在场景中可以被移动或者旋转,但不会被重力所影响,并且当与动态物体发生碰撞的时候也不会受到影响。注意当它与静态物体发生接触的时候,它们之间是没有相互作用的。

在大多数游戏中,动态物体通常被用来创建玩家和其它场景中的角色,静态物体被用来创建墙,地板等等。运动学物体通常用来扮演那些可以移动或旋转但是不能被动态物体所相撞的物体。一个比较恰当的例子是平台场景游戏中,移动的平台可以使用运动学物体来模拟-这可以保证不论玩家如何跳跃,都不能与之发生相撞。

获取物体属性(Getting body properties)

很多情况下你都想知道物体目前在哪儿或者移动有多块,旋转角度等等。实现这个很简单,让我们马上就尝试一下。为了达到这个效果,我们需要在Step()方法中访问物体变量,所以我们需要声明一个类的成员变量来代替只在构造函数中声明变量。

?
1
2
//in the class itself, not inside the constructor!
b2Body* dynamicBody;

…然后使用类的成员变量替换物体类型的局部变量。现在在Step()方法中,我们可以加入如下代码来打印出物体的一些先关信息:

?
1
2
3
4
5
6
7
8
b2Vec2 pos = dynamicBody->GetPosition();
float angle = dynamicBody->GetAngle();
b2Vec2 vel = dynamicBody->GetLinearVelocity();
float angularVel = dynamicBody->GetAngularVelocity();
m_debugDraw.DrawString(5, m_textLine, "Position:%.3f,%.3f Angle:%.3f" , pos.x, pos.y, angle * RADTODEG);
m_textLine += 15;
m_debugDraw.DrawString(5, m_textLine, "Velocity:%.3f,%.3f Angular velocity:%.3f" , vel.x, vel.y, angularVel * RADTODEG);
m_textLine += 15;

你可以通过GetPositon()和GetAngle()方法返回SetTransform所设置的值,而且不会发生值的改变。比如说,像下面这行代码根本不会改变物体的移动。

?
1
body->SetTransform( body->GetPosition(), body->GetAngle() );

当然了,这么做并没有什么意义,但是如果你只想改变位置或者角度,你就可以这么做。

遍历世界中的物体

如果你想监视世界中的所有物体,你可以像下面这样做。GetBodyList()方法可以返回物体链表的第一个元素。

?
1
2
3
4
for ( b2Body* b = m_world->GetBodyList(); b; b = b->GetNext())
{
     //do something with the body 'b'
}

清除

当一个物体完成了它的使命,你可以通过调用世界对象的DestroyBody方法:

?
1
m_world->DestroyBody(dynamicBody);

当像上面这样销毁物体之后,物体所附加的所有定制器(fixtures)和连接器(joins)都会被销毁。记住!当使用这个方法之后不要再调用这个已经删除的物体指针!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Box2D C++ 教程 第五节:物体(Bodies) 的相关文章

  • 柯美背包服务器系统,全能升级!全面合作!经纬科技与柯美中国正式签约

    经纬长期关注客户需求 现针对图文行业客户核心需求 加推卷材送料功能 该功能已在海外市场成熟应用1年多时间 可助力客户承接更多业务 但又不会因订单数量起伏导致设备闲置 真正实现一机多能 提升效率 创造价值 横向打通 睿思新科技 锐启新合作 真
  • .env.development(开发环境)、.env.prodction(正式环境)、自定义环境的使用

    1 配置文件 env development 开发环境下的配置文件 env production 生产环境下的配置文件 2 命名 属性必须以VUE APP 开头 案列 env development NODE ENV development
  • 《趣谈Linux》总结十:虚拟化

    37 虚拟化 Linux越来越强大了 例如 内存动不动就是百G内存 网络设备一个端口的带宽就能有几十G甚至上百G 存储在数据中心至少是PB级别的 一个P是1024个T 一个T是1024个G 这自然有了一些不灵活的地方 资源大小不灵活 有时候
  • python初阶---基础语法篇(二)

    文章目录 一 数据类型 二 列表 三 元组 四 集合 五 字典 六 序列 七 遍历函数map 八 筛选函数filter 九 累计函数reduce 一 数据类型 1 逻辑型 逻辑型又称布尔型 取值只有两种 0和1 或者真和假 False和Tr
  • 7.2

    include
  • Android自定义RecyclerView实现多级树

    Android自定义RecyclerView实现多级树 在Android开发中 RecyclerView是一个强大灵活的控件 常用于展示大量数据列表 而有时候我们需要实现多级树结构的列表 即每个节点下面可以包含子节点 这时候就需要对Recy
  • shell脚本启动jar包

    bin bash NAME spring admin echo NAME PID ps ef grep NAME grep java grep v grep awk print 2 echo 当前进程号为 PID echo for pid
  • iphone屏蔽系统更新_iphone如何实现永久屏蔽IOS系统更新?

    一直以来苹果的新系统更新覆盖率是全行业最快也是最高的 截止到ios13发布为止 ios12的全网覆盖率已经达到了惊人的90 iphone手机如何永久屏蔽IOS系统更新 对于ios13加入的诸多功能升级以及隐藏的一些不稳定因素 更多用户会选择
  • 线性代数 - 矩阵形式下的最小二乘法

    20201001 0 引言 最近在看 异常点检测 的时候 其中在PCA部分 准确来说是前面一小节 在进行推导的时候 使用了最小二乘法 其实这个东西本质上并不难 但是让我比较尴尬的是 很多线性代数的东西有些遗忘了 好在最近直截了当的复习让大部
  • Python3中with用法

    Python中的with语句用于用上下文管理器 context manager 定义的方法包装块的执行 它允许将常见的try except finally使用模式封装起来以方便重用 在Python中 在处理非托管资源 unmanaged r
  • Idea代码上传至Git完整教程(阿里云)

    项目背景 本期项目是一个数据化应用系统 使用的是idea开发后台 前端使用微信小程序的项目 项目中 为了代码管理方便 使用了阿里云作为代码托管 直接使用idea上传下载代码 本期文章介绍idea上传代码的过程 与大家分享 如有不行详细或错误
  • Python code模块

    code 解释器基类 code 模块提供了在 Python 中实现 read eval print 循环的功能 它包含两个类和一些快捷功能 可用于构建提供交互式解释器的应用程序 class code InteractiveInterpret

随机推荐

  • Kmeans原理公式图文详解

    在网上查看了些博客 感觉大家都对数学公式的解释的比较晦涩 下面我结合一个非常简单的示意图解释下他的数学公式 理解不到位的请留言 kmeans是一种聚类算法下面是算法的描述 给定训练样本是每一个 即每一个样本元素都是n维向量 为了便于理解在后
  • 淘宝淘金币助手,自动完成淘金币任务,蚂蚁庄园和蚂蚁森林,天猫领红包和收取能量

    最新软件下载 详见群文件 长期更新 QQ群号 636677598 或者直接点击链接加群 https jq qq com wv 1027 k 8rmAofkO 微信 baohuikf 1 下载安装金币助手 2 打开无障碍服务和悬浮窗权限 授权
  • Android进阶(五)DataBinding解析

    1 概述 在上篇文章Android进阶 四 LiveData解析中讲到了关于JetPack框架的LiveData解析 这是一个基于ViewModel和观察者模式的实践 这篇文章要讲的DataBinding同样可以认为是基于ViewModel
  • MIB、SIB

    1 1 概述 系统信息分成MasterInformationBlock MIB 和多个SystemInformationBlocks SIBs MIB包括有限个最重要 最常用的传输参数 其需要从该小区中获得其它的信息 同时其在 BCH上进行
  • 还在为ElementUI的原生校验方式苦恼吗,快用享受element-ui-verify插件的快乐吧(待续)

    element ui verify 本文章意在介绍element ui verify插件使用 以及对比elementUI原生校验方式 突显该插件用少量代码也能实现原生的校验效果甚至更好 1 先观察一个示例
  • Maven Helper插件 IDEA配置使用(详细配置)

    转自 https blog csdn net qq 33541575 article details 80211122 配置Maven Helper插件 因为在准备讲Maven用Maven Helper插件的时候 在网上学习 发现资料很少
  • 一个常用的 C++ 学习、了解平台特性和数据类型的小工具(源代码)

    这是一段C 代码 运行后会输出不同数据类型在当前平台下所占字节数 最大值和最小值等信息 具体解释如下 首先 包含两个头文件 iostream 输入输出流的标准头文件 用于标准输入输出 包含定义在 std 命名空间的 cout 和 endl
  • SpringCloud Alibaba之Ribbon 修改和自定义负载均衡策略

    Ribbon 简介 Spring Cloud Ribbon是一个基于HTTP和TCP的客户端负载均衡工具 它基于Netflix Ribbon实现 通过Spring Cloud的封装 可以让我们轻松地将面向服务的REST模版请求自动转换成客户
  • 文件服务器 选择,文件服务器选择

    文件服务器选择 内容精选 换一换 从本地上传日志文件 是指从浏览器所在机器选择日志文件并上传 目前只支持选择 log的日志文件 如果日志文件中包含其他格式文件 则导入时会提示格式错误 如图2所示 单击Upload 则只会上传 log的日志文
  • request.getParameterNames();

    详情查询 J2EE 1 3 1 API
  • 第2章 信息系统集成及服务管理

    本章考试分值 1 2 分 主要考点 1 ITSS 信息技术服务标准 2 信息系统设计 一 信息系统集成及服务管理体系 1 信息系统集成及服务管理体系 了解 信息系统集成及服务是一个范围相当广泛的概念 所有以满足企业和机构的业务发 展所带来的
  • Android平台安全(一)

    刚好五一了 已经过去两三天了 今天接触到了关于Android安全的一些东西 记录下来 Android安全我大致分三个部分来说明 今天我就先说第一个部分 在典型的场景中 安全主要用于解决一下4类需求 保密 鉴别 认证 完整性 不可以否认性 安
  • IncrediBuild 联合编译

    01 基本信息 官网 https www incredibuild com Make 和其他构建工具示例 要使用IncrediBuild 必须有License 可以免费申请试用版本的license 可以到 https www incredi
  • 【H5】两种加密解密方法:

    H5 两种加密解码方法 encodeURI 加密 decodeURI 解密 加密成base64编码格式 btoa 加密 atob 解密 实现代码如下
  • 【C语言】计数排序

    一 算法描述 得到最小值和最大值 即得到临时数组的长度 数等于临时数组的下标 下标对应的值就加一 把临时数组的信息对应到原数组中 计数排序有很大的约束 最小值和最大值不能相差很大 排序的数适用于非负数 否则得另加代码将负数偏移为正数 最后还
  • MySQL——存储过程详解及实例分析

    目录 一 储存过程简介 1 什么是存储过程 2 存储过程优缺点 3 存储过程入门程序 4 在idea中如何调用储存过程 二 存储过程编程 1 存储过程的变量 2 存储过程中的参数 3 选择结构if 4 分支结构case 5 3个循环结构 6
  • 中文分词jieba学习笔记

    中文分词jieba学习笔记 一 分词模式 二 自定义词典 2 1 命令 2 2 使用方式 三 关键词抽取 基于TF IDF算法 3 1 用jieba analyse extract tags 3 2 用jieba analyse textr
  • idea配置tomcat启动服务器时控制台乱码

    项目场景 在idea中配置tomcat启动时候控制台乱码问题 问题描述 idea中以tomcat启动控制台出现乱码问题 原因分析 由于tomcat8以后默认编码格式是utf 8 tomcat7之前的都是iso8859 1 与idea中的编码
  • 反激式开关电源双环PID(电压环+电流环)控制之MATLAB仿真

    前面一篇文章我讲解了反激式开关电源输出电压的pid控制的matlab仿真 反激式开关电源输出电压PID控制的MATLAB仿真 我只对输出电压做了控制 不管负载多大 只要在设计功率之内 都能把电压维持在12V 但在实际电路设计中 我们还需要考
  • Box2D C++ 教程 第五节:物体(Bodies)

    Box2D C 教程 第五节 物体 Bodies 作者 firedragonpzy 14 十一月 2012 暂无评论 声明 本教程翻译自 Box2D C tutorials Bodies 仅供学习参考 物体 Bodies 物体是物理场景中的