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

Pixel & Quiz - Pierwsza własna gra (Technologia C++ & SFML)

Object Storage Arubacloud
0 głosów
625 wizyt
pytanie zadane 24 maja 2018 w Nasze projekty przez Maciej Szostak Początkujący (290 p.)
Witam,
Jest to mój pierwszy projekt gry w technologi c++ & SFML, nie bardzo wiem na co zwrócić dalej uwagę a po chwili odpoczynku chciałbym zacząć z nowym pomysłem to też zwracam się z prośbą o ocenę do bardziej doświadczonych.

Kod: https://github.com/Craix/Pixel-Quiz-
Pliki wraz z skompilowaną wersją gry: https://drive.google.com/open?id=1DFq-swUtkDEGnx2IU4DrHDEQNKbjfe5E

Konfiguracja kompilacji:
Release mode x86
Microsoft Visual Studio 2017
System Windows 8.1
komentarz 25 maja 2018 przez Secrus Nałogowiec (32,880 p.)
W C++ nie robię, ale pod względem UX to brakuje zasad/instrukcji
komentarz 29 maja 2018 przez Maciej Szostak Początkujący (290 p.)
edycja 29 maja 2018 przez Maciej Szostak
[Poprawione] Edytowałem plik readme.

Dzięki za uwagę ;)

4 odpowiedzi

0 głosów
odpowiedź 25 maja 2018 przez 10kw10 Pasjonat (22,880 p.)

Na pierwszy rzut oka:

void Game::single()
{
	Engine engine(window, background, font, wybrany_lvl, sound_button, music);

	state = MENU;
}

Czemu ciagle tworzysz nowy obiekt? 

komentarz 29 maja 2018 przez Maciej Szostak Początkujący (290 p.)
[Poprawione]
Tylko nie jestem pewny na ile dobrze to zrobiłem, jeśli masz chwilę prosił bym o komentarz.

Linka do porównania zmian: https://github.com/Craix/Pixel-Quiz-/commit/9358d9d352609d88371e9ca775383879fbea603a#diff-a184ccc8cbef597d31078638a1851fbc

Obiekt tworzę jednorazowo w klasie game, elementy które były przekazywane przez konstruktor zamieniłam na przekazywanie przez metodę runGame();

Dzięki za uwagę ;)
0 głosów
odpowiedź 25 maja 2018 przez Hiskiel Pasjonat (22,830 p.)

Jako osoba bardzo początkująca mogę się tylko przyczepić do tego:

text[i].setPosition((float)width / 2 - text[i].getGlobalBounds().width / 2,(float)128 + i * ((height - 64) / 3));

Oprócz tego, iż jest to strasznie długie, to chodzi mi o castowanie na floata. Użyłeś castowania (obj)obj (gdzie jako obj może być zmienna, obiekt, liczba, ...). W takim castowaniu kompilator wybiera odpowiedni rodzaj, co może być niebezpieczne. 

http://www.mateuszmidor.com/2011/05/static_cast-vs-dynamic_cast-vs-reinterpret_cast-vs-const_cast/

komentarz 25 maja 2018 przez rafal.budzis Szeryf (85,260 p.)
Wydaje mi się ze w tej linijce można by było jeszcze coś zmienić :D Jeśli zmienna width jest INTem to zamiast dzielenia powinieneś przesunąć bity o jeden ;)  Co prawda nie będziesz miał reszty z dzielenia po przecinku ale zyskujesz niewiarygodnie na szybkości. A pół piksela różnicy nikt nie zobaczy ;)
komentarz 25 maja 2018 przez Hiskiel Pasjonat (22,830 p.)
Uświadomiłbyś mnie o co chodzi? :D
komentarz 25 maja 2018 przez niezalogowany

Chodzi o takie coś:

#include <iostream>

int main() {
	std::cout << (10 >> 1) << "\n"; // dzielenie
	std::cout << (10 << 1) << "\n"; // mnożenie
}

Chociaż wydaje mi się, że takie rzeczy to kompilator powinien optymalizować od razu.

komentarz 26 maja 2018 przez rafal.budzis Szeryf (85,260 p.)

@Hipcio kompilator nie zoptymalizuje gdy wynik działania będzie inny ;) Chociaż dawno się C++ nie bawiłem wiec nei wiem jak to dokładnie wygląda. 

 

3 / 2 = 1,5 // Dzielenie 
3 >> 1 = 1 // Przesuwanie bitowe

 

komentarz 26 maja 2018 przez niezalogowany
edycja 26 maja 2018

Chodziło mi o dzielenie przy dwóch intach ;) W C++ wygląda to tak:

3 / 2 = 1 // int
3.0 / 2.0 = 1.5 // double
komentarz 26 maja 2018 przez Hiskiel Pasjonat (22,830 p.)
A czy mógłbym się dowiedzieć jak to działa? Temat wydaje się być ciekawy, ale poziom abstrakcji jest na tyle duży, że nie widać co się dzieje ://.
komentarz 30 maja 2018 przez Maciej Szostak Początkujący (290 p.)

[Poprawione] Dzięki za uwagę :)

 

@Swipeyro,
 

text[i].setPosition((float)width / 2 - text[i].getGlobalBounds().width / 2,(float)128 + i * ((height - 64) / 3));

Zamieniłam na 

text[i].setPosition(sf::Vector2f(static_cast<float>(width - text[i].getGlobalBounds().width) / 2, static_cast<float>(128 + i * (height - 64) / 3)));


W innych miejscach zastosowałem taką kombinację:

tiled[level.poziom[i][j] - 1].setPosition(sf::Vector2f(sf::Vector2i(level.title_size * i, level.title_size * j + 64)));

Na podstawie dokumentacji SFML: 
https://www.sfml-dev.org/documentation/2.5.0/classsf_1_1Vector2.php#aed26a72164e59e8a4a0aeee2049568f1 
 


sf::Vector2< T >::Vector2    (    const Vector2< U > &     vector    )    

Construct the vector from another type of vector.

Tylko nie jestem pewny na ile takie rozwiązanie jest poprawne, prosił bym więc o komentarz. 

komentarz 30 maja 2018 przez Maciej Szostak Początkujący (290 p.)

@rafal612b,

Operacje bitowe są mi znane, ale nie stosowałem ich ogólnie w tym projekcie i na razie z tego zrezygnuję. Wymagało by to wielu zmian w kodzie na co teraz za bardzo nie mam czasu. 

0 głosów
odpowiedź 25 maja 2018 przez rafal.budzis Szeryf (85,260 p.)
komentarz 29 maja 2018 przez Maciej Szostak Początkujący (290 p.)
[Poprawione] Literówka ;) Dzięki za uwagę.
0 głosów
odpowiedź 25 maja 2018 przez niezalogowany
edycja 25 maja 2018

Wszystkie moje uwagi jakie przyszły mi do głowy:

1. Zmieniłem rozmiar okna i przyciski przestały prawidłowo reagować. Wypadałoby zablokować rozszerzanie np poprzez nadanie sf::RenderWindow innego typu okna:

sf::RenderWindow window(sf::VideoMode(512, 576), "Pixel Quiz", sf::Style::Close);

albo użyć metody mapPixelToCoords przy pobieraniu położenia myszki:

sf::Vector2f mouse(window.mapPixelToCoords(sf::Mouse::getPosition(window)));

2. Czemu konsola jest włączona?

3. MessageBox jest z WinApi. Dodatkowe okna też mogą być robione w SFML dzięki czemu gra będzie mogła być skompilowana również na inne niż windows systemy.

4. Przydałby się jakiś menedżer zasobów. Często piszesz coś takiego:

if (!level.loadMap(selected_lvl))
	{
		MessageBox(NULL, "Faile do load map file", "ERROR", NULL);
		return;
	}

4. Wszystkie nazwy zmiennych powinny być zrozumiałe i spójne:

  

bool tp, wat, game_status;

 5. Kolory można podawać na dwa sposoby:

text.setFillColor(sf::Color::Color(255, 153, 0)); // #ff9900
text.setFillColor(sf::Color(0xff9900ff)); // bo RGBA 

6. Engine::colision(sf::Vector2f xy)

if (level.poziom[(int)xy.x][(int)xy.y] == level.ICE || level.poziom[(int)xy.x][(int)xy.y] == level.PADLOCK 
		|| level.poziom[(int)xy.x][(int)xy.y] == level.DOOR)
	{
		return true;
	}
	else
	{
		return false;
	}

zamień na:

	return (level.poziom[(int)xy.x][(int)xy.y] == level.ICE || level.poziom[(int)xy.x][(int)xy.y] == level.PADLOCK
		|| level.poziom[(int)xy.x][(int)xy.y] == level.DOOR);

7. Patrzę na tę funkcję i zastanawia mnie jedno. Czemu funkcja otrzymuje parę liczb zmiennoprzecinkowych. Nie lepiej od razu sf::Vector2i/u? W tym momencie szukam kontekstu i trafiam na wywołanie

if (colision(player.getPosition() + sf::Vector2f(0, -1)) == false)

skąd przeszedłem do metody Player::getPosition():

return sf::Vector2f(((sprite.getPosition().x - 8) / 16), (((sprite.getPosition().y - 64) - 8) / 16));

Niby wszystko działa, ale gdzieś po tych wszystkich działaniach tracisz trochę prędkości, trochę wygody i dokładności. Lepiej jakbyś przechowywał w tym przypadku pozycję gracza jako nr od razu, a nie je wyliczał. 

8. Czemu pliki nagłówkowe są dużej litery, a pliki źródłowe z małej?

9. Używaj "\n" zamiast std::endl na strumieniach plikowych (będzie szybciej zwłaszcza dla plików).

10. sf::RenderWindow nie powinno być elementem klasy Game?

11. Dobrze, że często stosujesz angielskie nazewnictwo, ale postaraj się, aby było wszędzie:

wybrany_lvl = 0;

12. Metoda resize jest zbędna, bo konstruktor może robić dokładnie to samo:

std::vector <sf::Sprite> lvl_field(16);

13. Funkcja Level::lose_rgb() - powinna zostać wyłączona z tej klasy (to zupełnie niezwiązany element) i zmień jej nazwę!

sf::Uint8 randUint8()
{
    return rand() % 256;
}

sf::Color w jednym z konstruktorów przyjmuje właśnie 4 sf::Uint8, a one mogą przyjmować wartości od 0 - 256 (chociaż nie będzie błędu przy przekroczeniu wartości tylko zostanie zapisana wartość kolejna dla np 257 będzie 1).

14. Sterowanie jest troszkę niewygodne. Gdy raz nacisnę przycisk przesunę się raz, a po chwili będę przesuwał się bardzo szybko przez co można nie skręcić w odpowiednim momencie więc trzeba na niektórych korytarzach cały czas wduszać dany przycisk. IMHO gdyby poruszanie się byłoby ciągłe można by wygodniej sterować (czyli sterowanie za pomocą sf::Keyboard::isKeyPressed).

15. Wyszedłem z gry i nie zapisały mi się wszystko levele crying

komentarz 25 maja 2018 przez Hiskiel Pasjonat (22,830 p.)

9. Używaj "\n" zamiast std::endl na strumieniach plikowych (będzie szybciej zwłaszcza dla plików).

Robiłem test, 100000 razy std::cout . Jeden z "\n" inny z "std::endl". Robiłem 5 testów i uśredniłem wyniki. Różnica jest o niecałą sekundę. Czy to serio takie ważne?

komentarz 25 maja 2018 przez niezalogowany
Dla std::cout nie będzie dużej różnicy, ale dla std::ofstream wykonanie std::endl u mnie jest 5 razy dłuższe.
komentarz 25 maja 2018 przez Hiskiel Pasjonat (22,830 p.)
Zaraz zrobię test, 10000 zapisów.
komentarz 25 maja 2018 przez Hiskiel Pasjonat (22,830 p.)
Dobra, zrobiłem test 1000000 zapisów i po pierwszym teście już nic mi nie trzeba..

https://i.imgur.com/hhXRAk4.jpg
komentarz 5 czerwca 2018 przez Maciej Szostak Początkujący (290 p.)

@Hipcio,

1.[Poprawione]
2.[Poprawione]
3. MessageBox jest z WinApi. Dodatkowe okna też mogą być robione w SFML dzięki czemu gra będzie mogła być skompilowana również na inne niż windows systemy.

Odp: Był to mój pierwszy projekt, a ponieważ korzystam tylko z windowsa to skupiłem się na tym systemie. Nie widzę sensu rozwijać tego w kierunku innych systemów, ale wezmę to pod uwagę przy następnym projekcie. 

4.1. Przydałby się jakiś menedżer zasobów. 

Odp. Nie bardzo rozumiem co kryje się pod pojęciem "menedżer zasobów", dopisać fragment który w jednym miejscu sprawdzał by dostępność wszystkich elementów?

4.2. [Poprawione]
5. [Poprawione]
6. [Poprawione]
7. [Poprawione]
8. [Poprawione]
9. [Poprawione]
10. [Poprawione]
11. [Poprawione]
12. [Poprawione]


13. Funkcja Level::lose_rgb() - powinna zostać wyłączona z tej klasy (to zupełnie niezwiązany element) i zmień jej nazwę!

Odp. Zmieniłem budowę tej funkcji jednak nie widzę sensu usuwania jej z klasy level skoro tylko tam jest ona stosowana. 

14. Sterowanie jest troszkę niewygodne. Gdy raz nacisnę przycisk przesunę się raz, a po chwili będę przesuwał się bardzo szybko przez co można nie skręcić w odpowiednim momencie więc trzeba na niektórych korytarzach cały czas wduszać dany przycisk. IMHO gdyby poruszanie się byłoby ciągłe można by wygodniej sterować (czyli sterowanie za pomocą sf::Keyboard::isKeyPressed).

Odp Działa tak ponieważ zastosowałem konstrukcję while (window.pollEvent(event)), oczywiście mógłbym to zmienić na sf::Keyboard::isKeyPressed). ale wiązało by się to z kilkoma innymi problemami, pętla stałokrokowa, ograniczenie fps itd...

15. Wyszedłem z gry i nie zapisały mi się wszystko levele 


Odp. Dziwne...  Nawet nie mam pomysłu jak do tego mogło dojść... 
Prosił bym o więcej informacji w tym temacie, najlepiej opis...

Dzięki za uwagi, liczę na feedback ;)

 

komentarz 8 czerwca 2018 przez niezalogowany

4.1. Chodziło mi o dopisanie fragmentu, który wyświetlałby komunikat w momencie gdy zasób nie został załadowany. Póki co powtarzasz wszędzie fragmenty typu:

if (!music.openFromFile("sounds//Pixel.ogg"))
{
	MessageBox(NULL, "Failed to load sounds Pixel.ogg", "ERROR", NULL);
	return;
}
// lub

if (!player_texture.loadFromFile("graphic//player.png"))
{
	MessageBox(NULL, "Failed to load image player.png", "ERROR", NULL);
	return;
}

Myślę, że wygodniej (i bez powtarzania) byłoby zrobić coś takiego:

musicManager.load(music, "sounds//Pixel.ogg");
textureManager.load(player_texture, "graphic//player.png");

W internecie są też wygodniejsze rozwiązania typu przechowywanie zasobów w mapie nazwa-zasób (możesz wykorzystać w kolejnych projektach - przykład1przykład2).

13. Funkcja pasowałaby bardziej do jakiegoś pliku typu SFMLRandUtils.cpp

15. O ile dobrze pamiętam chodziło o sytuację gdy ktoś nie wyjdzie przez menu tylko przez krzyżyk :D (sf::Event::Closed).

Podobne pytania

0 głosów
0 odpowiedzi 491 wizyt
+6 głosów
4 odpowiedzi 450 wizyt
pytanie zadane 5 grudnia 2015 w Nasze projekty przez niezalogowany
+9 głosów
4 odpowiedzi 962 wizyt
pytanie zadane 23 czerwca 2015 w Nasze projekty przez DiZZie Gaduła (3,170 p.)

92,575 zapytań

141,424 odpowiedzi

319,649 komentarzy

61,960 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!

...