• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Tworzenie obiektów tablicy vector spowalnia znacząco program.

Object Storage Arubacloud
0 głosów
452 wizyt
pytanie zadane 13 maja 2017 w C i C++ przez neos Początkujący (320 p.)
edycja 13 maja 2017 przez neos

Witam, piszę grę RPG w SFMLu. Chcąc stworzyć lokację postanowiłem stworzyć obiekty sciany (kwadraty) Wall za pomocą fora, który przypisuje obiektowy współrzędne i następnie push_backiem "stwarza" go. Okazaju się że takim sposobem, tworząc około 40 obiektów klasy Wall program uruchamia się o około 2s dłużej. Przy większych ilościach czas uruchamiania potrafi sięgać do 7-8s. Znalazłem na internecie metodę vector<type>.reserve(int) dzieki ktorej program trochę przyśpieszył ( z 8s zrobiło się około 2s). Czy jest jakiś sposób by to obejść? Czy moja metoda jest wgl dobra czy powinienem ją zmienić, jak tak to na jaką? Pozdrawiam.

 

 

 

class Engine
{    
public:
    Engine(sf::RenderWindow &win);
    //Create Player object
    Player player;
    //Create Bullet object
    Bullet bullet;
    //Create Bullet vector
    vector<Bullet>::const_iterator iter;
    vector<Bullet> BulletArray;

    

    //Create Enemy object
    Enemy enemy;
    //Create Enemy vector
    vector<Enemy>::const_iterator iter2;
    vector<Enemy> EnemyArray;
    //Create displayText object
    displayText display_text;
    //Create displayText vector
    vector<displayText>::const_iterator iter3;
    vector<displayText> displayTextArray;
    //Create Coin object
     Coin coin;
    //Create Coin vector
    vector<Coin>::const_iterator iter4;
    vector<Coin> CoinArray;
  //Create Wall object
    Wall wall;
    //Create Wall vector
    vector<Wall>::const_iterator iter5;
    vector<Wall> WallArray;
    //Create Box object
    Box box;
    //Create Box vector
    vector<Box>::const_iterator iterBox;
    vector<Box> BoxArray;
};

void Engine::createRoom (int roomSize, int roomStartPositionX, int roomStartPositionY, int doorPosition, int numberEnemies)
{
    wall.sprite.setTextureRect(sf::IntRect(0,50,50,50));
    //create box
    box.rect.setPosition(roomStartPositionX+80, roomStartPositionY+100);
    BoxArray.push_back(box);
    box.rect.setPosition(roomStartPositionX+160, roomStartPositionY+200);
    BoxArray.push_back(box);
    //create enemies
    for(int i=0; i<numberEnemies; i++)
    {
    enemy.rect.setPosition(roomStartPositionX+roomSize*50/2+generateRandom(400),roomStartPositionY+roomSize*50/2+generateRandom(400));
    EnemyArray.push_back(enemy);
    }
    //horizontal wall
    int counterW = 0;
    while(counterW<roomSize)
    {
        wall.rect.setPosition(50*counterW + roomStartPositionX, roomStartPositionY);
        WallArray.push_back(wall);
        counterW++;
    }
    //horizontal wall
    counterW = 0;
    while(counterW<roomSize)
    {
        wall.rect.setPosition(50*counterW + roomStartPositionX, 50*roomSize+roomStartPositionY);
        WallArray.push_back(wall);
        counterW++;
    }
    //vertical wall
    counterW=0;
    while(counterW<roomSize)
    {
        wall.rect.setPosition(roomStartPositionX, 50*counterW + roomStartPositionY);
        WallArray.push_back(wall);
        counterW++;
    }
    //vertical wall
    counterW=0;
    while(counterW<roomSize+1)
    {
        if(counterW!=doorPosition-1 && counterW!=doorPosition && counterW!=doorPosition+1)
        {
        wall.rect.setPosition(50*roomSize+roomStartPositionX, 50*counterW + roomStartPositionY);
        WallArray.push_back(wall);
        }
        counterW++;
    }
}

 

1
komentarz 13 maja 2017 przez 10kw10 Pasjonat (22,880 p.)
Daj ekran ladowania na ten czas.
komentarz 13 maja 2017 przez neos Początkujący (320 p.)
w jaki sposób? jakiś obrazek z timerem?
1
komentarz 14 maja 2017 przez d0n Mądrala (6,440 p.)
Funkcja push_back uzywana n-razy na jednym vectorze, ma zaamortyzowana zlozonosc liniowa, więc już powinna być bardzo szybka, metoda reserve ( albo resize ) tylko przyspieszy sprawe, ale ogolnie jesli nie potrzebujesz tablicy o nieznanej w trakcie wykonywania programu wielkosci, albo wiesz jaka jest "gorna granica" na wielkosc tablicy, to mozesz uzyc wbudowanej w C++ tablicy ( to chyba najszybsze rozwiazanie ).

Wiem, ze to co napisalem praktycznie nie pomaga, dlatego wrzucam w komentarz
1
komentarz 14 maja 2017 przez criss Mędrzec (172,590 p.)

 metoda reserve ( albo resize ) tylko przyspieszy sprawe

 Zdecydowanie preferowana reserve. Resize faktycznie rozszerza vector o nowe elementy (nowe obiekty są tworzone), a reserve tylko alokuje pamięć na której obiekty dopiero będą mogły powstać. (oczywiście mówię o tej sytuacji, nie ogólnie)

 (...) to mozesz uzyc wbudowanej w C++ tablicy ( to chyba najszybsze rozwiazanie ).

Raczej bez większego znaczenia jeśli znamy ilość elementów i przed push_back-ami zarezerwujemy odpowiedną ilość pamięci (.reserve). Możliwe nawet, że jeśli mają to być obiekty utworzone nie-domyślnym konstruktorem, to lepiej sprawdziłby się vector. 

1
komentarz 14 maja 2017 przez Ehlert Ekspert (212,670 p.)
Nie to, że hejtuję, ale z tą implementacją dotarcie do trzeciego questa może okazać się nie lada wyzwaniem.
komentarz 14 maja 2017 przez neos Początkujący (320 p.)
Mógłbyś jaśniej? To moja pierwsza taka gra (wcześniej napisałem platformówkę w SDL2 i C) i bardzo możliwe że niektóre rzeczy robię źle, ale wszelkie opinie przyjmuję jako porady :)
komentarz 14 maja 2017 przez neos Początkujący (320 p.)

A czy takie coś zaraz przed wywołaniem funkcji tworzenia obiektów typu Wall  i innych 

    WallArray.reserve(1000);
    BoxArray.reserve(500);
    CoinArray.reserve(500);
    displayTextArray.reserve(500);
    EnemyArray.reserve(500);
    BulletArray.reserve(500);

jest sensowne? Dzięki temu uruchamia mi się już w około 1.4s ale skąd dalej to późnienie? :/ Zaznaczam że występuje ono tylko i wyłącznie gdy wywołuję funkcje tworzenia ścian.

1
komentarz 14 maja 2017 przez Milesq Nałogowiec (32,020 p.)
poczytaj o wątkach. W sfml jest to bardzo proste.

 

 #include <SFML/System.hpp> #include <iostream> void func() { // ta funkcja uruchomi się przy uruchomieniu thread.launch() for (int i = 0; i < 10; ++i) std::cout << "I'm thread number one" << std::endl; } int main() { // przypisanie func() do wątku sf::Thread thread(&func); // uruchomienie wątku thread.launch(); // główny wątek kontynuuje swoje działanie for (int i = 0; i < 10; ++i) std::cout << "I'm the main thread" << std::endl; return 0; }
komentarz 14 maja 2017 przez neos Początkujący (320 p.)
Dzięki wielkie, spróbuję to wykorzystać. Pozdrawiam :)

2 odpowiedzi

+1 głos
odpowiedź 14 maja 2017 przez criss Mędrzec (172,590 p.)
Upewnij się czy przypadkiem nie ładujesz tekstury przy każdym utworzonym obiekcie. Poza tym (oczywiście nie wiem jak wygląda twoja gra i na co możesz sobie pozwolić) powinieneś się zastanowić czy musisz tworzyć tyle obiektów Wall - być może wystarczy jeden obiekt rysowany wielokrotnie w wielu miejscach (jedynie pozycje mogłyby być przetrzymywane) ?
komentarz 14 maja 2017 przez neos Początkujący (320 p.)
edycja 14 maja 2017 przez neos

Mógłbyś dać wskazówkę jak stworzyć jeden obiekt wall rysowany wielokrotnie, bo jakoś tego nie widzę.. :/ A jeśli już udałoby mi się stworzyć to w ten sposób jaki sugerujesz to nie byłoby problemów z kolizją? 

 

 //COLLISION PLAYER WITH WALLS
    counterWalls = 0;
    for(iter5=WallArray.begin(); iter5 !=WallArray.end(); iter5++)
    {
        
        if(player.rect.getGlobalBounds().intersects(WallArray[counterWalls].rect.getGlobalBounds()))
        {
            //cout<<"Wall collision"<<endl;
            
            if(player.direction==1) //down
            {
                player.canMoveDown =false;
                
                player.rect.move(0, -5);
            }
            else if(player.direction==2) //up
            {
                player.canMoveUp =false;
                
                player.rect.move(0, 5);
            }
            else if(player.direction==3) //left
            {
                player.canMoveLeft =false;
                
                player.rect.move(5, 0);
            }
            else if(player.direction==4) //right
            {
                player.canMoveRight =false;
                
                player.rect.move(-5, 0);
            }
            else
            {
                
            }
            
            
        }
        counterWalls++;
    }

 Pozdrawiam i liczę na szybką odpowiedź!

1
komentarz 14 maja 2017 przez criss Mędrzec (172,590 p.)

Po prostu zmienić transform (np. pozycje) i narysować jeszcze raz. Możesz też wykorzystać sf::RenderStates. 

A jeśli już udałoby mi się stworzyć to w ten sposób jaki sugerujesz to nie byłoby problemów z kolizją? 

Nie wiem co masz na myśli. Jeśli istniałby tylko jeden obiekt, to ofc kolizje musiałbyś zaprojektować nieco inaczej.

Może nie powinieneś sobie tym jeszcze zawalać głowy jeśli sobie nie radzisz. Prędzej czy później nauczysz się troche więcej i sam będziesz zauważał możliwości.

komentarz 14 maja 2017 przez neos Początkujący (320 p.)
A co do tego transform, to jeżeli zrobię to na obiekcie wall to  będzie to wyglądać tak, że zmieni się pozycja bieżącego sprite i narysuje się ten sam sprite tylko o zmienionych pozycjach ( tak jakby zostałby przesunięty ) ? Jeśli źle rozumuję to proszę popraw mnie bo chyba nie za bardzo wiem o co Ci chodzi z tym rysowaniem tego samego obiektu kilkukrotnie, a zdaje mi się że byłoby to słuszne rozwiązanie.
1
komentarz 14 maja 2017 przez criss Mędrzec (172,590 p.)
    sf::RenderWindow window(sf::VideoMode(1000, 1000), "Circle");
    sf::RectangleShape r({300, 50});


    while (window.isOpen())
    {

        window.clear();

        r.setPosition({100, 200});
        window.draw(r);

        r.setPosition({200, 300});
        window.draw(r);        

        window.display();
    }

Mały przykład. Sprawdź sobie. sf::Sprite (czy sf::RectangleShape i inne rysowalne klasy) są tylko w pewnym sensie takimi rendererami, ale nie reprezentują żadnego "bytu" siedzącego gdzieś głębiej. Traktuj je bardziej jako pędzle niż graficzną reprezentacje jednego, konkretnego obiektu. Oczywiście bez przesady - jeśli znacznie wygodniej jest po prostu utworzyć sto sprajtów zamiast jeden rysować sto razy, to nic strasznego się nie stanie.

komentarz 14 maja 2017 przez neos Początkujący (320 p.)
Chyba już rozumiem, wielkie dzięki! :)
+1 głos
odpowiedź 14 maja 2017 przez j23 Mędrzec (194,920 p.)
WallArray.push_back(wall);

Jeśli obiekty klasy Wall są ciężkie, użyj emplace_back zamiast push_back, ewentualnie trzymaj wskaźniki.

Podobne pytania

0 głosów
3 odpowiedzi 164 wizyt
pytanie zadane 2 stycznia 2016 w C i C++ przez Avernis Nałogowiec (27,400 p.)
0 głosów
1 odpowiedź 239 wizyt
pytanie zadane 14 czerwca 2023 w C i C++ przez cpp_enjoyer Nowicjusz (150 p.)
0 głosów
1 odpowiedź 507 wizyt
pytanie zadane 7 kwietnia 2020 w C i C++ przez qwx6 Początkujący (300 p.)

92,568 zapytań

141,420 odpowiedzi

319,622 komentarzy

61,954 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...