简单RPG场景实现(改

  1. 顺便取消了可以同时键盘与鼠标移动的功能(因为没啥用),现在只能使用鼠标
  2. 删除了一些冗余的代码
  3. 修改了鼠标点击某些地方导致程序崩溃的bug
//windows.h文件中包含应用程序中所需的数据类型和数据结构的定义
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include "menu_4.h"
#include <math.h>
//TransparentBlt需要导入以下头文件
#pragma  comment(lib,"Msimg32.lib")
#include <wingdi.h>

HBITMAP hBm_Dir[24]; //人物动作
HBITMAP hBm_bg;     //背景图
HBITMAP hBm_dia;    //弹出对话的图片

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInst,LPSTR lpszCmdLine,int nCmdShow)
{
    HWND hwnd;
    MSG Msg;
    WNDCLASS wndclass;
    /*
      关于为啥在WINMAIN里面载入位图
      是因为LoadBitmap需要传入HInstance参数
      当然在WinProc里载入也是可以的
      就需要设一个全局的HInstance变量
      所以为了方便还是在WINmain里载入
    */
    //载入动作图
    hBm_Dir[0] = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAP_L1));
    hBm_Dir[1] = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAP_L2));
    hBm_Dir[2] = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAP_L3));
    hBm_Dir[3] = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAP_R1));
    hBm_Dir[4] = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAP_R2));
    hBm_Dir[5] = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAP_R3));
    hBm_Dir[6] = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAP_U1));
    hBm_Dir[7] = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAP_U2));
    hBm_Dir[8] = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAP_U3));
    hBm_Dir[9] = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAP_D1));
    hBm_Dir[10] = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAP_D2));
    hBm_Dir[11] = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAP_D3));
    hBm_Dir[12] = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAP_RD1));
    hBm_Dir[13] = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAP_RD2));
    hBm_Dir[14] = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAP_RD3));
    hBm_Dir[15] = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAP_RU1));
    hBm_Dir[16] = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAP_RU2));
    hBm_Dir[17] = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAP_RU3));
    hBm_Dir[18] = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAP_LD1));
    hBm_Dir[19] = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAP_LD2));
    hBm_Dir[20] = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAP_LD3));
    hBm_Dir[21] = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAP_LU1));
    hBm_Dir[22] = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAP_LU2));
    hBm_Dir[23] = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAP_LU3));
    //载入背景图
    hBm_bg = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAP_BG));
    //载入对话图
    hBm_dia = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAP_DIA));
    char lpszClassName[] = "窗口";
    char lpszTitle[] = "[Vic.]模仿_上古神器2";    //窗口标题名

    //窗口类的定义
    wndclass.style = CS_HREDRAW | CS_VREDRAW;
    wndclass.lpfnWndProc = WndProc;
    wndclass.cbClsExtra = 0;
    wndclass.cbWndExtra = 0;
    wndclass.hInstance = hInstance;

    wndclass.hIcon = LoadIcon(NULL,IDI_APPLICATION);
    wndclass.hCursor = LoadCursor( NULL, IDC_ARROW);
    wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    //载入rs文件
    wndclass.lpszMenuName = "menu4" ;
    wndclass.lpszClassName = lpszClassName;

    if (!RegisterClass(&wndclass))
    {
        MessageBeep (0);
        return FALSE;
    }

//创建窗口
    hwnd = CreateWindow(
                        lpszClassName, lpszTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,  //窗口左上角坐标为默认值
                        640,   //窗口宽度
                        510,  //窗口的髙
                        NULL, NULL, hInstance,  NULL
                        );

    ShowWindow( hwnd, nCmdShow);
    UpdateWindow(hwnd);
    while( GetMessage(&Msg, NULL, 0, 0))
    {
        TranslateMessage(&Msg);
        DispatchMessage(&Msg);
    }
    return Msg.wParam;
}

//窗口函数
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    // hdc_old和 hBmp是用于双缓冲,如果不懂双缓冲是啥,可以看看我的博客
    HDC hDC, hdc_old;
    HBITMAP hBmp;
    // 用于与hDC绑定的位图hDC与hBmp(人物,背景,对话)
    static HDC hdcmem_ch, hdcmem_bg, hdcmem_dia;
    static BITMAP bm_ch, bm_bg, bm_dia;

    RECT rect;
    PAINTSTRUCT ps;
    //j是用来
    static int i, j = 0;

    static int mx, my; //记录鼠标的位置
    static int toX = 0, toY = 0; //记录鼠标点击时的位置
    static int beforeX, beforeY;    //记录鼠标点击之前的坐标
    //设置全局标记(对话)
    static bool isDia = false, isMoving = false;
    /*
    state代表的时加载哪种类型的位图
    0:抬右手
    1:抬左手
    2:静止

    这个主要是因为我的人物动作位图每个方位都分解为3张
    之后我将它们按这样的顺序命名与载入了
    */
    static int state = 2;

    /*
        dir代表的是方位标记
        按照载入顺序进行标记
        L,R,U,D, RD,RU,LD,LU
    */
    static int dir = 0;
    char str[100];
    static int x = 12, y = 204; //人物的初始位置坐标
    static int keep; //用于切换方向位图
    static int pre_dir = dir; //用于记录两次按键是否同一方向
    //int di;
    switch(message)
    {
    case WM_CHAR:
        return 0;
    case WM_KEYUP:
        return 0;
    case WM_KEYDOWN:
        return 0;
    case WM_MOUSEMOVE:
        //对话状态,不需要记录鼠标的位置
        if (!isDia)
        {
            mx = LOWORD(lParam);
            my = HIWORD(lParam);
            InvalidateRect(hWnd, NULL,1);
        }
        return 0;
    case WM_LBUTTONDOWN:
        //对话状态,如果用鼠标左键点击则解除对话状态
        if (isDia)
        {
            isDia = false;
            x -= 10;//将人物位置后退一点以免重复触发
        }
        //其他状态,鼠标点击代表移动
        else
        {
            j = 0;
            isMoving = true;
            beforeX = x, beforeY = y; //记录点击之前人物的位置
            if (state == 2) state = 0; //将人物重置为静止状态先
            toX = mx-bm_ch.bmWidth/2, toY = my-bm_ch.bmHeight*4/5; //将点击位置作为人物的落脚点(右下角)
            //设置边界
            if (toX >= 430) toX = 430;
            if (toX <= 20) toX = 20;
            if (toY >= 239) toY = 239;
            if (toY <= 179) toY = 179;

            //判断人物方向
            if (mx <= x && my <= y)  dir = 7;
            else if (mx <= x && my >= y+bm_ch.bmHeight)  dir = 6;
            else if (mx >= x+bm_ch.bmWidth && my >= y+bm_ch.bmHeight) dir = 4;
            else if (my <= y && mx >= x+bm_ch.bmWidth) dir = 5;
            else if (my <= y) dir = 2;
            else if (my >= y+bm_ch.bmHeight) dir = 3;
            else if (mx <= x) dir = 0;
            else if (mx >= x+bm_ch.bmWidth) dir = 1;

        }
        InvalidateRect(hWnd, NULL,1);
        return 0;
    case WM_ERASEBKGND:
        return 1;
    case WM_CREATE:
        //创建位图hDC
        hDC=GetDC(hWnd);
        hdcmem_ch=CreateCompatibleDC(hDC);
        hdcmem_dia=CreateCompatibleDC(hDC);
        hdcmem_bg=CreateCompatibleDC(hDC);
        ReleaseDC(hWnd, hDC);
        return 0;
    case WM_PAINT:
        //双缓冲绑定
        hdc_old = BeginPaint(hWnd, &ps);
        hDC = CreateCompatibleDC(hdc_old);
        GetClientRect(hWnd,&rect);
        hBmp = CreateCompatibleBitmap(hdc_old,rect.right,rect.bottom);
        SelectObject(hDC,hBmp);

        SelectObject(hdcmem_ch, hBm_Dir[dir*3+state]);
        //判断是否对话状态
        if (!isDia)
        {
            SelectObject(hdcmem_bg, hBm_bg);
            GetObject(hBm_bg, sizeof(BITMAP), &bm_bg);
        }
        else
        {
            SelectObject(hdcmem_dia, hBm_dia);
            GetObject(hBm_dia, sizeof(BITMAP), &bm_dia);
        }
        //绑定动作位图
        GetObject(hBm_Dir[dir*3+state], sizeof(BITMAP), &bm_ch);
        //如果持续在一个方向上就使keep增加
        //if (pre_dir == dir) 
            keep++;
        //如果不在一个方向上就将keep初始话
        //else pre_dir = dir, keep = 0;


        if (isMoving)
        {
            Sleep(10);
            //j代表
            j+=100;
            int di = 100*(abs(toX-beforeX)+abs(toY-beforeY));
            di /= 3;
            if (di)
                x = beforeX + (toX-beforeX)*j/di, y = beforeY + (toY-beforeY)*j/di;
            if (j >= di) state = 2, isMoving = false;
            if (keep >= 10)
            {
                if (state == 0) state = 1;
                else if (state == 1) state = 0;
                keep = 0;
            }
            InvalidateRect(hWnd, NULL, 1);
        }
        
        //如果到了那个位置就弹出对话
        if (x >= 430) isDia = true;
        //加载对话图片
        if (isDia) BitBlt(hDC, 0, 0, bm_dia.bmWidth, bm_dia.bmHeight,hdcmem_dia,0,0,SRCCOPY);
        //加载背景图片
        else BitBlt(hDC, 0, 0, bm_bg.bmWidth, bm_bg.bmHeight,hdcmem_bg,0,0,SRCCOPY);
        //加载人物图片
        //sprintf(str," %d %d", x, y);
        //DrawText(hDC, str, -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
        TransparentBlt(hDC, x, y, bm_ch.bmWidth, bm_ch.bmHeight, hdcmem_ch, 0, 0, bm_ch.bmWidth, bm_ch.bmHeight, RGB(255,255,255));
        BitBlt(hdc_old,0,0,rect.right,rect.bottom,hDC,0,0,SRCCOPY);
        DeleteObject(hBmp);
        DeleteDC(hDC);
        ReleaseDC(hWnd, hDC); //释放
        EndPaint(hWnd, &ps); //结束缓制
        return 0;

    case WM_DESTROY:
        //将位图释放
        for (i = 0; i < 24; i++) DeleteObject(hBm_Dir[i]);
        DeleteObject(hBm_bg);
        DeleteObject(hBm_dia);
        PostQuitMessage(0);                 //调用 PostQuitMessage 发出 WM_QUIT 消息

        return 0;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam); //默认时采用系统消息默认处理函数

    }

}

原文地址:https://www.cnblogs.com/Vikyanite/p/12678196.html