Спрайты и текстуры в C++/SFML

  Дмитрий Бушуев  | 

  Обновл. 26 Ноя 2020  | 

 15314

 ǀ   10 

“Я знаю, чем ты занимаешься… почему ты плохо спишь, почему живешь один и почему ночь за ночью сидишь за своим компьютером. Ты ищешь его. Я знаю, потому что я сама искала. И когда он нашел меня, он сказал, что на самом деле я искала не его. Я искала ответ. Этот вопрос ведет нас. Он сводит нас с ума! Этот вопрос привел тебя сюда. Ты знаешь этот вопрос точно так же, как и я… СПРАЙТЫ И ТЕКСТУРЫ… КАК SFML РАБОТАЕТ С НИМИ?”

Спрайты и текстуры

Итак, что же такое текстура, спрайт и чем они отличаются друг от друга.

   Текстура — это обычная картинка, которая накладывается на двумерный объект.

   Спрайт — это затекстурированный прямоугольник.

Ниже приведена картинка, демонстрирующая эти концепции, которую я нагло спёр из официальной документации по SFML.

Сложного здесь ничего нет, поэтому двигаемся дальше.

Загрузка текстуры


Прежде чем создавать какой-нибудь спрайт, нам нужна текстура. Класс SFML, который предоставляет возможность работать с текстурами, называется внезапно Texture. Так как единственной целью текстуры является её загрузка из источника и нанесение на объект, то назначение практически всех функций данного класса сводится в большинстве своем к двум задачам: к загрузке текстуры и к её отображению в программе.

Основным способом загрузки текстуры является считывание информации о ней из графического файла, расположенного на компьютере. Ниже я привел простейший пример по созданию спрайта и наложению на него текстуры:

Результат выполнения программы:

Стоит отметить, что библиотека SFML поддерживает работу со всеми основными форматами графических файлов.

Есть еще несколько способов загрузки текстуры:

   загрузка файла текстуры из памяти с помощью метода loadFromMemory();

   загрузка из потока с помощью метода loadFromStream();

   загрузка из файла, который уже был загружен, с помощью метода loadFromImage().

Все эти функции имеют необязательный аргумент, который можно использовать, если вы хотите загрузить лишь часть изображения. Например, следующий код загружает небольшой кусочек текстуры размером 32×32 пикселя, начинающийся с координат (10; 10):

Помимо этого, у текстуры есть два интересных свойства, которые влияют на то, как она будет отображаться на экране. Первое свойство — это сглаживание, которое делает границы пикселей менее видимыми (правда из-за этого изображение становится немного размытым). Например:

Особенно полезным это свойство является при масштабировании текстуры. Ниже в прикрепленной гифке вы можете увидеть разницу между вариантом со сглаживанием и без:

Второе интересное свойство позволяет многократно повторять текстуру в пределах одного спрайта. Например:

Результат выполнения программы:

Стоит отметить, что данный способ работает только тогда, когда размеры спрайта больше размеров текстуры, в противном случае — ничего не получится.

Также можно изменить и цвет самого спрайта, который будет мультипликативно складываться с текущей текстурой. Благодаря этому свойству удобно изменять значение прозрачности спрайта. Например:

Результат выполнения программы:

Трансформации

К спрайтам могут быть применены различные варианты трансформаций: изменение позиции, изменение ориентации в пространстве и масштабирование. Все они выполняются с помощью методов setPosition()/move(), setRotation()/rotate() и setScale()/scale(), соответственно. Вы можете спросить: «А почему данные методы написаны через слэш?». А дело в том, что первые методы в каждой паре производят абсолютные преобразования (преобразования относительно начала координат). Вторые же методы в каждой паре производят преобразования относительно текущих значений координат/угла/масштаба. Например:

Результат выполнения программы:

Точкой (началом координат), относительно которой происходят эти преобразования, является по умолчанию верхний левый угол спрайта. Если нам нужно установить начало координат в другую точку (например, в центр спрайта), то можно использовать метод setOrigin():

Проблема белого квадрата


Вы успешно загрузили текстуру, правильно построили спрайт и… всё, что вы видите на экране сейчас — это белый квадрат. Что случилось?

Это распространенная ошибка. Когда вы устанавливаете текстуру для спрайта, то «под капотом» сохраняется указатель на экземпляр текстуры. Поэтому, если текстура уничтожается или перемещается в другое место в памяти, спрайт получает некорректный указатель на текстуру.

Данная проблема возникает при написании следующего рода функций:

Поэтому всегда нужно перепроверять время жизни ваших текстур.

Использование большого количества текстур

Хорошей тактикой является использовать как можно меньше текстур. Причиной этому является то, что изменение текущей текстуры — это дорогостоящая операция для видеокарты. Рисование множества спрайтов, использующих одну и ту же текстуру, даст лучшую производительность.

Кроме того, использование одной текстуры позволяет группировать статическую геометрию в одну сущность, что будет намного быстрее отрисовываться, чем набор из множества сущностей. Постарайтесь помнить об этом и по возможности используйте как можно меньше текстур.

Заключение


На этом уроке мы разобрались со спрайтами и текстурами, научились накладывать текстуру на спрайт, изменять цвет. Поработали с различными типами трансформации спрайта: изменение положения, вращение, масштабирование (как в абсолютных, так и в относительных величинах). И даже рассмотрели проблему белого квадрата. На этом мы закончим знакомство с базовыми возможностями библиотеки SFML и будем двигаться дальше. Надеюсь, что вам понравилось, ведь впереди нас ждет нечто грандиозное…

«Ты можешь лучше.
Предела нет. Знай, ты можешь.
Будь уверен… Хватит попыток! Действуй!»

  GitHub / Спрайты и текстуры в C++/SFML — Исходный код

Оценить статью:

Звёзд: 1Звёзд: 2Звёзд: 3Звёзд: 4Звёзд: 5 (39 оценок, среднее: 4,95 из 5)
Загрузка...

Комментариев: 10

  1. Аватар Виталий:

    Здравствуйте, у меня вопрос. А может даже просьба.
    Подскажите мне. Может есть статья или тут мне подскажите.
    Вот есть готовая игра , а мне нужно стереть некоторые текстуры чтобы добиться багов в игре. Например пол дома в игре будет прозрачная. Мне чисто интересно для себя поиграть и поделать баги своими руками.
    Может подскажите как стирать текстуры ? Может статья есть какая ? Что да как и где так сказать.
    Заранее благодарен за ответ.

    1. Дмитрий Бушуев Дмитрий Бушуев:

      >>Вот есть готовая игра , а мне нужно стереть некоторые текстуры чтобы добиться багов в игре.
      Никогда не задавался таким вопросом. Обычно приходится решать обратную задачу — как заставить всё это дело работать без багов :). Поэтому даже и не знаю что подсказать.

  2. Аватар Владимир:

    Скажите, я сейчас делаю функцию, которая загружает текстуры один раз и потом эти текстуры могут быть использованы неограниченное кол-во раз. Я её реализовал, но она не отдаёт текстуры. Можете помочь?

    1. Дмитрий Бушуев Дмитрий Бушуев:

      >>Можете помочь?
      Для этого нужно увидеть исходники вашей программы… 🙂

  3. Аватар Евгений:

    > sf::Sprite — это прямоугольник, наложенный на текстуру
    > На изображениях — sf::CircleShape, наложенный на текстуру. Молодец, автор, бездумно копипастить…
    Стоит упомянуть, что операции с трансформациями весьма ресурсозатратны, но выполняются строго при вызове методов отрисовки.

    Также, забыт sf::Sprite::setTextureRect(). Это неотъемлемая часть спрайта, что в корне отличает его от других фигур в sfml и позволяет создавать анимированные элементы / сущности.

    Про методы проверки коллизий тоже стоило бы написать отдельную статью. Это всё про спрайт, да — да, материал выше, в основном, про sf::Texture и sf::RectangleShape

    1. Дмитрий Бушуев Дмитрий Бушуев:

      Автор, вот вы сами хоть понимаете, что пишете? Как по мне — это просто какой-то сплошной поток мыслей.

      >"Стоит упомянуть…"
      Да есть много чего, про что стоит упомянуть. Но тогда объем материала уже будет тянуть не на статью, а на небольшую книгу.

      Вообще говоря, когда я начинал писать данные статьи, то цель состояла в том, чтобы показать пользователям ravesli.com, освоившим раздел "Уроки С++", дальнейшие возможные пути продвижения в освоении языка C++.
      Вдаваться в какие бы то ни было тонкости и нюансы работы SFML в данном материале считаю абсолютно нецелесообразным.

      >"Про методы проверки коллизий тоже стоило бы написать отдельную статью…."
      Так напишите, кто ж вам мешает. Напишите и отправьте ее на admin@ravesli.com. Если всё будет в порядке, то администратор опубликует её на сайте (с указанием авторства), и вы получите благодарность в свой адрес от довольных читателей. 🙂

  4. Аватар Александр:

    Ждемс!
    Есть еще просьба. Вот мы рассмотрели довольно подробно возможности языка C++. Теперь на очереди, как я понимаю, разные фреймворки.
    Можно ли увидеть какую-то статью, где будет кратко расписано, какой фреймворк для какой категории задач предназначен?
    -фреймворк "А" для разработки 3D-игр;
    -фреймворк "B" для клиент-серверных приложений;
    -фреймворк "C" для разработки 2D-игр;
    -фреймвор для разработки VR-контента.

    1. Дмитрий Бушуев Дмитрий Бушуев:

      >>Можно ли увидеть какую-то статью, где будет кратко расписано, какой фреймворк для какой категории задач предназначен?

      Как я уже писал, сейчас готовится очень интересный материал по SFML ;). Дальше запланирована статья-продолжение туториалов по Qt. А за ней, я думаю, можно будет выпустить то, о чем вы просите, т.е. обзорную статью по различным C++-фреймворкам. 🙂

  5. Аватар Александр:

    А продолжение будет?! =)
    Большое спасибо за материал!

    1. Дмитрий Бушуев Дмитрий Бушуев:

      В данный момент готовится новая статья по SFML. Так что следите за анонсами 🙂

Добавить комментарий для Дмитрий Бушуев Отменить ответ

Ваш E-mail не будет опубликован. Обязательные поля помечены *