用C++和SFML写游戏-纹理及精灵(5.1)

对于 2D3D 游戏来说,纹理是一个很重要的东西,它能够将一张图片映射到我们程序中的对象里。而精灵可以看作是包含其他显示对象的容器。

在这篇文章中,将会讲解一下内容:

  • 读取纹理
  • 将纹理绘制在shape中
  • 什么是精灵
  • 资源管理

一、读取纹理

纹理是一个非常简单的对象。一个 2D 纹理本质上是一幅图片,通常存储在 GPU 中。SFML 使用 Image 类处理图片,使用 Texture 类绘制图片。

二、创建 images

在介绍纹理之前,我们先看看如何创建和读取图片。Image 类中的很多方法在 Texture 都可以使用。例如,我们想要创建一个 50 x 50 且被红色填充的图片。

sf::Image image;
image.create(50, 50, sf::Color::Red);

create() 方法第一个参数是图片的宽,第二个参数是高,第三个参数是图片的颜色(RGBA)

除此之外,我们也可以使用像素数组来创建。数组每个元素是 Uint8 类型(一个字节)。一个像素的大小是 4 个字节,表示 RGBA。如下面的代码所示:

const unsigned int kWidth = 5, kheight = 5
// 数组大小 kWidth * kHeight * 4
sf::Uint8 pixels[kWidth * kHeight * 4] = {
    255, 255, 255, 255, // 白
    0, 0, 0, 255, // 黑
    255, 0, 0, 255, // 红
    128, 128, 128, 255, // 灰
    
    // ... 其他像素颜色
};
sf::Image image;
image.create(kWidth, kHeight, pixels);

当然,我们也可以从现有的图片中创建。如下:

sf::Image image;
image.loadFromFile("myImage.png");

SFML 能够处理的图片格式包括:bmp, png, tga, gif, psd, hdr, pic 以及 jpg(不包括jpeg)

如果图片不存在, loadFromFile() 会返回 false,导致不必要的 bug。因此上面的代码改为:

sf::Image image;
if (!image.loadFromFile("myImage.png")) {
    return -1;
}

这里强烈推荐使用无损格式的图片,比如 png 格式。除非我们不关心图片质量或者内存有限的情况下,对图片恰当的进行压缩。

Image 类提供了一些常用的方法,

  • Image::getPixel()Image::setPixel() 改变图片某个像素
  • Image::getPixelPtr() 获取所有的图片像素,它返回的事数组的起始地址,数组的定义跟前面我们使用的像素数组一眼。

三、创建 Textures

Texture 类跟 Image 类很多方法都是类似的,例如我们创建一个纹理:

sf::Texture texture;
if (texture.loadFromFile("myTexture.png"))
    return -1;

loadFromFile() 还允许我们只截取图片的部分区域,代码如下:

sf::Texture texture;
if (texture.loadFromFile("myTexture.png", sf::IntRect(0, 0, 32, 32)))
    return -1;

上面的代码截取图片 32*32 大小,原点坐标在图片的左上角。如果需要多次截取图片,我们可以用 Image 读取图片一次,然后用这个图片去创建纹理。

sf::Image image;
image.create(50, 50, sf::Color::Red);


sf::Texture texture;
texture.loadFromFile(image);

四、将纹理绘制在shape中

前面都是在介绍怎么创建或者读取图片,这里将介绍我们如何将图片显示出来。

Texture 是像素的集合,它不能直接绘制到屏幕上,还需要设置它的位置,旋转角度等参数。Shape 类能够起到这么一个作用。

sf::Texture texture;
texture.loadFromFile("myTexture.png");

sf::RectangleShape rectShape(sf::Vector2f(300, 150));
rectShape.setTexture(&texture);

while (window.isOpen()) {
    window.clear(sf::Color::Black);
    window.draw(rectShape);
    window.display();
}

上面的代码将 Texture 对象放入 RectangleShape 中。Texture 对象会适当的缩放自身使之适合 RectangleShape 的大小。例如,我们的 Texture 如果是 200 * 200 大小的,** RectangleShape** 是 300 * 150 大小的。那么 ** Texture** 将会在 x 方向拉伸显示,而在 y 方向压缩显示。

未设置正确大小

一般来说,我们不希望看到这样的效果。。。

为此,我们需要正确的设置 RectangleShape 的大小,可以使用 Texture::getSize() 获取我们 Texture 的大小。

因此,代码可以修改为:

sf::Vector2u textureSize = texture.getSize();
float rectWidth = static_cast<float>(textureSize.x);
float rectHeight = static_cast<float>(textureSize.y);

sf::RectangleShape rectShape(sf::Vector2f(rectWidth, rectHeight));
rectShape.setTexture(&texture);
设置正确大小

除此之外,Texture 对象还可以绘制到其他 Shape 当中,例如 CircleShapeConvexShape

某些时候,一张大图片可能由一张小图片多次出现组成,如下图所示。

这时候,我们可以通过 SFML 实现,以减少空间的占用。 Texture 中有一个方法叫做 Texture::setRepeated(),设置为 True 的时候表示当前 Texture 对象是可重复的。

例如我们有一张 128 * 221大小的图片,我们需要在 x 轴上重复 3 次,在 y 轴上重复 2 次。

sf::Texture texture;
texture.loadFromFile("rep.png");
texture.setRepeated(true);

sf::RectangleShape rectShape(sf::Vector2f(128 * 3, 221 * 2));

rectShape.setTexture(&texture);

但是上面这份代码达不到我们需要的效果,它会将原图片单纯的拉伸显示而不是重复显示。这里的解决办法是将这个纹理矩形设置的比原来的要大。

sf::Texture texture;
texture.loadFromFile("rep.png");
texture.setRepeated(true);

sf::RectangleShape rectShape(sf::Vector2f(128 * 3, 221 * 2));
// 将纹理矩形设置的比原来的要大
rectShape.setTextureRect(sf::IntRect(0, 0, 128 * 3, 221 * 2));

rectShape.setTexture(&texture);

这样就达到了我们需要的效果:

下面这个图显示了一个默认的纹理矩形如何映射到一个比它大的显示区域中,以及当纹理矩形设置的比原来的纹理要大的时候又是如何映射的。

示例代码在 Github

这部分内容先写到这里,下半部分将介绍精灵的使用?。

使用C++SFML库来编2048小游戏是一个不错的实践项目,可以帮助你熟悉C++编程和SFML图形库的使用。SFML(Simple and Fast Multimedia Library)是一个简单易用的多媒体库,可以用来处理音频、视频、窗口等多媒体元素,非常适合用来开发游戏。以下是使用C++SFML2048游戏的基本步骤和概念: 1. **安装SFML库**:首先需要在你的开发环境中安装SFML库。你可以从SFML的官方网站下载并按照指南进行安装。 2. **创建游戏窗口**:使用SFML创建一个窗口,这是游戏运行的基础。你可以设置窗口的大小、标题等属性。 3. **处理用户输入**:2048游戏需要响应用户的键盘输入,例如上下左右箭头键来移动方块。你需要捕捉这些键盘事件,并根据用户的操作更新游戏状态。 4. **游戏逻辑实现**:编核心游戏逻辑,包括初始化游戏板、随机生成新的数字方块、处理方块的移动和合并规则等。 5. **渲染游戏界面**:使用SFML的图形渲染功能来绘制游戏界面,包括数字方块、分数显示等。 6. **游戏循环**:游戏循环是游戏运行的核心,它负责不断地处理用户输入、更新游戏状态和渲染游戏画面。 7. **结束条件检测**:在游戏逻辑中加入检测游戏是否结束的条件,如无法移动或达到2048的数字。 以下是实现2048游戏的简化示例代码结构: ```cpp #include <SFML/Graphics.hpp> int main() { // 创建游戏窗口 sf::RenderWindow window(sf::VideoMode(400, 400), "2048 Game"); // 游戏状态初始化 // ... // 游戏主循环 while (window.isOpen()) { sf::Event event; while (window.pollEvent(event)) { if (event.type == sf::Event::Closed) window.close(); // 处理键盘输入 // ... } // 更新游戏逻辑 // ... // 渲染游戏界面 window.clear(); // 绘制游戏元素 // ... window.display(); } return 0; } ```
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值