使用2D阵列作为工作空间

时间:2016-03-19 09:24:37

标签: c++

我正在制作蛇游戏并制作原型。我附上了代码。它可能不是那么好但仍然是凌乱的。我可以让它移动,但我不知道为什么下界区域闪烁。如何减少这种整体闪烁,这几乎让我头晕目眩?还有,还有一个问题:如何使角色移动(就像在原始的蛇游戏中一样),而不是等到我的命令?请帮我!对不起该语言。

#include<iostream.h>
#include<stdlib.h>
#include<windows.h>

int main() {
  char a[25][80]={0};
  system("Color 0");
  int x=40,y=15;
  int m=0,n;
  a[16][2]='X';
  a[y][x]='O';
  for(int i=0;i<25;++i) {
    for(int j=0;j<80;++j) cout<<a[i][j];
  }
  while(m!=1000) {
    Sleep(70);
    if(GetAsyncKeyState(VK_LEFT)) {
      a[y][x]=0;
      x--;++m;a[y][x]='O';
    }
    if(GetAsyncKeyState(VK_RIGHT)) {
      a[y][x]=0;
      x++;
      ++m;
      a[y][x]='O';
    }
    if(GetAsyncKeyState(VK_UP)) {
      a[y][x]=0;
      y--;
      ++m;
      a[y][x]='O';
    }
    if(GetAsyncKeyState(VK_DOWN)) {
      a[y][x]=0;
      y++;
      ++m;
      a[y][x]='O';
    }
    system("cls");
    for(int i=0;i<25;++i) {
      for(int j=0;j<80;++j) cout<<a[i][j];
    }
  }
}
return 0;
}

3 个答案:

答案 0 :(得分:0)

你选择了一种图形渲染方法,没有人计划过无闪烁。您需要将图形绘制到窗口,或学习如何使用Windows控制台功能。考虑到你的时间紧迫,我建议你忽略闪烁。

为了让蛇继续移动,记住玩家移动蛇的最后方向;如果没有按下按键,则移动该方向。

您的代码不按原样编译。练习复制和粘贴更难(将其从stackoverflow复制回编译器以确保其有效)

答案 1 :(得分:0)

要克服闪烁,你必须减少你的系统(“cls”)时间。一转后,你的代码没有为蛇提供其他饲料。让它循环。 并且还可以制作地图的边界墙,以便人们可以理解地图的范围。当你按任何一个移动键时,你必须为它的运动运行循环,以便它连续移动。希望这会有所帮助。

答案 2 :(得分:0)

考虑到您可以在不清除之前绘制“屏幕”,可以部分避免闪烁。例如,在Windows控制台环境中(显然您正在使用),此功能可用于清除屏幕而不是system("cls")

void clear_screen ( void ) {
    DWORD n;                         /* Number of characters written */
    DWORD size;                      /* number of visible characters */
    COORD coord = {0,0};               /* Top left screen position */
    CONSOLE_SCREEN_BUFFER_INFO csbi;

    /* Get a handle to the console */
    HANDLE h = GetStdHandle ( STD_OUTPUT_HANDLE );

    GetConsoleScreenBufferInfo ( h, &csbi );

    /* Find the number of characters to overwrite */
    size = csbi.dwSize.X * csbi.dwSize.Y;

    /* Overwrite the screen buffer with whitespace */
    FillConsoleOutputCharacter ( h, TEXT ( ' ' ), size, coord, &n );
    GetConsoleScreenBufferInfo ( h, &csbi );
    FillConsoleOutputAttribute ( h, csbi.wAttributes, size, coord, &n );

    /* Reset the cursor to the top left position */
    SetConsoleCursorPosition ( h, coord );
}

读取代码时,您会注意到它用足够的空格覆盖屏幕,然后将光标位置重置为左上角位置。因此,我们可以将光标设置在原点,然后编写已经包含空格的字符串,而不是消隐屏幕然后绘制字符串。

此外,我们可以使用单维空终止的char数组,大到足以代表整个屏幕。你使用80x25的大小,但在Windows中控制台更大(至少我的宽度约为100焦),所以我会考虑将81x25的大小放在每行的额外字符中\n。所以我最终得到了这个:

void update_screen ( char *buffer )
{
    COORD coord = {0,0};               /* Top left screen position */

    /* Get a handle to the console */
    HANDLE h = GetStdHandle ( STD_OUTPUT_HANDLE );

    /* Reset the cursor to the top left position */
    SetConsoleCursorPosition ( h, coord );

    /* Draw the screen buffer */
    cout << buffer;    
}

要使角色移动,您必须在每次绘制时更新其位置,并仅在按下某个键时更改移动方向。最好还是检查边界碰撞,至少停止游戏:

#include<iostream>
#include<stdlib.h>
#include<windows.h>
#include<string>

using std::cout;
using std::string;

const int scr_rows = 25;
const int scr_cols = 80;
constexpr int buf_rows = scr_rows;
constexpr int buf_cols = scr_cols + 1;
constexpr int buf_size = scr_rows * buf_cols;

void draw( char *buf, int x, int y, char c) {
    //  warning, unchecked out of bounds;
    buf[y * buf_cols + x] = c;
}

char value_at( char *buf, int x, int y ) {
    //  warning, unchecked out of bounds;
    return buf[y * buf_cols + x];
}

int main() {
    // initialize buffer
    char screen[buf_size + 1];
    for ( int i = 0, pos = 0; i < scr_rows; ++i ) {
        for ( int j = 0; j < scr_cols; ++j ) {
            screen[pos] = ' ';
            ++pos;
        }
        screen[pos] = '\n';
        ++pos;
    }
    screen[buf_size] = '\0';

    clear_screen();
    int x = 40, y = 15;
    draw(screen, 2, 16,'X');
    draw(screen, x, y, 'O');

    int vx = -1;
    int vy = 0;
    bool victory = false;

    while( !GetAsyncKeyState(VK_ESCAPE) ) {
        Sleep(100);
        if (GetAsyncKeyState(VK_LEFT)) {
            vx = -1;
            vy = 0; 
        }
        if (GetAsyncKeyState(VK_RIGHT)) {
            vx = 1;
            vy = 0; 
        }
        if (GetAsyncKeyState(VK_UP)) {
            vx = 0;
            vy = -1;    
        }
        if (GetAsyncKeyState(VK_DOWN)) {
            vx = 0;
            vy = 1; 
        }
        draw(screen, x, y, ' ');
        x += vx;
        y += vy;
        // check bounds
        if ( x < 0 || x >= scr_cols || y < 0 || y >= scr_rows ) 
            break;
        if ( 'X' == value_at(screen, x, y) ) {
            victory = true;
            break;
        }

        draw(screen, x, y, 'O');

        update_screen(screen);
    }
    if ( victory ) 
        cout << "\n  ****   You win!   ****\n";
    else 
        cout << "\n  ****  You loose!  ****\n";

    return 0;
}