OczkoSX Temat założony przez niniejszego użytkownika |
[SFML] View - stałe tło + renderowanie tylko spriteów które są widoczne w View. » 2014-03-16 09:26:19 Witam! Na początku może zapodam kod: mapy.h
#ifndef mapy_h #define mapy_h
#include "fzi.h" #include "bloki.h"
class CMapa { private: int wybr_mapa = 0; int ilosc_map; int wys, szer; string nazwa; short int ** mapa_tab; public: void stw_tablice() { { mapa_tab = new short int *[ wys ]; for( int i = 0; i < wys; i++ ) { mapa_tab[ i ] = new short int[ szer ]; } } } void zaladuj_tablice() { stringstream sciezka; sciezka << "maps\\mapa" << wybr_mapa << ".dat"; fstream mapa_file( sciezka.str() ); if( !mapa_file.good() ) exit( 0 ); getline( mapa_file, nazwa ); mapa_file >> wys >> szer; stw_tablice(); for( int i = 0; i < wys; i++ ) { for( int j = 0; j < szer; j++ ) { mapa_file >> mapa_tab[ i ][ j ]; } } mapa_file.close(); } void liczba_map() { while( true ) { stringstream sciezka; sciezka.str( "" ); sciezka << "maps\\mapa" << ilosc_map << ".dat"; ifstream exist( sciezka.str().c_str() ); if( exist.good() ) ilosc_map++; else break; } } void rys_mape() { for( int i = 0; i < wys; i++ ) { for( int j = 0; j < bloki.ilosc_blokow; j++ ) { bloki.blok[ j ].setPosition( 0, i *( bloki.blok[ j ].getGlobalBounds().height ) ); } for( int j = 0; j < szer; j++ ) { if( mapa_kaf.mapa_tab[ i ][ j ] != - 1 ) APP.draw( bloki.blok[ mapa_kaf.mapa_tab[ i ][ j ] ] ); for( int k = 0; k < bloki.ilosc_blokow; k++ ) { bloki.blok[ k ].move( bloki.blok[ k ].getGlobalBounds().height, 0 ); } } } } } mapa_kaf;
#endif
bloki.h
#ifndef bloki_h #define bloki_h
#include "fzi.h"
class CBloki { private: friend class CMapa; int blok_szer = 50, blok_wys = 50; static const int ilosc_blokow = 2; sf::Texture blok_tex[ ilosc_blokow ]; sf::Sprite blok[ ilosc_blokow ]; public: void bloki() { for( int i = 0; i < ilosc_blokow; i++ ) { ostringstream sciezka; sciezka.str( "" ); sciezka << "bloki\\blok" << i << ".png"; if( !blok_tex[ i ].loadFromFile( sciezka.str() ) ) exit( 0 ); blok[ i ].setTexture( blok_tex[ i ] ); blok[ i ].setScale( blok_szer / blok[ i ].getGlobalBounds().width, blok_wys / blok[ i ].getGlobalBounds().height ); } } } bloki;
#endif bloki_h
fzi.h
#ifndef fzi_h #define fzi_h
using namespace std;
#include <SFMl/Graphics.hpp> #include <fstream> #include <string> #include <sstream>
extern sf::RenderWindow APP;
#endif
main.cpp #include "fzi.h" #include "bloki.h" #include "mapy.h"
sf::RenderWindow APP;
int main() { APP.create( sf::VideoMode( 1600, 900, 32 ), "Okno Aplikacji" ); bloki.bloki(); mapa_kaf.liczba_map(); mapa_kaf.zaladuj_tablice(); while( APP.isOpen() ) { if( sf::Keyboard::isKeyPressed( sf::Keyboard::Escape ) ) APP.close(); mapa_kaf.rys_mape(); APP.display(); APP.clear(); } } Jest to kod wszystkiego co na razie napisałem. Program wczytuje mape z pliku, odpowiednie textury i wyświetla je na ekranie (zaczątki gry :D). Chciałbym dodać View i mam odnośnie co do tego kilka pytań: 1. Czy jak będe rysował sprite wielkosci ekranu (tło) w View, to czy będzie cały czas statyczne i nie będzie się przemieszczało razem z innymi obiektami? 2. Możecie podsunąć pomysł jak przerobić metodę CMapa::rys_mape() aby rysowała tylko to co widzi użytkownik? (za pomocą View) PS. W SFML'u siedzę dopiero tydzień więc nie bijcie jeśli coś nie tak z kodem :D Jeśli macie jakieś zastrzeżenia co do kodu to piszcie (jest to mój pierwszy program napisany obiektowo w oparciu o klasy) |
|
Pokropow |
» 2014-03-16 09:58:35 Jeżeli chcesz zrobić tło które nie porusza się względem kamery to w pętli głównej zmieniaj pozycje Sprajta-Tła na pozycję View np: Sprite sprajt_tlo; sprajt_tlo.setCenter( ustawienie srodka tla ); View kamera; while( petlaGlowna ) { sprajt_tlo.setPosition( kamera.getCenter() ); }
|
|
OczkoSX Temat założony przez niniejszego użytkownika |
» 2014-03-16 10:07:02 Dzięki wielkie! A powiedz mi, wyjdzie to samo jeśli zrobię to tak (piszę obecnie z głowy)? PS. To jest moje pierwsze spotkanie z widokami, myślałem nad tym sposobem, gdyż z tego co mi wiadomo to każdy obiekt rysowany po ustawieniu widoku stosuje się do niego. Czyli jak narysuje sprite, to będzie on tam gdzie view. Mam rację? Czy może i tak trzeba ustawić jego pozycję? |
|
Pokropow |
» 2014-03-16 10:16:47 Ale jak później przesuniesz widok, to sprajt chyba zostanie tam gdzie był. Tak mi się przynajmniej wydaje. Najlepszym sposobem byłoby po prostu wstawienie tego do kodu i sprawdzenie czy działa. |
|
Pokropow |
» 2014-03-16 10:27:59 A co do drugiego pytania rozwiązła bym to funkcją która sprawdza czy sprajt jest w polu widzenia kamery i rysował tylko jeżeli zwróci true Funkcja: int czy_w_polu_View( sf::Sprite & sprajt, sf::View & view ) { Vector2f pos = Vector2f( view.getCenter().x - view.getSize().x / 2, view.getCenter().y - view.getSize().y / 2 ); Vector2f spriteSize = Vector2f( sprajt.getGlobalBounds().width, sprajt.getGlobalBounds().height ); if( sprajt.getPosition().x + spriteSize.x < pos.x ) return 0; if( sprajt.getPosition().x > pos.x + view.getSize().x ) return 0; if( sprajt.getPosition().y + spriteSize.y < pos.y ) return 0; if( sprajt.getPosition().y > pos.y + view.getSize().y ) return 0; return 1; } w metodzie rysującej: if( czy_w_polu_View( sprajt, widok ) ) draw( sprajt );
Funkcja działa tylko jeżeli środek sprajta jest ustawiony na lewy górny róg (0,0) czyli domyślnie Trochę zmodyfikowałem bo zauważyłem błąd. Jak zapewne zauważyłeś ta funkcja działa podobnie do wykrywania kolizji. |
|
OczkoSX Temat założony przez niniejszego użytkownika |
» 2014-03-16 10:51:31 Hym, z tego co mi wiadomo jest też metoda .contains. Myślisz że zadziała jak zrobię: if( polozenie + rozmiar widoku.contains( polozenie + rozmiar sprite ) ) ? Dobra, pokombinuję i jeśli coś nie wyjdzie to się zgłoszę do was :D |
|
OczkoSX Temat założony przez niniejszego użytkownika |
» 2014-03-16 11:29:18 Jakbym tego nie zrobił to nie działa... Łapcie kod: #include "fzi.h" #include "bloki.h" #include "mapy.h"
sf::RenderWindow APP; sf::RectangleShape hero; sf::View view; void postac(); void widok();
int main() { APP.create( sf::VideoMode( 1600, 900, 32 ), "Okno Aplikacji" ); bloki.bloki(); mapa_kaf.liczba_map(); mapa_kaf.zaladuj_tablice(); postac(); sf::Texture bg_txt; bg_txt.loadFromFile( "bg.png" ); sf::Sprite bg( bg_txt ); bg.setScale( APP.getSize().x / bg.getGlobalBounds().width, APP.getSize().y / bg.getGlobalBounds().height ); bg.setOrigin( sf::Vector2f( bg.getGlobalBounds().width / 2, bg.getGlobalBounds().height / 2 ) ); while( APP.isOpen() ) { if( sf::Keyboard::isKeyPressed( sf::Keyboard::D ) ) hero.move( 1, 0 ); if( sf::Keyboard::isKeyPressed( sf::Keyboard::A ) ) hero.move( - 1, 0 ); if( sf::Keyboard::isKeyPressed( sf::Keyboard::W ) ) hero.move( 0, - 1 ); if( sf::Keyboard::isKeyPressed( sf::Keyboard::S ) ) hero.move( 0, 1 ); if( sf::Keyboard::isKeyPressed( sf::Keyboard::Escape ) ) APP.close(); widok(); bg.setPosition( sf::Vector2f( view.getCenter() ) ); APP.draw( bg ); mapa_kaf.rys_mape(); APP.draw( hero ); APP.display(); APP.clear(); } }
void postac() { hero.setSize( sf::Vector2f( 50, 50 ) ); hero.setFillColor( sf::Color::Red ); }
void widok() { view.setSize( sf::Vector2f( APP.getSize() ) ); view.setCenter( sf::Vector2f( hero.getPosition().x +( hero.getGlobalBounds().width / 2 ), hero.getPosition().y +( hero.getGlobalBounds().height / 2 ) ) ); APP.setView( view ); } Zrobiłem ładnie że w gracz jest w centrum, ale nie mogę ustawić tej nieszczęsnej tapety... Oto rezultat: http://screenshooter.net/4771684/odeoangEDIT: OK, poradziłem sobie. Wystarczyło dac setOrigin przed SCALE. PS. Sory za double post :< PS. Zostało mi jeszcze renderowanie tych obiektów... |
|
OczkoSX Temat założony przez niniejszego użytkownika |
» 2014-03-16 13:07:47 void rys_mape() { for( int i = 0; i < wys; i++ ) { for( int j = 0; j < bloki.ilosc_blokow; j++ ) { bloki.blok[ j ].setPosition( 0, i *( bloki.blok[ j ].getGlobalBounds().height ) ); } for( int j = 0; j < szer; j++ ) { if( czy_w_polu_View( i, j ) ) { if( mapa_kaf.mapa_tab[ i ][ j ] != - 1 ) APP.draw( bloki.blok[ mapa_kaf.mapa_tab[ i ][ j ] ] ); } for( int k = 0; k < bloki.ilosc_blokow; k++ ) { bloki.blok[ k ].move( bloki.blok[ k ].getGlobalBounds().height, 0 ); } } } }
int czy_w_polu_View( int & i, int & j ) { sf::Vector2f pos = sf::Vector2f( view.getCenter().x - view.getSize().x / 2, view.getCenter().y - view.getSize().y / 2 ); sf::Vector2f spriteSize = sf::Vector2f( bloki.blok[ mapa_kaf.mapa_tab[ i ][ j ] ].getGlobalBounds().width, bloki.blok[ mapa_kaf.mapa_tab[ i ][ j ] ].getGlobalBounds().height ); if( bloki.blok[ mapa_kaf.mapa_tab[ i ][ j ] ].getPosition().x + spriteSize.x < pos.x ) return 0; if( bloki.blok[ mapa_kaf.mapa_tab[ i ][ j ] ].getPosition().x > pos.x + view.getSize().x ) return 0; if( bloki.blok[ mapa_kaf.mapa_tab[ i ][ j ] ].getPosition().y + spriteSize.y < pos.y ) return 0; if( bloki.blok[ mapa_kaf.mapa_tab[ i ][ j ] ].getPosition().y > pos.y + view.getSize().y ) return 0; return 1; } Moja funkcja rysująca. nie zauważyłem jakichkolwiek zmian wydajnosciowych... nadal około 675fps. może coś skopalem? 400 kafelek. w domu jak będę zrobię więcej //EDIT Przepisałem na nowo funkcję. Teraz jest ponad 2 razy mniejsza :D void rys_mape() { for( int i = 0; i < wys; i++ ) { for( int j = 0; j < szer; j++ ) { bloki.blok[ mapa_kaf.mapa_tab[ i ][ j ] ].setPosition( sf::Vector2f( j * bloki.blok_szer, i * bloki.blok_wys ) ); if( mapa_kaf.mapa_tab[ i ][ j ] != - 1 && czy_w_polu_View( i, j ) ) APP.draw( bloki.blok[ mapa_kaf.mapa_tab[ i ][ j ] ] ); } } }
int czy_w_polu_View( int & i, int & j ) { sf::Vector2f pos = sf::Vector2f( view.getCenter().x - view.getSize().x / 2, view.getCenter().y - view.getSize().y / 2 ); if( bloki.blok[ mapa_kaf.mapa_tab[ i ][ j ] ].getPosition().x + bloki.blok_szer < pos.x ) return 0; if( bloki.blok[ mapa_kaf.mapa_tab[ i ][ j ] ].getPosition().x > pos.x + view.getSize().x ) return 0; if( bloki.blok[ mapa_kaf.mapa_tab[ i ][ j ] ].getPosition().y + bloki.blok_wys < pos.y ) return 0; if( bloki.blok[ mapa_kaf.mapa_tab[ i ][ j ] ].getPosition().y > pos.y + view.getSize().y ) return 0; return 1; } Idę zaraz zrobić na szybko programik, który będzie wybranym klockiem uzupełniać obszar o podanych wymiarach (tymczasowo dla testów wydajności). EDIT 2: Jest różnica D: Na mapie 100x100 wypełnionej jednym obiektem normalnie jest 180fps, a gdy renderuje się tylko obszar który jest widoczny prawie 500! (na trybie debug :D) Na mapie wielkości miliona kafelek (1000x1000) normalnie są 1 - 2fps'y, a przy opcji z view 9... I tu się trochę zdziwiłem. Wpadłem na pomysł, że przecież musi dla miliona kafelek sprawdzać czy się znajdują w obszarze View. Postanowiłem, że muszę napisać funkcję, lub przerobić tą, aby więcej nie sprawdzało kiedy jedna wychodzi. Jak ktoś chce pomóc to się nie obraże :D |
|
« 1 » 2 |