Sprites and textures

系列文章

SFML-windows 篇
SFML-Events explained 篇
SFML-Keyboard, mouse and joystick 篇
SFML-Using OpenGL in a SFML window 篇
SFML-Drawing 2D stuff 篇
SFML-Shapes 篇
SFML-Sprites and textures 篇


一、Vocabulary


你们中的大多数人(如果不是所有人)已经熟悉这两个非常常见的对象Sprites and textures,那么让我们非常简单地定义它们。

texture是一个图像。但我们称之为“ texture”,因为它有一个非常特殊的角色:映射到2D实体。

sprite只不过是一个纹理矩形。
在这里插入图片描述这就是Sprite and texture

二、Loading a texture


在创建任何精灵之前,我们需要一个有效的纹理。令人惊讶的是,在SFML中封装纹理的类是sf::Texture。由于纹理的唯一作用是加载并映射到图形实体,因此其几乎所有功能都与加载和更新有关。

加载纹理最常见的方法是从磁盘上的图像文件加载纹理,这是通过loadFromFile函数完成的。

sf::Texture texture;
if (!texture.loadFromFile("image.png"))
{
    // error...
}

loadFromFile函数有时会在没有明显原因的情况下失败。首先,检查SFML打印到标准输出的错误消息(检查控制台)。如果消息是“无法打开文件”,请确保工作目录(即任何文件路径将被解释的相对目录)是您认为的:当您从桌面环境运行应用程序时,工作目录是可执行文件夹。但是,当您从IDE启动程序时(Visual Studio,代码::块,…)工作目录有时可能设置为项目目录。这通常可以在项目设置中很容易地更改。

您还可以从内存(loadFromMemory)、自定义输入流(loadFromStream)或已加载的图像(loadFromImage)加载图像文件。后者从sf::Image加载纹理,这是一个帮助存储和操作图像数据(修改像素、创建透明度通道等)的实用类。sf::image的像素保留在系统内存中,这确保了对它们的操作将尽可能快,而纹理的像素位于视频内存中,因此检索或更新速度较慢,但绘制速度非常快。

SFML支持最常见的图像文件格式。完整列表可在API文档中找到。

所有这些加载函数都有一个可选参数,如果您想加载图像的较小部分,可以使用该参数。

// load a 32x32 rectangle that starts at (10, 10)
if (!texture.loadFromFile("image.png", sf::IntRect(10, 10, 32, 32)))
{
    // error...
}

IntRect类是一个表示矩形的简单实用程序类型。其构造函数采用左上角的坐标和矩形的大小。

如果您不想从图像加载纹理,而是想直接从像素阵列中更新纹理,可以将其创建为空,稍后再更新:

// create an empty 200x200 texture
if (!texture.create(200, 200))
{
    // error...
}

请注意,此时纹理的内容未定义。

要更新现有纹理的像素,必须使用更新功能。它具有多种数据源的重载:

// update a texture from an array of pixels
sf::Uint8* pixels = new sf::Uint8[width * height * 4]; // * 4 because pixels have 4 components (RGBA)
...
texture.update(pixels);

// update a texture from a sf::Image
sf::Image image;
...
texture.update(image);

// update the texture from the current contents of the window
sf::RenderWindow window;
...
texture.update(window);

这些示例都假设源与纹理大小相同。如果不是这种情况,即如果只想更新纹理的一部分,可以指定要更新的子矩形的坐标。有关更多详细信息,请参阅文档。

此外,纹理有两个属性,可以更改其渲染方式。

第一个属性允许平滑纹理。平滑纹理会降低像素边界的可视性(但图像会变得更模糊),如果将其放大,这可能是可取的。

texture.setSmooth(true);

在这里插入图片描述

第二个属性允许在单个精灵中重复平铺纹理。

texture.setRepeated(true);

在这里插入图片描述

三、现在可以拥有我的sprite了吗?


Yes, you can now create your sprite.

sf::Sprite sprite;
sprite.setTexture(texture);

… 最后画出来。

// inside the main loop, between window.clear() and window.display()
window.draw(sprite);

如果不希望精灵使用整个纹理,可以设置其纹理矩形。

sprite.setTextureRect(sf::IntRect(10, 10, 32, 32));

你也可以改变Sprite的颜色。设置的颜色将随精灵的纹理进行调制(相乘)。这也可以用于更改精灵的全局透明度(alpha)

sprite.setColor(sf::Color(0, 255, 0)); // green
sprite.setColor(sf::Color(255, 255, 255, 128)); // half transparent

这些精灵都使用相同的纹理,但颜色不同:
在这里插入图片描述
精灵也可以变换:它们有位置、方向和比例。

// position
sprite.setPosition(sf::Vector2f(10.f, 50.f)); // absolute position
sprite.move(sf::Vector2f(5.f, 10.f)); // offset relative to the current position

// rotation
sprite.setRotation(90.f); // absolute angle
sprite.rotate(15.f); // offset relative to the current angle

// scale
sprite.setScale(sf::Vector2f(0.5f, 2.f)); // absolute scale factor
sprite.scale(sf::Vector2f(1.5f, 3.f)); // factor relative to the current scale

默认情况下,这三个变换的原点是精灵的左上角。如果要将原点设置为不同的点(例如精灵的中心或另一个角),可以使用setOrigin函数。

sprite.setOrigin(sf::Vector2f(25.f, 25.f));

由于转换函数对于所有SFML实体都是通用的,因此在单独的教程:Transforming entities.中对其进行了解释。

四、The white square problem


您成功加载了纹理,正确构建了精灵,然后。。。你现在在屏幕上看到的是一个白色的正方形。怎么搞的?

这是一个常见的错误。设置精灵的纹理时,它在内部所做的只是存储指向纹理实例的指针。因此,如果纹理被破坏或移动到内存中的其他位置,则精灵最终会使用无效的纹理指针。

编写此类函数时会出现此问题:

sf::Sprite loadSprite(std::string filename)
{
    sf::Texture texture;
    texture.loadFromFile(filename);

    return sf::Sprite(texture);
} // error: the texture is destroyed here

你必须正确地管理你的纹理的生命周期,并确保它们在任何精灵使用的时候都有效。

五、The importance of using as few textures as possible

使用尽可能少的纹理是一个很好的策略,原因很简单:更改当前纹理对于显卡来说是一项昂贵的操作。绘制多个使用相同纹理的精灵将产生最佳性能。

此外,使用单个纹理可以将静态几何体分组到单个实体中(每次绘制调用只能使用一个纹理),这将比绘制一组多个实体快得多。静态几何体的批处理涉及其他类,因此超出了本教程的范围,有关更多详细信息,请参阅vertex array教程。

在创建动画表或平铺集时,请记住这一点:使用尽可能少的纹理。

六、Using sf::Texture with OpenGL code


如果您使用的是OpenGL而不是SFML的图形实体,那么仍然可以使用sf::Texture作为OpenGL纹理对象的包装,并将其与OpenGL代码的其余部分一起使用。

要绑定用于绘制的sf::Texture(基本上是glBindTexture),可以调用bind static函数。

sf::Texture texture;
...

// bind the texture
sf::Texture::bind(&texture);

// draw your textured OpenGL entity here...

// bind no texture
sf::Texture::bind(NULL);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Python sprites 是指在游戏开发中使用的图像对象,用于表示游戏中的角色、物体或动画效果在 Python 中,可以使用 Pygame 库来创建和处理游戏中的 sprites。 要创建一个 sprite,首先需要导入 Pygame 库,并创建一个继承自 Pygame.sprite.Sprite 的类。这个类可以包含一些属性和方法,用于定义 sprite 的行为和外观。 下面是一个简单的示例代码,展示了如何创建和使用 Python sprites: ```python import pygame from pygame.locals import * class MySprite(pygame.sprite.Sprite): def __init__(self): super().__init__() # 调用父类的构造函数 self.image = pygame.Surface((50, 50)) # 创建一个 50x50 大小的 surface self.image.fill((255, 0, 0)) # 将 surface 填充为红色 self.rect = self.image.get_rect() # 获取 surface 的矩形区域 self.rect.center = (200, 200) # 设置矩形区域的中心坐标 def update(self): self.rect.x += 1 # 在 x 轴方向上每次更新位置加 1 pygame.init() screen = pygame.display.set_mode((400, 400)) clock = pygame.time.Clock() sprite = MySprite() all_sprites = pygame.sprite.Group() all_sprites.add(sprite) running = True while running: for event in pygame.event.get(): if event.type == QUIT: running = False all_sprites.update() screen.fill((0, 0, 0)) all_sprites.draw(screen) pygame.display.flip() clock.tick(60) pygame.quit() ``` 这个示例创建了一个名为 `MySprite` 的 sprite 类,它继承自 `pygame.sprite.Sprite`。在 `__init__` 方法中,我们创建了一个红色的 50x50 surface,并将其放置在屏幕中心的矩形区域内。`update` 方法定义了 sprite 的更新行为,这里简单地将 sprite 在 x 轴方向上每次移动一个像素。 在主循环中,我们创建了一个 Pygame 的显示窗口,并使用 `pygame.time.Clock()` 跟踪游戏的帧率。我们创建了一个 `MySprite` 实例,并将它添加到 `all_sprites` 组中。在每一帧更新时,我们调用 `all_sprites.update()` 更新所有 sprite 的位置,然后使用 `all_sprites.draw(screen)` 将它们绘制到屏幕上。 这只是一个简单的示例,你可以根据自己的游戏需求来定义更复杂的 sprite 类和行为。希望对你有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值