我有一些形状为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));
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);
}
}
答案 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中的代码。
这就是我的模拟器上的样子:
(希望)最后的注释:这里的实现使用“视口”类来映射Box2d世界(米)和屏幕坐标(像素)。一个非常有用的结果是,您可以根据希望实体的大小(以米为单位)和图形的大小(以像素为单位)自动调整精灵的大小。这是我经常使用的更多组件的一部分。您可以找到有关他们的更多信息in this post。
这有用吗?