如果一个圆圈在发射阶段伸展,并变得拉长(获得高度和失去宽度)如何动态调整碰撞形状(在Box2D中),因为它的缩放?这可以通过所有步骤的每一帧完全拉伸并回到圆形吗?
同样地,当弹跳时,它会挤出一点,并需要检测更多的宽度和更少的高度。
想象一下,这是一个游戏中的英雄角色,他有点跳投,甚至可以做半空跳'。但大多数伸长和压扁都发生在地面相互作用过程中。像这样:
答案 0 :(得分:2)
我们有两个问题:
动态更改灯具形状
Box2D支持各种类型的形状,如:
这里的情况取决于您需要的形状类型。如果“简单”类型的形状足够,那么解决方案非常简单,并且(对于PolygonShape)类似
//! I'm using LibGDX in code examples but you can translate it to other engines
Body body;
...
//assuming that body has one fixture - if not just keep it's reference and call it directly
((PolygonShape) body.getFixtureList().first().getShape() ).setAsBox(hx, hy);
请注意,对于CircleShape,您甚至不需要投放它,因为Shape类包含setRadius
方法
如果您需要“复杂”的形状,情况会更复杂,但仍然很容易。处理它的方法是销毁当前夹具并使用其他形状重新创建,如
Body body;
FixtureDef fixtureDef;
...
//creating fixturDef - for further usage (setting friction, density etc...)
...
//again assuming that body has one fixture - but also can keep reference
body.destroyFixture( bb1.getFixtureList().first() );
ChainShape shape = new ChainShape();
//creating shape...
fixtureDef.shape = shape;
body.createFixture(fixtureDef);
//you must dispose shape after fixture creating!
shape.dispose();
创建椭圆
虽然Box2D支持各种形状没有椭圆类型,你需要使用一些技术来自己生成它。在互联网上有很多方法描述 - 我将向您展示如何生成椭圆作为ChainShape
实例。
我将parametric equation for ellipse与0 <= t < 2π
一起使用(以弧度表示)。该方法如下:
//overriding method to handle default STEPS value
ChainShape createEllipse(float width, float height)
{
return createEllipse(width, height, 64);
}
ChainShape createEllipse(float width, float height, int STEPS)
{
ChainShape ellipse = new ChainShape();
Vector2[] verts = new Vector2[STEPS];
for(int i = 0; i < STEPS; i++)
{
float t = (float)(i*2*Math.PI)/STEPS;
verts[i] = new Vector2(width * (float)Math.cos(t), height * (float)Math.sin(t));
}
ellipse.createLoop(verts);
return ellipse;
}
其中:
总而言之 - 假设您在模拟过程中知道身体的大小(因为如果您不知道它比这个问题更大的主题),那么情景就是:
在代码中它将类似于:
//in render method
if( bodySizeChanged() ) //this method is checking somehow if you should change fixture
{
//again assuming that body has one fixture - but also can keep reference
body.destroyFixture( body.getFixtureList().first() );
ChainShape ellipse = createEllipse(newWidth, newHeight);
fixtureDef.shape = ellipse;
body.createFixture(fixtureDef);
ellipse.dispose();
}
当然每次创建新形状效率不高,更好的方法是在加载时创建一些形状Array<ChainShape>
甚至FixtureDef
的集合(例如在show()
方法中)和只需在渲染方法中获得所需的 shape / fixtureDef 。
编辑 - 例如,如果您有动画精灵集合,则可以为每个精灵生成另一个形状集合 - 但仅限于之前的动画帧具有其他尺寸不要将形状改变为相同的形状 - 它会是这样的:
Sprite[] frames = new Sprite[N]; //N sprites for animation
ChainShape[] shapes = new ChainShape[N]; //N shapes
...
Vector2 lastSize = new Vector2(0,0); //or another initial value - depends on what sizes your sprites have
for(int i = 0; i < frames.length; i++)
{
Sprite s = frames[i];
if(lastSize.x != s.getWidth() || lastSize.y != s.getHeight())
{
shapes[i] = createEllipse(s.getWidth(), s.getHeight());
lastSize.set(s.getWidth(), s.getHeight());
}
else
{
shapes[i] = null;
}
}
然后在渲染方法
中 //render method
int index = getCurrentAnimationFrameIndex(animation); //some function to get index of current sprite of character
if(shapes[index] != null)
//change fixture
当然,您应该记得在应用程序结束时处理所有非空形状(至少如果它是Libgdx)!
我在这里发现的一件有趣的事情是,ChainShape
在碰撞过程中不会旋转对我来说有点奇怪。实际上它可能对你有好处(我猜球是某种角色而且它不应该有旋转 - 也许你甚至会在它的身体上设置一些setFixedRotation
但是如果你想让身体旋转这样做的方法是定义MassData
,将 I (惯性)设置为某个值,然后将此MassData
附加到正文
MassData m = new MassData();
m.center.set(0, 0);
m.I = 100; //example value
body.setMassData(m);
不幸的是,我不能告诉你应该在那里设置什么值,但你可以在Wikipedia site上阅读更多内容。