部分形状不动

时间:2016-12-25 21:06:57

标签: c++ console

我正在控制台上用C ++编写Space Invaders克隆 我有一个宇宙飞船课,我在控制台屏幕上创建了形状 我使用箭头键在屏幕上水平移动它 在这里你有图片,显示向右移动飞船 http://imgur.com/a/fos5M
这是我的方法

class BaseSpaceShip{
protected:
private: 
    char ship[4][19] = {
    "     \xDB      ",
    "   \xDB\xDB\xDB\xDB\xDB    ",
    "      \xDB\xDB\xDB\xDB\xDB\xDB\xDB\xDB\xDB"
    };   
         const int mapy = 4;
         int x, y;
         void Invalidate();
         void cls();
public:
    BaseSpaceShip();
    ~BaseSpaceShip();
    void Init();
    virtual void MoveShip(int dx, int dy);
};
BaseSpaceShip::BaseSpaceShip() {
    x = 130;
    y = 69;
    Init();
}
BaseSpaceShip::~BaseSpaceShip() {
}
void BaseSpaceShip::Init() {
    cls();
    for (int i = 0; i < mapy; i++) {
        gotoxy(x - i, y + i);
        cout << ship[i] << endl;
    }       
}
void BaseSpaceShip::MoveShip(int dx , int dy) {
    x+= dx;
    y += dy;
    Init();
}

为什么会出现这个错误,我该如何解决呢? 此外,当我移动宇宙飞船时,我听说双缓冲概念可以消除屏幕闪烁,但我该如何实现呢?

1 个答案:

答案 0 :(得分:0)

gotoxy(x - i, y + i); 应该是公正的 gotoxy(x, y + i); 您想要在相同的x偏移上打印船的所有线。你还需要注意你的船没有经过控制台边界,x = 130有点多,不是吗?闪烁正在出现,因为您正在更新整个控制台。有两种方法可以解决这个问题

  • 仅重绘已更新的对象:

假设您要更新您的船,因为它已移动。您只需将光标移动到旧船位置,在船上写下空格,移动到新船位置,然后重新绘制船只。

  • 使用您在问题中提到的“双缓冲”方法:

这看起来像这样:你有两个2D char数组(或者一个数组/矢量的字符串,哪个更好),你的场景大小相同,两者都会在开始时用空格初始化。

// Scene size is 100x100
std::vector<std::string> buffer_a(100, std::string(100, ' '));
std::vector<std::string> buffer_b(100, std::string(100, ' '));

现在,您不是直接cout进入屏幕,而是将更改写入buffer_b,而不是

for (int i = 0; i < mapy; i++)
{
    gotoxy(x, y + i);
    cout << ship[i] << endl;
}   
你正在做这样的事情:

for (unsigned int i = 0; i < ship_width; i++)
    for(unsigned int j = 0; j < ship_height; ++j)
        buffer_b[x + i][y + j] = ship[i][j];

完成更新后,您需要遍历两个缓冲区并绘制与buffer_a中不同的所有元素,然后将buffer_b复制到buffer_a。< / p>

for (unsigned int i = 0; i < scene_width; i++)
{
    for(unsigned int j = 0; j < scene_height; ++j)
    {
        if(buffer_a[i][j] != buffer_b[i][j])
        {
            gotoxy(i, j);
            std::cout << buffer_b[i][j];
            buffer_a[i][j] = buffer_b[i][j];
        }
    }
}

请注意,当您将更改写入buffer_b时,假设您要移动船只,在更新之前仍需要在buffer_b中的旧船位置上写空格,除非对于buffer_b为空时的第一次更新。使用这种方法,最好实现一个主循环,它首先读取输入,然后在每次迭代结束时更新然后交换缓冲区。

如果场景真的很大,第一种方法可能会更好,因为你在第二种方法中测试缓冲区的每个元素,Cameron在这里已经有了很好的答案:Update console without flickering - c++