2016-12-25 63 views
-1

我在控制檯上用C++編程Space Invaders克隆。 我有一個Spaceship類,我在其中創建控制檯屏幕上的形狀。 我使用箭頭鍵將其沿水平方向在屏幕上移動。該船由3部分組成。 在這裏你有圖片,顯示移動飛船在右邊。 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

我認爲gotoxy(X - 我,我+我);應該只是gotoxy(x,y + i);你想在同一個x偏移量上打印船的所有行 – FamZ

+0

它可能是特定於操作系統的。 [ncurses](https://www.gnu.org/software/ncurses/)不是C++ 14標準的一部分,並且不適用於每個操作系統。 –

+0

標籤在這裏工作得非常好。他們不需要你的幫助,也可以在標題中重複添加它們。在帖子的標題和文字中重複標籤信息是完全沒有必要的。讓標籤完成他們的工作。 –

回答

0

gotoxy(x - i, y + i); 應該只是 gotoxy(x, y + i); 要打印在同一x偏移量船上的所有行。另外你需要注意你的船沒有通過控制檯邊框,x = 130有點多,不是嗎?閃爍正在出現,因爲您在更新時清除整個控制檯。有兩種方法可以解決這個

  • 重繪只有更新的對象:

比方說,你要更新你的船,因爲它移動。您可以將光標移動到舊船位置,在船上寫空間,移動到新的船位,然後重新繪製船。

  • 使用你在你的問題中提到的「雙緩衝」的方法:

這看起來像:你有兩個二維字符數組(或字符串數​​組/向量,這是更好)在你的場景大小相同的情況下,兩者都將在開始時用空格初始化。

// 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_bbuffer_a

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爲空時。使用這種方法可以實現一個主循環,即首次讀取輸入,然後在每次迭代結束時更新並交換緩衝區。

也許第一種方法是更好,如果現場真的很大,因爲你是在第二種方法測試緩衝區中的每個元素,有已經在一個偉大的答案卡梅倫在這裏:Update console without flickering - c++

+0

嗨,x = 130是用於將船置於屏幕中間,因爲它是一個全屏控制檯應用程序。如果我只更新船舶,它仍然會閃爍,但只有船舶是正確的?它仍然沒有正確移動,是否有辦法一次性打印我的所有船隻,因爲我認爲這將解決問題。 –

+0

我試過你的代碼,它適用於我,唯一改變的是我做了一個數組的字符串數組,並刪除了第3個字符串開頭的一些空格 std :: string ship [] {「\ xDB」 ,\ xDB \ xDB \ xDB \ xDB \ xDB \ xDB「}; – FamZ

+0

順便說一下,船的下線應該靜止還是屬於船的一部分?這將改變一切,我也用ship.MoveShip(1,0)測試了運動。在一個循環 – FamZ