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;
}
相关文章
|
Rust 安全 Linux
如何使用Rust进行系统编程?
在 Rust 中,要调用系统调用并与底层 C 函数进行交互,通常会使用 `libc` crate。`libc` 提供了 Rust 到 C 的 FFI(Foreign Function Interface)绑定,允许 Rust 代码调用和使用底层的 C 函数和系统调用。
570 0
|
Java Shell 测试技术
如何使用Java连接Kerberos的Phoenix
如何使用Java连接Kerberos的Phoenix
810 0
|
Linux
Linux使用Aria2命令下载BT种子/磁力/直链文件
Linux使用Aria2命令下载BT种子/磁力/直链文件
2886 0
|
Java 中间件 开发者
springBoot中定时器注解@Schedule不生效问题
用@Schedule注解写了定时任务,本地测试好好的。发布服务器后到指定时间点不会执行!
2205 1
|
机器学习/深度学习 监控 API
合约量化/秒合约/永续合约对冲系统开发技术规则及源码示例
合约量化、秒合约、永续合约对冲系统的开发涉及策略编写、数据处理、交易执行、风险管理等关键技术。量化策略基于市场数据和机器学习,实现自动交易;秒合约强调高速交易和风险控制;永续合约通过资金费率机制平衡多空持仓。系统需具备高效的数据处理能力和实时监控功能,以确保交易的稳定性和安全性。
|
XML C# 数据格式
绝密档案曝光!Windows平台如何深挖一个dll背后的神秘依赖,揭露隐藏的秘密!
【8月更文挑战第14天】在Windows系统中,动态链接库(DLL)对程序运行至关重要。了解DLL的依赖关系有助于软件的调试与优化。本文以具体案例演示如何查看DLL依赖。首先确保环境已安装Windows及具备基本开发知识。
577 0
|
JavaScript Java 测试技术
基于微信小程序的家政服务预约系统的+php+vue.js附带文章和源代码设计说明文档ppt
基于微信小程序的家政服务预约系统的+php+vue.js附带文章和源代码设计说明文档ppt
376 3
基于微信小程序的家政服务预约系统的+php+vue.js附带文章和源代码设计说明文档ppt
BXA
|
算法 程序员 决策智能
动态规划详解背包问题及实践(附C++代码)
背包问题是一个经典的组合优化问题,它可以被抽象为一个把物品放入背包中的过程,以求最终背包中物品价值的最大化
BXA
1738 0
element UI 组件封装--搜索表单(含插槽和内嵌组件)
element UI 组件封装--搜索表单(含插槽和内嵌组件)
579 5
|
数据采集 传感器 新制造
学习PLC+LabVIEW
学习PLC+LabVIEW
366 0

热门文章

最新文章