【遊戲程式設計】二維遊戲示例-回合制Demo
阿新 • • 發佈:2018-12-12
執行結果:
原始碼:
#include <windows.h> #include <tchar.h> #pragma comment(lib, "winmm.lib") //呼叫PlaySound函式所需庫檔案t #define WINDOW_WIDTH 640 #define WINDOW_HEIGHT 510 #define WINDOW_TITLE L"【遊戲程式設計】回合制Demo" //定義一個結構體,表示遊戲物件 struct chr { int nHp; int fHp; int kind; //技能 int lv; int w; }; HINSTANCE hInst; HDC hdc, mdc, bufdc; HBITMAP hBg, hGirl, hMagic, hOver, hRecover, hSheep, hSkill, hSkillult, hSlash; DWORD g_tNow, g_tPre; bool attack, over; //玩家是否攻擊狀態,遊戲是否結束 int g_iNum, txtNum, f; //txtNum文字數目 f為攻擊畫面 chr player, monster; //玩家,怪物 wchar_t text[5][100]; //對戰文字訊息 int MyWindowClass(HINSTANCE); BOOL InitInstance(HINSTANCE, int); LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); void MyDraw(HDC); void MsgInsert(wchar_t*); //將新的訊息加入對戰文字陣列中 void CheckDie(int, bool); //檢查血量,若小於0則死亡,遊戲結束 /***************************************************************************************************************** 在不同的應用程式中,在此處新增相關的全域性變數 ******************************************************************************************************************/ int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPreInstace, LPSTR lpCmdLine, int nCmdShow) { MyWindowClass(hInstance); //PlaySound(L"sound.wav", NULL, SND_FILENAME| SND_ASYNC| SND_LOOP); //迴圈播放背景音樂 if(!InitInstance(hInstance, nCmdShow)) return FALSE; MSG msg = {}; while(msg.message != WM_QUIT) { if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } else { g_tNow = GetTickCount(); if(g_tNow - g_tPre >= 40) { MyDraw(hdc); g_tPre = GetTickCount(); //記錄此次繪圖時間 } } } return msg.wParam; } int MyWindowClass(HINSTANCE hInstance) { WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = NULL; wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wcex.lpszMenuName = NULL; wcex.lpszClassName = L"gamebase"; wcex.hIconSm = NULL; return RegisterClassEx(&wcex); } BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) { hInst = hInstance; HWND hwnd = CreateWindow(L"gamebase", WINDOW_TITLE, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, WINDOW_WIDTH, WINDOW_HEIGHT, NULL, NULL, hInstance, NULL); if(!hwnd) return FALSE; MoveWindow(hwnd, 10, 10, WINDOW_WIDTH, WINDOW_HEIGHT, true); ShowWindow(hwnd, nCmdShow); UpdateWindow(hwnd); hdc = GetDC(hwnd); mdc = CreateCompatibleDC(hdc); bufdc = CreateCompatibleDC(hdc); //載入遊戲點陣圖 hBg = (HBITMAP)LoadImage(NULL, L"bg.bmp", IMAGE_BITMAP, WINDOW_WIDTH, WINDOW_HEIGHT, LR_LOADFROMFILE); //背景 hGirl = (HBITMAP)LoadImage(NULL, L"girl.bmp", IMAGE_BITMAP, 480, 216, LR_LOADFROMFILE); //玩家 hMagic = (HBITMAP)LoadImage(NULL, L"magic.bmp", IMAGE_BITMAP, 200, 100, LR_LOADFROMFILE); //閃電鏈 hOver = (HBITMAP)LoadImage(NULL, L"over.bmp", IMAGE_BITMAP, 289, 148, LR_LOADFROMFILE); //遊戲結束 hRecover = (HBITMAP)LoadImage(NULL, L"recover.bmp", IMAGE_BITMAP, 300, 150, LR_LOADFROMFILE); //治療 hSheep = (HBITMAP)LoadImage(NULL, L"sheep.bmp", IMAGE_BITMAP, 130, 220, LR_LOADFROMFILE); //怪物 hSkill = (HBITMAP)LoadImage(NULL, L"skill.bmp", IMAGE_BITMAP, 50, 50, LR_LOADFROMFILE); //無敵斬 hSkillult = (HBITMAP)LoadImage(NULL, L"skillult.bmp", IMAGE_BITMAP, 50, 50, LR_LOADFROMFILE); //被動狂暴 hSlash = (HBITMAP)LoadImage(NULL, L"slash.bmp", IMAGE_BITMAP, 196, 162, LR_LOADFROMFILE); //攻擊效果(無敵斬,利爪攻擊,致命一擊) HBITMAP bmp = CreateCompatibleBitmap(hdc, WINDOW_WIDTH, WINDOW_HEIGHT); SelectObject(mdc, bmp); txtNum = 0; // 顯示訊息數目 g_iNum = 0; f = 0; player.fHp = 50; //設定玩家角色生命值及上限 player.nHp = 50; player.lv = 2; //設定玩家角色等級 player.w = 4; //設定攻擊傷害加權值 monster.fHp = 120; //設定怪物角色生命值及上限 monster.nHp = 120; monster.lv = 1; //設定怪物角色等級 monster.w = 1; //設定攻擊傷害加權值 SetBkMode(mdc, TRANSPARENT); //設定TextOut背景透明 return TRUE; } LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { PAINTSTRUCT ps; switch(message) { case WM_LBUTTONDOWN: //滑鼠左鍵訊息 if(!attack) { int x = LOWORD(lParam); //x座標 int y = HIWORD(lParam); //y座標 if(x >= 500 && x<= 550 && y >= 350 && y <= 400) //無敵斬圖示範圍,開始進入攻擊狀態 attack = true; } break; /************************************************************************************************************** 在退出程式前,往往在此處刪除建立的相關資源 ***************************************************************************************************************/ case WM_DESTROY: //視窗結束訊息 DeleteObject(hBg); DeleteObject(hGirl); DeleteObject(hMagic); DeleteObject(hOver); DeleteObject(hRecover); DeleteObject(hSheep); DeleteObject(hSkill); DeleteObject(hSkillult); DeleteObject(hSlash); DeleteDC(mdc); DeleteDC(bufdc); ReleaseDC(hwnd, hdc); PostQuitMessage(0); break; default: //預設訊息 return DefWindowProc(hwnd, message, wParam, lParam); } return 0; } void MsgInsert(wchar_t *s) { //直接複製到陣列中 if(txtNum < 5) { swprintf_s(text[txtNum], s); ++txtNum; } else { for(int i = 0; i < txtNum-1; ++i) //把第一條訊息覆蓋 swprintf_s(text[i], text[i+1]); swprintf_s(text[txtNum-1], s); //拷貝到最後一條訊息中 } } void CheckDie(int hp, bool player) { if(hp <= 0) { wchar_t str[100]; over = true; //遊戲結束 if(player) //如果是玩家被攻擊 swprintf_s(str, L"勝敗乃兵家常事,大俠請重新來過....."); else swprintf_s(str, L"你戰勝了敵人,獲得此次戰鬥勝利!"); MsgInsert(str); } } /*************************************************************************************************************** 在函式MyDraw()中進行相關繪製工作 ****************************************************************************************************************/ void MyDraw(HDC hdc) { wchar_t str[100] = {}; //貼上背景圖 SelectObject(bufdc, hBg); BitBlt(mdc, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, bufdc, 0, 0, SRCCOPY); //顯示對戰訊息 for(int i = 0; i < txtNum; ++i) TextOut(mdc, 0, 360+i*18, text[i], wcslen(text[i])); //貼上玩家圖 if(player.nHp > 0) { SelectObject(bufdc, hGirl); BitBlt(mdc, 500, 200, 60, 108, bufdc, g_iNum*60, 108, SRCAND); BitBlt(mdc, 500, 200, 60, 108, bufdc, g_iNum*60, 0, SRCPAINT); swprintf_s(str, L"%d / %d", player.nHp, player.fHp); TextOut(mdc, 520, 320, str, wcslen(str)); } ++g_iNum; if(g_iNum == 8) g_iNum = 0; //貼上怪物圖 if(monster.nHp > 0) { SelectObject(bufdc, hSheep); BitBlt(mdc, 70, 180, 130, 110, bufdc, 0, 110, SRCAND); BitBlt(mdc, 70, 180, 130, 110, bufdc, 0, 0, SRCPAINT); swprintf_s(str, L"%d / %d", monster.nHp, monster.fHp); TextOut(mdc, 100, 320, str, wcslen(str)); } if(over) //貼上游戲結束圖畫 { SelectObject(bufdc, hOver); BitBlt(mdc, 200, 200, 289, 74, bufdc, 0, 74, SRCAND); BitBlt(mdc, 200, 200, 289, 74, bufdc, 0, 0, SRCPAINT); } else if(!attack) //貼上攻擊命令圖畫 { SelectObject(bufdc,hSkill); BitBlt(mdc,500,350,50,50,bufdc,0,0,SRCCOPY); SelectObject(bufdc,hSkillult); BitBlt(mdc,430,350,50,50,bufdc,0,0,SRCCOPY); } else { srand(g_tPre); //設定隨機數種子 //第5-10個畫面顯示玩家攻擊目標 if(f >= 5 && f <= 10) { SelectObject(bufdc,hSlash); BitBlt(mdc, 100, 160, 98, 162, bufdc, 98,0,SRCAND); BitBlt(mdc, 100, 160, 98, 162, bufdc, 0, 0, SRCPAINT); //第10個畫面時計算怪物受傷害程度並加入顯示訊息 if(f == 10) { //計算傷害 int damage = rand()%10 + player.lv*player.w; if(rand() % 5) swprintf_s(str, L"玩家使用了無敵斬,對怪物照成了%d點傷害", damage); else //20%機率出發被動,4倍暴擊傷害 { damage *= 4; swprintf_s(str, L"觸發被動狂暴,對怪物照成了%d點暴擊傷害!", damage); } MsgInsert(str); monster.nHp -= damage; CheckDie(monster.nHp, false); } } //第15個畫面時判斷怪物進行哪項動作 if(f == 15) { if(monster.nHp > 20) //生命值大於20 { if(rand()%5) //進行利爪攻擊概率4/5 monster.kind = 0; else //進行閃電鏈攻擊概率1/5 monster.kind = 1; } else //生命值小於20 monster.kind = rand()%5; } //第26-30畫面顯示怪物攻擊圖示 if(f >= 26 && f <= 30) { switch(monster.kind) { case 0: //利爪攻擊 SelectObject(bufdc,hSlash); BitBlt(mdc, 480, 160, 98, 162, bufdc, 98, 0, SRCAND); BitBlt(mdc, 480, 160, 98, 162, bufdc, 0, 0, SRCPAINT); if(f == 30) //第30個畫面計算玩家受傷害程度並加入顯示訊息 { int damage = rand()%10 + monster.lv*monster.w; swprintf_s(str, L"怪物利爪攻擊...對玩家照成 %d 點傷害", damage); MsgInsert(str); player.nHp -= damage; CheckDie(player.nHp, true); } break; case 1: //釋放閃電鏈 SelectObject(bufdc,hMagic); BitBlt(mdc, 480, 190, 100, 100, bufdc, 100, 0, SRCAND); BitBlt(mdc, 480, 190, 100, 100, bufdc, 0, 0, SRCPAINT); //第30個畫面計算玩家受傷害程度並加入顯示訊息 if(f == 30) { int damage = rand()%10 + 3*monster.w; swprintf_s(str, L"怪物釋放閃電鏈...對玩家照成 %d 點傷害", damage); MsgInsert(str); player.nHp -= damage; CheckDie(player.nHp, true); } break; case 2: //致命一擊 SelectObject(bufdc,hSlash); BitBlt(mdc, 480, 160, 98, 162, bufdc, 98, 0, SRCAND); BitBlt(mdc, 480, 160, 98, 162, bufdc, 0, 0, SRCPAINT); //第30個畫面計算玩家受傷害程度並加入顯示訊息 if(f == 30) { int damage = rand()%10 + monster.lv*monster.w*5; swprintf_s(str, L"怪物致命一擊...對玩家照成 %d 點巨大傷害", damage); MsgInsert(str); player.nHp -= damage; CheckDie(player.nHp, true); } break; case 3: //使用治療術 SelectObject(bufdc, hRecover); BitBlt(mdc,60,160,150,150,bufdc,150,0,SRCAND); BitBlt(mdc,60,160,150,150,bufdc,0,0,SRCPAINT); //第30個畫面恢復生命值並加入顯示訊息 if(f == 30) { swprintf_s(str, L"怪物使用治療...恢復了30點生命值"); MsgInsert(str); monster.nHp += 30; //加血量 } break; case 4: //逃跑 //在第30個畫面時判斷怪物是否逃跑成功 if(f == 30) { if(rand() % 3) { swprintf_s(str, L"怪物逃跑中...逃跑失敗!"); MsgInsert(str); } else //逃跑機率1/3 { swprintf_s(str, L"怪物逃跑中...逃跑成功!"); MsgInsert(str); CheckDie(0, false); //逃跑成功,遊戲結束 } } break; } } ++f; if(f > 30) //回合結束 { attack = false; f = 0; } } BitBlt(hdc, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, mdc, 0, 0, SRCCOPY); }