将多个精灵旋转为一个(大约相同的原点)

时间:2013-11-30 11:59:09

标签: java box2d libgdx sprite

我有一些形状为T形的精灵,我想在同一个原点围绕它们,在我的情况下box2D身体原点,像这样:

enter image description here

我的形状在矩阵中定义如下:

int array[][]= {{0,1,1,1,0},
                     {0,0,1,0,0},
                     {0,0,1,0,0},
                     {0,0,0,0,0},
                     {0,0,0,0,0}};

这就是我创建身体的方式:

public void setBody(int[][] blocks){
        BodyDef def = new BodyDef();
        def.type = BodyType.DynamicBody;
        def.position.set(new Vector2(0 * WORLD_TO_BOX, 0 * WORLD_TO_BOX));
        Body body = world.createBody(def);
        body.setTransform(130*WORLD_TO_BOX, 200*WORLD_TO_BOX, -90*MathUtils.degreesToRadians);
        for (int x = 0; x < 5; x++) { // HARDCODED 5
            for (int y = 0; y < 5; y++) { // HARDCODED 5
                if(blocks[x][y] == 1){
                    PolygonShape poly = new PolygonShape();
                    Vector2 v = new Vector2((x*size/BOX_TO_WORLD),(y*size/BOX_TO_WORLD));
                    poly.setAsBox(size/2 * WORLD_TO_BOX, size/2 * WORLD_TO_BOX, v, 0);
                    Sprite sprite = new Sprite(new Texture(Gdx.files.internal("data/block.png")));
                    sprite.setSize(size, size);
                    sprites.add(sprite);
                    orig.add(v);
                    body.createFixture(poly, 1);
                    poly.dispose();
                }
            }
        }
        this.body = body;
    }

这是我的渲染方法:

public void draw(SpriteBatch batch){
        for (int i = 0;i< this.body.getFixtureList().size;i++) {
            Vector2 pos = this.body.getFixtureList().get(i).getBody().getPosition();
            Sprite sprite = sprites.get(i);
            sprite.setOrigin(this.body.getWorldCenter().x,this.body.getWorldCenter().y);
            sprite.setPosition(pos.x*BOX_TO_WORLD+orig.get(i).x*32-16, pos.y*BOX_TO_WORLD+orig.get(i).y*32-16);
            sprite.setRotation(this.body.getAngle()*MathUtils.radiansToDegrees);
            sprite.draw(batch);
        }
    }

2 个答案:

答案 0 :(得分:2)

正如您在图表中的“正确”示例中所看到的,精灵的位置取决于您不考虑的身体角度。

b2Vec2 pos = ...; // center of the sprite relative to body (local coords)
float ang = ...;  // angle of the sprite relative to body (probably zero)

//need to rotate image local center by body angle
b2Rot rot( body->GetAngle() );
pos = b2Mul(rot, pos) + body->GetPosition();
ang += -body->GetAngle();

sprite.setRotation( ang * RADTODEG ); // RADTODEG = 57.295779513082320876f
sprite.setPosition( PTM * pos.x,  PTM * -pos.y);

在此之前,我也做过:

sf::FloatRect rect = sprite.getLocalBounds();
sprite.setOrigin( 0.5 * rect.width, 0.5 * rect.height );

答案 1 :(得分:1)

最简单的方法是创建所有灯具,记住它们与身体的相对位置。为每个灯具创建一个精灵,并在每次物理更新时使用body-&gt; GetWorldPosition(灯具中心)更新它们。最后,精灵的旋转与身体的旋转相同(除了它是角度的负值)。

例如,要创建正文:

void MainScene::CreateBody()
{
   Vec2 position(0,0);

   // Create the body.
   b2BodyDef bodyDef;
   bodyDef.position = position;
   bodyDef.type = b2_dynamicBody;
   _body = _world->CreateBody(&bodyDef);
   assert(_body != NULL);

   // Now attach fixtures to the body.
   FixtureDef fixtureDef;
   PolygonShape polyShape;
   vector<Vec2> vertices;

   const float32 VERT_SCALE = .5;
   fixtureDef.shape = &polyShape;
   fixtureDef.density = 1.0;
   fixtureDef.friction = 1.0;
   fixtureDef.isSensor = false;

   // Main Box
   vertices.clear();
   vertices.push_back(Vec2(1*VERT_SCALE,1*VERT_SCALE));
   vertices.push_back(Vec2(-1*VERT_SCALE,1*VERT_SCALE));
   vertices.push_back(Vec2(-1*VERT_SCALE,-1*VERT_SCALE));
   vertices.push_back(Vec2(1*VERT_SCALE,-1*VERT_SCALE));
   polyShape.Set(&vertices[0],vertices.size());
   _body->CreateFixture(&fixtureDef);
   _fixturePositions.push_back(CalculateAverage(vertices));

   // Down one
   vertices.clear();
   vertices.push_back(Vec2(1*VERT_SCALE,-1*VERT_SCALE));
   vertices.push_back(Vec2(-1*VERT_SCALE,-1*VERT_SCALE));
   vertices.push_back(Vec2(-1*VERT_SCALE,-3*VERT_SCALE));
   vertices.push_back(Vec2(1*VERT_SCALE,-3*VERT_SCALE));
   polyShape.Set(&vertices[0],vertices.size());
   _body->CreateFixture(&fixtureDef);
   _fixturePositions.push_back(CalculateAverage(vertices));

   // Up One
   vertices.clear();
   vertices.push_back(Vec2(1*VERT_SCALE,3*VERT_SCALE));
   vertices.push_back(Vec2(-1*VERT_SCALE,3*VERT_SCALE));
   vertices.push_back(Vec2(-1*VERT_SCALE,1*VERT_SCALE));
   vertices.push_back(Vec2(1*VERT_SCALE,1*VERT_SCALE));
   polyShape.Set(&vertices[0],vertices.size());
   _body->CreateFixture(&fixtureDef);
   _fixturePositions.push_back(CalculateAverage(vertices));

   // T Left Top
   vertices.clear();
   vertices.push_back(Vec2(-1*VERT_SCALE,3*VERT_SCALE));
   vertices.push_back(Vec2(-3*VERT_SCALE,3*VERT_SCALE));
   vertices.push_back(Vec2(-3*VERT_SCALE,1*VERT_SCALE));
   vertices.push_back(Vec2(-1*VERT_SCALE,1*VERT_SCALE));
   polyShape.Set(&vertices[0],vertices.size());
   _body->CreateFixture(&fixtureDef);
   _fixturePositions.push_back(CalculateAverage(vertices));

   // T Right Top
   vertices.clear();
   vertices.push_back(Vec2(3*VERT_SCALE,3*VERT_SCALE));
   vertices.push_back(Vec2(1*VERT_SCALE,3*VERT_SCALE));
   vertices.push_back(Vec2(1*VERT_SCALE,1*VERT_SCALE));
   vertices.push_back(Vec2(3*VERT_SCALE,1*VERT_SCALE));
   polyShape.Set(&vertices[0],vertices.size());
   _body->CreateFixture(&fixtureDef);
   _fixturePositions.push_back(CalculateAverage(vertices));

   _body->SetAngularVelocity(M_PI/8);
}

注意 CalculateAverage(...)函数只是找到顶点的平均值。对于正方形,它将是中心。我可以手动设置中心,但我不想做一个简单的数学oopsie所以我写了一个快速的函数来处理它。

然后创建精灵:

void MainScene::CreateSprites()
{
   Viewport& vp = Viewport::Instance();

   for(int idx = 0; idx < _fixturePositions.size(); idx++)
   {
      CCSprite* sprite = CCSprite::create("arrow.png");
       sprite->setScale(1.0*vp.GetPTMRatio()/128);
      _fixtureSprites.push_back(sprite);
      addChild(sprite);
   }
}

然后在每次物理更新后更新精灵:

void MainScene::UpdateSprites()
{
   for(int idx = 0; idx < _fixturePositions.size(); idx++)
   {
      CCPoint spritePosition = Viewport::Instance().Convert(_body->GetWorldPoint(_fixturePositions[idx]));
      _fixtureSprites[idx]->setPosition(spritePosition);
      float32 bodyAngle = _body->GetAngle();
      bodyAngle = MathUtilities::AdjustAngle(bodyAngle);
      _fixtureSprites[idx]->setRotation(-CC_RADIANS_TO_DEGREES(bodyAngle));
   }
}

注意视口有一个转换(..)函数,它接受Vec2并将其转换为屏幕上的像素位置。 AdjustAngle只是将角度放回[-pi,pi]的范围内。其余的都应该相当简单,但随意问。

我已经在goc hub here上发布了针对Cocos2d-x(C ++)的解决方案。查看MainScene.cpp中的代码。

这就是我的模拟器上的样子:

enter image description here

(希望)最后的注释:这里的实现使用“视口”类来映射Box2d世界(米)和屏幕坐标(像素)。一个非常有用的结果是,您可以根据希望实体的大小(以米为单位)和图形的大小(以像素为单位)自动调整精灵的大小。这是我经常使用的更多组件的一部分。您可以找到有关他们的更多信息in this post

这有用吗?