2016-12-25 2 views
-1

Я программирую клонирование Space Invaders в C++ на консоли. У меня есть класс 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 (х - i, y + i); должен быть просто 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 = 130 немного, не так ли? Мерцание появляется, потому что вы очищаете всю консоль при обновлении. Есть два способа решить эту проблему

  • Redraw только обновленные объекты:

Допустим, вы хотите обновить свой корабль, так как он двигался. Вы можете просто переместить курсор на место старого корабля, записать пространства над кораблем, переместиться в новое местоположение судна и затем перерисовать корабль.

  • Используйте «двойной буферизации» метод вы упомянули в вашем вопросе:

Это будет выглядеть так: У вас есть две 2D массивы символов (или массив/вектор строк, который лучше) с тем же размером вашей сцены, оба будут инициализированы пробелами в начале.

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

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

Я пробовал свой код, и он работает для меня, единственное, что я изменил, это то, что я сделал массив кораблей строковым массивом и удалил некоторые пробелы в начале третьей строки. std :: string ship [] {"\ xDB" , "\ xDB \ xDB \ xDB \ xDB \ xDB", "\ xDB \ xDB \ xDB \ xDB \ xDB \ xDB \ xDB \ xDB \ xDB"}; – FamZ

+0

Btw, если нижняя линия судна стоит на месте или является частью корабля? что изменило бы все, также я испытал движение с корабль. MoveShip (1, 0); в цикле – FamZ

Смежные вопросы