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

SFML - symulacja deszczu

Cloud VPS
0 głosów
501 wizyt
pytanie zadane 1 kwietnia 2019 w C i C++ przez Milo Obywatel (1,180 p.)

Hej, chciałbym poprosić was o subiektywną ocenę mojego projektu w c++, w SFML. Nie pokoi mnie jedna rzecz. Jakby się tak przyjrzeć każdej kropli, to podczas spadania, w pewnym momencie lekko cofa się do góry. Kod wklejam tutaj, bo nie jest długi, ~60 linijek.

#include <SFML/Graphics.hpp>
#include <windows.h>
#include <vector>

using namespace sf;
using namespace std;

class rain : public RectangleShape
{
public:
    float speed; // zmienna przechowujaca predkosc kropli
    rain (float x, float y) : RectangleShape (Vector2f(x, y)) {};
};
vector <rain> RainVector;
RenderWindow window;

int main ()
{
    srand (time(NULL));

    window.create (VideoMode(960, 540), "Rain in SMFL", Style::Titlebar | Style::Close);
    window.setActive (true);
    window.setVerticalSyncEnabled (true);

    Event e;
    while (window.isOpen())
    {
        while (window.pollEvent(e))
        {
            if (e.type == Event::Closed || Keyboard::isKeyPressed(Keyboard::Escape)) window.close ();
        }

        /// generowanie 4 nowych kropli na jedna klatke
        for (int i = 0; i < 4; i++)
        {
            RainVector.push_back(rain(2, 20));
            RainVector.back().setFillColor(Color::Blue);
            RainVector.back().setOrigin(0, 0);
            RainVector.back().setPosition(rand()%959, -20);
            RainVector.back().speed = rand()%10+4; // ustawienie losowej predkosci
        }

        /// zrzucenie kazdej kropli
        for (int i = 0; i < RainVector.size(); i++)
        {
            int x, y; // pozycja kropli
            int v; // szybkosc kropli
            x = RainVector[i].getPosition().x;
            y = RainVector[i].getPosition().y;
            v = RainVector[i].speed;
            if (y > 540) RainVector.erase(RainVector.begin()+i); // sprawdzenie czy kropla nie wyszla poza okno
            else
            {
                RainVector[i].speed += 0.10; // przespieszenie spadania deszczu
                RainVector[i].setPosition(x, y+v); // zrzucenie kropli
            }
        }

        window.clear (Color::White);
        /// rysowanie deszczu
        for (int i = 0; i < RainVector.size(); i++)
        {
            window.draw (RainVector[i]);
        }
        window.display();
    }
}

 

1 odpowiedź

+2 głosów
odpowiedź 1 kwietnia 2019 przez niezalogowany
wybrane 1 kwietnia 2019 przez Milo
 
Najlepsza
  1. Nie stosuj globalnych zmiennych
  2. Nie używaj 'using namespace'
  3. Do losowania używaj <random>
  4. Co to za magiczne wartości:
    RainVector.back().setPosition(rand() % 959, -20); // window.getSize().x - 1
    if (y > 540) // window.getSize().y
  5. Brak obsługi czasu. Na różnych komputerach deszcz będzie padał wolniej/szybciej.
  6. Zamiast rain::setPosition możesz użyć rain::move
  7. Można zauważyć, że krople czasami wykonują znaczne skoki. Przyczyna: W momencie gdy usuwasz z vectora obiekt powinieneś zdekrementować i:
    if (y > 540) { 
    	RainVector.erase(RainVector.begin() + i); 
    	--i;
    }
  8. Nie powinieneś nic usuwać z vectora jest to strasznie wolne (za wyjątkiem usuwania ostatniego elementu). Gdy kropla wyjdzie poza ekran przesuń ją na pozycję startową i nadaj nową prędkość.
  9. Możesz używać range-based for z C++11
    /*for (int i = 0; i < RainVector.size(); i++)
    {
    	window.draw(RainVector[i]);
    }*/
    
    for (auto& drop: RainVector) {
    	window.draw(drop);
    }
    
  10. Czemu int, a nie float:
    int x, y; // pozycja kropli
    int v; // szybkosc kropli
2
komentarz 1 kwietnia 2019 przez adrian17 Mentor (354,620 p.)

2. Nie używaj przestrzeni nazw

konkretniej, nie używaj 'using namespace'. Same przestrzenie nazw fajnie jest używać :)

1
komentarz 1 kwietnia 2019 przez niezalogowany

@adrian17 dzięki za poprawienie ;)

komentarz 1 kwietnia 2019 przez Milo Obywatel (1,180 p.)
Okej, trochę tego jest. Ale co złego jest w używaniu 'using namespace'? Na czym polega ta obsługa czasu? I na czym polega punkt nr. 9? Mógłby mi ktoś wytłumaczyć? Myślę, że trochę za wcześnie zacząłem sfml'a i powinienem nauczyć się jeszcze paru (może parunastu) rzeczy.
komentarz 1 kwietnia 2019 przez Milo Obywatel (1,180 p.)

Jeżeli chcę mieć ograniczoną ilość kropli na ekranie ( w tym przypadku 230) to mogę napisać coś takiego? Czy jest to poprawne? Bo działa.

for (int i = 0; i < 4; i++)
{
    if (RainVector.size() < 230)
    {
        RainVector.push_back(rain(2, 20));
        RainVector.back().setFillColor(Color::Blue);
        RainVector.back().setOrigin(0, 0);
        RainVector.back().setPosition(rand()%window.getSize().x-1, -20);
        RainVector.back().speed = rand()%10+4; // ustawienie losowej predkosci
    }
}

 

komentarz 1 kwietnia 2019 przez niezalogowany

2. Wczytywanie wszystkich nazw do globalnego scope może powodować konflikty nazw. Poza tym łatwiej można zrozumieć kod jeżeli od razu wiemy np std::sort to znajduje się w standardowej bibliotece. Możesz używać 'using namespace' lokalnie wewnątrz jakiejś funkcji. Głównie w przypadku gdy klasy, czy funkcje są bardzo zagnieżdżone np boost::math::ublas::matrix, lub gdy jest to konieczne np dla literałów std::chrono_literals. Można nadać przestrzeni nazw jakąś inną nazwę. Można stosować pojedyncze 'using'. 

5. Każdy cykl pętli zajmuje określony czas, który nie musi być stały. Najprostszym rozwiązaniem byłoby ustawienie dla sf::RenderWindow stałego limitu klatek (nie jest to najdoskonalszy sposób). 

RainVector[i].setPosition(x, y+v); // y + v * dt

Dodatkowo tutaj można by przemnożyć prędkość przez czas pomiędzy klatkami w np sekundach. Uzyskana prędkość byłaby w bardzo przystępnej jednostce pixel / s. 

9. Jeżeli nie wiesz co C++11 to zacznij się go powoli uczyć. Włącz go w swoim kompilatorze. Zawiera wiele przydatnych narzędzi. Możesz równolegle uczyć się SFML.

Jeżeli chcę mieć ograniczoną ilość kropli na ekranie ( w tym przypadku 230) to mogę napisać coś takiego? Czy jest to poprawne? Bo działa.

Tak 

komentarz 1 kwietnia 2019 przez Milo Obywatel (1,180 p.)

A jeżeli mam w ustawieniach kompilatora zaznaczone C++14, to to też ma jakieś 'bajery'? Jeszcze w internecie spróbuje poszukać czegoś na temat obsługi czasu w sfml. Również wszystkie podstawowe wartości ustawiane podczas tworzenia kropli przeniosłem do konstruktora. Dzięki za pomoc, myślę, że te przestrogi pomogą mi na przysłość. yes

komentarz 1 kwietnia 2019 przez Milo Obywatel (1,180 p.)
Gdzie mogę znaleźć lekcje związaną z plikiem nagłówkowym <random>? Chodzi mi o stronę.
komentarz 1 kwietnia 2019 przez niezalogowany

A jeżeli mam w ustawieniach kompilatora zaznaczone C++14, to to też ma jakieś 'bajery'? 

Można to tak ująć :D

Gdzie mogę znaleźć lekcje związaną z plikiem nagłówkowym <random>? Chodzi mi o stronę.

https://diego.assencio.com/?index=6890b8c50169ef45b74db135063c227c

https://en.cppreference.com/w/cpp/numeric/random/uniform_int_distribution

https://en.cppreference.com/w/cpp/numeric/random/uniform_real_distribution

https://en.cppreference.com/w/cpp/numeric/random

https://dsp.krzaq.cc/post/180/nie-uzywaj-rand-cxx-ma-random/

komentarz 1 kwietnia 2019 przez Milo Obywatel (1,180 p.)

Chyba dzisiaj z linków skorzystać nie zdążę, ale naprawdę dziękuje ci za poświęcony dla mnie czas .smiley

komentarz 1 kwietnia 2019 przez Ehlert Ekspert (215,050 p.)

Najprostszym rozwiązaniem byłoby ustawienie dla sf::RenderWindow stałego limitu klatek

IMO to nic nie da, szczególnie na słabszym sprzęcie. winkNajlepszym rozwiązaniem byłaby pętla stałokrokowa która aktualizowałaby całą logikę np 30 razy na sekundę. Ale to chyba nie ten etap żeby tym mieszać laugh

komentarz 2 kwietnia 2019 przez niezalogowany
@Ehlert mógłbyś wyjaśnić czemu to nic nie da? :)
komentarz 2 kwietnia 2019 przez Ehlert Ekspert (215,050 p.)
Bo mimo stałego limitu klatek, to nie każdy komputer go wyrobi. Jeśli masz prędkość 20px/f i poruszasz obiekt per klatkę to inaczej będzie zasuwać przy 60fps a inaczej przy 20fps.

Podobne pytania

+1 głos
2 odpowiedzi 545 wizyt
pytanie zadane 20 marca 2017 w Nasze projekty przez QizmoPL Stary wyjadacz (11,440 p.)
+1 głos
2 odpowiedzi 299 wizyt
pytanie zadane 31 grudnia 2016 w C i C++ przez Patryk Krajewski Nałogowiec (26,170 p.)
0 głosów
2 odpowiedzi 498 wizyt
pytanie zadane 5 kwietnia 2016 w C i C++ przez Patryk Krajewski Nałogowiec (26,170 p.)

93,483 zapytań

142,417 odpowiedzi

322,763 komentarzy

62,895 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

Kursy INF.02 i INF.03
...