對話框就是一個簡單的窗口,僅包含標題、文字信息和一兩個特定文字的按鈕。windows
因此咱們先改造下上篇的按鈕,增長類型屬性,並添加幾個對話框專用的特定的按鈕。數組
// 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; // 一般對話框上的按鈕有三種形式:一、單「肯定」,二、「肯定」 + 「取消」,三、「是」 + 「否」。 // 默認定義爲 二、「肯定」 + 「取消」 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); // 控制按鈕數量一個,則只有 一、單「肯定」 int id; // 調整爲 三、「是」 和「否」 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; // 初始化:SDL二、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 也貼出來吧ui
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)
數據處理部分、圖片文件、聲音和前面同樣。指針
另外,這個辦法在安卓下無效,緣由不明。code