tBane Temat założony przez niniejszego użytkownika |
[SFML] Wiele map w grze - czyli jak wyświetlać tylko widoczne mapy » 2024-07-05 13:01:32 Witam. Świat mojej gry ma być w założeniu duży tzn, ma składać się z większej ilości map. Aby zoptymalizować renderowanie świata gry postanowiłem podzielić go na mniejsze mapy, tak aby renderować tylko te, które są widoczne. Jak to najlepiej zrobić ? Trzymać listę widocznych map i dodawać obiekty tych, które są widoczne do świata gry ? class Map { public: bool isVisible; };
class World { public: std::vector < Map * > maps; void mapVisiblings( sf::Vector2f worldMousePosition ) { for( auto & map: maps ) map->isVisible = false; Map * map = getMap( worldMousePosition ); if( map != nullptr ) map->isVisible = true; } void addVisibleGameObjectsToMainLists() { for( auto & map: maps ) { if( map->isVisible ) { for( auto & nature: map->_natures ) { gameObjects.push_back( nature ); natures.push_back( nature ); } for( auto & monster: map->_monsters ) { gameObjects.push_back( monster ); monsters.push_back( monster ); } for( auto & character: map->_characters ) { gameObjects.push_back( character ); characters.push_back( character ); } for( auto & item: map->_itemsOnMap ) { gameObjects.push_back( item ); itemsOnMap.push_back( item ); } for( auto & inventory: map->_inventoriesOnMap ) { gameObjects.push_back( inventory ); inventoriesOnMap.push_back( inventory ); } for( auto & path: map->_paths ) { gameObjects.push_back( path ); paths.push_back( path ); } for( auto & furniture: map->_furnitures ) { gameObjects.push_back( furniture ); furnitures.push_back( furniture ); } for( auto & building: map->_buildings ) { gameObjects.push_back( building ); buildings.push_back( building ); } } } } };
|
|
tBane Temat założony przez niniejszego użytkownika |
» 2024-07-05 13:59:10 Napisałem coś takiego. Najpierw czyszczę główne listy obiektów do renderowania, następnie sprawdzam mapy czy są w zasięgu pola widzenia, później iteruje wszystkie mapy i jeżeli jakaś jest w zasięgu pola widzenia to jej elementy dodaje do głównych list. Problem polega na tym, że pamięć cieknie, poza tym działa. void mapVisiblings() { int i = 0; sf::Vector2f map_position; for( auto & map: maps ) { map_position.x =( int( map->coords.x ) * 16 * tileSide ) + 8 * tileSide; map_position.y =( int( map->coords.y ) * 16 * tileSide ) + 8 * tileSide; float map_size = 16 * tileSide; rectMap[ i ] = sf::RectangleShape( sf::Vector2f( map_size, map_size ) ); rectMap[ i ].setFillColor( sf::Color( rand() % 256, rand() % 256, rand() % 256, 128 ) ); rectMap[ i ].setOrigin( map_size / 2.f, map_size / 2.f ); rectMap[ i ].setPosition( map_position ); rectView = sf::RectangleShape( sf::Vector2f( screenWidth / 4, screenHeight / 4 ) ); rectView.setFillColor( sf::Color( 256, 128, 128, 128 ) ); rectView.setOrigin( screenWidth / 8.f, screenHeight / 8.f ); rectView.setPosition( viewPosition ); map->isVisible = intersectionTwoRectangles( viewPosition.x, viewPosition.y, screenWidth / 4, screenHeight / 4, map_position.x, map_position.y, map_size, map_size ); i++; } }
void addVisibleGameObjectsToMainLists() { for( auto & map: maps ) { if( map->isVisible ) { for( auto & nature: map->_natures ) { gameObjects.push_back( nature ); natures.push_back( nature ); } for( auto & monster: map->_monsters ) { gameObjects.push_back( monster ); monsters.push_back( monster ); } for( auto & character: map->_characters ) { gameObjects.push_back( character ); characters.push_back( character ); } for( auto & item: map->_itemsOnMap ) { gameObjects.push_back( item ); itemsOnMap.push_back( item ); } for( auto & inventory: map->_inventoriesOnMap ) { gameObjects.push_back( inventory ); inventoriesOnMap.push_back( inventory ); } for( auto & path: map->_paths ) { gameObjects.push_back( path ); paths.push_back( path ); } for( auto & furniture: map->_furnitures ) { gameObjects.push_back( furniture ); furnitures.push_back( furniture ); } for( auto & building: map->_buildings ) { gameObjects.push_back( building ); buildings.push_back( building ); } } } }
void clearAllMainListsOfGameObjects() { gameObjects.clear(); monsters.clear(); characters.clear(); natures.clear(); itemsOnMap.clear(); inventoriesOnMap.clear(); paths.clear(); furnitures.clear(); buildings.clear(); }
void update() { world->mapVisiblings(); clearAllMainListsOfGameObjects(); world->addVisibleGameObjectsToMainLists(); }
|
|
tBane Temat założony przez niniejszego użytkownika |
» 2024-07-05 14:44:01 Dobra działa :-) Nawet wyszło lepiej niż oczekiwałem. Mapy rysuje szybko i edytor działa płynnie #ifndef Maps_hpp #define Maps_hpp
float tileSide = 16.0f;
class Map : public sf::Drawable , public sf::Transformable { public: sf::Vector2i coords; sf::VertexArray vertexes; sf::Texture tileset; std::vector < Monster * > _monsters; std::vector < Character * > _characters; std::vector < Nature * > _natures; std::vector < ItemOnMap * > _itemsOnMap; std::vector < InventoryOnMap * > _inventoriesOnMap; std::vector < Path * > _paths; std::vector < Furniture * > _furnitures; std::vector < Building * > _buildings; bool isVisible; Map( int x, int y ) { tileset = sf::Texture(); tileset.loadFromFile( "assets/tiles/0_tileset.png" ); coords.x = x; coords.y = y; vertexes.setPrimitiveType( sf::Triangles ); vertexes.resize( 16 * 16 * 6 ); int coord_x, coord_y; int tu, tv; for( int y = 0; y < 16; y++ ) for( int x = 0; x < 16; x++ ) { sf::Vertex * triangles = & vertexes[( y * 16 + x ) * 6 ]; coord_x =( coords.x * 16 + x ); coord_y =( coords.y * 16 + y ); triangles[ 0 ].position = sf::Vector2f( coord_x * tileSide, coord_y * tileSide ); triangles[ 1 ].position = sf::Vector2f(( coord_x + 1 ) * tileSide, coord_y * tileSide ); triangles[ 2 ].position = sf::Vector2f( coord_x * tileSide,( coord_y + 1 ) * tileSide ); triangles[ 3 ].position = sf::Vector2f( coord_x * tileSide,( coord_y + 1 ) * tileSide ); triangles[ 4 ].position = sf::Vector2f(( coord_x + 1 ) * tileSide, coord_y * tileSide ); triangles[ 5 ].position = sf::Vector2f(( coord_x + 1 ) * tileSide,( coord_y + 1 ) * tileSide ); tu = int( coord_x * tileSide ) % 64; tv = int( coord_y * tileSide ) % 64; triangles[ 0 ].texCoords = sf::Vector2f( tu, tv ); triangles[ 1 ].texCoords = sf::Vector2f( tu + tileSide, tv ); triangles[ 2 ].texCoords = sf::Vector2f( tu, tv + tileSide ); triangles[ 3 ].texCoords = sf::Vector2f( tu, tv + tileSide ); triangles[ 4 ].texCoords = sf::Vector2f( tu + tileSide, tv ); triangles[ 5 ].texCoords = sf::Vector2f( tu + tileSide, tv + tileSide ); } clearAllLists(); loadGameObjects(); isVisible = false; } void clearAllLists() { _monsters.clear(); _characters.clear(); _natures.clear(); _itemsOnMap.clear(); _inventoriesOnMap.clear(); _paths.clear(); _furnitures.clear(); _buildings.clear(); } void loadGameObjects() { string filename = "world/map_" + to_string( int( coords.x ) ) + "_" + to_string( int( coords.y ) ) + ".txt"; ifstream file( filename ); if( !file.is_open() ) { return; } cout << "open map: " << filename << "\n"; string line; string objectType; string name; while( std::getline( file, line ) ) { if( line.empty() ) { continue; } std::istringstream lineStream( line ); lineStream >> objectType; if( objectType == "Nature" ) { int x, y; getline( lineStream, name, '"' ); getline( lineStream, name, '"' ); lineStream >> x; lineStream >> y; Nature * nature = new Nature( getPrefab( name ), x, y ); _natures.push_back( nature ); } if( objectType == "Monster" ) { int x, y; getline( lineStream, name, '"' ); getline( lineStream, name, '"' ); lineStream >> x; lineStream >> y; Monster * monster = new Monster( getPrefab( name ), x, y ); _monsters.push_back( monster ); } if( objectType == "Item" ) { int x, y; getline( lineStream, name, '"' ); getline( lineStream, name, '"' ); lineStream >> x; lineStream >> y; ItemOnMap * itemOnMap = new ItemOnMap( getItem( name ), x, y ); _itemsOnMap.push_back( itemOnMap ); } if( objectType == "Path" ) { string name; int x, y; getline( lineStream, name, '"' ); getline( lineStream, name, '"' ); lineStream >> x; lineStream >> y; Path * path = new Path( getPrefab( name ), x, y ); _paths.push_back( path ); } if( objectType == "Furniture" ) { string name; int x, y; getline( lineStream, name, '"' ); getline( lineStream, name, '"' ); lineStream >> x; lineStream >> y; Furniture * furniture = new Furniture( getPrefab( name ), x, y ); _furnitures.push_back( furniture ); } if( objectType == "Building" ) { string name; int x, y; getline( lineStream, name, '"' ); getline( lineStream, name, '"' ); lineStream >> x; lineStream >> y; Building * building = new Building( getPrefab( name ), x, y ); _buildings.push_back( building ); } } file.close(); } void editTile( sf::Vector2f worldMousePosition, int tileNumb = 0 ) { int global_x = worldMousePosition.x / 16; int global_y = worldMousePosition.y / 16; int onMap_x = global_x - coords.x * 16; int onMap_y = global_y - coords.y * 16; if( onMap_x < 0 || onMap_x > 15 || onMap_y < 0 || onMap_y > 15 ) return; sf::Vertex * triangles = & vertexes[( onMap_y * 16 + onMap_x ) * 6 ]; int tu =( int( global_x * tileSide ) % 64 ) +( tileNumb * 64 ); int tv =( int( global_y * tileSide ) % 64 ); triangles[ 0 ].texCoords = sf::Vector2f( tu, tv ); triangles[ 1 ].texCoords = sf::Vector2f( tu + tileSide, tv ); triangles[ 2 ].texCoords = sf::Vector2f( tu, tv + tileSide ); triangles[ 3 ].texCoords = sf::Vector2f( tu, tv + tileSide ); triangles[ 4 ].texCoords = sf::Vector2f( tu + tileSide, tv ); triangles[ 5 ].texCoords = sf::Vector2f( tu + tileSide, tv + tileSide ); } ~Map() { } private: virtual void draw( sf::RenderTarget & target, sf::RenderStates states ) const { states.transform *= getTransform(); states.texture = & tileset; target.draw( vertexes, states ); } };
class World { public: std::vector < Map * > maps; World() { maps.clear(); int start_x = 0; int end_x = 16; int start_y = 0; int end_y = 16; for( int y = start_y; y <= end_y; y++ ) for( int x = start_x; x <= end_x; x++ ) maps.push_back( new Map( x, y ) ); } Map * getMap( sf::Vector2f worldMousePosition ) { cout << worldMousePosition.x << ", " << worldMousePosition.y << "\n"; if( worldMousePosition.x < 0 || worldMousePosition.y < 0 ) return nullptr; sf::Vector2i mapCoords; mapCoords.x = int( worldMousePosition.x /( 16 * tileSide ) ); mapCoords.y = int( worldMousePosition.y /( 16 * tileSide ) ); Map * map = nullptr; for( auto & m: maps ) { if( m->coords == mapCoords ) { map = m; } } return map; } void mapVisiblings() { sf::Vector2f map_position; for( auto & map: maps ) { map_position.x =( int( map->coords.x ) * 16 * tileSide ) + 8 * tileSide; map_position.y =( int( map->coords.y ) * 16 * tileSide ) + 8 * tileSide; map->isVisible = intersectionTwoRectangles( viewPosition.x, viewPosition.y, screenWidth * 2.0f, screenHeight * 2.0f, map_position.x, map_position.y, 16 * tileSide, 16 * tileSide ); } } void addVisibleGameObjectsToMainLists() { for( auto & map: maps ) { if( map->isVisible ) { for( auto & nature: map->_natures ) { gameObjects.push_back( nature ); natures.push_back( nature ); } for( auto & monster: map->_monsters ) { gameObjects.push_back( monster ); monsters.push_back( monster ); } for( auto & character: map->_characters ) { gameObjects.push_back( character ); characters.push_back( character ); } for( auto & item: map->_itemsOnMap ) { gameObjects.push_back( item ); itemsOnMap.push_back( item ); } for( auto & inventory: map->_inventoriesOnMap ) { gameObjects.push_back( inventory ); inventoriesOnMap.push_back( inventory ); } for( auto & path: map->_paths ) { gameObjects.push_back( path ); paths.push_back( path ); } for( auto & furniture: map->_furnitures ) { gameObjects.push_back( furniture ); furnitures.push_back( furniture ); } for( auto & building: map->_buildings ) { gameObjects.push_back( building ); buildings.push_back( building ); } } } } void save() { for( auto & map: maps ) { string filename = "world/map_" + to_string( int( map->coords.x ) ) + "_" + to_string( int( map->coords.y ) ) + ".txt"; std::ofstream file( filename ); if( !file.is_open() ) { cout << "cant open file to save map: " << filename << "\n"; return; } for( auto & nature: map->_natures ) file << "Nature " << char( 34 ) << nature->name << char( 34 ) << " " << int( nature->position.x ) << " " << int( nature->position.y ) << "\n"; for( auto & monster: map->_monsters ) file << "Monster " << char( 34 ) << monster->name << char( 34 ) << " " << int( monster->position.x ) << " " << int( monster->position.y ) << "\n"; for( auto & item: map->_itemsOnMap ) file << "Item " << char( 34 ) << item->name << char( 34 ) << " " << int( item->position.x ) << " " << int( item->position.y ) << "\n"; for( auto & path: map->_paths ) file << "Path " << char( 34 ) << path->name << char( 34 ) << " " << int( path->position.x ) << " " << int( path->position.y ) << "\n"; for( auto & furniture: map->_furnitures ) file << "Furniture " << char( 34 ) << furniture->name << char( 34 ) << " " << int( furniture->position.x ) << " " << int( furniture->position.y ) << "\n"; for( auto & building: map->_buildings ) file << "Building " << char( 34 ) << building->name << char( 34 ) << " " << int( building->position.x ) << " " << int( building->position.y ) << "\n"; file.close(); } } void render() { for( auto & map: maps ) { if( map->isVisible ) window->draw( * map ); } } };
World * world;
#endif
|
|
pekfos |
» 2024-07-05 16:21:13 Jak duży jest duży świat? Dopóki się spokojnie mieści w pamięci, nie kombinowałbym z ładowaniem po kawałku. Podawanie znaków jako liczby jest niepożądane w kodzie bo obniża czytelność. Czemu nie \"? Jeśli chcesz mieć jeden znak, nie musisz nawet go escape'ować a w dłuższym tekście masz też raw stringi std::cout << R"(taki "długi" tekst, escape'ować niczego nie trzeba, a nawet nie można
enter starcza jako \n, bo "\n" przecież nie można. )"; |
|
tBane Temat założony przez niniejszego użytkownika |
» 2024-07-05 18:39:00 na chwilę obecną świat ma 16x16 map o wymiarach 16x16 pól. Czym się różnią te stringi i jaki kiedy stosować ? cout << "hello world!"; cout << L"(hello world!)"; cout << R"(hello world!)";
|
|
pekfos |
» 2024-07-05 18:59:40 L znaczy że typem znakowym ma być wchar_t, to niezwiązane bo możesz zrobić też LR"(....)";. W raw stringach nawiasy są częścią składni a nie napisu. przed otwarciem nawiasu można podać token tak żeby zamknięcie napisu było unikalne i można było w nim podać cokolwiek: #include <iostream>
int main() { std::cout << R"x( // teraz zamknięcie napisu musi być z 'x' w )"
#include <iostream>
int main()
{
std::cout << R"(taki "długi" tekst, escape'ować niczego nie trzeba, a nawet nie można
enter starcza jako \n, bo "\n" przecież nie można. )";
}
)x"; } https://en.cppreference.com/w/cpp/language/string_literal |
|
tBane Temat założony przez niniejszego użytkownika |
» 2024-07-07 18:29:12 Ok, rozumiem. |
|
tBane Temat założony przez niniejszego użytkownika |
» 2024-07-10 17:01:51 Mam buga, wiem gdzie i nie wiem jak naprawić. BUG polega na tym, że potworek znika gdy mapa do której jest przypisany jest ustawiona na isVisible = false. Potrzebuję aby potworki były inaczej przetwarzane i nie znikały w dowolnej odległości od mapy gdy ścigają gracza. Myślałem nad tym, by update'ować potworki niezależnie czy mapa do której są przypisane jest widoczna czy też nie, ale uważam, że to nie jest prawidłowe rozwiązanie, gdyż było by to mocno obciążające jeśli chodzi o CPU. video z BUGIEM: https://youtu.be/da7tK98Oe-0maps.hppvoid mapVisiblings() { sf::Vector2f map_position; for( auto & map: maps ) { map_position.x =( int( map->coords.x ) * 16 * tileSide ) + 8 * tileSide; map_position.y =( int( map->coords.y ) * 16 * tileSide ) + 8 * tileSide; float width = screenWidth * 2.0f; float height = screenHeight * 2.0f; viewRect = sf::RectangleShape( sf::Vector2f( width, height ) ); viewRect.setOrigin( width / 2.0f, height / 2.0f ); viewRect.setPosition( viewPosition ); viewRect.setFillColor( sf::Color( 128, 48, 48, 128 ) ); bool visible = intersectionTwoRectangles( viewPosition.x, viewPosition.y, width, height, map_position.x, map_position.y, 16 * tileSide, 16 * tileSide ); if( map->isVisible == false && visible == true ) { map->showVisibleGameObjects(); } if( map->isVisible == true && visible == false ) { map->hideUnvisibleGameObject(); } map->isVisible = visible; } }
void showVisibleGameObjects() { for( auto & monster: _monsters ) { monster->isVisible = true; gameObjects.push_back( monster ); monsters.push_back( monster ); } for( auto & nature: _natures ) { nature->isVisible = true; gameObjects.push_back( nature ); natures.push_back( nature ); } }
void hideUnvisibleGameObject() { for( auto & monster: _monsters ) { monster->isVisible = false; } for( auto & nature: _natures ) { nature->isVisible = false; } std::vector < GameObject * > new_gameObjects; std::vector < Monster * > new_monsters; std::vector < Nature * > new_natures; new_gameObjects.clear(); new_monsters.clear(); new_natures.clear(); for( auto & go: gameObjects ) { if( go->isVisible == true ) { new_gameObjects.push_back( go ); if( go->type == gameObjectType::Monster ) new_monsters.push_back( dynamic_cast < Monster * >( go ) ); if( go->type == gameObjectType::Nature ) new_natures.push_back( dynamic_cast < Nature * >( go ) ); } gameObjects = new_gameObjects; monsters = new_monsters; natures = new_natures; } |
|
« 1 » 2 |