SFML и C++ Уроки \ Разработка игр › Форумы › SFML Graphics › Рисование карты, оптимизация алгоритма
В этой теме 14 ответов, 5 участников, последнее обновление RazorNd 7 года/лет, 1 месяц назад.
-
АвторСообщения
-
Всем привет!
Как можно оптимизировать программу? У меня есть функция которая рисует карту, размер карты 30×50, т.е в ней 1500 элементов. Эта функция вызывается много-много раз в секунду из главного цикла функции main. На каждый ее вызов расходуется много времени
C++1234567891011121314void DrawMap(sf::RenderWindow &window){for (int y=0; y<CY_MAP; ++y)for (int x=0; x<CX_MAP; ++x){if (map[y][x] == 0)continue; // Фон не рисуем.mapSprite.setTextureRect( sf::IntRect((map[y][x]%10-1)*16, map[y][x]/10*16, 16, 16) ); // 16 - ширина и высота каждого спрайтаmapSprite.setPosition(x*16, y*16);window.draw(mapSprite);}}Есть идея чтобы создать задний (невидимый) буфер и сначала рисовать на нем, а после полной прорисовки скопировать его содержимое на главное окно.
Но как это сделать? Какой тип данных должен быть у буфера? sf::Texture или может sf::Window? Не знаю как всё это правильно организовать.
Дайте советы
C++12345678910111213int vievX=view.getCenter().x,viewY= view.getCenter().y;for (int y=0; y<CY_MAP; ++y)for (int x=0; x<CX_MAP; ++x){if (map[y][x] == 0)continue; // Фон не рисуем.mapSprite.setTextureRect( sf::IntRect((map[y][x]%10-1)*16, map[y][x]/10*16, 16, 16) ); // 16 - ширина и высота каждого спрайтаmapSprite.setPosition(x*16, y*16);int dist = sqrt((mapSprite.getPosition().x - viewX)*(mapSprite.getPosition().x - viewX) + (mapSprite.getPosition().y - wiewY)*(mapSprite.getPosition().y - wiewY));if (dist<600)window.draw(mapSprite);}Легче просто отрисовать спрайты в определенном радиусе вокруг центра камеры.
а лучше даже так:
C++123456mapSprite.setPosition(x*16, y*16);int dist = sqrt((mapSprite.getPosition().x - viewX)*(mapSprite.getPosition().x - viewX) + (mapSprite.getPosition().y - wiewY)*(mapSprite.getPosition().y - wiewY));if (dist<600){ mapSprite.setTextureRect( sf::IntRect((map[y][x]%10-1)*16, map[y][x]/10*16, 16, 16) );window.draw(mapSprite);}Дело в том, что у меня в окне вся карта видна. Т.е. в камеру вся карта попадает. Так что это не выход.
И из-за того что все объекты одновременно видны, их все нужно рисовать, нужно проходиться по массиву из 1500 элементов и рисовать в окне.
Как создать невидимый буфер и сначала на нем нарисовать, а после прорисовки скопировать его в главное окно?
У меня только что еще вопрос появился)) Смотрите, в каком месте происходит рисование в окне?
C++1234window.clear( sf::Color(50,50,50) );DrawMap(window);myTank->Draw(window);window.display();Функция window.dispaly() ведь рисует в окне? Другие функции тоже рисуют на главном окне или нет? Вот
Нет display отображает на екране, а рисует Draw. А разве 1500 элементов много ? Например у меня карта 50*80 с физикой и освещением. Проц нагружен на 30% видеокарта на 40%, 75 000 кадров в секунду.
Насколько я понял вы хотите 1500 тайлов сначала слепить в 1 ,и потом рисовать как 1 ?
Сейчас посмотрел в диспетчере задач, нагрузка от этой программы маленькая. Так что наверно не буду менять функцию. Пусть так остается) Спасибо
Всем привет! Подскажите как вид камеры расположить так, чтобы игрок вместе с картой двигался не вправо, а вперед, т.е. это будет не игра типа марио,а обычная ходилка
Есть у меня подобная проблема. Отрисовываются 21к спрайтов размером 16Х16. Вроде производительность нормальная, но когда пытаюсь рисовать 21к rectangleShape начинаются лаги, как исправить?
В общем я решил склеить, алгоритм такой
C++1234567891011121314151617181920212223sf::Image imgMap;imgMap.create(255*16,156*16, sf::Color(100,100,100,100));for (int i = 0; i < 156; ++i){for (int x = 0; x < 255; ++x){if (field[i][x].G == 216){for (int q = 0; q < 16; ++q){for (int w = 0; w < 16; ++w){imgMap.setPixel(x*16+q, i*16+w, image.getPixel(16+w, 0+q));}}}if (field[i][x].G == 148) {for (int q = 0; q < 16; ++q){for (int w = 0; w < 16; ++w){imgMap.setPixel(x*16+q, i*16+w, image.getPixel(0+w, 0+q));}}}if (field[i][x].G == 255) {for (int q = 0; q < 16; ++q){for (int w = 0; w < 16; ++w){imgMap.setPixel(x*16+q, i*16+w, image.getPixel(32+w, 0+q));}}}if (field[i][x].G == 0) {for (int q = 0; q < 16; ++q){for (int w = 0; w < 16; ++w){imgMap.setPixel(x*16+q, i*16+w, image.getPixel(48+w, 0+q));}}}}}стало намного быстрее, но сама склейка идёт долго, так что скорее всего подойдёт только для статических карт, и для меня в перспективе не подходит, хочется туман войны и чтобы водичка плескалась.
Вообще есть класс sf::RenderTexture. С ним можно работать так же как и с sf::RenderWindow. Вот ссылка на доку с примером.
Ну у класса sf::RenderTexture есть недостаток, например максимальный размер в 8192×8192
barbar, данная проблема не у sf::RenderTexture. То о чем вы говорите это проблема sf::Texture. Кстати, там необязательно 8192×8192, это зависит от видеокарты. В любом случае вы не сможете целиком загрузить ваше большое изображение в текстуру и вам так же придется создавать отдельные текстуры под разные части изображения.
-
АвторСообщения
Для ответа в этой теме необходимо авторизоваться.