您的位置:首页 > 其它

SDL2 自建对话框

2016-02-15 00:00 429 查看
对话框就是一个简单的窗口,仅包含标题、文字信息和一两个特定文字的按钮。

所以我们先改造下上篇的按钮,增加类型属性,并添加几个对话框专用的特定的按钮。

// 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]
== 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)

数据处理部分、图片文件、声音和前面一样。

另外,这个办法在安卓下无效,原因不明。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: