实现起来也很容易,在Graphic类中添加一个ShowGameLevel函数:
void Graphic::ShowGameLevel(int nLevel)
{
COLORREF fill_color_save = getfillcolor();
COLORREF color_save = getcolor();
rectangle(BATTLE_GROUND_X1 + 100, BATTLE_GROUND_Y1 + 200, BATTLE_GROUND_X1 + 700, BATTLE_GROUND_Y1 + 380);
LOGFONT fontBak;
gettextstyle(&fontBak); // 获取当前字体设置
LOGFONT f = fontBak;
f.lfHeight = 48; // 设置字体高度为 48
_tcscpy_s(f.lfFaceName, _T("黑体")); // 设置字体为“黑体”
f.lfQuality = ANTIALIASED_QUALITY; // 设置输出效果为抗锯齿
settextstyle(&f); // 设置字体样式
wsprintf((LPWSTR)m_pArray, _T("第 %d 关"), nLevel);
outtextxy(BATTLE_GROUND_X1 + 300, BATTLE_GROUND_Y1 + 250, (LPWSTR)m_pArray);
f.lfHeight = 18;
settextstyle(&f);
wsprintf((LPWSTR)m_pArray, _T("按 Enter 键开始"), nLevel);
outtextxy(BATTLE_GROUND_X1 + 550, BATTLE_GROUND_Y1 + 350, (LPWSTR)m_pArray);
settextstyle(&fontBak);
setcolor(color_save);
setfillcolor(fill_color_save);
}
这里需要注意,我们使用了特殊字体和大小,因此在绘制完成后需要恢复默认字体。如果注释掉函数退出前的settextstyle(&fontBak);语句,界面上其他地方的字体会发生错乱。大家可以试试。
显示提示信息
在main函数中,我们要在每一关结束之后调用这个函数,同时让程序暂停。代码如下:
void main()
{
Init();
bool loop = true;
bool skip = false;
while (loop)
{
if (kbhit())
{
int key = getch();
if (skip && key != 13)
{
continue;
}
switch (key)
{
// Up
case 72:
mainTank.SetDir(Dir::UP);
break;
// Down
case 80:
mainTank.SetDir(Dir::DOWN);
break;
// Left
case 75:
mainTank.SetDir(Dir::LEFT);
break;
// Right
case 77:
mainTank.SetDir(Dir::RIGHT);
break;
case 224: // 方向键高8位
break;
// Esc
case 27:
loop = false;
break;
// Space
case 32:
mainTank.Shoot(lstMainTankBullets);
break;
// Enter
case 13:
if (skip)
skip = false;
else
skip = true;
break;
default:
break;
}
}
if (!skip)
{
// Draw Background
cleardevice();
Graphic::DrawBattleGround();
Graphic::ShowScore();
// New Game Level
if (Setting::m_bNewLevel)
{
Setting::m_bNewLevel = false;
Setting::NewGameLevel();
Graphic::ShowGameLevel(Setting::GetGameLevel());
for (int i = 0; i < Setting::GetTankNum(); i++)
{
EnemyTank* p = new EnemyTank();
lstTanks.push_back(p);
}
// 设置暂停,按Enter开始
skip = true;
continue;
}
CheckCrash();
mainTank.Move();
mainTank.Display();
/* Draw Tanks */
for (list<Tank*>::iterator it = lstTanks.begin(); it != lstTanks.end();)
{
(*it)->Move();
if ((*it)->IsDisappear())
{
Setting::TankDamaged();
// Add a bomb
(*it)->Boom(lstBombs);
// Delete the tank
delete *it;
it = lstTanks.erase(it);
continue;
}
(*it)->Display();
if ((*it)->NeedShoot())
{
EnemyTank* p = (EnemyTank*)*it;
p->Shoot(lstBullets);
}
it++;
}
/* Draw Bullets */
for (list<Object*>::iterator it = lstMainTankBullets.begin(); it != lstMainTankBullets.end();)
{
(*it)->Move();
if ((*it)->IsDisappear())
{
// Add a bomb
(*it)->Boom(lstBombs);
// Delete the bullet
delete *it;
it = lstMainTankBullets.erase(it);
continue;
}
(*it)->Display();
it++;
}
for (list<Object*>::iterator it = lstBullets.begin(); it != lstBullets.end();)
{
(*it)->Move();
if ((*it)->IsDisappear())
{
// Add a bomb
(*it)->Boom(lstBombs);
// Delete the bullet
delete *it;
it = lstBullets.erase(it);
continue;
}
(*it)->Display();
it++;
}
/* Draw Bombs */
for (list<Object*>::iterator it = lstBombs.begin(); it != lstBombs.end();)
{
(*it)->Move();
if ((*it)->IsDisappear())
{
delete *it;
it = lstBombs.erase(it);
continue;
}
(*it)->Display();
it++;
}
}
Sleep(100);
}
// Destroy
Dispose();
}
重点看这里,当程序通过Setting::m_bNewLevel属性判断出到了新的一关时,执行下面这段代码:
if (Setting::m_bNewLevel)
{
Setting::m_bNewLevel = false;
Setting::NewGameLevel();
Graphic::ShowGameLevel(Setting::GetGameLevel());
for (int i = 0; i < Setting::GetTankNum(); i++)
{
EnemyTank* p = new EnemyTank();
lstTanks.push_back(p);
}
// 设置暂停,按Enter开始
skip = true;
continue;
}
这段代码完成了下面几个动作:
- 初始化新一关的相关变量
- 绘制刚才的提示信息
- 创建新关卡中的敌人坦克
- 通过设置skip变量将程序暂停
玩家需要通过按下Enter键来继续游戏。是不是很简单呢。
重点
这一篇的内容不多,但重点是如何在main函数中通过代码控制程序的流程。大家可以试试在不同的位置添加控制代码,会得到不同的效果。
至于main函数中的程序流程如何安排更好,请大家仔细思考一下。这一篇涉及的代码请在GitHub中下载。
下一篇中,我们开始让敌人的坦克发挥出应有的威力。游戏的难度该来了。
我是天花板,让我们一起在软件开发中自我迭代。
如有任何问题,欢迎与我联系。
上一篇:C++代码训练营 | 坦克大战(7)
下一篇:C++代码训练营 | 坦克大战(9)
网友评论