SFML2.6 图形模块 您所在的位置:网站首页 图像镜面翻转怎么设置 SFML2.6 图形模块

SFML2.6 图形模块

2024-06-02 04:23| 来源: 网络整理| 查看: 265

变换SFML实体

所有SFML类(精灵、文本、形状)都使用相同的界面进行转换:sf::Transformable。这个基类提供了一个简单的API来移动、旋转和缩放你的实体。它不提供最大的灵活性,而是定义了一个易于理解和使用的接口,覆盖了99%的所有用例——对于剩下的1%,请参阅最后一章。

sf::Transformable(以及所有派生类)定义了四个属性:位置、旋转、比例和原点。它们都有各自的getter和setter。这些变换组件都是相互独立的:如果你想改变实体的方向,你只需要设置它的旋转属性,你不必关心当前的位置和比例。

位置

位置是实体在2D世界中的位置。我认为它不需要更多的解释。 😃

// 'entity' can be a sf::Sprite, a sf::Text, a sf::Shape or any other transformable class // set the absolute position of the entity entity.setPosition(10.f, 50.f); // move the entity relatively to its current position entity.move(5.f, 5.f); // retrieve the absolute position of the entity sf::Vector2f position = entity.getPosition(); // = (15, 55)

在这里插入图片描述 默认情况下,实体是相对于它们的左上角定位的。我们稍后将看到如何使用“原点”属性更改它。

旋转

旋转是实体在二维世界中的方向。它以度数定义,按顺时针顺序(因为在SFML中,Y轴向下指向)。

// 'entity' can be a sf::Sprite, a sf::Text, a sf::Shape or any other transformable class // set the absolute rotation of the entity entity.setRotation(45.f); // rotate the entity relatively to its current orientation entity.rotate(10.f); // retrieve the absolute rotation of the entity float rotation = entity.getRotation(); // = 55

在这里插入图片描述 请注意,当您调用 getRotation 时,SFML始终以[0,360)的范围返回角度。

与位置一样,旋转默认情况下围绕左上角执行,但可以通过设置原点来更改。

缩放

比例因子允许调整实体的大小。默认比例为1。将其设置为小于1的值会使实体变小,大于1的值会使实体变大。也可以使用负的比例值,以便您可以镜像实体。

// 'entity' can be a sf::Sprite, a sf::Text, a sf::Shape or any other transformable class // set the absolute scale of the entity entity.setScale(4.f, 1.6f); // scale the entity relatively to its current scale entity.scale(0.5f, 0.5f); // retrieve the absolute scale of the entity sf::Vector2f scale = entity.getScale(); // = (2, 0.8)

在这里插入图片描述

原点

原点是三个其他变换的中心点。实体的位置是它的原点的位置,它的旋转是围绕原点进行的,并且比例也相对于原点应用。默认情况下,它是实体的左上角(点(0,0)),但是您可以将其设置为实体的中心或实体的任何其他角落。

为了简化事情,所有三个变换组件只有一个原点。这意味着您无法将实体相对于其左上角定位,同时围绕其中心旋转。如果您需要执行此类操作,请查看下一章节。

// 'entity' can be a sf::Sprite, a sf::Text, a sf::Shape or any other transformable class // set the origin of the entity entity.setOrigin(10.f, 20.f); // retrieve the origin of the entity sf::Vector2f origin = entity.getOrigin(); // = (10, 20)

请注意,更改原点也会更改实体在屏幕上绘制的位置,即使其位置属性没有更改。如果您不理解原因,请再次阅读本教程!

转换你自己的类

sf::Transformable不仅适用于SFML的类,它也可以是你自己的类的基类或成员。

class MyGraphicalEntity : public sf::Transformable { // ... }; MyGraphicalEntity entity; entity.setPosition(10.f, 30.f); entity.setRotation(110.f); entity.setScale(0.5f, 0.2f);

如果你需要获取实体的最终变换(通常在绘制它时需要),可以调用getTransform函数。该函数返回一个sf::Transform对象。下面将解释如何使用它来转换SFML实体。

如果你不需要或不想使用sf::Transformable接口提供的完整函数集,可以将其作为成员使用,并在其上提供自己的函数。它不是一个抽象类,因此可以实例化它,而不仅仅是将其用作基类。

自定义变换

sf::Transformable类易于使用,但也具有一定的限制。某些用户可能需要更灵活的功能。他们可能需要将最终变换指定为单个变换的自定义组合。针对这些用户,有一个更低级别的类可用:sf :: Transform。它不过是一个3x3矩阵,因此它可以表示2D空间中的任何变换。

有许多构造sf::Transform的方法:

使用最常见变换(平移、旋转、缩放)的预定义函数通过组合两个变换通过直接指定其9个元素

以下是一些示例:

// the identity transform (does nothing) sf::Transform t1 = sf::Transform::Identity; // a rotation transform sf::Transform t2; t2.rotate(45.f); // a custom matrix sf::Transform t3(2.f, 0.f, 20.f, 0.f, 1.f, 50.f, 0.f, 0.f, 1.f); // a combined transform sf::Transform t4 = t1 * t2 * t3;

您也可以将几个预定义变换应用于同一个变换。它们将按顺序依次组合。请注意,通过组合多个变换来转换对象等效于以相反的顺序应用每个操作。最后一个操作(在此处为缩放)首先应用,并且将受到代码上方的操作的影响(例如第二个操作可能是translate(-10.f,50.f))。

sf::Transform t; t.translate(10.f, 100.f); t.rotate(90.f); t.translate(-10.f, 50.f); t.scale(0.5f, 0.75f);

回到重点:如何将自定义变换应用于图形实体?简单:将它传递给draw函数即可。

window.draw(entity, transform);

…实际上是以下代码的简写:

sf::RenderStates states; states.transform = transform; window.draw(entity, states);

如果你的实体是 sf::Transformable(如:sprite、text、shape),它包含自己的内部 transform,那么这两个 transform 会合并成最终的 transform。

边界框

对于已经进行过变换并且绘制出来的实体,你可能想要执行一些计算,例如检查它们之间是否发生了碰撞。

SFML 实体可以提供它们的边界框。边界框是一个最小矩形,它包含了实体的所有点,并且边缘与 X 和 Y 轴对齐。 在这里插入图片描述 边界框在实现碰撞检测时非常有用:可以非常快速地检查点或另一个轴对齐矩形与其之间的关系,并且其面积足够接近真实实体的面积,从而提供了一个很好的近似值。

// get the bounding box of the entity sf::FloatRect boundingBox = entity.getGlobalBounds(); // check collision with a point sf::Vector2f point = ...; if (boundingBox.contains(point)) { // collision! } // check collision with another box (like the bounding box of another entity) sf::FloatRect otherBox = ...; if (boundingBox.intersects(otherBox)) { // collision! }

函数被命名为getGlobalBounds,因为它返回实体在全局坐标系中的边界框,即在应用所有变换(位置、旋转、缩放)后的边界框。

还有另一个函数getLocalBounds,它返回实体在其本地坐标系中的边界框(在应用变换之前)。例如,可以使用此函数获取实体的初始大小或执行更特定的计算。

对象层次结构(场景图)

使用前面介绍的自定义变换,实现对象层次结构(场景图)变得非常简单,其中子对象相对于其父对象进行变换。在绘制它们时,您只需要将从父对象到子对象的组合变换传递即可,一直到达最终可绘制的实体(精灵、文本、形状、顶点数组或您自己的可绘制实体)。

// the abstract base class class Node { public: // ... functions to transform the node // ... functions to manage the node's children void draw(sf::RenderTarget& target, const sf::Transform& parentTransform) const { // combine the parent transform with the node's one sf::Transform combinedTransform = parentTransform * m_transform; // let the node draw itself onDraw(target, combinedTransform); // draw its children for (std::size_t i = 0; i draw(target, combinedTransform); } private: virtual void onDraw(sf::RenderTarget& target, const sf::Transform& transform) const = 0; sf::Transform m_transform; std::vector m_children; }; // a simple derived class: a node that draws a sprite class SpriteNode : public Node { public: // .. functions to define the sprite private: virtual void onDraw(sf::RenderTarget& target, const sf::Transform& transform) const { target.draw(m_sprite, transform); } sf::Sprite m_sprite; };


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有