我正在控制台上用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();
}
为什么会出现这个错误,我该如何解决呢? 此外,当我移动宇宙飞船时,我听说双缓冲概念可以消除屏幕闪烁,但我该如何实现呢?
答案 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++