SDL基础使用05(事件系统event)

简介: 本文介绍了如何使用SDL库中的事件系统来控制图片的平铺和前景图的移动,包括响应键盘和鼠标事件调整图片位置和大小。

SDL事件实现背景平铺、前景图移动

#include <iostream>
#include <string>
// SDL_Event事件使用 sdl_event.h
extern "C"
{
#include <SDL.h>
#include <SDL_image.h>
}
#pragma comment(lib, "SDL2.lib")


// 窗口宽度
#define SCREEN_WIDTH  1600
#define SCREEN_HEIGHT  900

// 全局窗口和渲染器
SDL_Window   *window   = nullptr;
SDL_Renderer *renderer = nullptr;

// 加载图片(返回纹理指针)
SDL_Texture* LoadImage(std::string file)
{
    SDL_Texture* tex = nullptr;
    tex = IMG_LoadTexture(renderer, file.c_str());            // 加载图片到纹理
    if (tex == nullptr)
        throw std::runtime_error("Load image failed" + file + IMG_GetError());
    return tex;
}

// 拷贝纹理到渲染器
void copyTextureToRender(int x, int y, SDL_Texture *tex, SDL_Renderer *rend)
{
    SDL_Rect pos;            // srcRect
    pos.x = x;
    pos.y = y;
    SDL_QueryTexture(tex, NULL, NULL, &pos.w, &pos.h);            // 查询纹理的宽高
    SDL_RenderCopy(rend, tex, NULL, &pos);                        // 拷贝纹理到渲染器
}

#undef main
int main(int argc, char** argv)
{
    // 1. 初始化SDL
    if (::SDL_Init(SDL_INIT_EVERYTHING) == -1)
    {
        std::cout << SDL_GetError() << std::endl;
        return 1;
    }

    // 2. 创建窗口
    window = ::SDL_CreateWindow("Event Demo",
        SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
        SCREEN_WIDTH, SCREEN_HEIGHT, 
        SDL_WINDOW_SHOWN);
    if (window == nullptr)
    {
        std::cout << SDL_GetError() << std::endl;
        return 2;
    }

    // 3. 基于窗口创建渲染器
    renderer = ::SDL_CreateRenderer(window, -1,
        SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
    if (renderer == nullptr)
    {
        std::cout << SDL_GetError() << std::endl;
        return 3;
    }

    // 4. 创建背景和前景纹理            ::IMG_LoadTexture
    SDL_Texture *background = nullptr, *image = nullptr;
    try {
        background = LoadImage("./bk.jpg");
        image = LoadImage("./longong.jpg");
    }
    catch (const std::runtime_error &e) {
        std::cout << e.what() << std::endl;
        return 4;
    }

    bool quit = false;            // 是否退出循环
    SDL_Event e;                // SDL事件
    int iW, iH, x, y;            // x y为前景图pos, iW iH 为前景图宽高
    int dx = 0, dy = 0;            // 前景图偏移pos
    // 主循环(CPU高占用)
    while (!quit)
    {
        // 轮询事件栈e
        while (SDL_PollEvent(&e))        // 循环从事件队列中获取事件
        {
            if (e.type == SDL_QUIT)        // 退出事件
                quit = true;

            if (e.type == SDL_KEYDOWN)    // 键盘事件
            {
                if (e.key.keysym.sym == SDLK_LEFT)    
                {
                    dx -= 10;
                    printf("SDLK_LEFT...");
                }
                else if (e.key.keysym.sym == SDLK_RIGHT)
                {
                    printf("SDLK_RIGHT...");
                    dx += 10;

                }
                else if (e.key.keysym.sym == SDLK_UP)
                {
                    printf("SDLK_UP...");
                    dy -= 10;
                }
                else if (e.key.keysym.sym == SDLK_DOWN)
                {
                    printf("SDLK_DOWN...");
                    dy += 10;
                }

            }

            if (e.type == SDL_MOUSEBUTTONDOWN)             // 用户点击鼠标
                quit = true;

            // 清空渲染器
            SDL_RenderClear(renderer);

            // 在渲染器内平铺背景
            int bW, bH;
            SDL_QueryTexture(background, NULL, NULL, &bW, &bH);        // 查询背景纹理宽高
            for (int y = 0; y <= SCREEN_HEIGHT; y += bH)            // (0, 0) (bW, bH)  防止背景图太小,循环平铺         
            for (int x = 0; x <= SCREEN_WIDTH; x += bW)                
                copyTextureToRender(x, y, background, renderer);    


            // 在渲染器中央放置前景            
            SDL_QueryTexture(image, NULL, NULL, &iW, &iH);            // 查询前景纹理宽高
            x = SCREEN_WIDTH / 2 - iW / 2 + dx;
            y = SCREEN_HEIGHT / 2 - iH / 2 + dy;
            copyTextureToRender(x, y, image, renderer);

            SDL_RenderPresent(renderer);                            // 刷新渲染器显示
        }
    }

    // 释放资源
    if (background)
    {
        SDL_DestroyTexture(background);
    }
    if (image)
    {
        SDL_DestroyTexture(image);
    }
    if (renderer)
    {
        SDL_DestroyRenderer(renderer);
    }
    if (window)
    {
        SDL_DestroyWindow(window);
    }
    SDL_Quit();

    return 0;
}

使用SDL事件实现图片的移动、缩放

#include <iostream>

extern "C"
{
    #include <SDL.h>
}

#undef main
int main()
{
    // 1. 初始化SDL
    SDL_Init(SDL_INIT_EVERYTHING);

    // 2. 创建窗口
    SDL_Window* win = SDL_CreateWindow("yx3sxmeng", 
        SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 
        800, 600, 
        SDL_WINDOW_SHOWN);

    // 3. 创建渲染器
    SDL_Renderer* renderer = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED);

    // 4. 将图片加载到surface
    SDL_Surface* surface = SDL_LoadBMP("./Panda.bmp");

    // 5. 根据surface创建纹理
    SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, surface);


    // 6. SDL事件循环机制 
    bool quit = false;
    SDL_Event ev;                        // SDL 事件
    SDL_Rect rect = { 0, 0, 800, 600 };    // 图片位置大小(x,y, w,h);
    int sx = 0, sy = 0;                    // 保存经过事件处理后的图片的位置
    while (!quit)
    {
        while (SDL_PollEvent(&ev))        // 从循环队列中获取事件
        {
            switch (ev.type)
            {
            case SDL_QUIT:
                quit = true;
                break;
            case SDL_MOUSEBUTTONDOWN:            // 鼠标按下(记录鼠标按下位置到图片x y的距离)
                sx = ev.button.x + rect.x;
                sy = ev.button.y + rect.y;
                break;
            case SDL_MOUSEMOTION:                            // 鼠标左键按下移动
                if (ev.motion.state & SDL_BUTTON_LMASK)
                {
                    rect.x = ev.motion.x - sx;                // 计算图片应该绘制的xy位置(通过鼠标按下记录的sx xy)
                    rect.y = ev.motion.y - sy;
                }
                break;
            case SDL_KEYDOWN:
                if (ev.key.keysym.sym == SDLK_LEFT)        // 向左移动
                {
                    rect.x -= 10;                    
                    printf("SDLK_LEFT...");
                }
                else if (ev.key.keysym.sym == SDLK_RIGHT)        // 向右移动
                {        
                    rect.x += 10;
                    printf("SDLK_RIGHT...");
                }
                else if (ev.key.keysym.sym == SDLK_UP)            // 放大
                {
                    rect.w += 10;
                    rect.h += 10;
                    printf("SDLK_UP...");
                }
                else if (ev.key.keysym.sym == SDLK_DOWN)        // 缩小
                {
                    rect.w -= 10;
                    rect.h -= 10;
                    printf("SDLK_DOWN...");
                }
                printf("scancode=%d\n", ev.key.keysym.scancode);
                break;
            case SDL_MOUSEWHEEL:
                if (ev.wheel.y > 0)        // 放大
                {
                    rect.h *= 1.1;
                    rect.w *= 1.1;
                }
                if (ev.wheel.y < 0)        // 缩小
                {
                    rect.w /= 1.1;
                    rect.h /= 1.1;
                }
                break;
            }
        }
        // 7. 渲染三部曲
        SDL_RenderClear(renderer);
        SDL_RenderCopy(renderer, texture, NULL, &rect);
        SDL_RenderPresent(renderer);
        SDL_Delay(16);
    }

    // 8. 释放资源 退出
    SDL_DestroyTexture(texture);
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(win);

    SDL_Quit();
    return 0;
}
相关文章
|
11月前
|
存储 Cloud Native 程序员
C++ Qt 事件(event)
C++ Qt 事件(event)
|
11月前
25 QT - event函数
25 QT - event函数
47 0
|
11月前
24 QT - 事件
24 QT - 事件
36 0
|
3天前
SDL事件处理以及线程使用(2)
SDL库中事件处理和多线程编程的基本概念和示例代码,包括如何使用SDL事件循环来处理键盘和鼠标事件,以及如何创建和管理线程、互斥锁和条件变量。
11 1
SDL事件处理以及线程使用(2)
|
2月前
|
开发者
【Qt 学习笔记】Qt系统相关 | Qt事件 | 事件的介绍及基本概念
【Qt 学习笔记】Qt系统相关 | Qt事件 | 事件的介绍及基本概念
157 4
|
4月前
|
安全 图形学
【unity实战】事件(Event)的基本实战使用
【unity实战】事件(Event)的基本实战使用
75 1
|
5月前
|
存储 Java Linux
Android系统获取event事件回调等几种实现和原理分析
Android系统获取event事件回调等几种实现和原理分析
236 0
|
5月前
|
JavaScript 前端开发
qml 信号和处理程序事件系统(Signal and Handler Event System)
qml 信号和处理程序事件系统(Signal and Handler Event System)
60 0
Revit空闲事件(Idling Event)增强和外部事件(External Event)
Revit空闲事件(Idling Event)增强和外部事件(External Event)
Revit空闲事件(Idling Event)增强和外部事件(External Event)
|
消息中间件 存储 Android开发
【音视频连载-003】基础学习篇-SDL 消息循环和事件响应
在前面的文章中已经创建了一个 SDL 窗口并且显示指定的颜色。
219 0
【音视频连载-003】基础学习篇-SDL 消息循环和事件响应