文档章节

SDL2 自建对话框

 四彩
发布于 2016/02/15 11:17
字数 3541
阅读 279
收藏 1
点赞 1
评论 0

对话框就是一个简单的窗口,仅包含标题、文字信息和一两个特定文字的按钮。

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

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

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

另外,这个办法在安卓下无效,原因不明。



© 著作权归作者所有

共有 人打赏支持
粉丝 25
博文 49
码字总数 77226
作品 0
茂名
Windows32 下 SDL2 库的安装

一、下载 进入官网 http://www.libsdl.org/ ,网站相当简洁,直接在左下角找下载链接即可 点 SDL 2.0,转到 2.0 页面,现在最新的是 2.04,拉到下面找开发库 根据你的编译器下载对应的版本,...

四彩
2016/02/04
127
0
在CodeBlocks下配置SDL2开发环境

最近在学习SDL的开发,想用平时熟悉的IDE:Code::Blocks来编写SDL程序。但是我按照网上的方法试了一下,都配置不成功.然后编译不了: 我用的是Code::Blocks 12.11.用的SDL2是官网下载的SDL2-...

刘越
2013/10/27
3.6K
7
将五子棋和时钟移植到安卓(C4droid)下,示例 SDL2 的夸平台移植、触摸事件

SDL2 跨越多种平台,那个五子棋很容易移至到 Android 上去,只需要调整下 Five.c 中的消息响应(把鼠标消息改成触摸消息),在调整下窗口风格为全屏即可。另外,安卓下SDL_mixer 支持 wav、o...

四彩
2016/02/14
130
0
android SDL系列讲解(十三) 播放音乐库 SDL_mixer教程

项目外包项目信息更新: qq抢红包,因为评估时间问题,没有对接下来。 一个网页开发项目,已经内部消耗掉了。 机会总是稍纵即逝,有兴趣探讨技术,以及项目事宜,可以联系代码GG微信: code...

代码GG陆晓明
2017/10/28
0
0
SDL2源代码分析4:纹理(SDL_Texture)

===================================================== SDL源代码分析系列文章列表: SDL2源代码分析1:初始化(SDLInit()) SDL2源代码分析2:窗口(SDLWindow) SDL2源代码分析3:渲染器...

leixiaohua1020
2014/11/05
0
0
SDL中的Anti-aliasing

  默认情况下,SDL2中默认是不启用MSAA.为了能启用,必须做些设置.如果渲染器工作在OpenGL/ES模式下,那么直接使用: SDLGLSetAttribute(SDLGLMULTISAMPLEBUFFERS,1); SDLGLSetAttribute(SDLGL...

小耶果
2014/05/04
0
0
最简单的基于FFmpeg的移动端例子附件:SDL Android HelloWorld

===================================================== 最简单的基于FFmpeg的移动端例子系列文章列表: 最简单的基于FFmpeg的移动端例子:Android HelloWorld 最简单的基于FFmpeg的移动端例...

leixiaohua1020
2015/07/25
0
0
SDL2源代码分析7:显示(SDL_RenderPresent())

===================================================== SDL源代码分析系列文章列表: SDL2源代码分析1:初始化(SDLInit()) SDL2源代码分析2:窗口(SDLWindow) SDL2源代码分析3:渲染器...

leixiaohua1020
2014/11/09
0
0
SDL 的 Python 移植版本--Py-SDL2

Py-SDL2 是 SDL 的 Python 移植版本。Py-SDL2 使用上没有任何许可证限制。

红薯
2013/11/12
1K
0
SDL2源代码分析6:复制到渲染器(SDL_RenderCopy())

===================================================== SDL源代码分析系列文章列表: SDL2源代码分析1:初始化(SDLInit()) SDL2源代码分析2:窗口(SDLWindow) SDL2源代码分析3:渲染器...

leixiaohua1020
2014/11/08
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

LSM树(Log-Structured Merge Tree)存储引擎浅析

其实每一种数据库,它都是一种抽象的数据结构的具体实现。 随着rocksDB(facebook的),levelDB(google的),以及我们熟知的hbase,他们都是使用的LSM树结构的数据库。 它的核心思路其实非常...

算法之名
15分钟前
6
0
ARTS说明

湾曲日报,作者每天阅读5篇优质英文文章,从2014/08/06开始,到今天也1216期了. 阮一峰的每周分享,从2018/04/20开始,每周5分享一周作者认为值得分享的东西,现在最新是14期. 关于ARTS Algorithm ...

yysue
17分钟前
0
0
sql优化原则

批量查询/更新/获得表结构 1.sp_help table_name;-sqlserver==desc table_name-mysql 如: sp_help Student; sql优化: 应尽量避免在 where 子句中使用!=或<>操作符,否则将引擎放弃使用索引...

xd03122049
24分钟前
0
0
python爬虫日志(6)小小实践

经过3天的学习,现在对简单的网页基本可以爬取想爬取的信息了,但还无法应对网站一些复杂的反爬虫措施。 今天利用目前为止所学的知识,试着爬取了煎蛋网几页图片并下载到本地。 #首先还是先导...

茫羽行
30分钟前
0
0
js中用oop思想封装轮播

用户可以自己设置:1、速度speed:fast,normal,slow 2、是否自动轮播:true,false 3、选择器(当然可以根据需求,增加,目前先封的这三个)仅供参考 觉得oop面向对象的思想比较有意思,前端...

琴妹
30分钟前
0
0
使用fastjson将json格式的数据转化为对象

1. 导入fastjson的jar包 <!-- 9.fastjson --> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.47</version> </dependency> 2. 常用几种类型的......

Lucky_Me
32分钟前
0
0
JDK11的ZGC小试牛刀

序 本文主要试一下JDK11的ZGC ZGC ZGC全称是Z Garbage Collector,是一款可伸缩(scalable)的低延迟(low latency garbage)、并发(concurrent)垃圾回收器,旨在实现以下几个目标: 停顿时间不超...

go4it
37分钟前
0
0
电信ss/ssr速度慢 电信国际出口速度慢 被QoS限速

很多人跟我反应,同一条线路,电信用户的国际出口速度很慢,而移动/联通用户却还不错,可能移动/联通可以流畅看1080P,而电信卡的连国外网页都打不开。明明电信的国际出口宽带是三家中最高的...

flyzy2005
41分钟前
0
0
java中equals,hashcode和==的区别

1、== java中的数据类型,可分为两类: 1.基本数据类型,也称原始数据类型 byte,short,char,int,long,float,double,boolean 他们之间的比较,应用双等号(==),比较的是他们的值。 2.引用类型...

小海bug
今天
0
0
Win10专业版安装GIT后使用Git Bash闪退解决办法

百度后把过程和最终解决办法记录下来: 百度首先出来的解决办法如下: 来自:https://segmentfault.com/q/1010000012722511?sort=created 重启电脑 重新安装 安装到C盘 尝试网上的教程 \Git...

特拉仔
今天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部