小学期作业总结报告

游戏: flappy bird(草稿版)

游戏素材

  1. 在网上找了几张素材图片
  2. 将图片转成bmp格式
  3. 对图片进行一些处理,方便后面操作

代码部分

先放图:


大体来说,用到的函数就是这些

代码详解

#include <windows.h>

#pragma comment(lib,"winmm.lib")        //调用PlaySound函数所需库文件
#pragma  comment(lib,"Msimg32.lib")     //添加使用TransparentBlt函数所需的库文件

#define WINDOW_WIDTH    450     //为窗口宽度定义的宏,以方便在此处修改窗口宽度
#define WINDOW_HEIGHT   650     //为窗口高度定义的宏,以方便在此处修改窗口高度
#define TUBE_WIDTH      52      //管道的宽度为52像素
#define TUBE_HEIGHT     320     //管道的高度为320像素
#define BIRD_WIDTH      48      //鸟的宽度
#define BIRD_HEIGHT     48      //鸟的高度
#define BIRD_X          100     //鸟的X坐标
#define GRAVITY         2       //重力加速度
#define PASSWAY         130     //管道中间距离130

这部分就是进行一些库的包括,以及宏的定义

int tube_x[3] = { WINDOW_WIDTH ,WINDOW_WIDTH + 167,WINDOW_WIDTH + 167 * 2 }, i; //管道左上角的水平位置
int randomNumber[3] = { 0 }, loopNumber = 0, score = 0, rgb[3] = {0};
int bird_y = 250, birdSpeed = 0;
HDC g_hdc = NULL, g_mdc = NULL, g_bufdc = NULL; //全局变量环境句柄和全局内存DC句柄
DWORD g_tPre = 0, g_tNow = 0, g_tGra = 0, g_tStart = 0,g_tRGB=0;
HBITMAP g_hBackground = NULL, g_hGround = NULL, g_hTubeDown = NULL, g_hTubeUp = NULL, g_hBird = NULL;

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);//窗口过程函数
BOOL Game_Init(HWND hwnd);      //在此函数中进行资源的初始化
VOID Game_Paint(HWND hwnd);     //在此函数中进行绘图代码的书写
BOOL Game_CleanUp(HWND hwnd);   //在此函数中进行资源的清理

声明变量和函数

WinMain函数内部

    PlaySound("GameMedia\\8bitMusic.wav", NULL, SND_FILENAME | SND_ASYNC);

播放背景音乐

        WNDCLASSEX wndClass = { 0 };
    wndClass.cbSize = sizeof(WNDCLASSEX);
    wndClass.style = CS_HREDRAW | CS_VREDRAW;
    wndClass.lpfnWndProc = WndProc;
    wndClass.cbClsExtra = 0;
    wndClass.cbWndExtra = 0;
    wndClass.hInstance = hInstance;
    wndClass.hIcon = (HICON)::LoadImage(NULL, "icon.ico", IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_LOADFROMFILE);
    wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
    wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    wndClass.lpszMenuName = NULL;
    wndClass.lpszClassName = "myWindow";

窗口类的设计

if (!RegisterClassEx(&wndClass))    //注册窗口
    {
        return -1;
    }

窗口类的注册

HWND hwnd = CreateWindow("myWindow", "GameBy1zhou",
        WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, WINDOW_WIDTH,
        WINDOW_HEIGHT, NULL, NULL, hInstance, NULL);    //创建窗口

窗口类的创建

MoveWindow(hwnd, 250, 80, WINDOW_WIDTH, WINDOW_HEIGHT, true);
ShowWindow(hwnd, nShowCmd);
UpdateWindow(hwnd);

窗口的显示、更新

if (!Game_Init(hwnd))
    {
        MessageBox(hwnd, "资源初始化失败", "ERROR", 0); //使用MessageBox函数,创建一个消息窗口
        return FALSE;
    }

游戏的初始化

MSG msg = { 0 };                //定义并初始化msg
    while (msg.message != WM_QUIT)      //使用while循环,如果消息不是WM_QUIT消息,就继续循环
    {

        if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))   //查看应用程序消息队列,有消息时将队列中的消息派发出去。
        {
            TranslateMessage(&msg);     //将虚拟键消息转换为字符消息
            DispatchMessage(&msg);          //分发一个消息给窗口程序。
        }
        else
        {
            g_tNow = GetTickCount();   //获取当前系统时间
            if (g_tNow - g_tPre >= 20) //当此次循环运行与上次绘图时间相差0.02秒时再进行重绘操作
            {
                Game_Paint(hwnd);
            }
        }
    }

消息循环(这里我用的是PeekMessage,方便游戏画面的刷新)

UnregisterClass("myWindow", wndClass.hInstance);  //程序准备结束,注销窗口类

窗口类的注销

窗口过程函数

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{


    switch (message)
    {
    case WM_KEYUP:
        switch (wParam)
        {
        case VK_UP:
            birdSpeed = -3;
            break;
        }
    case WM_KEYDOWN:
        switch (wParam)
        {

        case VK_ESCAPE:
            Game_CleanUp(hwnd);
            DestroyWindow(hwnd);
            PostQuitMessage(0);

            break;
        }

        break;
    case WM_DESTROY:
        Game_CleanUp(hwnd);
        PostQuitMessage(0);

        break;

    default:
        return DefWindowProc(hwnd, message, wParam, lParam);
    }

    return 0;
}

Game_Init函数

srand((unsigned)timeGetTime());

    for (i = 0; i < 3; i++)
    {
        randomNumber[i] = 80 + rand() % 240;
    }

管道长度的随机产生

HBITMAP bmp;

g_hdc = GetDC(hwnd);
g_mdc = CreateCompatibleDC(g_hdc); //内存DC
g_bufdc = CreateCompatibleDC(g_hdc); //缓存DC
bmp = CreateCompatibleBitmap(g_hdc, WINDOW_WIDTH, WINDOW_HEIGHT);

SelectObject(g_mdc, bmp);

三缓存(先把资源放进缓存DC中,然后在贴到内存DC上,所有资源全部贴好后,最后在直接把内存DC的画面直接贴到HDC)

g_hBackground = (HBITMAP)LoadImage(NULL, "GameMedia\\background.bmp", IMAGE_BITMAP, WINDOW_WIDTH, WINDOW_HEIGHT, LR_LOADFROMFILE);
g_hGround = (HBITMAP)LoadImage(NULL, "GameMedia\\ground.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
g_hTubeDown = (HBITMAP)LoadImage(NULL, "GameMedia\\tubeDown.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
g_hTubeUp = (HBITMAP)LoadImage(NULL, "GameMedia\\tubeUp.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
g_hBird = (HBITMAP)LoadImage(NULL, "GameMedia\\bird.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);

加载游戏资源

HFONT hFont;
hFont = CreateFont(20, 0, 0, 0, 700, 0, 0, 0, GB2312_CHARSET, 0, 0, 0, 0, TEXT("微软雅黑"));
SelectObject(g_mdc, hFont);
SetBkMode(g_mdc, TRANSPARENT);

创建字体

Game_Paint函数

(贴图部分我用的是透明色彩法 TransparentBlt )

SelectObject(g_bufdc, g_hBackground);
BitBlt(g_mdc, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, g_bufdc, 0, 0, SRCCOPY);

SelectObject(g_bufdc, g_hGround);
BitBlt(g_mdc, 0, 530, 225, 120, g_bufdc, 0, 0, SRCCOPY);
BitBlt(g_mdc, 225, 530, 225, 120, g_bufdc, 0, 0, SRCCOPY);

先贴上背景和地面(地面的素材图片长度不够,贴了两次)

for (i = 0; i < 3; i++)
    {
        SelectObject(g_bufdc, g_hTubeDown);
        TransparentBlt(g_mdc, tube_x[i], 0, TUBE_WIDTH, randomNumber[i], g_bufdc, 0, TUBE_HEIGHT- randomNumber[i], TUBE_WIDTH, randomNumber[i], RGB(255, 255, 255));

        SelectObject(g_bufdc, g_hTubeUp);
        TransparentBlt(g_mdc, tube_x[i], 130 + randomNumber[i], TUBE_WIDTH, 400 - randomNumber[i], g_bufdc, 0, 0, TUBE_WIDTH, 400 - randomNumber[i], RGB(255, 255, 255));

        if (BIRD_X >= tube_x[i] - BIRD_WIDTH + 10 && BIRD_X <= tube_x[i] + TUBE_WIDTH - 10)
        {
            //这里的加10、减10是因为图片本身边缘有一定的空隙,所以通过这样来使判断更精确一点 =_=
            if (bird_y <= randomNumber[i] - 10 || bird_y >= randomNumber[i] + PASSWAY - BIRD_HEIGHT + 10)
            {
                char result[100];

                PlaySound(NULL, NULL, SND_FILENAME); //结束播放音乐

                wsprintf(result, "GAME OVER!\n你的分数是:%d", score);
                MessageBox(hwnd, result, "游戏结束", 0);

                Game_CleanUp(hwnd);
                DestroyWindow(hwnd);
                PostQuitMessage(0);
            }
        }

        if (bird_y >= 530 - BIRD_HEIGHT + 10)
        {
            char result[100];

            PlaySound(NULL, NULL, SND_FILENAME);
            
            wsprintf(result, "GAME OVER!\n你的分数是:%d", score);
            MessageBox(hwnd, result, "游戏结束", 0);
            Game_CleanUp(hwnd);
            DestroyWindow(hwnd);
            PostQuitMessage(0);
        }

贴上管道、碰撞检测以及游戏结束相应的处理

if (tube_x[i] > -52)
    {
        tube_x[i] -= 1;
    }
    else if (tube_x[i] <= -52)
    {

        tube_x[i] = WINDOW_WIDTH;
        randomNumber[i] =80 + rand() % 240;
    }

管道的重复生成

g_tNow = GetTickCount();
    if (g_tNow - g_tGra >= 500)
    {
        birdSpeed += GRAVITY;
        g_tGra = GetTickCount();

    }

重力的模拟

SelectObject(g_bufdc, g_hBird);

    TransparentBlt(g_mdc, BIRD_X, bird_y, BIRD_WIDTH, BIRD_HEIGHT, g_bufdc, BIRD_WIDTH*loopNumber, 0, BIRD_WIDTH, BIRD_HEIGHT, RGB(0, 0, 0));


    if (loopNumber < 2)
    {
        loopNumber += 1;
    }
    else
    {
        loopNumber = 0;
    }

    bird_y += birdSpeed;

贴上小鸟

if (GetTickCount() - g_tRGB >= 200) //控制颜色的刷新时间
    {
        for (i = 0; i < 3; i++)
        {
            rgb[i] = rand() % 255;
        }

        g_tRGB = GetTickCount();
    }


    if (BIRD_X == tube_x[1]+TUBE_WIDTH || BIRD_X == tube_x[2] + TUBE_WIDTH || BIRD_X == tube_x[0] + TUBE_WIDTH)
    {
        score++;
    }

    char str[3][10];
    wsprintf(str[0], "得");
    wsprintf(str[1], "分");
    wsprintf(str[2], "%d", score);
    SetTextColor(g_mdc, RGB(rgb[0], rgb[1], rgb[2]));
    TextOut(g_mdc, 20, 20, str[0], strlen(str[0]));

    SetTextColor(g_mdc, RGB(rgb[1], rgb[2], rgb[0]));
    TextOut(g_mdc, 40, 20, str[1], strlen(str[1]));

    SetTextColor(g_mdc, RGB(rgb[2], rgb[1], rgb[0]));
    TextOut(g_mdc, 60, 20, str[2], strlen(str[2]));

得分的实时输出

BitBlt(g_hdc, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, g_mdc, 0, 0, SRCCOPY);

将g_mdc的内容全部贴到g_hdc中去,将画面显示在窗口中

Game_CleanUp函数

DeleteObject(g_hBackground);
    DeleteObject(g_hBird);
    DeleteObject(g_hGround);
    DeleteObject(g_hTubeDown);
    DeleteObject(g_hTubeUp);
    

    ReleaseDC(hwnd, g_hdc);
    DeleteDC(g_mdc);
    DeleteDC(g_bufdc);

这里总结一下就是,如果是自己创建的,就需要删除;如果是跟系统要的,就需要释放

总结

  • win32窗口化编程
  • windows系统的消息机制
  • GDI
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,907评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,987评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,298评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,586评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,633评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,488评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,275评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,176评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,619评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,819评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,932评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,655评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,265评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,871评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,994评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,095评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,884评论 2 354

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 172,129评论 25 707
  • 本程序在 VS2003 下调试通过。 建立工程打开 VS2003 选择 文件->新建->项目->Visual C+...
    wingkingcn阅读 610评论 0 0
  • 一:什么是协同程序? 答:在主线程运行时同时开启另一段逻辑处理,来协助当前程序的执行。换句话说,开启协程就是开启一...
    好怕怕阅读 3,886评论 2 23
  • 1) 直接识别字符集,eg:enca -L zh_CN test.cppSimplified Chinese Na...
    风亡小窝阅读 738评论 0 0
  • 这是一个属于我慵懒周末的美好时光。不想起床,我只想听着音乐,码着我的心情文字。 音乐可以让心境沉静下来,简...
    乐乐蘑菇头阅读 258评论 5 0