C++代码训练营 | 坦克大战(7)

目前我们的主战坦克已经能够开炮击毁敌人坦克了,但敌人坦克不会开炮貌似比较欺负人。今天我们让敌人坦克也拥有开炮功能。同时,我们要为游戏设定关卡,让它变得好玩起来。

让敌人坦克开炮

在EnemyTank类中,添加Shoot函数几乎和MainTank中完全相同,代码如下:

void EnemyTank::Shoot(list<Object*>& lstBullets)
{
    Bullet* pBullet = new Bullet(m_pos, m_dir, m_color);

    lstBullets.push_back(pBullet);

    m_bNeedShoot = false;
}

这里唯一的区别是最后一句话,我们对m_bNeedShoot属性进行了赋值。

敌人坦克和主战坦克最大的区别在于自动开炮,它不像主战坦克那样通过相应空格键执行开炮函数,它是通过一定的算法完成自主开炮。因此我们在main函数中通过判断m_bNeedShoot属性来执行Shoot函数。

在Move函数中,我们添加下面这段代码:

if (m_stepCnt % MAX_STEP_SHOOT == 0)
{
    m_bNeedShoot = true;
}

这段代码有点类似于敌人坦克的自动转向功能,我们让它每移动MAX_STEP_SHOOT步就通过将m_bNeedShoot设为true来执行开炮功能。

最后,我们在main函数中绘制坦克时加入下面这段代码:

if ((*it)->NeedShoot())
{
    EnemyTank* p = (EnemyTank*)*it;
    p->Shoot(lstBullets);
}

当判断NeedShoot()返回值为true时,调用Shoot()函数进行开炮。

关卡设置

我们在玩游戏时,有一些必要的参数非常重要。比如,主要人物的生命值,等级,敌人数,分数等等。下面我们就给坦克大战中添加这些元素,让它变得更有游戏的乐趣。

我们为工程添加一组新的文件Setting.h和Setting.cpp,代码如下:

Setting.h

#ifndef __SETTING_H__
#define __SETTING_H__

#include <list>

using namespace std;

class Setting
{
public:
    static void NewGameLevel();
    static void TankDamaged();

    static int GetLife()
    {
        return m_nLife;
    }

    static int GetGameLevel()
    {
        return m_nGameLevel;
    }

    static int GetTankLevel()
    {
        return m_nTankLevel;
    }

    static int GetTankNum()
    {
        return m_nTankNum;
    }

    static int GetSumScore()
    {
        return m_nSumScore;
    }

    static int GetTankSum()
    {
        return m_nTankSum;
    }

    static bool m_bNewLevel;

private:
    static int m_nLife; // 生命值

    static int m_nGameLevel;    // 当前游戏关卡
    static int m_nTankLevel;    // 当前坦克级别
    
    static int m_nTankNum;      // 当前坦克数

    static int m_nSumScore;     // 总分

    static int m_nTankScore;    // 击毁坦克得分
    
    static int m_nTankSum;      // 共击毁坦克数
};

#endif

在Setting类中,我们添加了一组static属性。同时,添加了访问这些参数的static接口。这里重点关注两个函数:

NewGameLevel()函数,在每一关开始时初始化每一关的属性信息。TankDamaged()函数,在每次击毁一个坦克时调用,完成相关属性的数据更新。具体如下:

Setting.cpp

include "Setting.h"

bool Setting::m_bNewLevel = true;

int Setting::m_nLife = 3;

int Setting::m_nGameLevel = 0;
int Setting::m_nTankLevel = 1;

int Setting::m_nTankNum = 5;

int Setting::m_nSumScore = 0;

int Setting::m_nTankScore = 5;

int Setting::m_nTankSum = 0;

void Setting::NewGameLevel()
{
    m_nGameLevel++;

    m_nTankNum = 10 + 5 * (m_nGameLevel - 1);
    m_nTankScore += 5;
}

void Setting::TankDamaged()
{
    m_nTankNum--;
    m_nSumScore += m_nTankScore;

    m_nTankLevel = m_nSumScore / 150 + 1;

    m_nTankSum++;

    if (m_nTankNum == 0)
    {
        m_bNewLevel = true;
    }
}

前一部分是static属性的初始化,后面是两个函数的实现。相信大家一看就懂。这里的具体规则大家可以自行修改,制定规则才是游戏开发中最有乐趣的一部分。

绘制成绩

相关的数据我们需要绘制在屏幕的右半部分。我们在Graphic类中添加一个static函数:

static void ShowScore();

实现如下:

const int SCORE_LEFT = 810;
const int SCORE_TOP = 5;

void Graphic::ShowScore()
{
    COLORREF fill_color_save = getfillcolor();
    COLORREF color_save = getcolor();

    //setfillcolor(m_color);
    //setcolor(m_color);

    rectangle(SCORE_LEFT, SCORE_TOP, SCORE_LEFT + 200, SCORE_TOP + 40);


    RECT r = { SCORE_LEFT, SCORE_TOP, SCORE_LEFT + 200, SCORE_TOP + 40 };
    wsprintf((LPWSTR)m_pArray, _T("第 %d 关"), Setting::GetGameLevel());
    drawtext((LPWSTR)m_pArray, &r, DT_CENTER | DT_VCENTER | DT_SINGLELINE);

    r.top += 50;
    r.bottom += 50;
    wsprintf((LPWSTR)m_pArray, _T("分  数  :  %d"), Setting::GetSumScore());
    drawtext((LPWSTR)m_pArray, &r, DT_VCENTER | DT_SINGLELINE);

    r.top += 50;
    r.bottom += 50;
    wsprintf((LPWSTR)m_pArray, _T("级  别  :  %d"), Setting::GetTankLevel());
    drawtext((LPWSTR)m_pArray, &r, DT_VCENTER | DT_SINGLELINE);

    r.top += 50;
    r.bottom += 50;
    wsprintf((LPWSTR)m_pArray, _T("生  命  :  %d"), Setting::GetLife());
    drawtext((LPWSTR)m_pArray, &r, DT_VCENTER | DT_SINGLELINE);

    r.top += 50;
    r.bottom += 50;
    wsprintf((LPWSTR)m_pArray, _T("敌人数  :  %d"), Setting::GetTankNum());
    drawtext((LPWSTR)m_pArray, &r, DT_VCENTER | DT_SINGLELINE);

    r.top += 50;
    r.bottom += 50;

    line(SCORE_LEFT, r.bottom, SCREEN_WIDTH - 5, r.bottom);

    r.top += 50;
    r.bottom += 50;
    wsprintf((LPWSTR)m_pArray, _T("共击毁敌人数  :  %d"), Setting::GetTankSum());
    drawtext((LPWSTR)m_pArray, &r, DT_VCENTER | DT_SINGLELINE);


    setcolor(color_save);
    setfillcolor(fill_color_save);
}

最后,需要把这些调用放在main函数中,这里不做说明,请大家自己试一下。如果自己写不出来请在我的GitHub中下载完整代码。

执行效果就是文章开头的图片效果。

我是天花板,让我们一起在软件开发中自我迭代。
如有任何问题,欢迎与我联系。


上一篇:C++代码训练营 | 坦克大战(6)
下一篇:C++代码训练营 | 坦克大战(8)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,817评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,329评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,354评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,498评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,600评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,829评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,979评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,722评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,189评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,519评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,654评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,329评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,940评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,762评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,993评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,382评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,543评论 2 349

推荐阅读更多精彩内容

  • 上一篇中,我们添加了可以自动行驶的敌人坦克,今天我们给主战坦克添加最核心的功能——开炮。 第一次重构 既然要开炮,...
    天花板阅读 4,073评论 1 13
  • 上一篇中我们给主战坦克添加了发射炮弹的功能。不过有一个问题,炮弹飞到战场边缘时,自动消失的感觉不太好。我们今天来给...
    天花板阅读 3,476评论 4 9
  • 上一篇中我们已经得到了一个比较完善的游戏,不过有人反馈说目前的难度较大,第三关已经很难通过了。今天我们来做点小的修...
    天花板阅读 3,776评论 11 18
  • 现在我们的游戏已经初具规模,但如果主战坦克一直是无敌状态那也很无趣。今天我们来让敌人的炮火发挥作用。 主战坦克被击...
    天花板阅读 2,689评论 1 8
  • 这一篇中,我们继续继续进行我们的坦克大战。 位置信息数据结构 在游戏设计过程中,需要记录大量的位置信息,如果仅仅使...
    天花板阅读 7,480评论 14 25