Унаследованные переменные не читаются правильно при использовании побитовых сравнений - PullRequest
0 голосов
/ 30 марта 2010

У меня есть несколько классов, настроенных для игры, с XMapObject в качестве основы и XEntity, XEnviron и XItem, унаследовавшими его.

MapObjects имеет несколько флагов, одним из которых является MAPOBJECT_SOLID. Моя проблема в том, что XEntity является единственным классом, который правильно определяет MAPOBJECT_SOLID. Оба предмета являются окружающей средой, игра всегда считается твердой, независимо от состояния флага. Важно то, что Environs и Item почти никогда не должны быть прочными.

Каждый класс имеет очень простой предварительный конструктор, просто инициализирующий все переменные нулем или NULL. На этапе CreateX () объекты связываются с картой и устанавливаются в связанный связанный список.

И XItem, и XEnviron немного небрежны. Они оба новые, и в середине или в моих попытках отладки.

Вот примеры примеров кода:

XMapObject:

#define MAPOBJECT_ACTIVE 1
#define MAPOBJECT_RENDER 2
#define MAPOBJECT_SOLID 4

class XMapObject : public XObject
{
    public:
    Uint8 MapObjectType,Location[2],MapObjectFlags;

    XMapObject *NextMapObject,*PrevMapObject;

    XMapObject();

    void CreateMapObject(Uint8 MapObjectType);
    void SpawnMapObject(Uint8 MapObjectLocation[2]);
    void RemoveMapObject();
    void DeleteMapObject();

    void MapObjectSetLocation(Uint8 Y,Uint8 X);
    void MapObjectMapLink();
    void MapObjectMapUnlink();
};

XMapObject::XMapObject()
{
    MapObjectType = 0;
    Location[0] = 0;
    Location[1] = 1;
    NextMapObject = NULL;
    PrevMapObject = NULL;
}

void XMapObject::CreateMapObject(Uint8 Type)
{
    MapObjectType = Type;
}

void XMapObject::SpawnMapObject(Uint8 MapObjectLocation[2])
{
    if(!(MapObjectFlags & MAPOBJECT_ACTIVE)) { MapObjectFlags += MAPOBJECT_ACTIVE; }

    Location[0] = MapObjectLocation[0];
    Location[1] = MapObjectLocation[1];

    MapObjectMapLink();
}

XEntity:

XEntity *StartEntity = NULL,*EndEntity = NULL;

class XEntity : public XMapObject
{
    public:
    Uint8 Health,EntityFlags;
    float Speed,Time;
    XEntity *NextEntity,*PrevEntity;
    XItem *IventoryList;

    XEntity();

    void CreateEntity(Uint8 EntityType,Uint8 EntityLocation[2]);
    void DeleteEntity();

    void EntityLink();
    void EntityUnlink();

    Uint8 MoveEntity(Uint8 YOffset,Uint8 XOffset);
};

XEntity::XEntity()
{
    Health = 0;
    Speed = 0;
    Time = 1.0;
    EntityFlags = 0;
    NextEntity = NULL;
    PrevEntity = NULL;
    IventoryList = NULL;
}

void XEntity::CreateEntity(Uint8 EntityType,Uint8 EntityLocation[2])
{
    CreateMapObject(EntityType);
    SpawnMapObject(EntityLocation);

    if(!(MapObjectFlags & MAPOBJECT_SOLID) { MapObjectFlags += MAPOBJECT_SOLID; }
    EntityFlags = ENTITY_CLIPPING;
    Time = 1.0;
    Speed = 1.0;

    EntityLink();
}

void XEntity::EntityLink()
{
    if(StartEntity == NULL)
    {
        StartEntity = this;
        PrevEntity = NULL;
        NextEntity = NULL;
    }
    else
    {
        EndEntity->NextEntity = this;
    }

    EndEntity = this;   
}

XEnviron:

class XEnviron : public XMapObject
{
    public:
    Uint8 Effect,TimeOut;

    void CreateEnviron(Uint8 Type,Uint8 Y,Uint8 X,Uint8 TimeOut);
};

void XEnviron::CreateEnviron(Uint8 EnvironType,Uint8 Y,Uint8 X,Uint8 TimeOut)
{
    CreateMapObject(EnvironType);

    Location[0] = Y;
    Location[1] = X;

    SpawnMapObject(Location);

    XTile *Tile = GetTile(Y,X);
    Tile->Environ = this;

    MapObjectFlags = MAPOBJECT_ACTIVE + MAPOBJECT_SOLID;
    printf("%i\n",MapObjectFlags);
}

XItem:

class XItem : public XMapObject
{
    public:
    void CreateItem(Uint8 Type,Uint8 Y,Uint8 X);
};

void XItem::CreateItem(Uint8 Type,Uint8 Y,Uint8 X)
{
    CreateMapObject(Type);

    Location[0] = Y;
    Location[1] = X;

    SpawnMapObject(Location);
}

И, наконец, код перемещения сущности. Только сущности способны двигаться сами.

Uint8 XEntity::MoveEntity(Uint8 YOffset,Uint8 XOffset)
{
    Uint8 
      NewY = Location[0] + YOffset,
      NewX = Location[1] + XOffset;

    if((NewY >= 0 && NewY < MAPY) && (NewX >= 0 && NewX < MAPX))
    {
        XTile *Tile = GetTile(NewY,NewX);

        if(Tile->MapList != NULL)
        {
            XMapObject *MapObject = Tile->MapList;

            while(MapObject != NULL)
            {
                if(MapObject->MapObjectFlags & MAPOBJECT_SOLID)
                {
                    printf("solid\n");
                    return 0;
                }

                MapObject = MapObject->NextMapObject;
            }
        }

        if(Tile->Flags & TILE_SOLID && EntityFlags & ENTITY_CLIPPING)
        {
            return 0;
        }

        this->MapObjectSetLocation(NewY,NewX);

        return 1;
    }

    return 0;
}

Что странно, так это то, что побитовый оператор всегда возвращает true, когда MapObject является Environ или Item, но он работает правильно для Entities. Для отладки я использую printf «Solid», а также printf, содержащий значение флага для Environs и Items.

Любая помощь очень ценится, так как это серьезная ошибка для маленькой игры, над которой я работаю. Я также очень новичок в объектно-ориентированном программировании, любые советы, предложения и / или критика также приветствуются.

Ответы [ 3 ]

1 голос
/ 30 марта 2010

Ваша проблема в том, что вы никогда не инициализируете MapObjectFlags ни в каких классах, кроме XEnviron, поэтому в качестве базового типа он будет иметь неопределенное значение в XItem, XEntity и других производных XMapObject объекты. Я полагаю, что как член XMapObject вы явно инициализируете его известным значением.

Как правило, обычно рекомендуется убедиться, что все члены базового типа явно инициализируются в списке инициализаторов каждого определяемого вами конструктора.

, например

XMapObject()
    : MapObjectFlags(0)
    , // ... other initializers
{
    // Other initializations
}
0 голосов
/ 01 апреля 2010

Я выяснил проблему ранее сегодня - это не имело никакого отношения к ОО-программированию, наследованию или побитам; это была простая ошибка области видимости.

Проблема заключалась в том, что во время моего быстрого теста, чтобы получить Environ в игре, я объявил новую переменную внутри последовательности переключателей управления, поэтому при следующем использовании любого элемента управления Environ будет действовать непредсказуемым образом.

switch(Event.key.keysym.sym)
{
    ...
    case SDLK_c: { XEnviron Environ; Environ.InitEnviron(...); }
    ...
}
0 голосов
/ 30 марта 2010

Вы не можете (юридически) вызывать XEntity :: MoveEntity для MapObject или Environ, потому что у них нет такого метода. Если вы используете static_cast для изменения указателя объекта на XEntity, чтобы вы могли вызывать MoveEntity для него, то у вас действительно нет никаких гарантий относительно того, как будет работать битовая операция. В некоторых реализациях может показаться, что в MoveEntity все работает, но на самом деле происходит интерпретация памяти другого объекта как XEntity. Когда он пытается получить доступ к смещению, в котором он считает, что MapObjectFlags существует, на самом деле его там нет, и этот бит всегда имеет значение 1.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...