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

战场范围

之前我们的坦克从战场的一边走出之后会从另一边重新进入战场。这样不符合我们游戏的定义。我们需要把它们改成遇到战场边就不能再继续向前走了。

主战坦克

修改MainTank.cpp中的Move方法,如下:

void MainTank::Move()
{
    switch (m_dir)
    {
    case UP:
        m_pos.SetY(m_pos.GetY() - m_step);
        if (m_rectSphere.GetStartPoint().GetY() < Graphic::GetBattleGround().GetStartPoint().GetY())
            m_pos.SetY(m_pos.GetY() + m_step);
        break;
    case DOWN:
        m_pos.SetY(m_pos.GetY() + m_step);
        if (m_rectSphere.GetEndPoint().GetY() > Graphic::GetBattleGround().GetEndPoint().GetY())
            m_pos.SetY(m_pos.GetY() - m_step);
        break;
    case LEFT:
        m_pos.SetX(m_pos.GetX() - m_step);
        if (m_rectSphere.GetStartPoint().GetX() < Graphic::GetBattleGround().GetStartPoint().GetX())
            m_pos.SetX(m_pos.GetX() + m_step);
        break;
    case RIGHT:
        m_pos.SetX(m_pos.GetX() + m_step);
        if (m_rectSphere.GetEndPoint().GetX() > Graphic::GetBattleGround().GetEndPoint().GetX())
            m_pos.SetX(m_pos.GetX() - m_step);
        break;
    default:
        break;
    }

    CalculateSphere();
}

敌人坦克

敌人坦克也是一样,Move方法完全相同。修改EnemyTank.cpp中的Move方法,如下:

void EnemyTank::Move()
{
    switch (m_dir)
    {
    case UP:
        m_pos.SetY(m_pos.GetY() - m_step);
        if (m_rectSphere.GetStartPoint().GetY() < Graphic::GetBattleGround().GetStartPoint().GetY())
            m_pos.SetY(m_pos.GetY() + m_step);
        break;
    case DOWN:
        m_pos.SetY(m_pos.GetY() + m_step);
        if (m_rectSphere.GetEndPoint().GetY() > Graphic::GetBattleGround().GetEndPoint().GetY())
            m_pos.SetY(m_pos.GetY() - m_step);
        break;
    case LEFT:
        m_pos.SetX(m_pos.GetX() - m_step);
        if (m_rectSphere.GetStartPoint().GetX() < Graphic::GetBattleGround().GetStartPoint().GetX())
            m_pos.SetX(m_pos.GetX() + m_step);
        break;
    case RIGHT:
        m_pos.SetX(m_pos.GetX() + m_step);
        if (m_rectSphere.GetEndPoint().GetX() > Graphic::GetBattleGround().GetEndPoint().GetX())
            m_pos.SetX(m_pos.GetX() - m_step);
        break;
    default:
        break;
    }

    CalculateSphere();
}

运行一下程序,效果如下:

C++代码训练营 | 坦克大战(3)_第1张图片

问题大家肯定看到了,坦克运行到战场边就停止了,这样游戏没法进行下去了。我们要修改敌人的坦克,让它们自己会调整方向。

自动转向的敌人坦克

敌人坦克的自动转向包括两个部分:

  • 坦克遇到战场边后随机调转方向
  • 坦克每走10步随机调转方向

代码如下:

EnemyTank.h

#ifndef __ENEMY_TANK__
#define __ENEMY_TANK__

#include "Tank.h"

#define MAX_STEP 10

class EnemyTank : public Tank
{
public:
    EnemyTank()
    {
        RandomTank();
    }

    ~EnemyTank(){}

    void Display();
    void Move();

protected:
    void CalculateSphere();
    void RandomTank();
    // 随机产生坦克方向 type: 1, 新方向必须与之前方向不同 2, 任意一个新方向
    void RandomDir(int type);

    int m_stepCnt;
};

#endif

EnemyTank类中添加了一个m_stepCnt属性,用来记录坦克当前行驶的步数。又定义了一个MAX_STEP宏定义最大的行驶步数。

RandomDir()用来随即地产生坦克方向,参数type为1时产生一个和当前方向不同的新方向,参数type为0时,产生任意一个新方向。

EnemyTank.cpp

这个文件中只有三个函数有变化。

void EnemyTank::RandomTank()
{
    m_pos.SetX(rand() % Graphic::GetBattleGround().GetWidth());
    m_pos.SetY(rand() % Graphic::GetBattleGround().GetHeight());
    m_color = WHITE;
    m_dir = (Dir)(Dir::UP + (rand() % 4));
    m_step = 2;
    m_stepCnt = rand() % MAX_STEP;
}

这个函数在初始化变量的时候为m_stepCnt随机产生一个当前步数。为什么要在这里用随即数呢?如果每个坦克的当前步数相同的话,那么到第十歩的时候所有的坦克会集体转向,这样会很奇怪。不信大家可以试试。

void EnemyTank::RandomDir(int type)
{
    if (type == 1)
    {
        Dir dir;
        while ((dir = (Dir)(Dir::UP + (rand() % 4))) == m_dir)
        {
            // Do nothing
        }

        m_dir = dir;
    }
    else
    {
        m_dir = (Dir)(Dir::UP + (rand() % 4));
    }
}

这个函数的功能刚才已经介绍过了,实现方式也很简单。

void EnemyTank::Move()
{
    switch (m_dir)
    {
    case UP:
        m_pos.SetY(m_pos.GetY() - m_step);
        if (m_rectSphere.GetStartPoint().GetY() < Graphic::GetBattleGround().GetStartPoint().GetY())
        {
            m_pos.SetY(m_pos.GetY() + m_step);
            this->RandomDir(1);
        }
        break;
    case DOWN:
        m_pos.SetY(m_pos.GetY() + m_step);
        if (m_rectSphere.GetEndPoint().GetY() > Graphic::GetBattleGround().GetEndPoint().GetY())
        {
            m_pos.SetY(m_pos.GetY() - m_step);
            this->RandomDir(1);
        }
        break;
    case LEFT:
        m_pos.SetX(m_pos.GetX() - m_step);
        if (m_rectSphere.GetStartPoint().GetX() < Graphic::GetBattleGround().GetStartPoint().GetX())
        {
            m_pos.SetX(m_pos.GetX() + m_step);
            this->RandomDir(1);
        }
        break;
    case RIGHT:
        m_pos.SetX(m_pos.GetX() + m_step);
        if (m_rectSphere.GetEndPoint().GetX() > Graphic::GetBattleGround().GetEndPoint().GetX())
        {
            m_pos.SetX(m_pos.GetX() - m_step);
            this->RandomDir(1);
        }
        break;
    default:
        break;
    }

    CalculateSphere();

    m_stepCnt++;
    if (m_stepCnt >= MAX_STEP)
    {
        m_stepCnt = 0;
        this->RandomDir(0);
    }
}

Move()函数中,一旦遇到战场边就调用RandomDir()函数随机出一个新的方向。每次移动都用m_stepCnt属性计步一次,每走10歩就做一次随机改变方向。

下面就是执行效果:

C++代码训练营 | 坦克大战(3)_第2张图片

这篇文章的相关代码已经上传至GitHub

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


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

你可能感兴趣的:(C++代码训练营 | 坦克大战(3))