对话框就是一个简单的窗口,仅包含标题、文字信息和一两个特定文字的按钮。
所以我们先改造下上篇的按钮,增加类型属性,并添加几个对话框专用的特定的按钮。
// MySDL_Button.h // SDL2 自定义部件 - 按钮 #include <SDL2/SDL.h> #include <SDL2/SDL_ttf.h> #ifndef MYSDL2_BUTTON_H #define MYSDL2_BUTTON_H // 按钮状态 typedef enum en_SDL_Button_State { BTN_STATE_NORMAL, // 正常 BTN_STATE_DOWN, // 按下 BTN_STATE_UP // 弹起 } SDL_Button_State; // 按钮类型 typedef enum en_SDL_Button_Type { BT_TYPE_CUSTOM = 0, // 自定义类型,显示给定文字 BT_TYPE_OK = 1, // 其他类型,显示特定文字 BT_TYPE_CANCEL = 2, BT_TYPE_YES = 4, BT_TYPE_NO = 8, BT_TYPE_OKCANCEL = BT_TYPE_OK | BT_TYPE_CANCEL, BT_TYPE_YESNO = BT_TYPE_YES | BT_TYPE_NO } SDL_Button_Type; // 按钮结构 typedef struct st_SDL_Button { SDL_Button_Type type; // 类型 int id; // ID int x, y, w, h; // 尺寸 char *text; // 文字 _Bool enable; // 是否可用 SDL_Button_State state; // 状态 } SDL_Button; // 画按钮 // 参数:pRen = 渲染器;pFont = 字体;pBtn = 按钮数组;btnNum = 按钮数量 void SDL_DrawButton(SDL_Renderer *pRen, TTF_Font *pFont, SDL_Button *pBtn, int btnNum); // 坐标是否在有效按钮上 // 参数:x,y = 坐标;pBtn = 按钮数组;btnNum = 按钮数量 // 返回值:按钮ID,或者 -1(不在有效按钮上) int SDL_isOnButton(int x, int y, SDL_Button *pBtn, int btnNum); #endif
// MySDL_Button.h // SDL2 自定义部件 - 按钮 #include "MySDL_Texture.h" #include "MySDL_Button.h" // 自定义按钮文字 static char *szOKCANCEL[] = {" 确定 ", " 取消 ",}; static char *szYESNO[] = {" 是 ", " 否 "}; // 坐标是否在有效按钮上 // 参数:x,y = 坐标;pBtn = 按钮数组;btnNum = 按钮数量 // 返回值:按钮ID,或者 -1(不在有效按钮上) int SDL_isOnButton(int x, int y, SDL_Button *pBtn, int btnNum) { for(int i = 0; i < btnNum; i++) if(pBtn[i].enable && x >= pBtn[i].x && x <= pBtn[i].x + pBtn[i].w && y >= pBtn[i].y && y <= pBtn[i].y + pBtn[i].h) return pBtn[i].id; return -1; } // 画按钮 // 参数:pRen = 渲染器;pFont = 字体;pBtn = 按钮数组;btnNum = 按钮数量 void SDL_DrawButton(SDL_Renderer *pRen, TTF_Font *pFont, SDL_Button *pBtn, int btnNum) { int bgc, tc; // 背景颜色、文字颜色 Uint8 ulc, dlc; // 按钮上、下线的颜色(单R、G、B) SDL_Texture *pBGTxt, *pTextTxt; // 背景、文字纹理 SDL_Rect rt; for(int i = 0; i < btnNum; i++) { // 根据按钮是否可用及其状态决定底色、文字颜色 if(pBtn[i].enable) { tc = 0; switch(pBtn[i].state) { case BTN_STATE_NORMAL : bgc = 0xC5C5C5; ulc = 0xFF; dlc = 0; break; case BTN_STATE_DOWN : bgc = 0xA0A0A0; ulc = 0; dlc = 0xFF; break; case BTN_STATE_UP : bgc = 0xF1F1F1; ulc = 0xFF; dlc = 0; break; default : break; } } else { tc = 0x989898; bgc = 0xF1F1F1; ulc = 0xFF; dlc = 0; } // 根据类型决定按钮上显示的文字 pBGTxt = GetRGBTexture(pRen, pBtn[i].w, pBtn[i].h, bgc); switch(pBtn[i].type) { case BT_TYPE_OK : pTextTxt = GetTextTexture(pRen, pFont, szOKCANCEL[0], 0); break; case BT_TYPE_CANCEL : pTextTxt = GetTextTexture(pRen, pFont, szOKCANCEL[1], 0); break; case BT_TYPE_YES : pTextTxt = GetTextTexture(pRen, pFont, szYESNO[0], 0); break; case BT_TYPE_NO : pTextTxt = GetTextTexture(pRen, pFont, szYESNO[1], 0); break; case BT_TYPE_CUSTOM : pTextTxt = GetTextTexture(pRen, pFont, pBtn[i].text, tc); break; default : break; } if(pBGTxt != NULL && pTextTxt != NULL) { rt.x = pBtn[i].x; rt.y = pBtn[i].y; rt.w = pBtn[i].w; rt.h = pBtn[i].h; SDL_RenderCopy(pRen, pBGTxt, NULL, &rt); SDL_RenderCopy(pRen, pTextTxt, NULL, &rt); // 画上边线 SDL_SetRenderDrawColor(pRen, ulc, ulc, ulc, SDL_ALPHA_OPAQUE); SDL_RenderDrawLine(pRen, rt.x, rt.y, rt.x + rt.w, rt.y); SDL_RenderDrawLine(pRen, rt.x, rt.y, rt.x, rt.y + rt.h); // 画下边线 SDL_SetRenderDrawColor(pRen, dlc, dlc, dlc, SDL_ALPHA_OPAQUE); SDL_RenderDrawLine(pRen, rt.x + rt.w, rt.y, rt.x + rt.w, rt.y + rt.h); SDL_RenderDrawLine(pRen, rt.x, rt.y + rt.h, rt.x + rt.w, rt.y + rt.h); } if(pBGTxt != NULL) SDL_DestroyTexture(pBGTxt); if(pTextTxt != NULL) SDL_DestroyTexture(pTextTxt); } }
有了按钮,就可以建一个简单的窗口,只显示标题和文字内容,再加几个按钮。是窗口,当然也要自己处理消息了。
// MySDL_Dialog.h // SDL2 自定义部件 - 对话框 #include <SDL2/SDL.h> #include <SDL2/SDL_ttf.h> #include "MySDL_Button.h" #ifndef MYSDL2_DIALOG_H #define MYSDL2_DIALOG_H // 对话框结构 typedef struct st_SDL_Dialog { char *title; // 标题 char *text; // 文字 SDL_Button_Type btn_type; // 按钮类型 } SDL_Dialog; // 显示一个简单的对话框 // 参数:pWin = 父窗口;pFont = 字体;title = 标题;text = 文字;btn_type = 按钮类型 //返回值:被点击的按钮的类型值 extern SDL_Button_Type ShowDialog(SDL_Window *pWin, TTF_Font *pFont, char *title, char *text, SDL_Button_Type btn_type); #endif
// MySDL_Dialog.c // SDL2 自定义部件 - 对话框 #include <string.h> #include "MySDL_Texture.h" #include "MySDL_Dialog.h" #define MARGIN 10 // 窗口边宽 static void UpdateWindow(SDL_Window *pWin, SDL_Renderer *pRen, SDL_Texture **pTxt, TTF_Font *pFont, char *title, char *text, SDL_Button *pBtn, int btnNum); // 显示一个简单的对话框 // 参数:pWin = 父窗口;pFont = 字体;title = 标题;text = 文字;btn_type = 按钮类型 //返回值:被点击的按钮的类型值 extern SDL_Button_Type ShowDialog(SDL_Window *pWin, TTF_Font *pFont, char *title, char *text, SDL_Button_Type btn_type) { int w, h; SDL_Window *pThisWin; SDL_Renderer *pRen; SDL_Texture *pTxt[4]; // 整体背景(标题栏、边框),文字背景,标题、文字的纹理 SDL_Event event; _Bool bRun = 1; SDL_Button_Type ret = -1; // 通常对话框上的按钮有三种形式:1、单“确定”,2、“确定” + “取消”,3、“是” + “否”。 // 默认定义为 2、“确定” + “取消” SDL_Button btn[2] = { {BT_TYPE_OK, 0, 0, 0, 0, 0, NULL, 1, BTN_STATE_NORMAL}, {BT_TYPE_CANCEL, 1, 0, 0, 0, 0, NULL, 1, BTN_STATE_NORMAL} }; int btnNum = (btn_type == BT_TYPE_OK ? 1 : 2); // 控制按钮数量一个,则只有 1、单“确定” int id; // 调整为 3、“是” 和“否” if(btn_type == BT_TYPE_YESNO) { btn[0].type = BT_TYPE_YES; btn[1].type = BT_TYPE_NO; } SDL_GetWindowSize(pWin, &w, &h); if(SDL_CreateWindowAndRenderer(w / 2, h / 2, SDL_WINDOW_BORDERLESS | SDL_WINDOW_INPUT_GRABBED, &pThisWin, &pRen) == -1) goto label_error; pTxt[0] = GetRGBTexture(pRen, w / 2, h / 2, 0x00FFFF); pTxt[1] = GetRGBTexture(pRen, w / 2 - 2 * MARGIN, h / 2 - 5 * MARGIN, 0xFFFFFF); pTxt[2] = GetTextTexture(pRen, pFont, title, 0); pTxt[3] = GetTextTexture(pRen, pFont, text, 0); if(NULL == pTxt[0] || NULL == pTxt[1] || NULL == pTxt[2] || NULL == pTxt[3]) goto label_error; while(bRun && SDL_WaitEvent(&event)) { switch(event.type) { case SDL_MOUSEMOTION : // 鼠标移动 id = SDL_isOnButton(event.button.x, event.button.y, btn, btnNum); if(id >= 0) // 鼠标在某个按钮上 { // 鼠标左键压下则该按钮处于凹状态,无鼠标键压下则该按钮处于凸状态 if(event.motion.state == SDL_BUTTON_LMASK) btn[id].state = BTN_STATE_DOWN; else btn[id].state = BTN_STATE_UP; } else // 鼠标不在按钮上,则所有按钮正常显示 { for(int i = 0; i < btnNum; i++) btn[i].state = BTN_STATE_NORMAL; } UpdateWindow(pThisWin, pRen, pTxt, pFont, title, text, btn, btnNum); break; case SDL_MOUSEBUTTONDOWN : // 鼠标键按下 id = SDL_isOnButton(event.button.x, event.button.y, btn, btnNum);; if(id >= 0) // 按下某个按钮,该按钮处于凹状态 { btn[id].state = BTN_STATE_DOWN; UpdateWindow(pThisWin, pRen, pTxt, pFont, title, text, btn, btnNum); } break; case SDL_MOUSEBUTTONUP : // 鼠标按键弹起 id = SDL_isOnButton(event.button.x, event.button.y, btn, btnNum); if(id >= 0) // 在某个按钮上则结束对话框,返回按钮类型 { ret = btn[id].type; bRun = 0; } break; case SDL_KEYUP :// 键盘的 Esc 键 也当“取消”处理 if(event.key.keysym.sym == SDLK_ESCAPE) { ret = BT_TYPE_CANCEL; bRun = 0; } break; case SDL_WINDOWEVENT : // 有窗口消息,重新计算窗口尺寸 UpdateWindow(pThisWin, pRen, pTxt, pFont, title, text, btn, btnNum); break; default : break; } } label_error: if(pTxt[0] != NULL) SDL_DestroyTexture(pTxt[0]); if(pTxt[1] != NULL) SDL_DestroyTexture(pTxt[1]); if(pTxt[2] != NULL) SDL_DestroyTexture(pTxt[2]); if(pTxt[3] != NULL) SDL_DestroyTexture(pTxt[3]); if(pRen != NULL) SDL_DestroyRenderer(pRen); if(pThisWin != NULL) SDL_DestroyWindow(pThisWin); return ret; } // 重绘窗口 static void UpdateWindow(SDL_Window *pWin, SDL_Renderer *pRen, SDL_Texture **pTxt, TTF_Font *pFont, char *title, char *text, SDL_Button *pBtn, int btnNum) { SDL_Rect rt; int w, h; SDL_GetWindowSize(pWin, &w, &h); SDL_RenderClear(pRen); // 整体背景(标题栏、边框) SDL_RenderCopy(pRen, pTxt[0], NULL, NULL); //文字背景 rt.x = MARGIN; rt.y = 4 * MARGIN; rt.w = w - 2 * MARGIN; rt.h = h - 5 * MARGIN; SDL_RenderCopy(pRen, pTxt[1], NULL, &rt); // 标题 rt.x = MARGIN; rt.y = MARGIN / 2; rt.w = MARGIN * strlen(title); rt.h = 3 * MARGIN; SDL_RenderCopy(pRen, pTxt[2], NULL, &rt); // 文字 rt.y = 6 * MARGIN; rt.w = MARGIN * strlen(text); rt.h = 3 * MARGIN; SDL_RenderCopy(pRen, pTxt[3], NULL, &rt); // 按钮 if(btnNum == 1) { pBtn[0].x = 3 * w / 4; pBtn[0].y = 3 * h / 4; } else { pBtn[0].x = w / 4; pBtn[1].x = 3 * w / 4; pBtn[0].y = pBtn[1].y = 3 * h / 4; } pBtn[1].w = pBtn[0].w = w / 6; pBtn[1].h = pBtn[0].h = h / 6; SDL_DrawButton(pRen, pFont, pBtn, btnNum); SDL_RenderPresent(pRen); }
然后就可以在五子棋里测试了,给“悔棋”按钮加上显示对话框的功能
// Five.c // SDL2 五子棋 //#define _DEBUG_ #include <SDL2/SDL.h> #include <SDL2/SDL_image.h> #include <SDL2/SDL_ttf.h> #include <SDL2/SDL_mixer.h> #include <stdio.h> #include <string.h> #include "MySDL_Texture.h" #include "MySDL_Button.h" #include "MySDL_Dialog.h" #include "FiveData.h" // 资源文件 int BackColor = 0xFFFFFF; // 棋子图片的背景色 char *ImgFileName[] = { "Resource/BackGround.jpg", // 棋盘背景图文件 "Resource/BlackPiece.jpg", // 黑棋子图文件 "Resource/WhitePiece.jpg" // 白棋子图文件 }; char SoundFileName[] = "Resource/Stone.mp3"; // 落子音效文件 char FontFileName[] = "C:/Windows/Fonts/msyh.ttf"; // Windows 下字体文件 // 字符串常量 char szWinTitle[] = "SDL2 五子棋"; char *szWho[] = {"黑方", "白方"}; char *szGameTips[] = {"第 %d 手,轮到 %s 落子", "共 %d 手,%s 取得本局胜利"}; _Bool OnKeyUp(int x, int y, int nSpacing); void DrawBoard(SDL_Renderer *pRen, int nSpacing, int c); void DrawPieces(SDL_Renderer *pRen, int nSpacing, SDL_Texture **pImgTxt); void PrintString(SDL_Renderer *pRen, int nSpacing, TTF_Font *pFont, char *text, int c); static void UpdateWindow(SDL_Window *pWin, SDL_Renderer *pRen, int nSpacing, TTF_Font *pFont, SDL_Texture **pImgTxt, SDL_Button *pBtn, int n); #undef main int main(int argc, char **argv) { int WinW = 640, WinH = 480; // 屏幕尺寸 int nSpacing; // 棋盘线距 SDL_Window *pWin; // 主窗口 SDL_Renderer *pRen; // 主窗口渲染器 SDL_Texture *pImgTxt[3]; // 棋盘背景、黑白棋子图纹理 TTF_Font *pFont; // 提示文字字体 Mix_Music *pMusic; // 音效 SDL_Event event; // 事件 _Bool bRun = 1; // 持续等待事件控制循环标识 // 按钮 SDL_Button btn[] = { {BT_TYPE_CUSTOM, 0, 0, 0, 0, 0, " 新局 ", 0, BTN_STATE_NORMAL}, {BT_TYPE_CUSTOM, 1, 0, 0, 0, 0, " 悔棋 ", 0, BTN_STATE_NORMAL}, }; int btnNum = sizeof(btn) / sizeof(SDL_Button); int id; // 初始化:SDL2、SDL_image(jpg)、SDL_ttf、SDL_mixer(mp3) if(SDL_Init(SDL_INIT_EVERYTHING) == -1 || IMG_Init(IMG_INIT_JPG) == -1 || TTF_Init() == -1 || Mix_Init(MIX_INIT_MP3) == -1 || Mix_OpenAudio(MIX_DEFAULT_FREQUENCY, MIX_DEFAULT_FORMAT, MIX_DEFAULT_CHANNELS, 4096) == -1) { #ifdef _DEBUG_ fprintf(stderr, "1 %s", SDL_GetError()); #endif return 1; } // 创建主窗口及其渲染器 if(SDL_CreateWindowAndRenderer(WinW, WinH, SDL_WINDOW_FULLSCREEN, &pWin, &pRen) == -1) { #ifdef _DEBUG_ fprintf(stderr, "2 %s", SDL_GetError()); #endif goto label_error; } SDL_SetWindowTitle(pWin, szWinTitle); // 加载图片文件 if(NULL == (pImgTxt[0] = GetImageTexture(pRen, ImgFileName[0], 0, 0)) || NULL == (pImgTxt[1] = GetImageTexture(pRen, ImgFileName[1], 1, BackColor)) || NULL == (pImgTxt[2] = GetImageTexture(pRen, ImgFileName[2], 1, BackColor))) { #ifdef _DEBUG_ fprintf(stderr, "3 %s", IMG_GetError()); #endif goto label_error; } // 加载字体文件 if(NULL == (pFont = TTF_OpenFont(FontFileName, 20))) { #ifdef _DEBUG_ fprintf(stderr, "4 %s", TTF_GetError()); #endif goto label_error; } // 加载声音文件 if(NULL == (pMusic = Mix_LoadMUS(SoundFileName))) { #ifdef _DEBUG_ fprintf(stderr, "5 %s", Mix_GetError()); #endif goto label_error; } Five_ResetData(); while(bRun && SDL_WaitEvent(&event)) { switch(event.type) { case SDL_MOUSEMOTION : // 鼠标移动 id = SDL_isOnButton(event.button.x, event.button.y, btn, btnNum); // 鼠标在某个按钮上 if(id >= 0) { // 鼠标左键压下则该按钮处于凹状态,无鼠标键压下则该按钮处于凸状态 if(event.motion.state == SDL_BUTTON_LMASK) btn[id].state = BTN_STATE_DOWN; else btn[id].state = BTN_STATE_UP; } // 鼠标不在按钮上 else { // 所有按钮正常显示 for(int i = 0; i < btnNum; i++) btn[i].state = BTN_STATE_NORMAL; } UpdateWindow(pWin, pRen, nSpacing, pFont, pImgTxt, btn, btnNum); break; case SDL_MOUSEBUTTONDOWN : // 鼠标键按下 id = SDL_isOnButton(event.button.x, event.button.y, btn, btnNum);; // 按下某个按钮,该按钮处于凹状态 if(id >= 0) { btn[id].state = BTN_STATE_DOWN; UpdateWindow(pWin, pRen, nSpacing, pFont, pImgTxt, btn, btnNum); } break; case SDL_MOUSEBUTTONUP : // 鼠标按键弹起 id = SDL_isOnButton(event.button.x, event.button.y, btn, 2); // 在某个按钮上则响应功能,在棋盘则检测落子 // 新局 if(id == 0) { btn[0].enable = 0; btn[1].enable = 0; Five_ResetData(); } // 悔棋 else if(id == 1) { id = ShowDialog(pWin, pFont, "悔棋", "要悔棋吗?", BT_TYPE_YESNO); if(id == BT_TYPE_YES) ShowDialog(pWin, pFont, "对不起", "还没实现悔棋功能呢", BT_TYPE_OKCANCEL); else if(id == BT_TYPE_NO) ShowDialog(pWin, pFont, "还好", "你没点是", BT_TYPE_OK); } // 有效落子 else if(id < 0 && g_iWho != NONE && OnKeyUp(event.button.x, event.button.y, nSpacing)) { Mix_PlayMusic(pMusic, 0); btn[0].enable = 1; btn[1].enable = 1; if(Five_isFive()) g_iWho = NONE; } UpdateWindow(pWin, pRen, nSpacing, pFont, pImgTxt, btn, btnNum); break; case SDL_WINDOWEVENT : // 有窗口消息,重新计算窗口尺寸 SDL_GetWindowSize(pWin, &WinW, &WinH); nSpacing = SDL_min(WinW, WinH) / (MAX_LINES + 2); UpdateWindow(pWin, pRen, nSpacing, pFont, pImgTxt, btn, btnNum); break; case SDL_QUIT : bRun = 0; break; default : break; } } label_error: // 清理 if(pImgTxt[0] != NULL) SDL_DestroyTexture(pImgTxt[0]); if(pImgTxt[1] != NULL) SDL_DestroyTexture(pImgTxt[1]); if(pImgTxt[2] != NULL) SDL_DestroyTexture(pImgTxt[2]); if(pRen != NULL) SDL_DestroyRenderer(pRen); if(pWin != NULL) SDL_DestroyWindow(pWin); if(pFont != NULL) TTF_CloseFont(pFont); if(pMusic != NULL) Mix_FreeMusic(pMusic); Mix_CloseAudio(); TTF_Quit(); IMG_Quit(); SDL_Quit(); return 0; } // 重绘窗口 static void UpdateWindow(SDL_Window *pWin, SDL_Renderer *pRen, int nSpacing, TTF_Font *pFont, SDL_Texture **pImgTxt, SDL_Button *pBtn, int btnNum) { char szString[256]; SDL_RenderClear(pRen); SDL_RenderCopy(pRen, pImgTxt[0], NULL, NULL); DrawBoard(pRen, nSpacing, 0); DrawPieces(pRen, nSpacing, pImgTxt); sprintf(szString, szGameTips[g_iWho == NONE], g_nHands + (g_iWho != NONE), szWho[(g_nHands + (g_iWho == NONE)) % 2]); PrintString(pRen, nSpacing, pFont, szString, 0); pBtn[1].x = pBtn[0].x = nSpacing * (MAX_LINES + 1); pBtn[0].y = nSpacing; pBtn[1].y = nSpacing * 3; pBtn[1].w = pBtn[0].w = nSpacing * 2; pBtn[1].h = pBtn[0].h = nSpacing; SDL_DrawButton(pRen, pFont, pBtn, btnNum); SDL_RenderPresent(pRen); } // 响应落子按键 // 参数:(x,y) = 被点击的窗口坐标;nSpacing = 棋盘线距 _Bool OnKeyUp(int x, int y, int nSpacing) { // 计算落点棋盘坐标 int m = (x - 0.5 * nSpacing) / nSpacing; int n = (y - 0.5 * nSpacing) / nSpacing; // 处理有效落点 if(m >= 0 && m < MAX_LINES && n >= 0 && n < MAX_LINES && g_iBoard[m][n] == NONE) { Five_AddPiece(m, n, g_iWho); return 1; } return 0; } // 画圆(SDL2 没有画圆的函数,先用矩形框代替吧) // 参数:pRen = 渲染器;(x,y) = 圆心坐标;r = 半径;c = 填充色 void FillCircle(SDL_Renderer *pRen, int x, int y, int r, int c) { SDL_Rect rt = {x - r, y - r, 2 * r, 2 * r}; SDL_SetRenderDrawColor(pRen, c >> 16, (c >> 8) & 0xFF, c & 0xFF, SDL_ALPHA_OPAQUE); SDL_RenderFillRect(pRen, &rt); } // 画棋盘 // 参数:pRen = 渲染器;nSpacing = 棋盘线距;c = 线及星颜色 void DrawBoard(SDL_Renderer *pRen, int nSpacing, int c) { int r, x, y, z; // 棋盘线 SDL_SetRenderDrawColor(pRen, c >> 16, (c >> 8) & 0xFF, c & 0xFF, SDL_ALPHA_OPAQUE); for(int i = 1; i <= MAX_LINES; i++) { SDL_RenderDrawLine(pRen, nSpacing, i * nSpacing, MAX_LINES * nSpacing, i * nSpacing); SDL_RenderDrawLine(pRen, i * nSpacing, nSpacing, i * nSpacing, MAX_LINES * nSpacing); } // 星位 r = nSpacing * 0.2; // 星半径 x = nSpacing * 4; // 第四线 y = nSpacing * (MAX_LINES + 1) / 2; // 中线 z = nSpacing * (MAX_LINES - 3); // 倒数第四线 FillCircle(pRen, x, x, r, c); FillCircle(pRen, y, x, r, c); FillCircle(pRen, z, x, r, c); FillCircle(pRen, x, y, r, c); FillCircle(pRen, y, y, r, c); FillCircle(pRen, z, y, r, c); FillCircle(pRen, x, z, r, c); FillCircle(pRen, y, z, r, c); FillCircle(pRen, z, z, r, c); } // 画棋子 // 参数:pRen = 渲染器;nSpacing = 棋盘线距;pImgTxt = 棋子纹理 void DrawPieces(SDL_Renderer *pRen, int nSpacing, SDL_Texture **pImgTxt) { int r = 0.4 * nSpacing; // 棋子半径 SDL_Rect rt = {0, 0, 2 * r, 2 * r}; if(g_nHands <= 0) return; for(int i = 0; i < MAX_LINES; i++) { for(int j = 0; j < MAX_LINES; j++) { rt.x = (i + 1) * nSpacing - r; rt.y = (j + 1) * nSpacing - r; if(g_iBoard[i][j] == BLACK) SDL_RenderCopy(pRen, pImgTxt[1], NULL, &rt); else if(g_iBoard[i][j] == WHITE) SDL_RenderCopy(pRen, pImgTxt[2], NULL, &rt); } } } // 提示文字 // 参数:pRen = 渲染器;nSpacing = 棋盘线距;pFont = 字体;text = 文字内容;c = 文字颜色 void PrintString(SDL_Renderer *pRen, int nSpacing, TTF_Font *pFont, char *text, int c) { SDL_Texture *pTextTxt; SDL_Rect rt; rt.x = nSpacing; rt.y = nSpacing * (MAX_LINES + 1); rt.w = nSpacing * strlen(text) / 4; // 这个 4 和字体大小有关 rt.h = nSpacing; if((pTextTxt = GetTextTexture(pRen, pFont, text, c)) != NULL) { SDL_RenderCopy(pRen, pTextTxt, NULL, &rt); SDL_DestroyTexture(pTextTxt); } }
为了统一,把获得纹理的模块也稍微改了下格式
// MySDL_Texture.h // SDL2 公共函数 - 取得 RGB、图片、文字的纹理 #include <SDL2/SDL.h> #include <SDL2/SDL_image.h> #include <SDL2/SDL_ttf.h> #ifndef MYSDL2_TEXTURE_H #define MYSDL2_TEXTURE_H // 取得 RGB 纹理 // 参数:pRen = 渲染器;w, h = 宽、高;c = 颜色 // 返回值:纹理指针 SDL_Texture *GetRGBTexture(SDL_Renderer *pRen, int w, int h, int c); // 取得图片文件纹理 // 参数:pRen = 渲染器;FileName = 图片文件名;bTrn = 是否透明处理;c = 背景色 // 返回值:纹理指针 SDL_Texture *GetImageTexture(SDL_Renderer *pRen, char *FileName, _Bool bTrn, int c); // 取得文字纹理 // 参数:pRen = 渲染器;pFont = 字体;text = 文字内容;c = 文字颜色 // 返回值:纹理指针 SDL_Texture *GetTextTexture(SDL_Renderer *pRen, TTF_Font *pFont, char *text, int c); #endif
// MySDL_Texture.c // SDL2 公共函数 - 取得 RGB、图片、文字的纹理 #include "MySDL_Texture.h" // 取得 RGB 纹理 // 参数:pRen = 渲染器;w, h = 宽、高;c = 颜色 // 返回值:纹理指针 SDL_Texture *GetRGBTexture(SDL_Renderer *pRen, int w, int h, int c) { SDL_Texture *pTexture; SDL_Surface *pSurface; if((pSurface = SDL_CreateRGBSurface(0, w, h, 32, 0, 0, 0, 0)) == NULL) return NULL; SDL_FillRect(pSurface, NULL, c); pTexture = SDL_CreateTextureFromSurface(pRen, pSurface); SDL_FreeSurface(pSurface); return pTexture; } // 取得图片文件纹理 // 参数:pRen = 渲染器;FileName = 图片文件名;bTrn = 是否透明处理;c = 背景色 // 返回值:纹理指针 SDL_Texture *GetImageTexture(SDL_Renderer *pRen, char *FileName, _Bool bTrn, int c) { SDL_Texture *pTexture; SDL_Surface *pSurface; if((pSurface = IMG_Load(FileName)) == NULL) return NULL; if(bTrn) SDL_SetColorKey(pSurface, 1, SDL_MapRGB(pSurface->format, c>>16, (c>>8)&0xFF, c&0xFF)); pTexture = SDL_CreateTextureFromSurface(pRen, pSurface); SDL_FreeSurface(pSurface); return pTexture; } // 取得文字纹理 // 参数:pRen = 渲染器;pFont = 字体;text = 文字内容;c = 文字颜色 // 返回值:纹理指针 SDL_Texture *GetTextTexture(SDL_Renderer *pRen, TTF_Font *pFont, char *text, int c) { SDL_Texture *pTexture; SDL_Surface *pSurface; SDL_Color color = {c>>16, (c>>8)&0xFF, c&0xFF}; if((pSurface = TTF_RenderUTF8_Blended(pFont, text, color)) == NULL) return NULL; pTexture = SDL_CreateTextureFromSurface(pRen, pSurface); SDL_FreeSurface(pSurface); return pTexture; }
把 Makefile 也贴出来吧
SourceFile = Five.c FiveData.c MySDL_Dialog.c MySDL_Button.c MySDL_Texture.c Library = -lSDL2 -lSDL2main -lSDL2_image -lSDL2_ttf -lSDL2_mixer ALL: $(SourceFile) Makefile gcc -mwindows -o Five $(SourceFile) $(Library)
数据处理部分、图片文件、声音和前面一样。
另外,这个办法在安卓下无效,原因不明。