纯WINDOWS API的C++2D小游戏Subterra(目前还未开发,实时更新)
运行方式:
- Visual Studio (请拥有“使用 C++ 的桌面开发”工作负载)
下载方式:https://visualstudio.microsoft.com/zh-hans/dowloads/
(若上述方法不行,请在 Microsoft Store 内尝试搜索 Visual Studio Community 并下载)
请启动VS(建议使用VS2026):创建新项目> Windows 桌面应用程序> 输入项目名称> 创建
右键“源代码”> 新建> main.cpp
main.cpp源代码
#include<windows.h>#include<gdiplus.h>#pragmacomment(lib,"gdiplus.lib")#defineCLASS_NAMEL"Subterra"#defineWINDOW_WIDTH800#defineWINDOW_HEIGHT512#defineICON_WIDTH32#defineICON_HEIGHT32#defineFDS_MS16structPLAYER{intX=400;intY=256;intWidth=14;intHeight=20;doubleG=80;doubleStart_Jump_Speed=60000;doubleMove_Speed=24000;doubleJump_Speed=0;boolIs_Jumping=false;intMoving=0;//0sat, 1left 2rightboolIs_Squating=false;boolGame_Over=false;boolKeys[95]={false};}Player1;HWND hWnd;HINSTANCE g_hInstance;HDC hPlayerDC;HBITMAP hBitPlayer;intMap[WINDOW_WIDTH/16][WINDOW_HEIGHT/16]={0};HBITMAPCreateTransparentMask(HDC hMemDC,intWidth,intHeight);HICONCreateTransparentIcon(intWidth,intHeight);voidInitGraphics(HDC hdcScreen);voidCleanupGraphics();voidDrawCharacter(HDC hdcScreen);voidDrawGrid();voidUpdatePosition();voidUpdateBackGround();voidUpdate();LRESULT CALLBACKWindowProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam);intWINAPIWinMain(HINSTANCE hInstance,HINSTANCE hPrevlstance,LPSTR lpCmdLine,intnCmdShow){g_hInstance=hInstance;WNDCLASSEX wcex={0};wcex.cbSize=sizeof(WNDCLASSEX);wcex.hbrBackground=(HBRUSH)(COLOR_WINDOW+1);wcex.hCursor=LoadCursor(NULL,IDC_ARROW);wcex.hIcon=LoadIcon(NULL,IDC_ARROW);wcex.hInstance=hInstance;wcex.lpfnWndProc=WindowProc;wcex.lpszClassName=CLASS_NAME;wcex.style=CS_HREDRAW|CS_VREDRAW;if(!RegisterClassEx(&wcex)){MessageBox(NULL,L"Failed to register window class",L"ERROR",MB_ICONERROR);return0;}hWnd=CreateWindowEx(0,CLASS_NAME,CLASS_NAME,WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,WINDOW_WIDTH,WINDOW_HEIGHT,NULL,NULL,hInstance,NULL);if(!hWnd){MessageBox(NULL,L"Failed to create window",L"ERROR",MB_ICONERROR);return0;}ShowWindow(hWnd,nCmdShow);UpdateWindow(hWnd);MSG msg={0};while(GetMessage(&msg,NULL,0,0)){TranslateMessage(&msg);DispatchMessage(&msg);}return(int)msg.wParam;}LRESULT CALLBACKWindowProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam){switch(uMsg){caseWM_CREATE:{HICON hMyIcon=CreateTransparentIcon(32,32);if(hMyIcon){SendMessage(hwnd,WM_SETICON,ICON_SMALL,(LPARAM)hMyIcon);SendMessage(hwnd,WM_SETICON,ICON_BIG,(LPARAM)hMyIcon);}InitGraphics(GetDC(hwnd));ReleaseDC(hwnd,GetDC(hwnd));SetTimer(hwnd,1,FDS_MS,NULL);break;}caseWM_KEYDOWN:Player1.Keys[wParam]=true;break;caseWM_KEYUP:Player1.Keys[wParam]=false;break;caseWM_TIMER:Update();break;caseWM_PAINT:{PAINTSTRUCT ps;HDC hdc=BeginPaint(hwnd,&ps);DrawCharacter(hdc);EndPaint(hwnd,&ps);break;}caseWM_DESTROY:KillTimer(hwnd,1);CleanupGraphics();PostQuitMessage(0);break;}returnDefWindowProc(hwnd,uMsg,wParam,lParam);}HBITMAPCreateTransparentMask(HDC hMemDC,intWidth,intHeight){HBITMAP hMaskBmp=CreateBitmap(Width,Height,1,1,NULL);SelectObject(hMemDC,hMaskBmp);HBRUSH hBrushWhite=CreateSolidBrush(RGB(255,255,255));RECT rc={0,0,Width,Height};FillRect(hMemDC,&rc,hBrushWhite);DeleteObject(hBrushWhite);HPEN hPenBlack=CreatePen(PS_SOLID,1,RGB(0,0,0));SelectObject(hMemDC,hPenBlack);Ellipse(hMemDC,4,4,Width-4,Width-4);DeleteObject(hPenBlack);returnhMaskBmp;}HICONCreateTransparentIcon(intWidth,intHeight){HDC hScreenDC=GetDC(NULL);if(!hScreenDC)returnNULL;HDC hMemDC=CreateCompatibleDC(hScreenDC);BITMAPINFOHEADER biHeader={0};biHeader.biSize=sizeof(BITMAPINFOHEADER);biHeader.biWidth=Width;biHeader.biHeight=Height;biHeader.biPlanes=1;biHeader.biBitCount=32;biHeader.biCompression=BI_RGB;void*pBits=NULL;HBITMAP hColorBmp=CreateDIBSection(hScreenDC,(BITMAPINFO*)&biHeader,DIB_RGB_COLORS,&pBits,NULL,0);if(!hColorBmp||!pBits){DeleteDC(hMemDC);ReleaseDC(NULL,hScreenDC);returnNULL;}SelectObject(hMemDC,hColorBmp);DWORD*pPixel=(DWORD*)pBits;for(intj=0;j<Height;j++)for(inti=0;i<Width;i++)pPixel[j*Width+i]=0x00000000;intcx=Width/2,cy=Height/2,r=Width/2-2;for(inty=cy-r;y<=cy+r;y++)for(intx=cx-r;x<=cx+r;x++)if((x-cx)*(x-cx)+(y-cy)*(y-cy)<=r*r)if(y>=0&&y<Height&&x>=0&&x<Width)pPixel[y*Width+x]=0xFF0000FF;//BGRAHBITMAP hMaskBmp=CreateTransparentMask(hMemDC,Width,Height);ICONINFO iconInfo={0};iconInfo.fIcon=TRUE;iconInfo.xHotspot=Width/2;iconInfo.yHotspot=Height/2;iconInfo.hbmColor=hColorBmp;iconInfo.hbmMask=hMaskBmp;HICON hIcon=CreateIconIndirect(&iconInfo);DeleteObject(hColorBmp);DeleteObject(hMaskBmp);DeleteDC(hMemDC);ReleaseDC(NULL,hScreenDC);returnhIcon;}voidInitGraphics(HDC hdcScreen){hPlayerDC=CreateCompatibleDC(hdcScreen);hBitPlayer=CreateCompatibleBitmap(hdcScreen,Player1.Width,Player1.Height);SelectObject(hPlayerDC,hBitPlayer);HBRUSH hBrushWhite=CreateSolidBrush(RGB(255,255,255));HBRUSH hBrushRed=CreateSolidBrush(RGB(255,0,0));SelectObject(hPlayerDC,hBrushRed);Rectangle(hPlayerDC,0,0,Player1.Width,Player1.Height);DeleteObject(hBrushWhite);DeleteObject(hBrushRed);}voidCleanupGraphics(){if(hPlayerDC)DeleteDC(hPlayerDC);if(hBitPlayer)DeleteObject(hBitPlayer);}voidDrawCharacter(HDC hdcScreen){BitBlt(hdcScreen,Player1.X-Player1.Width/2,Player1.Y-Player1.Height,Player1.Width,Player1.Height,hPlayerDC,0,0,SRCCOPY);}voidUpdate(){UpdatePosition();}voidUpdatePosition(){if(Player1.Game_Over)return;intdx=0;intdy=0;if(Player1.Keys['W'])dy-=3;if(Player1.Keys['S'])dy+=3;if(Player1.Keys['A'])dx-=3;if(Player1.Keys['D'])dx+=3;Player1.X+=dx;Player1.Y+=dy;if(Player1.X<0)Player1.X=0;if(Player1.X>WINDOW_WIDTH)Player1.X=WINDOW_WIDTH;if(Player1.Y<0)Player1.Y=0;if(Player1.Y>WINDOW_HEIGHT)Player1.Y=WINDOW_HEIGHT;InvalidateRect(hWnd,NULL,TRUE);}备注:目前仅实现矩形的wasd移动
编辑者:zzxjason