【游戏程序设计】二维游戏示例-回合制Demo
运行结果:
源代码:
#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);
}