Box2D v2.3.0 用户指南(第十一章)

news/2024/7/20 22:07:46 标签: IOS, box2d, 用户指南



第十一章零碎资料(loose ends)

11.1用户数据(user data

b2Fixtureb2Body,以及b2Joint类允许你通过一个通用指针(void pointer)来附加一个用户数据,如果你需要检查Box2D的数据结构来看他们是怎样关联到游戏引擎中的对象的时候,会觉得用户数据非常方便。

例如,一种非常典型的用法是将一个角色(actor)的指针附加到它对应的刚体上(注:通过设置刚体的UserData属性),这建立了一个循环引用,如果你有角色对象,你可以获取它对应的物体对象,如果你有物体对象,你也可以获取它对应的角色对象。

GameActor*actor = GameCreateActor();

b2BodyDefbodyDef;

bodyDef.userData= actor;

actor->body= box2DWorld->CreateBody(&bodyDef);

下面是一些需要用到用户数据的具体例子:

·通过碰撞结果对角色施加伤害

·在玩家进入一个AABB中的时候调用一段脚本

·Box2D通知你一个关节要被析构掉的时候,获取一个游戏元素(结构)

注意你可以有选择的使用或者不使用用户数据,你可以用它存放任何东西。但是你前后需要保持一致。例如,如果你想要在物体上存储一个角色的指针,那么对于所有的物体,都需要将其对应的角色指针存储到用户数据中。千万不要在一个物体中存储角色指针,而在另一个物体中存储一个别的乱七八糟的(foo)指针,当将角色物体指针转强制换成其他的指针的时候,会导致异常发生。

用户数据指针默认指向NULL。

对于装置,你可能想要定义一个用户数据结构用来存储游戏中特定的信息,例如材质类型,特效钩子(effecthooks),声音钩子(sound hooks)等等。

structFixtureUserData

{

int materialIndex;

};

FixtureUserDatamyData = new FixtureUserData;

myData->materialIndex= 2;

b2FixtureDeffixtureDef;

fixtureDef.shape= &someShape;

fixtureDef.userData= myData;

b2Fixture*fixture = body->CreateFixture(&fixtureDef);

deletefixture->GetUserData();

fixture->SetUserData(NULL);

body->DestroyFixture(fixture);

 

11.2隐式析构(implicitdestruction

Box2D不使用引用计数(referencecounting),所以如果你析构一个物体的话,那么它就真的不存在了。要访问一个已经释放了的物体指向的空间,会导致未知的问题。换句话说,你的程序很可能会崩溃。为了修复这些问题,在Debug编译模式下的内存管理器会将释放掉的内存区域填充上“FDFDFDFD”,这样在某些情况下,能使得查找问题原因变得更容易。

如果你析构了Box2D中的实体,你需要自己确保删掉所有指向被析构物体的引用,如果你只有一个实体的引用,那么很容易这样做,但是如果你有很多引用的话,那么你就应该考虑实现一个句柄类(handleclass)来封装一下原始指针(raw pointer)。

通常在Box2D中你会构造和析构很多物体、形状和关节。这些实体在某种意义上说都是由Box2D来管理的,如果你析构一个物体的话,那么所有相关的形状和关节都自动析构掉了,这就是标题中所谓的隐式析构。

当你析构一个物体的时候,所有附加到它上面的形状,关节和接触都被析构掉了,这就叫做隐式析构。(这个地方不知道为什么又要来一遍,原文中就是这么说的…)所有连接到这些析构掉的关节或者接触的物体都被唤醒(woken)了。这种处理方式通常很方便,但是你要留意一个严重的问题:你需要将指向这些析构掉的形状和关节的指针置为NULL,否则,当你的程序后面尝试访问或者析构这些对象的时候,它会死的很惨(diehorribly)。

为了帮助你将关节指针置为NULL,Box2D提供了一个叫b2DestructionListener的监听类,你可以实现这个类,然后将这个类传递给世界对象。接着世界对象就会在有关节被隐式析构的时候通知你的实现类。

需要注意的是,当某个关节或者装置被显示析构掉的时候,是没有通知的,这种情况下所有关系非常明确,你可以立即进行必要的清理工作。如果你愿意的话,你可以调用你自己实现的b2DestructionListener类中的清理方法,以保持方法的统一性。

隐式析构在很多情况下非常方便,但是同时它也可能让你的程序崩溃。你可能在你的代码中某处存储指向形状、关节等实体的指针,当指向的物体被析构的时候,这些指针也就失效了,更糟糕的情况是:你想一下,关节的创建代码通常和与它相关联的物体的管理代码无关,例如,testbed为了模拟和屏幕物体的交互而创建的b2MouseJoint类型的关节。

当隐式析构发生时,Box2D提供了一个回调机制来通知你的应用。这给你的程序提供了一个机会来将那些无效指针置为NULL,这个回调机制会在后面做描述。

你可以实现一个b2DestructionListener类,允许b2World来通知你某个形状或者关节被隐式析构了(由于相关的物体被析构了),这可以避免你的代码访问野指针。

classMyDestructionListener: public b2DestructionListener

{

void SayGoodbye(b2Joint* joint)

{

    // remove all references to joint

}

};

然后你需要将你的析构监听器(destructionlistener)的实例注册到世界中,在世界对象的初始化方法中使用下面的语句进行注册:

myWorld->SetListener(myDestructionListener);

 

11.3像素和坐标系(pixels andcoordinate systems

回忆一下我们讲过的,Box2D使用MKS(米,千克,秒)单位制以及弧度制,在使用米为单位的时候,你可能会遇到麻烦,因为你的游戏是用像素来作为单位的。在testbed中我们有一个游戏完全使用米作为单位,仅仅需要使用OpenGL提供的视图变换(viewporttransformation)来将世界坐标转换为屏幕坐标系下的尺寸。

floatlowerX = -25.0f, upperX = 25.0f, lowerY = -5.0f, upperY = 25.0f;

gluOrtho2D(lowerX,upperX, lowerY, upperY);

如果你的游戏必须要再像素单位制下才能工作,那么当你从Box2D重传出参数时,需要将长度单位从米转换为像素。当你需要向Box2D中传入参数时,需要将长度单位从像素转换为米。这样能够提高物理模拟的稳定性。

你需要一个合理的转换因子(conversionfactor),我建议根据你的角色大小来做一个合理的选择。假设你决定使用50像素来代表1米(因为你的角色可能是75像素高),那么你可以通过下面的方程来进行转换:

xMeters= 0.02f * xPixels;

yMeters= 0.02f * yPixels;

反过来:

xPixels= 50.0f * xMeters;

yPixels= 50.0f * yMeters;

你应该考虑在你的游戏代码中使用MKS单位制,仅仅在渲染的时候使用像素。这样可以简化你的游戏逻辑,减少犯错的机会,因为在渲染时做变换可以被隔离为一小段代码。

如果你使用转换因子,你应该尝试去修改它,以保证不会出现异常。你也可以尝试去调整它来提高稳定性。



http://www.niftyadmin.cn/n/878343.html

相关文章

微信小程序swiper图片尺寸_微信小程序 swiper 轮播图 高度自适应

微信小程序 swiper 轮播图 高度自适应发布时间:2018-07-20 15:34,浏览次数:588, 标签:swiper小程序中使用swiper 组件 ,实现轮播图高度自适应效果。先上最终实现效果图先看一下微信官方文档介绍 swiper 组件https://developers.w…

Box2D v2.3.0 用户指南(第十二章)

第十二章调试绘图(debug drawing) 你可以实现b2DebugDraw类来获取物理世界的细节绘图。下面是一些可用的实体: 形状外轮廓(shape outlines) 关节连接线(joint connectivity&…

anaconda安装pyrr_跨平台桌面剪切板共享工具过程

前言办公电脑,一台是Deepin OS, 另外一台是Win10, 平时两台都在用的时候,经常发现在Deepin OS上找到好的文字信息无法通过简单的方法复制到Win10系统上,通常要么是通过firefox的标签推送,但是对firefox浏览器意外的就没招了&#…

Box2D v2.3.0 用户指南(第十三章)

第十三章限制(limitions) Box2D使用很多近似来高效地模拟刚体的物理效果,这样做导致了一些限制。 下面列出了当前的一些限制: 1. 在非常轻的物体上面堆叠重物会不稳定,当质量比达到10&am…

java 分层_Java分层架构的全面解析

什么是分层架构?据我了解,分层体系结构是将项目结构组织为四个主要类别: 表示,应用程序,领域和基础结构。每个层都包含与其表示的特定关注点有关的对象。 表示层包含负责向最终用户呈现UI或将响应发送回客户端的所有类…

java从控制台输入数字_Java中控制台输入数字的解决方法

控制台输入在java中有一个System.in.read(),但是跟c#中的Console.ReadLine()不同,不知道为何,我即使象在C#中使用强制类型转换也不可以得到输入的数字.这是因为,Java将Enter的键也输入进去了.但是解决的方法还是有的,下面给一个小的例子,是将加仑转换成升的例子:/** This progr…

详解Photoshop中标尺工具和参考线的使用方法

这篇教程中,我们介绍两个Photoshop中非常有用的辅助参考工具。 首先是标尺(ruler)工具: 选中标尺工具后,鼠标变为尺子的形状,我们可以在图片上任意两点之间绘制一个标尺&#xff1…

手把手教你使用Photoshop制作炭笔素描线稿

这次我们综合利用Photoshop中的蒙版和图层混合模式以及滤镜来制作一个简易的炭笔素描线稿,如果对蒙版或者混合模式不了解的,可以参考博客中的相关教程。 先来看一下最终的效果: 我们的素材图片: 首先在PS…