Фигуры

Введение

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

Общие свойства фигур

Трансформация (позиция, поворот, масштаб)

Это свойство является общим для всех графических классов SFML, поэтому они описаны в отдельном руководстве: (пока тут ссылка на не переведённый оригинал).

Цвет

Одно из главнейших свойств фигур — это их цвет, который можно менять с помощью метода setFillColor().

sf::CircleShape shape(50);

// задаём фигуре зелёный цвет
shape.setFillColor(sf::Color(100, 250, 50));

graphics-shape-color

 

Контур

Фигуры могут иметь контур. Вы можете задать толщину и цвет контура методами setOutlineThickness() и setOutlineColor().

sf::CircleShape shape(50);
shape.setFillColor(sf::Color(150, 50, 250));

// задаём контур толщиной 10 пикселей оранжевого цвета
shape.setOutlineThickness(10);
shape.setOutlineColor(sf::Color(250, 150, 100));

graphics-shape-outline

По умолчанию контур вырисовывается снаружи фигуры (если у вас есть круг с радиусом 10 и контур толщиной 5, то вы получите круг с радиусом 15). Контур можно применять и по направлению к центру фигуры, для этого необходимо задавать отрицательные значения толщины.

Для того что бы убрать контру, необходимо задать нулевую толщину. Если же вам нужен только контур, то в функции setFillColor() следует задать в качестве аргумента цвет sf::Color::Transparent.

Текстура

Фигуры, также как и спрайты, могут быть затекстурированы. Для указания того, какая часть текстуры должна отобразиться на фигуре, вам необходимо использовать метод setTextureRect(). Он принимает в качестве аргумента прямоугольную область текстуры для сопоставления ограничивающего прямоугольника фигуре. Этот метод не обеспечивает максимальной гибкости, но зато он гораздо проще в использовании, чем индивидуальное задание текстурных координат каждой точке фигуры.

sf::CircleShape shape(50);

// сопоставляем текстурированный прямоугольник 100x100 фигуре
shape.setTexture(&texture); // texture это sf::Texture
shape.setTextureRect(sf::IntRect(10, 10, 100, 100));

graphics-shape-texture

Обратите внимание что контур не текстурируется.

В случае когда фигура имеет цвет заливки, текстура модулируется (умножается) на него. Для отключения текстурирования следует вызвать setTexture(NULL).

Рисование фигуры

Рисование фигур такое же простое как и рисование других объектов SFML:

window.draw(shape);

Типы форм

Прямоугольник

Для рисования прямоугольников необходимо использовать класс sf::RectangleShape. Он имеет только одно свойство: размер прямоугольника.

// определяем прямоугольник размером 120x50
sf::RectangleShape rectangle(sf::Vector2f(120, 50));

// меняем размер 100x100
rectangle.setSize(sf::Vector2f(100, 100));

graphics-shape-rectangle

Круг

Круг представлен классом sf::CircleShape. Класс имеет два свойства: радиус и количество граней. Количество граней является дополнительным свойством, позволяющим настроить качество отображения круга: круги имитируются многоугольниками с большим числом граней (видеокарты просто не способны рисовать идеальные круги), в общем это свойство устанавливает число граней. Если вы рисуете маленькие круги, то вам нужно совсем немного граней что бы они отображались достаточно гладкими. Обратное тоже верно — чем больше круг, тем больше нужно граней.

// определяем круг с радиусом = 200
sf::CircleShape circle(200);

// меняем радиус на 40
circle.setRadius(40);

// меняем число граней на 100
circle.setPointCount(100);

Правильные многоугольники

На самом деле для них нет отдельного класса, да он и не нужен. Воспользовавшись классом sf::CircleShape и установив число граней равным 3, мы получим треугольник, если взять 4 грани, то получится квадрат и т.д.

// определяем треугольник
sf::CircleShape triangle(80, 3);

// определяем квадрат
sf::CircleShape square(80, 4);

// определяем восьмиугольник
sf::CircleShape octagon(80, 8);

graphics-shape-regular

Выпуклые фигуры

Класс sf::ConvexShape является последним из классов фигур: он позволяет определить фигуру, до тех пор пока она является выпуклой. Действительно, SFML не способен нарисовать вогнутые фигуры; если такие нарисовать необходимо, то их всегда можно разбить на несколько выпуклых.

Для определения выпуклой фигуры для начала необходимо указать общее число точек-вершин, и только потом определить эти точки.

// создаём пустую фигуру
sf::ConvexShape convex;

// изменяем размер на 5 вершин
convex.setPointCount(5);

// определяем вершины
convex.setPoint(0, sf::Vector2f(0, 0));
convex.setPoint(1, sf::Vector2f(150, 10));
convex.setPoint(2, sf::Vector2f(120, 90));
convex.setPoint(3, sf::Vector2f(30, 100));
convex.setPoint(4, sf::Vector2f(0, 50));

Очень важно определять вершины по часовой или против часовой стрелки, если определять их в произвольном порядке, то результат может быть непредсказуем!

graphics-shape-convex

Формально, sf::ConvexShape позволяет создавать только выпуклые фигуры. На деле же требования немножко мягче..На самом деле ваша форма должна соответствовать следующему критерию: любая из линий проведённых от центра тяжести фигуры до вершины, не должна пересекать границу фигуры. Следуя этому правилу можно, например, рисовать звёзды.

Линии

Для линий нет отдельного класса. Причина очень простая: если у линии есть толщина, используется фигура прямоугольник, если толщины нет, используется примитив линия.

Линия с толщиной:

sf::RectangleShape line(sf::Vector2f(150, 5));
line.rotate(45);

graphics-shape-line-rectangle

 

Линия без толщины:

sf::Vertex line[] =
{
 sf::Vertex(sf::Vector2f(10, 10)),
 sf::Vertex(sf::Vector2f(150, 150))
};

window.draw(line, 2, sf::Lines);

graphics-shape-line-primitive

 

Больше о примитивах будет рассказано в другом уроке (пока тут ссылка на не переведённый оригинал).

Пользовательские типы фигур

Вы можете расширить набор классов, имеющих свои типы форм. Для этого понадобится создать производный класс от класса sf::Shape и переопределить два метода:

  • getPointCount: возвращает число вершин фигуры
  • getPoint: возвращает вершину фигуры

Кроме того, каждый раз как у вашей фигуры изменяются вершины, вы должны вызывать защищённый (protected) метод update(), что бы базовый класс знал об этом и мог обновить своё состояние.

Вот полный пример создания подобного класса class: EllipseShape:

class EllipseShape : public sf::Shape
{
public :

 explicit EllipseShape(const sf::Vector2f& radius = sf::Vector2f(0, 0)) :
 m_radius(radius)
 {
 update();
 }

 void setRadius(const sf::Vector2f& radius)
 {
 m_radius = radius;
 update();
 }

 const sf::Vector2f& getRadius() const
 {
 return m_radius;
 }

 virtual unsigned int getPointCount() const
 {
 return 30; // здесь фиксировано, но может быть атрибутом класса, если это необходимо
 }

 virtual sf::Vector2f getPoint(unsigned int index) const
 {
 static const float pi = 3.141592654f;

 float angle = index * 2 * pi / getPointCount() - pi / 2;
 float x = std::cos(angle) * m_radius.x;
 float y = std::sin(angle) * m_radius.y;

 return sf::Vector2f(m_radius.x + x, m_radius.y + y);
 }

private :

 sf::Vector2f m_radius;
};

graphics-shape-ellipse

Сглаживание фигур

Нет каких-то функций для сглаживания конкретной фигуры. Если вы хотите получить сглаженные края фигур, то необходимо включить глобальное сглаживание на этапе создания окна. Это делается при помощи соответствующего атрибута структуры sf::ContextSettings.

sf::ContextSettings settings;
settings.antialiasingLevel = 8;

sf::RenderWindow window(sf::VideoMode(800, 600), "SFML shapes", sf::Style::Default, settings);

graphics-shape-antialiasing

 

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

3 Комментарии

  1. Maroon6

    Перевод отличный. Спасибо, что продолжаешь выкладывать.

  2. Андрей

    Сглаживание работает только с треуголниками.

  3. Сергей

    Мне нужно нарисовать несколько правильных многоугольников. Почему у меня при значении PointCount = 3, 4 и т.д. всё равно рисуются круги? ContextSettings не помогает.
    Видеокарта Radeon HD 7640G + HD 7600M Dual Graphics

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

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

Капча * Лимит времени истёк. Пожалуйста, перезагрузите CAPTCHA.

Этот сайт использует Akismet для борьбы со спамом. Узнайте как обрабатываются ваши данные комментариев.