Box2D C++ 教程-查询 World

2023-11-19

声明:本文翻译自Box2D C++ tutorial-World querying,仅供学习参考。

查询World

通常你可能想知道在给定的场景中都有哪些实体。例如有一个炸弹爆炸了,周围的所有实物都会受到不同程度的破坏,那么在RTS(译者注:Real-Time Strategy,即时战略)游戏当中,当玩家拖拉一个选框的时候,玩家可以合理的选中其中尚未完全破坏的单位。这种快速查询部分场景中尚未被完全损坏的单位的方法及其细节,就属于“查询World”的范畴。

Box2D提供了两个工具来完成这个功能-射线投射和AABB框测试。呃,射线投射是…别忘了上一篇刚刚介绍过哦!在上一篇中我们使用近似纯手工的方法实现的这个功能,当时通过遍历World中的定制器(fixture)来检测哪个物体距离射线原点最近。当场景中有大量物体时候,这种方法很低效。一个更好的办法是使用world自有的RayCast方法。此方法可以通过引擎来捕捉射线路径附近的定制器。

射线投射,高效的遍历方法

既然上一篇中我们已经对射线投射已经做过详细的介绍了,那么这里我们就不做额外的示范了,直接来看world中的RayCast方法如何使用。完整的方法声明:

1
void RayCast(b2RayCastCallback* callback, const b2Vec2& point1, const b2Vec2& point2);

方法中最后两个参数很简单,就是射线的起点和终点,通过这些参数我们就可以检测射线是否与单个定制器有交点。其中’callback’是个新参数,但是到目前为止我们应该已经熟悉了Box2D中回调方法通常是如何工作的了,所以这对于我们实现一个b2RayCastCallback的子类并没什么感到可奇怪的,然后我们实例化一个对象作为callback参数传入方法当中。b2RayCastCallback类只有一个可覆盖的方法,它就是:

1
2
//in b2RayCastCallback class
float32 ReportFixture(b2Fixture* fixture, const b2Vec2& point, const b2Vec2& normal, float32 fraction);

当射线进行投射计算的时候,每当与定制器有碰撞,callback方法就会被调用。对于每一次碰撞我们都能够知道当前与哪个定制器有交点,交点是多少,定制器“表面”的法线是多少以及沿着point1和point2射线方向上的交点段值是多少。如果你忘记了fraction参数的具体含义,可以回头温习下射线投射话题。

最后需要说的一点是处理callback方法的返回值问题。注意如果你的射线足够长,可能会和很多定制器发生碰撞,在一次RayCast的期间可能会多次调用回调方法。非常重要的一点是,射线并不会为你按照从近到远的顺序排列所检测到的定制器,它只会以上一次检测到的顺序依次排序-这对于处理大场景非常高效。引擎允许你自己处理射线所遇到的每一个定制器。这就是callback方法中返回值的来由。callback方法中你将会返回一个浮点型数值,在投射过程中你可以通过设置这个值来调整射线的长度。看到这里可能有一小点困惑,让我们放慢脚步…

  • 返回-1意味着忽略当前交点
  • 返回0~1来调整射线的长度,例如:
    • 返回0意味着根本没有射线
    • 返回1意味着射线的长度保持不变
    • 返回fraction值让射线保持至少能够与定制器有交点的长度

这里的fraction值指的是callback方法中传入的’fraction’参数(译者注:这里指的是ReportFixture方法当中传入的名为fraction的参数)。如果有人被我搞糊涂了,以后我可以为此做一张图,要是上面的描述不是很清楚的话就记住下面的通用规则:

  • 只找出最近的交点:
    -直接返回callback方法当中的fraction参数
    -使用最近一次的交点作为结果值
  • 沿着射线找出所有交点:
    -通过callback方法返回1
    -在列表中存储所有交点
  • 只是简单的找出射线的是否有交点:
    -如果callback被调用了,说明有交点(但不一定是最近的交点)
    -为了高效,把callback方法返回值设为0

区域查询(又名AABB查询)

在给定区域内,Box2D有另外一个方法来找出所覆盖的定制器,就是AABB查询。根据这一点我们可以定义一个矩形区域,引擎可以帮助我们找出矩形区域当中的所有定制器,并为其中的每一个定制器进行方法回调。通常情况下callback方法可以对定制器链表上的定制器做一些设置,为接下来的操作做一些准备,但是callback方法也允许你高效的实现一些其它操作。例如在给定区域有大量的定制器,但是呢你又想确定它们的总质量是否大于给定的数值,那么你可以在进行查询的时候累计它们的质量,当你能够确定结果的时候就停止查询。

这种方法称作AABB查询(QueryAABB),此名字的由来也是因为区域被指定为’axis-aligned bounding box(译者注:或许可以翻译成’同轴包围盒’?)’。这也就意味着区域是矩形的而且不能够以任意角度旋转。这也就意味着测试定制器是否在区域中,其实就是在测试定制器的AABB是否在区域中。你可以在testbed右面的面板上勾选渲染定制器AABB的选项。这个例子里显示了一些定制器的AABB(紫色)。

pic

此方法如下:

1
void QueryAABB(b2QueryCallback* callback, const b2AABB& aabb);

你喜欢用回调方法吗?我希望你喜欢,因为下边又有一个回调方法。像之前一样,你需要定义一个b2QueryCallback类的子类并且实现一个方法。类中的这个方法如下:

1
bool ReportFixture(b2Fixture* fixture);

这个不错,只有一个参数。既然AABB查询只是为了确定一个定制器是否在给定区域内,就没有必要像上面一样搞那么详细了。当你调用QueryAABB方法的时候,你的ReportFixture方法将会针对区域中的每个定制器进行回调,通过参数fixture进行传递。让我们用这个特性做一个例子。

我们将创建一个矩形区域,然后对区域中当前所覆盖的每一个定制器做标记。这里我们还是使用上一个话题中所使用的场景,从这里拷贝场景代码。

pic

首先获取屏幕上所显示的区域。我们可以覆盖Test类中MouseUp和MouseDown方法来获取鼠标坐标,接下来可以作为矩形的角的坐标,紧接着作为成员变量存储到FooTest类中。接下来在Step()方法中,使用Footest类中已存储的坐标画出一个矩形:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//FooTest class member variable
b2Vec2 mouseDownPos, mouseUpPos;

//FooTest class functions
void MouseDown(const b2Vec2& p) { mouseDownPos = mouseUpPos = p; Test::MouseDown(p); }
void MouseUp(const b2Vec2& p) { mouseUpPos = p; Test::MouseUp(p); }

//in Step() function, draw the rectangle
b2Vec2 lower( min(mouseDownPos.x,mouseUpPos.x), min(mouseDownPos.y,mouseUpPos.y) );
b2Vec2 upper( max(mouseDownPos.x,mouseUpPos.x), max(mouseDownPos.y,mouseUpPos.y) );

glColor3f(1,1,1);//white
glBegin(GL_LINE_LOOP);
glVertex2f(lower.x, lower.y);
glVertex2f(upper.x, lower.y);
glVertex2f(upper.x, upper.y);
glVertex2f(lower.x, upper.y);
glEnd();

不幸的是,此Box2D版本(v2.1.2)的testbed框架不允许我们覆盖MouseMove方法,所以我们不能直接看到当我拖拽鼠标的时候所画的矩形。

pic

使用区域查询过步骤中,现在我们可以真正得到AABB查询自身的信息。首先让我们创建b2QueryCallback类的子类并持有回调方法,然后用一个链表来保存查询区域中的定制器。你需要把链表设置成全局的或者是类可见的,但是区域查询的结果通常都是临时结果,更直观的方法也可以把结果存储在回调类中的链表里,然后每次用一个新实例来遍历这个链表。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//subclass b2QueryCallback
class MyQueryCallback : public b2QueryCallback {
public:
    std::vector<b2Body*> foundBodies;

    bool ReportFixture(b2Fixture* fixture) {
        foundBodies.push_back( fixture->GetBody() );
        return true;//keep going to find all fixtures in the query area
    }//对我来说最有价值的一段
};

//in Step() function
MyQueryCallback queryCallback;
b2AABB aabb;
aabb.lowerBound = lower;
aabb.upperBound = upper;
m_world->QueryAABB( &queryCallback, aabb );


//draw a point on each body in the query area
glPointSize(6);
glBegin(GL_POINTS);
for (int i = 0; i < queryCallback.foundBodies.size(); i++) {
    b2Vec2 pos = queryCallback.foundBodies[i]->GetPosition();
    glVertex2f( pos.x, pos.y );
}
//对我来说最有价值的一段
glEnd();

pic

注意我们需要让callback方法一直返回true,以确保查询区域中包含的定制器全部存储到链表中。你可以看到在鼠标所画AABB区域当中包含的所有定制器上都会有白点。在上面的截图中,你可以看到例子的左下方,有一个定制器本身并没有在查询AABB范围内,但是也有白点的出现(译者注:原因很简单,因为左下角的圆形AABB框和查询AABB框有重叠,只不过圆形的AABB框没有显示出来而已:D )。


转载自:http://ohcoder.com/blog/2012/12/11/world-querying/

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

Box2D C++ 教程-查询 World 的相关文章

  • 使用 Box2D 模拟“牛顿万有引力定律”

    我想模拟牛顿万有引力定律使用 Box2D 我浏览了手册 但找不到执行此操作的方法 基本上我想做的是将几个物体放置在太空中 零重力 并模拟运动 有小费吗 实现起来非常容易 for int i 0 i lt numBodies i b2Body
  • 通过触摸在贝塞尔曲线路径上旋转精灵 - Cocos2D/Box2D

    我有一个可以通过触摸旋转的箭头 我想知道是否可以沿曲线旋转箭头 我做了一些研究 我认为它被称为贝塞尔路径 是否可以使用此代码在贝塞尔曲线路径上旋转精灵 如果可以 我将如何合并它 UITouch touch touches anyObject
  • ios 在“确认您的应用内购买”对话框中显示不同的价格

    为 iOS 应用添加应用内购买 我可以成功购买该产品 但 确认您的应用内购买 对话框始终显示与我格式化的本地化价格相比的额外价格 示例 产品的本地化价格为 39 99 欧元 但在确认对话框中 产品的价格增加到 41 73 欧元 预先感谢您提
  • 如何创造漩涡/漩涡效果?

    我试图在作为传感器的圆形体上产生涡旋效果 我一直在寻找这个 我寻找的所有示例都是用 C 或 Objective C 编写的 但我似乎没有很好地翻译它们 当我的对象碰撞时 它调用 beginContact 并设置一个标志 以便我可以调用 bo
  • box2d 中的碰撞不正确

    我正在开发一款游戏 用户必须击打高速球 为了击球 我使用旋转关节将一个矩形体与演员连接起来 并启用其电机 以指定的速度 电机速度 旋转它 现在一切都很完美 但有时当球的速度很高时 它会绕过矩形体 使用碰撞监听器 我发现碰撞正在发生 但球在碰
  • MouseJointDef libgdx - 像愤怒的小鸟一样绘制轨迹线

    在 libgdx 游戏中 我想触地 然后拖动某处 然后在释放 触地 时根据距目标身体的距离和方向应用方向力 当您触地时 目标身体保持静止 然后在触地时 力沿着所需的轨迹施加 与 愤怒的小鸟 非常相似 当你握住弹弓时 你可以看到目标身体的虚线
  • 两个第 3 方库中 uint32 的 Typedef 重新定义 (C2371)

    在我的应用程序中我使用Box2D http www box2d org and 蜘蛛猴 https developer mozilla org en spidermonkey 这两个库都定义了 uint32 类型 这显然在同一编译单元中使用
  • 恢复0的SKPhysicsBody仍然会反弹

    我正在尝试以恒定速度掉落 SKSpriteNode 并且不会弹跳 这是我正在使用的代码 SKSpriteNode floor SKSpriteNode spriteNodeWithColor UIColor clearColor size
  • 如何制作双向平台box2d主体?

    我使用 box2d 创建了平台 我想要 box2d 身体检测而不是动态检测 Box2d 形状将执行以下操作 在某些条件下检测碰撞 在某些情况下不检测碰撞 两种条件都适用于同一 box2d 对象中的不同条件 任何想法都会有很大帮助 提前致谢
  • Box2D 中的 ChainShape

    最近开始学习libgdx 遇到Box2D的CainShape的问题 我的第一个目标是简单地创建一个带有 ChainShape 的盒子 为了实现这一点 我将四个 Vector2 添加到一个数组中 并使用它们创建一个循环 结果取决于数组中的排列
  • 绕着正方形滚动一个圆

    近一个月后 我仍然停留在这个问题上 我设法决定圆圈 或我所说的行人 是否应该向左 向右或向上 向下移动 但我需要有可能移动行人around一座建筑物 这意味着他们必须转角 基本上无论方向如何 他们只需要转90度 非常感谢 import nu
  • Libgdx box2D 中的碰撞对于某些物体失败

    我正在使用 libgdx 和 box2d 开发我的第一个游戏 我正在使用调试渲染器来测试我的对象 我创建了一些类似汽车的物体 每辆车都有一个主体 它是一个6点的大多边形 长约1米 高0 7米 并有2个通过旋转关节连接的车轮 主车还通过旋转接
  • 像 CCSprite 对象一样移动 Box2d 实体

    在cocos2d中 您可以轻松使用CCSprites并以各种方式移动它们 最重要的是 他们可以缓入 缓出 对于大多数游戏来说 这对于平滑移动等是可取的 id action CCMoveTo actionWithDuration dur po
  • 基于 cocos2d-box2d 的项目中出现“'uniqueIdentifier' is deprecated”警告

    我基于cocos2d box2d创建一个新项目 两个文件中总是有4个警告 一个是CLScoreServerPost m 代码有警告如下 self addValue UIDevice currentDevice uniqueIdentifie
  • 嵌入式 cocos2d-js 应用程序可以回调 C++ 吗?

    我正在研究通过将 cocos2d js 作为视图嵌入现有 iOS 应用程序中来使用它的可能性 为了完成这项工作 我需要在 cocos2d 和周围的应用程序之间进行双向通信 经过一些初步调查 我确定可以致电in到 cocos 使用Script
  • Emscripten 绑定:如何从 Javascript 创建可访问的 C/C++ 数组?

    我在用box2d https github com kripken box2d js 并尝试创建一个链条形状 为了创建链形状或多边形形状 我必须传递向量数组才能指定几何形状 我没有看到任何文档可以帮助我完成此任务 也没有看到有关绑定的注释h
  • 带有外部图像的 box2d-js 元素

    到目前为止 在各种 box2d js 实现的示例中 我只能找到形状 球 盒子 等 中定义的元素 有没有办法创建由图像定义的元素 例如一块巨石 您可以使用b2PolyDef and b2PolyShape对象来创建多边形 本文档 http w
  • Xcode C++ 和 Objective-C 重构

    有没有办法refactorXcode 中的混合 C Objective C 代码 我正在使用 Cocos2D 和 Box2D 编写游戏 而 Box2D 是用 C 编写的 因此我编写的每个类都应该具有 mm 扩展名 因此当我尝试例如重命名变量
  • 如何在cocos2dx 3.0中调用callfunc函数

    我必须将 Objective C 转换为 C 11 我坚持使用以下语法 我已在 testcpp 中引用并尝试以下语法 这是我尝试过的代码 this gt runAction Sequence create blink CallFunc cr
  • CMake 错误:CMake 无法找到与“MinGW Makefiles”对应的构建程序

    我正在尝试使用 cmake 为 c 构建 Box2D 库 当我运行 cmake gui 时出现错误 CMake Error CMake was unable to find a build program corresponding to

随机推荐

  • 二手房各项税费计算公式

    北京的房屋类型有很多种 有商品房 公房 一类经适房 二类经适房 两限房 现针对这些类型的房子列一下二手房购置过程中 需要考虑的税费 一 各类房源简介 1 商品房 正规从售楼处买的房源 2 公房 单位分的房子 由于不知道原值 所以个税按 网签
  • sbrk/brk函数用法

    头文件unistd h sbrk brk函数重新指定数据段的结束位置 sbrk 0 获得当前数据段结束地址 sbrk 增量 增量可正 可负 可为0 都返回原来数据段的结束地址 失败返回 1 brk 地址 返回0或 1 通过重新指定数据段新的
  • Matlab导入Excel数据快速绘图

    现在使用Matalb绘图越来越多 不会这个绘图技能感觉都要被时代抛弃了 所以 本文主要是介绍怎么用Matlab导入Excel数据快速绘图 目录 一 基本使用 二 细致调节 1 颜色选项 2 形状选项 3 网格线选项 一 基本使用 事先 建议
  • Python爬虫进阶--js逆向

    目标网址 aHR0cHM6Ly93d3cuZG5zLmNvbS9sb2dpbi5odG1s 抓包定位 首先抓包看请求 这里 password 和 email 都经过加密了 token 可以在页面上找到 从这里进去搜索 直接搜索 passwo
  • 【赠书活动|第六期《强化学习:原理与Python实战》】

    文章目录 RLHF是什么 RLHF适用于哪些任务 RLHF和其他构建奖励模型的方法相比有何优劣 什么样的人类反馈才是好的反馈 RLHF算法有哪些类别 各有什么优缺点 RLHF采用人类反馈会带来哪些局限 如何降低人类反馈带来的负面影响 图书简
  • 打卡C语言学习第十三天

    对之前所学内容复习和补充 练习函数书写
  • ruoyi登录流程

    首先加载登录界面会发送验证码请求和获取Cookie 会调用created函数 Getcode是获取验证码 GetCookie是获取cookie GetCodeImg函数会调用ajax发送请求给后端 后端GetMapping接口接收到请求后执
  • 搜狐2012.9.15校园招聘会笔试题

    一 不定项选择题 1 以下程序的打印结果是 include
  • Android SurfaceView

    下面就贴上一个小程序代码 主要运用SurfaceView来实现在屏幕上画一个圆 你可以通过按方向键和触摸屏幕来改变圆的位置 代码 Activity java view plain copy print package com view im
  • TypeError: 'function' object is not subscriptable

    报错 function object is not subscriptable 原因是Hi是个匿名函数 应该用 而不是 改成 即可 像这种问题TypeError function object is not subscriptable 一般
  • 迷宫问题java老鼠走迷宫(回溯法,递归,二维数组)(超级容易理解)

    回溯法迷宫问题 思路 利用回溯法和递归思想解决 findWay 方法就是专门来找出迷宫的路径 如果找到 就返回 true 否则返回 false map 就是二维数组 即表示迷宫 i j 就是老鼠的位置 初始化的位置为 1 1 因为我们是递归
  • mysql索引实现

    目前大部分数据库系统及文件系统都采用B Tree B树 或其变种B Tree B 树 作为索引结构 B Tree是数据库系统实现索引的首选数据结构 在MySQL中 索引属于存储引擎级别的概念 不同存储引擎对索引的实现方式是不同的 本文主要讨
  • Ubuntu下无法看到共享文件夹的解决办法

    1 输入以下指令 确定共享文件夹是否设置成功 vmware hgfsclient 若是设置成功 会输出贡献文件夹的名字 2 如果已经设置了共享文件夹 请输入下列指令 如果之前没有命令包则先执行sudo apt get install ope
  • 在linux下如何查看局域网的所有主机的ip地址

    策略 用nmap对局域网扫描一遍 然后查看arp缓存表就可以知道局域内ip对应的mac了 nmap比较强大也可以直接扫描mac地址和端口 执行扫描之后就可以 cat proc net arp查看arp缓存表了 或者使用命令arp a 参考
  • 【Goland】巧妙用批量替换Replace

    今天想提一嘴 IDE 的一个功能 就是批量替换 Replace in Path 大家可以按快键键 commnd 进入 Preference 然后搜索 Keymap 也就是快键键 然后搜索 Replace 找到批量替换的快键键 因为快键键就是
  • C# 处理异常

    using System using System Collections Generic using System Linq using System Text namespace Ch13CardLib public class Car
  • YAML 文件语法学习

    一 概述 YAML是一个类似 XML JSON 的标记性语言 YAML 强调以数据为中心 并不是以标识语言为重点 YAML 是一种较为人性化的数据序列化语言 可以配合目前大多数编程语言使用 YAML 的语法比较简洁直观 特点是使用空格来表达
  • 解决打印org.apache.http.wire,org.apache.http.headers日志的问题

    最近在调试接口的过程中 发现使用httpClient的时候 控制台输出了很多org apache http wire org apache http headers相关的日志 不便于我观察自己调试业务过程中输出的日志 内容如下 10 02
  • 如何把一张照片用PS做成漫画风格

    如何把一张照片用PS做成漫画风格 原素材 漫画天空 1 打开ps 打开素材 然后按住ctrl j 复制一个图层 并修改好名字 如下图操作 2 执行 滤镜 滤镜库 干画笔 如图所示 三个参数分别是 0 10 2 3 执行 滤镜 Camera
  • Box2D C++ 教程-查询 World

    声明 本文翻译自Box2D C tutorial World querying 仅供学习参考 查询World 通常你可能想知道在给定的场景中都有哪些实体 例如有一个炸弹爆炸了 周围的所有实物都会受到不同程度的破坏 那么在RTS 译者注 Re