将多个精灵旋转为一个(大约相同的原点) [英] Rotating multiple sprites as one ( around same origin )

查看:127
本文介绍了将多个精灵旋转为一个(大约相同的原点)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些形状为T形的精灵,我想围绕相同的原点进行训练,在我的情况下box2D身体原点,如下所示:





我的形状在矩阵中定义这个:

  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));
身体= 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(精灵);
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);
}
}


解决方案

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



例如,要创建身体:

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

//创建正文。
b2BodyDef bodyDef;
bodyDef.position = position;
bodyDef.type = b2_dynamicBody;
_body = _world-> CreateBody(& bodyDef);
断言(_body!= NULL);

//现在将固定装置贴在身上。
FixtureDef fixtureDef;
PolygonShape polyShape;
vector< Vec2>顶点;

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

//主盒
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));

//下来一个
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 $
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右上$
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所以我写了一个快速的函数来处理它。



然后创建sprite:

  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);
}
}

然后在每次物理更新后更新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));
}
}

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



我在git hub上发布了一个解决方案。



这有用吗?


I have array of sprites forming T shape, and I want to ratate them around the same origin, in my case box2D body origin, like this:

my shape is defined in matrix like this:

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}};

this is how I create the body:

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;
    }

this is my render method:

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);
        }
    }

解决方案

The easiest way to do this is to create all the fixtures, remembering what their relative position is to the body. Create a sprite for each fixture and update them using the body->GetWorldPosition(fixture center) each time the physics updates. Finally, the rotation of the sprites is the same as the rotation of the body (excepting it is the negative of the angle).

For example, to create the body:

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);
}

NOTE The CalculateAverage(...) function just finds the average of the vertices. For squares, it will be the center. I could manually set the centers, but I didn't want to make a simple math oopsie so I wrote a quick function to handle it.

Then create the sprites:

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);
   }
}

Then update the sprites after each physics update:

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));
   }
}

NOTE The viewport has a function Convert(..) that takes a Vec2 and converts it to a pixel position on the screen. AdjustAngle just puts the angle back in the range of [-pi,pi). All the rest should be fairly straightforward, but feel free to ask.

I have posted a solution on git hub here for Cocos2d-x (C++). Check out the code in MainScene.cpp.

And this is what it looks like on my simulator:

(Hopefully) Final Note: The implementation here uses a "Viewport" class to map between the Box2d world (meters) and the screen coordinates (pixels). One very useful consequence of this is that you can automatically adjust the sizes of sprites based on the size you want the bodies to be in meters and the size of the graphic in pixels. This is part of a larger set of components that I often use. You can find more information about them in this post.

Was this helpful?

这篇关于将多个精灵旋转为一个(大约相同的原点)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆