0

I have created a game which uses a color coded image to create different bodies/fixtures. So for example if the pixel is green it will get stored into an array as 7 and then the program will create a body called enemy. If there are 10 green pixels, 10 enemies will be created:

            else if (array[w][h]==7)
            {
                b2BodyDef Enemy_BodyDef;
                Enemy_BodyDef.type = b2_kinematicBody;
                Enemy_BodyDef.position.Set(x,y);
                m_enemyBody = m_world->CreateBody(&Enemy_BodyDef);
                m_enemyBody->SetAngularVelocity(0.0);
                m_enemyBody->SetAngularDamping(0.3f);
                m_enemyBody->SetLinearDamping(5.0f);
                m_enemyBody->SetFixedRotation(true);
                b2PolygonShape Enemy_dynamicBox;
                Enemy_dynamicBox.SetAsBox(2.5f, 2.5f);
                b2FixtureDef Enemy_fixtureDef;
                Enemy_fixtureDef.shape = &Enemy_dynamicBox;
                Enemy_fixtureDef.density = 1.0f;
                Enemy_fixtureDef.friction = 0.1f;
                Enemy_fixtureDef.restitution=.0f;
                m_enemyFixture=m_enemyBody->CreateFixture(&Enemy_fixtureDef);
                enemyBody a;
                m_enemybodies.push_back(a);

            }

within render:

       ngl::ShaderLib *shader9=ngl::ShaderLib::instance();
(*shader9)["nglDiffuseShader"]->use();

for(unsigned int i=0; i<m_enemybodies.size(); ++i)
{
    m_enemybodies[i].m_enemy_position.m_x = m_enemyBody->GetPosition().x;
    m_enemybodies[i].m_enemy_position.m_y = m_enemyBody->GetPosition().y;
    m_enemybodies[i].m_enemy_dimention.set(5.0f,5.0f);

    m_transform.reset();
    {
        shader9->setShaderParam4f("Colour",1.0f,0.0f,0.0f,1.0f);
        m_transform.setScale(m_enemybodies[i].m_enemy_dimention.m_x,m_enemybodies[i].m_enemy_dimention.m_y,0.1);
        m_transform.setPosition(m_enemybodies[i].m_enemy_position.m_x,m_enemybodies[i].m_enemy_position.m_y,0.0);
        loadMatricesToShader();
        prim->draw("cube");
    }
}

The b2Fixtures are being placed in the correct location however ONLY the last one is being rendered. this is also true for when I try to set the linear velocity of them, only the last one in the array is moved and rendered.

Using the fact that they are in a Vector, how can I iterate through and get them to render and move?

Edit:

    enemyBody a;
    m_enemybodies.push_back(a);

this refers to a struct that I created for the placement and rendering of the bodies:

        typedef struct
{
    ngl::Vec2 m_enemy_position;
    ngl::Vec2 m_enemy_dimention;
 }enemyBody;
MichaelN
  • 1
  • 1

1 Answers1

1

There are two things I see which may cause issues. First, and most importantly, is the apparent use of pointers to local/temporary variables:

b2BodyDef Enemy_BodyDef;
...
m_enemyBody = m_world->CreateBody(&Enemy_BodyDef);

b2PolygonShape Enemy_dynamicBox;
...
Enemy_fixtureDef.shape = &Enemy_dynamicBox;

b2FixtureDef Enemy_fixtureDef;
...
m_enemyFixture=m_enemyBody->CreateFixture(&Enemy_fixtureDef);

After you leave this function/method these local variables no longer exist and any pointers to them are invalid. Trying to access a pointer to these local variables at this point will result in undefined behaviour. If you really need to create multiple objects with references to each other you'll need to use dynamic memory:

b2PolygonShape* pEnemy_dynamicBox = new b2PolygonShape;
Enemy_fixtureDef.shape = Enemy_dynamicBox;

Although you will need to remember to delete allocated memory. A more idiomatic C++ solution would use std::shared_ptr<>.

Another issue may be the last two lines:

enemyBody a;
m_enemybodies.push_back(a);

This seems to just push a new, uninitialized/setup enemy body to the vector. What happened to m_enemyBody that you just setup in the previous lines? Did you mean to do something like:

m_enemybodies.push_back(*m_enemyBody);

instead?

Update

Looking more closely at your rendering loop it is obvious why you're only getting one body being displayed. This code:

m_enemybodies[i].m_enemy_position.m_x = m_enemyBody->GetPosition().x;
m_enemybodies[i].m_enemy_position.m_y = m_enemyBody->GetPosition().y;
m_enemybodies[i].m_enemy_dimention.set(5.0f,5.0f);

simply sets each body in the vector to the same exact coordinates and dimensions. This, along with your confusion of pushing an empty enemyBody into the vector, is the cause of your problems.

To fix it change one line in your creation function(not including the fixes of using temporary variable pointers):

 m_enemybodies.push_back(*m_enemyBody);

and in your rendering loop simply do:

for(unsigned int i=0; i<m_enemybodies.size(); ++i)
{
    m_transform.reset();
    shader9->setShaderParam4f("Colour",1.0f,0.0f,0.0f,1.0f);
    m_transform.setScale(m_enemybodies[i].m_enemy_dimention.m_x,m_enemybodies[i].m_enemy_dimention.m_y,0.1);
    m_transform.setPosition(m_enemybodies[i].m_enemy_position.m_x,m_enemybodies[i].m_enemy_position.m_y,0.0);
    loadMatricesToShader();
    prim->draw("cube");
}

Note that if you are using a C++11 compatible compiler this loop can be more simply expressed like:

for (auto & body: m_enemybodies) {
    ...
    m_transform.setScale(body.m_enemy_dimention.m_x, body.m_enemy_dimention.m_y, 0.1);
    m_transform.setPosition(body.m_enemy_position.m_x, body.m_enemy_position.m_y, 0.0);
    ...
}
uesp
  • 6,194
  • 20
  • 15