SaveText.Ru

Без имени
  1. // level.h
  2. #pragma once
  3.  
  4. #include <SFML/Graphics.hpp>
  5. #include "tinyxml2.h"
  6. #include <iostream>
  7. #include <cctype>
  8.  
  9. class Object
  10. {
  11. public:
  12.         Object(float x, float y, float width, float height) : rect(x, y, width, height)
  13.         {
  14.  
  15.         }
  16.  
  17.         int         GetPropertyInt(const std::string& name);
  18.         float       GetPropertyFloat(const std::string& name);
  19.         std::string GetPropertyString(const std::string& name);
  20.  
  21.         std::string name;
  22.         std::string type;
  23.         std::map<std::string, std::string> properties;
  24.         sf::FloatRect rect;
  25. };
  26.  
  27. class TileMap : public sf::Drawable
  28. {
  29. public:
  30.         ~TileMap();
  31.  
  32.         bool load(const std::string& tmx_file_path);
  33.  
  34.         Object               getObject(const std::string& name);
  35.         std::vector<Object>  getObjectsByName(const std::string& name);
  36.         std::vector<Object>  getObjectsByType(const std::string& type);
  37.         std::vector<Object>& getAllObjects();
  38.  
  39. private:
  40.         void draw(sf::RenderTarget& target, sf::RenderStates states) const;
  41.  
  42.         sf::Texture* texture;
  43.         std::vector<sf::VertexArray> tile_layers;
  44.         std::vector<Object>          objects;
  45. };
  46.  
  47. TileMap::~TileMap()
  48. {
  49.         /*if (texture)
  50.                 delete texture;*/
  51. }
  52.  
  53. bool TileMap::load(const std::string& tmx_file_path)
  54. {
  55.         tinyxml2::XMLDocument document;
  56.  
  57.         if (document.LoadFile(tmx_file_path.c_str()) != tinyxml2::XML_SUCCESS)
  58.         {
  59.                 std::cout << "Loading file " << tmx_file_path << " failed..." << std::endl;
  60.                 return false;
  61.         }
  62.         // ѕолучаем все данные тайлсета
  63.         tinyxml2::XMLElement* root_element = document.FirstChildElement("map");
  64.         const size_t tile_width = std::stoul(root_element->Attribute("tilewidth"));
  65.         const size_t tile_height = std::stoul(root_element->Attribute("tileheight"));
  66.  
  67.         auto tileset = root_element->FirstChildElement("tileset");
  68.         const size_t tile_count = std::stoul(tileset->Attribute("tilecount"));
  69.         const size_t columns = std::stoul(tileset->Attribute("columns"));
  70.         // ѕолучаем путь до файла
  71.         auto image = tileset->FirstChildElement("image");
  72.         std::string path = image->Attribute("source");
  73.  
  74.         while (!isalpha(path.front())) // ≈сли путь редактор записал, например, так : "../textures/Tiles.png"
  75.                 path.erase(0, 1);          // то убираем все лишние символы в начале строки ( ../ ), чтобы избежать сбо€ загрузки
  76.  
  77.         texture = new sf::Texture();
  78.  
  79.         if (!texture->loadFromFile(path))
  80.                 return false;
  81.         // —оздаЄм сетку, где индекс каждого тайла зависит от его координат в текстуре
  82.         // Ќапример, если ширина тайла 32 пиксел€, координаты в текстуре :
  83.         // первого тайла (0, 0), второго (32, 0), третьего (64, 0) и так далее
  84.         std::vector<sf::Vector2f> texture_grid;
  85.         texture_grid.reserve(tile_count);
  86.  
  87.         size_t rows = tile_count / columns;
  88.  
  89.         for (size_t y = 0u; y < rows; ++y)
  90.                 for (size_t x = 0u; x < columns; ++x)
  91.                         texture_grid.emplace_back(sf::Vector2f((float)x * tile_width, (float)y * tile_height));
  92.         // ќбрабатываем csv-массивы
  93.         for (auto layer = root_element->FirstChildElement("layer");
  94.                 layer != nullptr;
  95.                 layer = layer->NextSiblingElement("layer"))
  96.         {
  97.                 /*if (!layer)
  98.                 {
  99.                         std::cerr << "Bad map. No layer information found." << std::endl;
  100.                         return false;
  101.                 }*/
  102.                 // Ўирина и высота сло€ в тайлах
  103.                 const size_t width = std::stoul(layer->Attribute("width"));
  104.                 const size_t height = std::stoul(layer->Attribute("height"));
  105.                 // ѕереводим слой в вектор целых чисел, где каждое число - номер тайла в тайлсете
  106.                 tinyxml2::XMLElement* data = layer->FirstChildElement("data");
  107.                 std::string dirty_string = data->GetText(), buffer;
  108.  
  109.                 std::vector<size_t> csv_array;
  110.                 csv_array.reserve(dirty_string.size());
  111.  
  112.                 for (auto& character : dirty_string)
  113.                 {
  114.                         if (isdigit(character))
  115.                                 buffer += character;
  116.                         else
  117.                                 if (!buffer.empty())
  118.                                 {
  119.                                         csv_array.push_back(std::stoi(buffer));
  120.                                         buffer.clear();
  121.                                 }
  122.                 }
  123.                 csv_array.shrink_to_fit();
  124.                 // —оздаЄм массив вершин
  125.                 sf::VertexArray vertices;
  126.                 vertices.setPrimitiveType(sf::Quads);
  127.  
  128.                 for (size_t y = 0u, index = 0u; y < height; ++y)
  129.                 {
  130.                         for (size_t x = 0u; x < width; ++x, ++index)
  131.                         {
  132.                                 size_t tile_num = csv_array[index];
  133.                                 // ≈сли номер тайла больше нул€, то есть место не пусто - записываем тайл в массив вершин
  134.                                 if (tile_num)
  135.                                 {   // ќбходим по часовой стрелке
  136.                                         sf::Vertex leftTop;     // Ћевый верхний угол тайла
  137.                                         sf::Vertex rightTop;    // ¬ерхний правый
  138.                                         sf::Vertex rightBottom; // Ќижний правый
  139.                                         sf::Vertex leftBottom;  // Ќижний левый
  140.                                         // ”станавливаем тайл в позицию на карте
  141.                                         leftTop.position = sf::Vector2f((float)x * tile_width, (float)y * tile_height);
  142.                                         rightTop.position = sf::Vector2f(((float)x + 1) * tile_width, (float)y * tile_height);
  143.                                         rightBottom.position = sf::Vector2f(((float)x + 1) * tile_width, (float)(y + 1) * tile_height);
  144.                                         leftBottom.position = sf::Vector2f((float)x * tile_width, (float)(y + 1) * tile_height);
  145.                                         // ќпредел€ем его текстурные координаты
  146.                                         leftTop.texCoords = sf::Vector2f(texture_grid[tile_num - 1].x, texture_grid[tile_num - 1].y);
  147.                                         rightTop.texCoords = sf::Vector2f(texture_grid[tile_num - 1].x + tile_width, texture_grid[tile_num - 1].y);
  148.                                         rightBottom.texCoords = sf::Vector2f(texture_grid[tile_num - 1].x + tile_width, texture_grid[tile_num - 1].y + tile_height);
  149.                                         leftBottom.texCoords = sf::Vector2f(texture_grid[tile_num - 1].x, texture_grid[tile_num - 1].y + tile_height);
  150.  
  151.                                         vertices.append(leftTop);
  152.                                         vertices.append(rightTop);
  153.                                         vertices.append(rightBottom);
  154.                                         vertices.append(leftBottom);
  155.                                 }
  156.                         }
  157.                 }
  158.                 tile_layers.push_back(std::move(vertices));
  159.         }
  160.         // «агружаем объекты, если есть
  161.         for (auto object_group = root_element->FirstChildElement("objectgroup");
  162.                 object_group != nullptr;
  163.                 object_group = object_group->NextSiblingElement("objectgroup"))
  164.         {// ѕолучаем все данные - тип, им€, позици€, etc
  165.                 for (auto object = object_group->FirstChildElement("object");
  166.                         object != nullptr;
  167.                         object = object->NextSiblingElement("object"))
  168.                 {
  169.                         std::string object_name;
  170.                         if (object->Attribute("name"))
  171.                                 object_name = object->Attribute("name");
  172.  
  173.                         std::string object_type;
  174.                         if (object->Attribute("type"))
  175.                                 object_type = object->Attribute("type");
  176.  
  177.                         float x = std::stof(object->Attribute("x"));
  178.                         float y = std::stof(object->Attribute("y"));
  179.  
  180.                         float width{}, height{};
  181.  
  182.                         if (object->Attribute("width") && object->Attribute("height"))
  183.                         {
  184.                                 width = std::stof(object->Attribute("width"));
  185.                                 height = std::stof(object->Attribute("height"));
  186.                         }
  187.  
  188.                         Object new_object(x, y, width, height);
  189.                         new_object.name = object_name;
  190.                         new_object.type = object_type;
  191.  
  192.                         auto properties = object->FirstChildElement("properties");
  193.  
  194.                         if (properties)
  195.                         {
  196.                                 for (auto property = properties->FirstChildElement("property");
  197.                                         property != nullptr;
  198.                                         property = property->NextSiblingElement("property"))
  199.                                 {
  200.                                         std::string name, value;
  201.  
  202.                                         if (property->Attribute("name"))
  203.                                                 name = property->Attribute("name");
  204.  
  205.                                         if (property->Attribute("value"))
  206.                                                 value = property->Attribute("value");
  207.  
  208.                                         new_object.properties[name] = value;
  209.                                 }
  210.                         }
  211.                         objects.emplace_back(std::move(new_object));
  212.                 }
  213.         }
  214.         return true;
  215. }
  216. // “олько первый объект с заданным именем
  217. Object TileMap::getObject(const std::string& name)
  218. {
  219.         auto found = std::find_if(objects.begin(), objects.end(), [&](const Object& obj)
  220.                 {
  221.                         return obj.name == name;
  222.                 });
  223.  
  224.         return *found;
  225. }
  226. // ¬се объекты с заданным именем
  227. std::vector<Object> TileMap::getObjectsByName(const std::string& name)
  228. {
  229.         std::vector<Object> objects_by_name;
  230.  
  231.         std::copy_if(objects.begin(), objects.end(), std::back_inserter(objects_by_name), [&](const Object& obj)
  232.                 {
  233.                         return obj.name == name;
  234.                 });
  235.  
  236.         return objects_by_name;
  237. }
  238. // ¬се объекты с заданным именем
  239. std::vector<Object> TileMap::getObjectsByType(const std::string& type)
  240. {
  241.         std::vector<Object> objects_by_type;
  242.  
  243.         std::copy_if(objects.begin(), objects.end(), std::back_inserter(objects_by_type), [&](const Object& obj)
  244.                 {
  245.                         return obj.type == type;
  246.                 });
  247.  
  248.         return objects_by_type;
  249. }
  250.  
  251. std::vector<Object>& TileMap::getAllObjects()
  252. {
  253.         return objects;
  254. }
  255.  
  256. void TileMap::draw(sf::RenderTarget& target, sf::RenderStates states) const
  257. {
  258.         for (auto& layer : tile_layers)
  259.                 target.draw(layer, texture);
  260. }
  261.  
  262. int Object::GetPropertyInt(const std::string& name)
  263. {
  264.         return std::stoi(properties[name]);
  265. }
  266.  
  267. float Object::GetPropertyFloat(const std::string& name)
  268. {
  269.         return std::stof(properties[name]);
  270. }
  271.  
  272. std::string Object::GetPropertyString(const std::string& name)
  273. {
  274.         return properties[name];
  275. }

Share with your friends:

Print