Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

Kontener struktur vector, usuwanie

Ostatnio zmodyfikowano 2017-01-02 21:10
Autor Wiadomość
sebox
Temat założony przez niniejszego użytkownika
Kontener struktur vector, usuwanie
» 2017-01-02 15:21:17
Zmagam się z dość, wydawało by się prostą sprawą. Mam vector w którym mieszczą się struktury bullet. I chciałbym móc zwyczajnie usunąć jeden z elementów kontenera.
C/C++
struct BULLET
{
    std::string name;
    sf::Sprite sprite;
    Vector2f coordinates;
};
C/C++
std::vector < BULLET > bullet;

Próbowałem standardowym sposobem czyli:
C/C++
bullet.erase( bullet.begin() + i );
ale dostaje komunikat:

Expression: vector subscript out of range
Próbowałem również tak:
C/C++
bullet.erase( std::remove( std::begin( bullet ), std::end( bullet ), i ), std::end( bullet ) );
ale miałem już błąd na poziomie kompilacji:

Error 10 error C2678: binary '==' : no operator found which takes a left-hand operand of type 'BULLET' (or there is no acceptable conversion)
P-155811
michal11
» 2017-01-02 15:49:05
Robisz to w pętli? Pokaż więcej kodu.

W pierwszym przypadku dostajesz wyjątek po pewnie nie uwzględniasz tego, że rozmiar vectora ci się zmniejsza. W drugim brakuje operatora do porównywania dla twojej struktury, funkcja nie wie jakie ma wybrać do usunięcia.
P-155814
sebox
Temat założony przez niniejszego użytkownika
» 2017-01-02 15:52:31
C/C++
for( int i = 0; i < bullet.size(); i++ )
{
}
Hmm, jeżeli chodzi o ten 1 sposób, to w jaki sposób mam to uwzględnić ?
P-155815
michal11
» 2017-01-02 16:08:24
Widzę, że dalej mam zgadywać co robisz i jak robisz, ok, z vectora można usuwać obiekty na przykład tak
C/C++
for( size_t i = 0; i < vec.size(); ++i )
{
    if( rand() % 2 )
    {
        vec.erese( vec.begin() + i );
        --i;
    }

można tez to zrobić tak

C/C++
for( auto it = vec.end() - 1; it != vec.begin(); )
{
    if( rand() % 2 )
    {
        it = vec.erase( it );
    }
    else
    {
        --it;
    }
}

albo tak
C/C++
vec.erase( std::remove_if( vec.begin(), vec.end(),[]( const YourStruct & s ) { return s.SomeProperty == Param::ToDestroy; } ), vec.end() );
P-155816
sebox
Temat założony przez niniejszego użytkownika
» 2017-01-02 16:19:56
C/C++
void Server::updateBullet()
{
    for( int i = 0; i < bullet.size(); i++ )
    {
        for( int j = 0; j < 50; j++ )
        {
            bullet[ i ].sprite.move( bullet[ i ].coordinates.x * 1, bullet[ i ].coordinates.y * 1 );
            for( int k = 0; k < players.size(); k++ )
            {
                FloatRect box( players[ k ].position.x, players[ k ].position.y, 135, 200 );
                FloatRect box2( bullet[ i ].sprite.getPosition().x, bullet[ i ].sprite.getPosition().y, 30, 11 );
                if( box.intersects( box2 ) )
                {
                    if( bullet[ i ].name != players[ k ].nick )
                    {
                        players[ k ].hp = players[ k ].hp - 10;
                        cout << "Gracz " << players[ k ].nick << " ma: " << players[ k ].hp << "hp" << endl;
                        bullet.erase( bullet.begin() + i );
                    }
                }
            }
        }
    }
}
Myślałem, że ten kod się nie przyda dlatego go nie wklejałem, ale faktycznie może i mam tu jakiś błąd. Generalnie przesuwam o 1 pixel pocisk i sprawdzam z każdym z graczy czy zachodzi kolizja, jeżeli tak to -10hp i tak z każdym pociskiem.
P-155817
michal11
» 2017-01-02 16:33:10
No to skorzystaj z 3 sposobu, dodaj pole do struktury czy pocisk został zniszczony czy nie i usuń wszystkie oznaczone na sam koniec, tak będzie najwydajniej. pro tip do kolizji możesz skorzystać z GetBoundingBox(), nie musisz go ręcznie wyliczać.

I jeszcze jakiś schematyczny kod
C/C++
struct Bullet
{
    float Damage;
    bool IsDestroyed;
   
    void OnCollision( Player & player )
    {
        player.ApplyDamage( Damage );
        IsDestroyed = true;
    }
};

std::vector < Bullet > Bullets;

for( Bullet & bullet: Bullets )
{
    for( Player & player: Players )
    {
        if( CheckCollisions( bullet, player ) )
        {
            bullet.OnCollision( player );
            player.OnCollision( bullet );
        }
    }
   
    Bullets.erase( std::remove_if( Bullets.begin(), Bullets.end(),[]( const Bullet & b ) { return b.IsDestroyed; } ), Bullets.end() );

jakoś tak mniej więcej bym to zrobił.
P-155818
mokrowski
» 2017-01-02 16:44:20
W vector jeśli naruszysz jego ciągłość usuwając element, następuje utrata aktualności wszelkich iteratorów oraz indeksów. Radzę skorzystać z rady @michal11 i na koniec wszystko usunąć z użyciem idiomu erase-remove.
Tu masz opis dlaczego to będzie efektywne i jak to zrobić: https://en.wikipedia.org/wiki​/Erase%E2%80%93remove_idiom
P-155819
sebox
Temat założony przez niniejszego użytkownika
» 2017-01-02 18:40:10
Wszystko działa, dzięki bardzo za pomoc, ale jak już jesteśmy przy temacie, to może powiecie mi, dlaczego np: w vectorze
std::vector < Vector2f > coordinates;
 działa mi bez zarzutu
coordinates.erase( coordinates.begin() + j );
a w vectorze struktur już trzeba kombinować z erase-remove ?
P-155823
« 1 » 2
  Strona 1 z 2 Następna strona