SDL下创建移动的图片

在上一章,我们已经了解到如何设置窗口背景,现在,我们将继续引进几张新图片,让它能够在窗口移动。下面的链接可以回顾前面的内容:

SDL下设置窗口背景图片

1.我们先要确定我们在窗口移动的是哪些图片和图片的大小。

string a[] = { "furong1.jpg",
               "furong2.jpg",
               "furong3.jpg",
               "furong4.jpg",
               "furong5.jpg" 
              };
const int image_longer = 100;

我们将这些图片放进了一个数组中,方便后面的读取操作,这里放的是图片的位置,因为我是把图片放在当前编译文件夹下的,所以直接用的图片名字,如果放在其他的文件夹下,要写出文件夹的位置。

2.编写一个函数,用来将图片的结构转换成纹理数据,也就是能够显示在窗口上的结构数据。

SDL_Texture* texture_image(const string& oip, SDL_Renderer* render)
{
    // 加载移动图片
    SDL_Surface* move_surface = IMG_Load(oip.c_str());
    if (!move_surface) {
        printf("移动的图片不能被加载! SDL_image Error: %s\n", IMG_GetError());
        return nullptr;
    }
    //将图片数据转换成纹理数据
    SDL_Texture* texture = SDL_CreateTextureFromSurface(render, move_surface);
    if (!texture) {
        printf("不能将Surface转换为Texrure! SDL_Error: %s\n", SDL_GetError());
        return nullptr;
    }
    return texture;
}

在上一章我们已经了解过了,`SDL_Suface()`函数只是将图片初步处理,通常用于存储未经优化的原始图像数据,而`SDL_Texture()`函数是一种专为渲染优化的数据结构,将图片数据转换成纹理数据,也就能直接映射到窗口上显示出来了。

3.初始化图片位置

void RandomPoints(int longer,int higt, int image_longer)
{
    \\定义一个随机数生成器,它可以定义一个伪随机数。
    default_random_engine e;
    \\定义一个整数范围在(1,longer-image_longer)的均匀分布,用于生成指定范围内的随机整数。
    uniform_int_distribution<int> u(1, (longer - image_longer));
    \\保证在多次调用时能保留种子数,这确保了每次程序运行时生成的随机数序列是不同的。
    static bool seeded = false;
    if (!seeded) {
        e.seed(static_cast<unsigned int>(time(0)));
        seeded = true;
    }
    for (int i = 0; i <= 4; i++)
    {

        lo[i].x = u(e);
        cout << i << " " << lo[i].x << endl;
    }
    std::uniform_int_distribution<int> n(1, (higt - image_longer));
    for (int i = 0; i <= 4; i++)
    {

        lo[i].y = n(e);
        cout << i << " " << lo[i].y << endl;
    }
     
}

这里我们是通过一个创建随机数,确定图片距离窗口左上角的位置,我们使用当前时间作为种子,保证随机数生成器能够生成随机序列。(在概率论和统计学中,均匀分布也叫矩形分布,它是对称概率分布,在相同长度间隔的分布概率是等可能的。)

4.使图片能够自主移动

//初始化每张图片在x轴和y轴上的移动方向
int v_x[] = {1,1,1,1,1};
int v_y[] = {1,1,1,1,1};
bool run=true;
while(!run){
 for (int i = 0; i <= 4; i++)
 {
     //获取图片的纹理
     SDL_Texture* texture = texture_image(a[i], renderer);
     //每次移动3像素。
     lo[i].x += v_x[i]*3;
     lo[i].y += v_y[i]*3;
     //如果图片碰到了窗口边缘,向反方向移动。
     if (lo[i].x <= 0|| lo[i].x >= (length - image_longer))
         v_x[i] *= -1;
     else if(lo[i].y<=0||lo[i].y>=(high-image_longer))
         v_y[i] *=-1;
     //更新图片位置
     SDL_Rect rect = { lo[i].x,lo[i].y,image_longer,image_longer};
     SDL_RenderCopy(renderer, texture, NULL, &rect);
     //释放纹理,防止空间泄露
     SDL_DestroyTexture(texture);

 }
}

我们通过不断的更新画面,来达到使图片有动感的效果。但我这里的做法是不准确的,每台电脑的屏幕刷新频率不是统一的,在我的电脑上,可能速度正合适,但是放在其他的电脑上就会出现过快或者过慢的现象。如何避免这种现象,我下次讲吧。最近耍如鸢耍的太入迷了,(这游戏好上头,现在好困)。

5.总的代码

#include <SDL.h>
#include <SDL_image.h>
#include<stdio.h>
#include<string>
#include<random>
#include<ctime>
#include<iostream>
const int length = 474;
const int high = 998;
const int image_longer = 100;
int v_x[] = {1,1,1,1,1};
int v_y[] = {1,1,1,1,1};
using namespace std;
string a[] = { "furong1.jpg",
               "furong2.jpg",
               "furong3.jpg",
               "furong4.jpg",
               "furong5.jpg" 
              };
typedef struct location
{
    int x;
    int y;
}location;
location lo[5];
SDL_Texture* texture_image(const string& oip, SDL_Renderer* render);
void RandomPoints(int longer, int image_longer,int higt);
int main(int argc, char* argv[]) {
    // 初始化 SDL
    if (SDL_Init(SDL_INIT_VIDEO) < 0) {
        printf("SDL视频子系统不能被初始化, SDL_Error: %s\n", SDL_GetError());
        return -1;
    }

    // 初始化 SDL_image 以支持 JPG 格式
    if (!(IMG_Init(IMG_INIT_JPG) & IMG_INIT_JPG)) {
        printf("SDL_image 不能被初始化! SDL_image Error: %s\n", IMG_GetError());
        return -1;
    }

    // 创建窗口
    SDL_Window* window = SDL_CreateWindow(
        "SDL Background ",
        SDL_WINDOWPOS_CENTERED,
        SDL_WINDOWPOS_CENTERED,
        length, high,
        SDL_WINDOW_SHOWN
    );
    if (!window) {
        printf("Window could not be created! SDL_Error: %s\n", SDL_GetError());
        return -1;
    }

    // 创建渲染器
    SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
    if (!renderer) {
        printf("渲染器不能被创造! SDL_Error: %s\n", SDL_GetError());
        return -1;
    }

    // 加载背景图片
    SDL_Surface* background_surface = IMG_Load("OIP-C.jpg");
    if (!background_surface) {
        printf("xiaomu.jpg 不能被加载! SDL_image Error: %s\n", IMG_GetError());
        return -1;
    }
    

    // 将图片数据转换成纹理数据
    SDL_Texture* background_texture = SDL_CreateTextureFromSurface(renderer, background_surface);
    if (!background_texture) {
        printf("不能将Surface转换为Texrure! SDL_Error: %s\n", SDL_GetError());
        return -1;
    }

    // 释放Surface占用的内存
    SDL_FreeSurface(background_surface);
    //创建初始位置
    RandomPoints(length,image_longer,high);

    // 主循环
    bool quit = false;
    SDL_Event event;

    while (!quit) {
        while (SDL_PollEvent(&event)) {
            if (event.type == SDL_QUIT) {
                quit = true;
            }
        }

        // 清屏
        SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
        SDL_RenderClear(renderer);

        // 渲染背景
        SDL_RenderCopy(renderer, background_texture, NULL, NULL);
        for (int i = 0; i <= 4; i++)
        {
            SDL_Texture* texture = texture_image(a[i], renderer);
            lo[i].x += v_x[i]*3;
            lo[i].y += v_y[i]*3;
            if (lo[i].x <= 0|| lo[i].x >= (length - image_longer))
                v_x[i] *= -1;
            else if(lo[i].y<=0||lo[i].y>=(high-image_longer))
                v_y[i] *=-1;
            SDL_Rect rect = { lo[i].x,lo[i].y,image_longer,image_longer};
            SDL_RenderCopy(renderer, texture, NULL, &rect);
            SDL_DestroyTexture(texture);

        }

        // 呈现内容
        SDL_RenderPresent(renderer);
    }

    // 清理资源
    SDL_DestroyTexture(background_texture);
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
    IMG_Quit();
    SDL_Quit();

    return 0;
}
SDL_Texture* texture_image(const string& oip, SDL_Renderer* render)
{
    // 加载移动图片
    SDL_Surface* move_surface = IMG_Load(oip.c_str());
    if (!move_surface) {
        printf("移动的图片不能被加载! SDL_image Error: %s\n", IMG_GetError());
        return nullptr;
    }
    //将图片数据转换成纹理数据
    SDL_Texture* texture = SDL_CreateTextureFromSurface(render, move_surface);
    if (!texture) {
        printf("不能将Surface转换为Texrure! SDL_Error: %s\n", SDL_GetError());
        return nullptr;
    }
    return texture;
}
void RandomPoints(int longer, int image_longer,int higt)
{
    std::default_random_engine e;
    std::uniform_int_distribution<int> u(1, (longer - image_longer));
    static bool seeded = false;
    if (!seeded) {
        e.seed(static_cast<unsigned int>(time(0)));
        seeded = true;
    }
    for (int i = 0; i <= 4; i++)
    {

        lo[i].x = u(e);
        cout << i << " " << lo[i].x << endl;
    }
    std::uniform_int_distribution<int> n(1, (higt - image_longer));
    for (int i = 0; i <= 4; i++)
    {

        lo[i].y = n(e);
        cout << i << " " << lo[i].y << endl;
    }
     
}

6.运行结果

SDL下图片移动

代码还有很多可以改进的地方,因为我也是新手,哈哈哈哈哈哈哈,所以很多地方也没有优化思路,自己也不知道咋优化,还在学习中,大家一起加油啊!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值