【问题标题】:objects' variables get reset in vector (casting from void*)对象的变量在向量中重置(从 void* 转换)
【发布时间】:2014-09-16 01:27:58
【问题描述】:

一些背景:

我正在制作的游戏中使用 Box2D。它有一种将“用户数据”存储到 Box2D 对象的方法。此“用户数据”采用 void*,因此可用于存储用户定义的数据。现在,当 Box2D 发生碰撞时,您可以使用此“用户数据”来识别哪些对象发生了碰撞。然后您可以将数据转换为一个类,并访问该类的函数或变量(以及该类的特定实例,如果您已将“用户数据”设置为对该实例的引用)。我有两组“用户数据”,一组是对类实例的引用,另一组是对结构的引用,因此我可以检查对象的类型。

这适用于不在向量中的对象。我已经对此进行了测试,我可以访问类实例的函数和变量(并修改它们)而无需重置它们。 但是当我通过从 void* 强制转换访问我的 std::vector 对象时,我修改的变量会立即重置。

相关代码:

我这样设置“用户数据”:

tile->SetUserData(static_cast<Entity*>(this));
ball->SetUserData(static_cast<Entity*>(this));

bUserData* bud = new bUserData;
bud->entityType = BALL;
ballFixture.userData = bud;

bUserData* bud = new bUserData;
bud->entityType = TILE;
tileFixture.userData = bud;

MyContactListener 类跟踪碰撞开始和结束的时间,这也是从 void* 到 foo* 的转换发生的地方:

MyContactListener.cpp

std::vector<Tile> solidTiles;
Ball ball;

// Called when two objects begin to touch.
void MyContactListener::BeginContact(b2Contact* contact) {

    // Cast from void* to a struct, from which I can check the object type.
    bUserData* budA = (bUserData*)contact->GetFixtureA()->GetUserData();
    bUserData* budB = (bUserData*)contact->GetFixtureB()->GetUserData();

    // Cast from void* UserData to Entity* (super-class of all the entities).
    Entity* entityA = (Entity*)contact->GetFixtureA()->GetBody()->GetUserData();
    Entity* entityB = (Entity*)contact->GetFixtureB()->GetBody()->GetUserData();

    if((budA->entityType == TILE && budB->entityType == BALL)) {
        Tile* tile = (Tile*)entityA; // Tiles are in std::vector<Tile>
        Ball* ball = (Ball*)entityB; // Only one ball instance exists

        // Modifying a tile instance variable, gets reset to the original value immediately!
        tile->flaggedToErase = true;
        // This works fine! 
        ball->setColorToBlue = true;
    }
}

问题:如何使向量中的 tile 实例的变量不被重置为原始值?

【问题讨论】:

  • 正在重置或根本没有改变?
  • 当您将用户数据指针设置为Tile* 时,您是否正在对Entity* 进行显式转换?否则,您的 Entity* 演员表是未定义的行为。您应该从Tile* 转换为Entity*,然后依赖隐式void* 转换,然后从void* 转换为Entity* 即可。
  • Tugrul:它们确实发生了变化,我在设置后尝试打印磁贴的变量,它表明磁贴->flaggedToErase 为真。
  • 简单:不,我只用 SetUserData(this) 设置用户数据指针。
  • 它应该是TileTile* 的向量吗?猜测一下,我怀疑这个问题是由于使用了存储对象副本的vector&lt;Tile&gt;,而不是vector&lt;Tile*&gt;,如果您以后想更改存储的对象,则需要这样做。

标签: c++ vector box2d reset void-pointers


【解决方案1】:

它应该是TileTile* 的向量吗?猜测一下,我怀疑这个问题是由于使用了存储对象副本的vector&lt;Tile&gt; 而不是存储对象指针的vector&lt;Tile*&gt;

比较一下:

std::vector< Tile > tiles;

Tile t;
t.foo = 123;
tiles.push_back( t ); // a copy of t is put into the vector

t.foo = 456; // changes t, but not the copy in the vector

Tile t2 = tiles[0]; // makes yet another copy (t2.foo == 123)

...用这个:

std::vector< Tile* > tiles;

Tile* t = new Tile;
t->foo = 123;
tiles.push_back( t ); // a pointer is put into the vector

t->foo = 456; // also changes in the vector because it's the same thing

Tile* t2 = tiles[0]; // still the same thing (t2->foo == 456)

如果你想拥有一个对象向量(不是指针)并在向量内改变它们,你可以这样做:

std::vector< Tile > tiles;
Tile& t = tiles[0]; // note the ampersand, accesses by reference
t.foo = 456; // changes inside the vector

// I think you can also do this
tiles[0].foo = 456;

但是,要做到这一点,您需要使向量本身可用,并且您需要知道要更改的元素在哪个位置。对于您的情况,您不知道元素在向量中的哪个位置,因此使用vector&lt;Tile*&gt; 是最简单的解决方案。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-06-02
    • 1970-01-01
    • 2015-07-09
    • 2022-12-16
    • 1970-01-01
    • 1970-01-01
    • 2016-04-20
    相关资源
    最近更新 更多