【问题标题】:How to get width and height from a body in box2d?如何从box2d中的身体获取宽度和高度?
【发布时间】:2014-03-28 07:12:31
【问题描述】:

我正在使用Libgdx 引擎开发一款游戏。我必须从box2d 的身体中获取宽度和高度。他们有什么方法可以从box2d 中的主体获取宽度和高度??

【问题讨论】:

  • 你可以看看我的一个老 Gists:gist.github.com/nooone/8363982。它可以为 Body 创建一个边界框,但它没有完全实现。看PhysicsUtil
  • @noone 非常好。这似乎是我正在寻找的正确方式。是否可以重新调整身体的大小?我已经看到要销毁夹具并重新创建它,但高度不适合演员和身体......
  • 不,无法调整大小。
  • @noone 你能考虑这个问题吗? stackoverflow.com/questions/22729244/…

标签: libgdx box2d


【解决方案1】:

我还在 gamedev.stackexchange.com 上的相同线程上发布了这个答案
我知道这是一个非常古老的线程,但我只是在这里用自己的方式获取 Body 的大小:https://github.com/Wasupmacuz/Box2DBodySize 如果链接对您来说太诡异,这里是代码:

import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.ChainShape;
import com.badlogic.gdx.physics.box2d.CircleShape;
import com.badlogic.gdx.physics.box2d.EdgeShape;
import com.badlogic.gdx.physics.box2d.Fixture;
import com.badlogic.gdx.physics.box2d.PolygonShape;
import com.badlogic.gdx.physics.box2d.Shape;

/**
 * Finds the size (width and height) of a body by checking its fixtures' shapes
 */
public class Sizerinator3000
{
    public static Vector2 getBodySize(Body body)
    {
        float maxTop = 0, maxRight = 0, maxBottom = 0, maxLeft = 0;
        for(Fixture f : body.getFixtureList())
        {
            MyVector4 vec = outerVals(f);
            if(vec.a > maxTop)
                maxTop = vec.a;
            if(vec.b > maxRight)
                maxRight = vec.b;
            if(vec.c > maxBottom)
                maxBottom = vec.c;
            if(vec.d > maxLeft)
                maxLeft = vec.d;
        }
        
        return new Vector2(Math.abs(maxRight - maxLeft), Math.abs(maxTop - maxBottom));
    }
    
    public static Vector2 getBodySize(Body body, float scale)
    {
        float maxTop = 0, maxRight = 0, maxBottom = 0, maxLeft = 0;
        for(Fixture f : body.getFixtureList())
        {
            MyVector4 vec = outerVals(f).scale(scale);
            if(vec.a > maxTop)
                maxTop = vec.a;
            if(vec.b > maxRight)
                maxRight = vec.b;
            if(vec.c > maxBottom)
                maxBottom = vec.c;
            if(vec.d > maxLeft)
                maxLeft = vec.d;
        }
        
        return new Vector2(Math.abs(maxRight - maxLeft), Math.abs(maxTop - maxBottom));
    }

    /**
     * Changing which method is called based on the fixture's shape
     * @param fixture the current fixture being analyzed
     * @return the outermost points of the fixture's shape
     */
    private static MyVector4 outerVals(Fixture fixture)
    {
        Shape shape = fixture.getShape();
        Shape.Type type = shape.getType();
        MyVector4 size = new MyVector4();
        switch(type)
        {
        case Polygon: 
        size = shapeVals((PolygonShape)shape);
        break;
        case Chain: 
        size = shapeVals((ChainShape)shape);
        break;
        case Edge: 
        size = shapeVals((EdgeShape)shape);
        break;
        case Circle: 
        size = shapeVals((CircleShape)shape);
        break;
        }
        
        return size;
    }

    /**
     * Calculates the outermost points for a PolygonShape
     * @param s the shape
     * @return the maximum upper, lower, left, and right values; given by the vertices
     */
    private static MyVector4 shapeVals(PolygonShape s)
    {
        MyVector4 size = new MyVector4(); // top, right, bottom, left
        for(int i = 0; i < s.getVertexCount(); i++)
        {
            Vector2 probe = new Vector2();
            s.getVertex(i, probe);
            if(probe.x > size.b) // right
                size.b = probe.x;
            if(probe.x < size.d) // left
                size.d = probe.x;
            
            if(probe.y > size.a) // top
                size.a = probe.y;
            if(probe.y < size.c) // bottom
                size.c = probe.y;
        }
        return size;
    }

    /**
     * Calculates the outermost points for a ChainShape
     * @param s the shape
     * @return the maximum upper, lower, left, and right values; given by the vertices
     */
    private static MyVector4 shapeVals(ChainShape s)
    {
        MyVector4 size = new MyVector4(); // top, right, bottom, left
        for(int i = 0; i < s.getVertexCount(); i++)
        {
            Vector2 probe = new Vector2();
            s.getVertex(i, probe);
            if(probe.x > size.b) // right
                size.b = probe.x;
            if(probe.x < size.d) // left
                size.d = probe.x;
            
            if(probe.y > size.a) // top
                size.a = probe.y;
            if(probe.y < size.c) // bottom
                size.c = probe.y;
        }
        return size;
    }

    /**
     * Calculates the outermost points for an EdgeShape
     * @param s the shape
     * @return the maximum upper, lower, left, and right values; given by the vertices
     */
    private static MyVector4 shapeVals(EdgeShape s)
    {
        MyVector4 size = new MyVector4(); // top, right, bottom, left
        Vector2 probe = new Vector2();
        s.getVertex1(probe);
        if(probe.x > size.b) // right
            size.b = probe.x;
        if(probe.x < size.d) // left
            size.d = probe.x;
        
        if(probe.y > size.a) // top
            size.a = probe.y;
        if(probe.y < size.c) // bottom
            size.c = probe.y;

        s.getVertex2(probe);
        if(probe.x > size.b) // right
            size.b = probe.x;
        if(probe.x < size.d) // left
            size.d = probe.x;
        
        if(probe.y > size.a) // top
            size.a = probe.y;
        if(probe.y < size.c) // bottom
            size.c = probe.y;
        
        return size;
    }

    /**
     * Calculates the outermost points for a CircleShape
     * @param s the shape
     * @return the maximum upper, lower, left, and right values; given by radius and position
     */
    private static MyVector4 shapeVals(CircleShape s)
    {
        MyVector4 size = new MyVector4(); // top, right, bottom, left
        size.a = s.getPosition().y + s.getRadius(); // top
        size.b = s.getPosition().x + s.getRadius(); // right
        size.c = s.getPosition().y - s.getRadius(); // bottom
        size.d = s.getPosition().x - s.getRadius(); // left
        
        return size;
    }
    
    /**
     * using this just to store the variables easily
     */
    private static class MyVector4
    {
        public float a, b, c, d;
        
        public MyVector4()
        {
            this.a = 0;
            this.b = 0;
            this.c = 0;
            this.d = 0;
        }
        
        @SuppressWarnings("unused")
        public MyVector4(float a, float b, float c, float d)
        {
            this.a = a;
            this.b = b;
            this.c = c;
            this.d = d;
        }
        
        @SuppressWarnings("unused")
        public void set(float a, float b, float c, float d)
        {
            this.a = a;
            this.b = b;
            this.c = c;
            this.d = d;
        }
        
        public MyVector4 scale(float val)
        {
            this.a *= val;
            this.b *= val;
            this.c *= val;
            this.d *= val;
            
            return this;
        }
    }
}

【讨论】:

    【解决方案2】:

    我以前遇到过这个问题,这是对我有用的解决方案,您必须遍历所有灯具,然后开始获取每个灯具的 b2AABB 矩形并将它们组合在一起,然后获得组合 AABB 的宽度和高度

        b2AABB aabb;
        b2Transform t;
        t.SetIdentity();
        b2Fixture* fixture = nearBody->GetFixtureList();
        while (fixture != NULL) {
            const b2Shape *shape = fixture->GetShape();
            const int childCount = shape->GetChildCount();
            for (int child = 0; child < childCount; ++child) {
                b2AABB shapeAABB;
                shape->ComputeAABB(&shapeAABB, t, child);
                shapeAABB.lowerBound = shapeAABB.lowerBound;
                shapeAABB.upperBound = shapeAABB.upperBound;
                aabb.Combine(shapeAABB);
            }
            fixture = fixture->GetNext();
        }
    
        CCPoint lowerVertex = aabb.lowerBound;
        CCPoint heigherVertex = aabb.upperBound;
        bodyWidth = heigherVertex.x - lowerVertex.x;
        bodyHeight = heigherVertex.y - lowerVertex.y;
    

    【讨论】:

    • b2AABB aabb 必须用类似 aabb.lowerBound = b2Vec2(FLT_MAX,FLT_MAX); aabb.upperBound = b2Vec2(-FLT_MAX,-FLT_MAX);否则 aabb.Combine(shapeAABB) 可能会使用随机初始值。
    【解决方案3】:

    检查 b2World.cpp,有一些代码可以帮助你:

    void b2World::DrawDebugData() {
        ...
        for (b2Body* b = m_bodyList; b; b = b->GetNext()) {
            const b2Transform& xf = b->GetTransform();
            for (b2Fixture* f = b->GetFixtureList(); f; f = f->GetNext()) {
                ...
                DrawShape(f, xf, b2Color(0.5f, 0.5f, 0.3f));
            }
        }
        ...
    }
    
    void b2World::DrawShape(b2Fixture* fixture, const b2Transform& xf, const b2Color& color) {
        ...
        case b2Shape::e_polygon: {
                b2PolygonShape* poly = (b2PolygonShape*)fixture->GetShape();
                int32 vertexCount = poly->m_count;
                b2Vec2 vertices[b2_maxPolygonVertices];
                for (int32 i = 0; i < vertexCount; ++i) {
                    //they are polygen's vertices, you can use these to get the height / width
                    vertices[i] = b2Mul(xf, poly->m_vertices[i]);
                }
                m_debugDraw->DrawSolidPolygon(vertices, vertexCount, color);
            }
        ...
    }
    

    【讨论】:

      【解决方案4】:

      这是我在学习this libgdx 教程时想到的。

      float w2 = 0f
      float h2 = 0f
      b.body.fixtureList.each { Fixture fixture ->
          if(fixture) {
              if(fixture.shape.type == Shape.Type.Circle) {
                  w2 += fixture.shape.radius * 2
                  h2 += fixture.shape.radius * 2
              } else if(fixture.shape.type == Shape.Type.Polygon) {
                  PolygonShape shape = fixture.shape as PolygonShape
                  Vector2 vector = new Vector2()
      
                  def vectors = []
                  shape.vertexCount.times {
                      shape.getVertex(it, vector)
                      vectors.add(new Vector2(vector.x, vector.y))
                  }
      
                  vectors.sort {it.x}
                  w2 = (vectors.first().x).abs() + (vectors.last().x).abs()
      
                  vectors.sort {it.y}
                  h2 = (vectors.first().y).abs() + (vectors.last().y).abs()
              }
          }
      }
      

      【讨论】:

        【解决方案5】:

        嗯,我不太确定,但这似乎很复杂,因为一个 box2d 主体可以由多个 Fixtures 组成,每个 Fixtures 都有不同的形状。

        您只是在寻找边界框的宽度和高度吗?

        然后您可能必须遍历身体的夹具列表并评估其中的形状,查看形状的位置并计算边界框。不幸的是,这看起来不太舒服。

        【讨论】:

        • 哦,实际上我只有一个固定装置,那就是 PolygonShape,我已将其设置为 setAsBox。所以有什么想法???
        【解决方案6】:
        ((Sprite)body.getUserData()).getWidth();
        

        ((Sprite)body.getUserData()).getHeight();
        

        使用它.. 如果我猜对了,它应该会回答您的问题

        【讨论】:

          【解决方案7】:

          如果您只是将多边形形状用作盒子,为什么不创建一个包装类。并将宽度、高度和位置等相关信息存储在包装类变量中。

          【讨论】:

            【解决方案8】:

            (如果您在运行时更改主体大小(添加/删除固定装置),则在将主体大小更改为以下方法时可能需要进行一些修改,但它应该可以工作。)

            注意:我使用的是Java+jbox2d

            我能想到的最简单的方法是自己在对象中存储高度和宽度,就像在创建主体时一样

            float objectHeight;
            float objectWidth;
            

            当您创建身体(特别是形状)时。 只需将所有维度加在一起

            objectWidth = fixture1Shape.width + ...;
            objectHeight = fixture1Shape.height + ...;
            

            那么它只是在对象中制作自定义方法

            float getWidth(){
               return objectWidth;
            }
            
            float getHeight(){
               return objectHeight;
            }
            

            现在您可以获得对象主体的确切宽度和高度。 使用

            o1.getHeight();
            o1.getWidth();
            

            [考虑到 o1 是您找到对象的位置,例如 Object o1 = fixture.getUserData();Object o1=body.getUserData()]

            您可能需要创建所需类的新对象并将其转换为对象,然后再调用方法

            //consider your object class is Player
            Player p1 = (Player) o1;
            p1.getHeight();
            p1.getWidth();
            

            PS:如果您需要 Box2D 世界大小,只需使用您的缩放因子对其进行缩放。 或者更好的是在创建形状时将其作为缩放版本存储在 objectHeight,objectWidth 中

            【讨论】:

              猜你喜欢
              • 2019-12-26
              • 1970-01-01
              • 2011-11-10
              • 2023-04-09
              • 2011-07-12
              • 2014-05-01
              • 1970-01-01
              • 2019-05-26
              • 1970-01-01
              相关资源
              最近更新 更多