【SLD游戏编程入门第十五卷】鼠标事件
一、前言
与按键一样,SDL 具有事件结构来处理鼠标事件,如鼠标运动、鼠标 按钮按下,鼠标按钮释放。
二、鼠标事件
在上一卷的基础上添加一些代码即可
int main(int argc, char* argv[]) // 必须要填写此参数,不然会出现链接错误
{
// 初始化 SDL
if (Init())
{
// 加载媒体资源
if (!LoadMedia())
std::cout << "[Error]: Failed to load media!" << std::endl;
// 窗口循环
SDL_Event e;
bool quit = false;
int mousePosX = 0;
int mousePosY = 0;
while (quit == false)
{
// 处理事件
while (SDL_PollEvent(&e))
{
if (e.type == SDL_QUIT)
quit = true;
else if (e.type == SDL_MOUSEMOTION || e.type == SDL_MOUSEBUTTONDOWN || e.type == SDL_MOUSEBUTTONUP) // 捕获鼠标事件
{
SDL_GetMouseState(&mousePosX, &mousePosY);
switch (e.type)
{
case SDL_MOUSEMOTION: // 鼠标移动
std::cout << "[Mouse move]: ( " << mousePosX << ", " << mousePosY << " )" << std::endl;
break;
case SDL_MOUSEBUTTONDOWN: // 鼠标按键按下
if (e.button.button == SDL_BUTTON_LEFT)
std::cout << "[Mouse Button Down]: 左键" << std::endl;
if (e.button.button == SDL_BUTTON_MIDDLE)
std::cout << "[Mouse Button Down]: 中键" << std::endl;
if (e.button.button == SDL_BUTTON_RIGHT)
std::cout << "[Mouse Button Down]: 右键" << std::endl;
break;
case SDL_MOUSEBUTTONUP: // 鼠标按键松开
if (e.button.button == SDL_BUTTON_LEFT)
std::cout << "[Mouse Button Up]: 左键" << std::endl;
if (e.button.button == SDL_BUTTON_MIDDLE)
std::cout << "[Mouse Button Up]: 中键" << std::endl;
if (e.button.button == SDL_BUTTON_RIGHT)
std::cout << "[Mouse Button Up]: 右键" << std::endl;
break;
}
}
}
// --- rendering -----------------------------------------------------------------------
// 设置渲染器绘制颜色(黑色)
SDL_SetRenderDrawColor(gRenderer, 0, 0, 0, 255);
// 清屏
SDL_RenderClear(gRenderer);
// 渲染字体纹理
gTextTexture.Render((SCREEN_WIDTH - gTextTexture.GetWidth()) / 2, (SCREEN_HEIGHT - gTextTexture.GetHeight()) / 2);
// 更新屏幕
SDL_RenderPresent(gRenderer);
}
}
// 清理资源
Close();
return 0;
}
✨参考文档 SDL2.0 API by Category
✨参考文档 Mouse Support
✨参考文档 SDL_MouseButtonEvent
三、示例代码
/* 此源代码版权归 AnnihilateSword (2022-*)所有,未经书面许可不得转载。*/
// 使用 SDL 和 iostream
#include <SDL.h>
#include <SDL_image.h>
#include <SDL_ttf.h>
#include <iostream>
// 链接库
#pragma comment(lib, "SDL2.lib")
#pragma comment(lib, "SDL2main.lib")
#pragma comment(lib, "SDL2_image.lib")
#pragma comment(lib, "SDL2_ttf.lib")
// 屏幕尺寸常量
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
bool Init(); // 启动 SDL 并创建窗口
bool LoadMedia(); // 加载媒体
void Close(); // 清理资源,关闭窗口以及SDL
SDL_Window* gWindow = nullptr; // 主窗口
SDL_Renderer* gRenderer = nullptr; // 主窗口渲染器
// TTF 字体
TTF_Font* gFont = nullptr;
// 纹理类
class Texture
{
private:
int m_Width;
int m_Height;
SDL_Texture* m_Texture;
public:
Texture()
: m_Width(0), m_Height(0), m_Texture(nullptr)
{
}
~Texture()
{
if (m_Texture)
{
SDL_DestroyTexture(m_Texture);
m_Texture = nullptr;
}
}
// 从文件中加载纹理
bool LoadFromFile(const char* path, int width = SCREEN_WIDTH, int height = SCREEN_HEIGHT, bool enableColorKey = false, Uint8 r = 0, Uint8 g = 0, Uint8 b = 0)
{
m_Width = width;
m_Height = height;
SDL_Surface* loadedSurface = IMG_Load(path);
if (enableColorKey) // 颜色键控
SDL_SetColorKey(loadedSurface, SDL_TRUE, SDL_MapRGB(loadedSurface->format, r, g, b));
m_Texture = SDL_CreateTextureFromSurface(gRenderer, loadedSurface); // 加载纹理
if (!m_Texture)
std::cout << "[Error]: Unable to create texture from" << path << " SDL_Error: " << SDL_GetError() << std::endl;
SDL_FreeSurface(loadedSurface);
return m_Texture != nullptr;
}
// 从字体字符串中创建图片
bool LoadFromRenderedText(const char* textureText, SDL_Color textColor)
{
SDL_Surface* textSurface = TTF_RenderText_Solid(gFont, textureText, textColor);
if (!textSurface)
{
std::cout << "[Error]: Unable to render text surface! SDL_ttf Error: " << TTF_GetError() << std::endl;
}
else
{
m_Texture = SDL_CreateTextureFromSurface(gRenderer, textSurface);
if (!m_Texture)
{
std::cout << "[Error]: Unable to create texture from rendered text! SDL_Error: " << SDL_GetError() << std::endl;
}
else
{
// 【这里设置了字体纹理大小】
m_Width = textSurface->w;
m_Height = textSurface->h;
}
}
// 释放临时表面
SDL_FreeSurface(textSurface);
return m_Texture != nullptr;
}
// 设置纹理颜色
void SetColor(Uint8 r, Uint8 g, Uint8 b)
{
SDL_SetTextureColorMod(m_Texture, r, g, b);
}
// 设置纹理透明度
void SetAlpha(Uint8 alpha)
{
SDL_SetTextureAlphaMod(m_Texture, alpha);
}
// 设置混合模式
void SetBlendMode(SDL_BlendMode blendMode)
{
SDL_SetTextureBlendMode(m_Texture, blendMode);
}
// 渲染纹理
inline void Render(int x, int y, SDL_Rect* clip = nullptr,
double angle = 0.0, SDL_Point* center = nullptr, SDL_RendererFlip flip = SDL_FLIP_NONE)
{
SDL_Rect dstRect{ x, y, m_Width, m_Height };
// center 为 nullptr 默认为纹理中心
SDL_RenderCopyEx(gRenderer, m_Texture, clip, &dstRect,
angle, center, flip); // 扩展功能
}
inline int GetWidth() const { return m_Width; }
inline int GetHeight() const { return m_Height; }
};
Texture gTextTexture;
int main(int argc, char* argv[]) // 必须要填写此参数,不然会出现链接错误
{
// 初始化 SDL
if (Init())
{
// 加载媒体资源
if (!LoadMedia())
std::cout << "[Error]: Failed to load media!" << std::endl;
// 窗口循环
SDL_Event e;
bool quit = false;
int mousePosX = 0;
int mousePosY = 0;
while (quit == false)
{
// 处理事件
while (SDL_PollEvent(&e))
{
if (e.type == SDL_QUIT)
quit = true;
else if (e.type == SDL_MOUSEMOTION || e.type == SDL_MOUSEBUTTONDOWN || e.type == SDL_MOUSEBUTTONUP) // 捕获鼠标事件
{
SDL_GetMouseState(&mousePosX, &mousePosY);
switch (e.type)
{
case SDL_MOUSEMOTION: // 鼠标移动
std::cout << "[Mouse move]: ( " << mousePosX << ", " << mousePosY << " )" << std::endl;
break;
case SDL_MOUSEBUTTONDOWN: // 鼠标按键按下
if (e.button.button == SDL_BUTTON_LEFT)
std::cout << "[Mouse Button Down]: 左键" << std::endl;
if (e.button.button == SDL_BUTTON_MIDDLE)
std::cout << "[Mouse Button Down]: 中键" << std::endl;
if (e.button.button == SDL_BUTTON_RIGHT)
std::cout << "[Mouse Button Down]: 右键" << std::endl;
break;
case SDL_MOUSEBUTTONUP: // 鼠标按键松开
if (e.button.button == SDL_BUTTON_LEFT)
std::cout << "[Mouse Button Up]: 左键" << std::endl;
if (e.button.button == SDL_BUTTON_MIDDLE)
std::cout << "[Mouse Button Up]: 中键" << std::endl;
if (e.button.button == SDL_BUTTON_RIGHT)
std::cout << "[Mouse Button Up]: 右键" << std::endl;
break;
}
}
}
// --- rendering -----------------------------------------------------------------------
// 设置渲染器绘制颜色(黑色)
SDL_SetRenderDrawColor(gRenderer, 0, 0, 0, 255);
// 清屏
SDL_RenderClear(gRenderer);
// 渲染字体纹理
gTextTexture.Render((SCREEN_WIDTH - gTextTexture.GetWidth()) / 2, (SCREEN_HEIGHT - gTextTexture.GetHeight()) / 2);
// 更新屏幕
SDL_RenderPresent(gRenderer);
}
}
// 清理资源
Close();
return 0;
}
/**
* @brief 启动 SDL 并创建窗口
*/
bool Init()
{
// 初始化 SDL
if (SDL_Init(SDL_INIT_VIDEO) < 0)
{
std::cout << "[Error]: SDL could not initialize! SDL_Error: " << SDL_GetError() << std::endl;
return false;
}
else
{
// 设置纹理线性过滤
if (!SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1"))
std::cout << "[Warning]: Linear texture filtering not enabled!" << std::endl;
// 创建窗口
gWindow = SDL_CreateWindow("HelloSDL", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
if (!gWindow)
{
std::cout << "[Error]: Window could not be created! SDL_Error: " << SDL_GetError() << std::endl;
return false;
}
else
{
// 创建窗口渲染器,设置硬件加速和垂直同步
gRenderer = SDL_CreateRenderer(gWindow, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); // -1 初始化支持所请求标志的第一个
if (!gRenderer)
{
std::cout << "[Error]: Renderer could not bo created! SDL_Error: " << SDL_GetError() << std::endl;
return false;
}
else
{
// 初始化 PNG 加载
int imgFlags = IMG_INIT_PNG;
if (!(IMG_Init(imgFlags) & imgFlags))
{
std::cout << "[Error]: SDL_image could not initialize! SDL_image Error: " << IMG_GetError() << std::endl;
return false;
}
// 初始化 SDL_ttf
if (TTF_Init() == -1)
{
std::cout << "[Error]: SDL_ttf could not initialize! SDL_ttf Error: " << TTF_GetError() << std::endl;
return false;
}
}
}
}
return true;
}
/**
* @brief 加载媒体
*/
bool LoadMedia()
{
// 打开字体
gFont = TTF_OpenFont(R"(res\fonts\COOPBL.TTF)", 28);
if (!gFont)
{
std::cout << "[Error]: Failed to load COOPBL font! SDL_ttf Error: " << TTF_GetError() << std::endl;
return false;
}
else
{
// 字体颜色(白色)
SDL_Color textColor{ 255, 255, 255 };
// 这句话使用很多不同的字母
if (!gTextTexture.LoadFromRenderedText("The quick brown fox jumps over the lazy dog", textColor))
{
std::cout << "[Error]: Failed to render text texture!" << std::endl;
return false;
}
}
return true;
}
/**
* @brief 清理资源,关闭窗口以及SDL
*/
void Close()
{
// 释放字体资源
TTF_CloseFont(gFont);
gFont = nullptr;
// 销毁窗口渲染器
if (gRenderer)
{
SDL_DestroyRenderer(gRenderer);
gRenderer = nullptr;
}
// 销毁窗口
if (gWindow)
{
SDL_DestroyWindow(gWindow);
gWindow = nullptr;
}
// 退出 TTF、IMG 和 SDL
TTF_Quit();
IMG_Quit();
SDL_Quit();
}
1. 运行结果
这里没有介绍鼠标滚轮事件,但如果您 查看文档和玩弄它 应该不难弄清楚。
本节内容就到这里了,下卷会继续分享 SDL 的基本使用
The End.