C ++中针对蛇游戏的建议

时间:2013-11-04 15:48:13

标签: c++ console clear

我想问你一件事。我不希望你有任何代码。我想做一个蛇游戏。我的想法是使用 GetAsyncKeyState()函数创建一个数组并控制蛇。我还没有决定如何移动蛇,但我正在考虑使用链表来保持蛇体的阵列中的坐标。

我有两个问题: 你喜欢我的想法使用链表吗? 我需要以某种方式清除控制台并再次输出表格。但如果我使用系统(“CLS”),屏幕会闪烁。是否有更好的方法来清除控制台而不闪烁?

任何其他想法将不胜感激。 :)

这是我现在的代码。

    #include<iostream>
#include<windows.h>
using namespace std;
int matrix[20][40];
void FillMatrix()
    {
        for(int i = 0; i < 20; i++)
            for(int j = 0; j < 40; j++)
                matrix[i][j] = 0;
    }
void Show()
    {
        COORD pos = {0, 0};
        SetConsoleCursorPosition(cout, pos);
        for(int i = 0; i < 20; i++)
            {
                for(int j = 0; j < 40; j++)
                    {
                        if(i == 0 || j == 0 || i == 19 || j == 39) cout << "#";
                        else if(matrix[i][j] == 0) cout << " ";
                        else cout << ".";
                    }
                cout << endl;
            }
    }
void Change(int i, int j)
    {
        matrix[i][j] = 1;
    }
int main()
    {
        FillMatrix();
        int x, y;
        x = 4;
        y = 4;
        while(!GetAsyncKeyState(VK_ESCAPE))
            {
                Sleep(100);
                //system("cls");
                if(GetAsyncKeyState(VK_LEFT)) 
                    {
                        y = y-1;
                        Change(x, y);
                    }
                else 
                    if(GetAsyncKeyState(VK_UP)) 
                        {
                            x = x-1;
                            Change(x, y);
                        }
                else 
                    if(GetAsyncKeyState(VK_RIGHT)) 
                        {
                            y = y+1;
                            Change(x, y);
                        }
                else 
                    if(GetAsyncKeyState(VK_DOWN)) 
                        {
                            x = x+1;
                            Change(x, y);
                        }
                Show();
            }
        system("pause");
        return 0;
    }

2 个答案:

答案 0 :(得分:1)

使用链表几乎总是一个糟糕的主意。在这种情况下,似乎有没有的理由甚至考虑使用一个。支持使用链接列表的主要观点是当您需要在列表中间插入或删除项目时(并且,为了获得更多,已经有一些指向列表中插入/删除需要的特定位置的东西)发生)。

由于您显然使用的是Win32,我根本不会清除屏幕。相反,我会使用WriteConsoleOutput将新输出写入屏幕,覆盖之前的任何内容。

虽然它不是蛇游戏本身,但这里是使用WriteConsoleOutput生成屏幕输出的John Conway的生命游戏实现的代码。它还包括一个ClrScr功能来清除屏幕,如果您确定必须这样做(但您可能不这样做)。

/*
** A quick "life" (2-d cellular automaton) implementation done in Turbo C 2.0 
** on the spur-of-the-moment by Jonathan Guthrie 9/20/1992 and donated to the 
** public domain.
**
** In keeping with the guidelines of the C_ECHO, this program has been tested,
** and does seem to operate properly.
*/

/* Modified into a native Win32 program, July 2001 by Jerry Coffin.
 */

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <conio.h>
#define WIN32_LEAN_AND_MEAN
#include <windows.h>

#ifndef random
 #define random(num) (int)(((long)rand()*(num))/RAND_MAX)
#endif

#ifndef randomize
 #define randomize() srand(((unsigned int)time(NULL))|1)
#endif

#define     ROWS        50
#define     COLS        80
#define     GENERATIONS 500

int civ1[ROWS+2][COLS+2], civ2[ROWS+2][COLS+2];
CHAR_INFO disp[ROWS][COLS];
HANDLE console;
COORD size = { COLS, ROWS };
COORD src = { 0, 0};
SMALL_RECT  dest = { 0, 0, COLS, ROWS };

void fill_edges(int civ1[ROWS+2][COLS+2]);

void ClrScrn(int attrib) {

    HANDLE screen = GetStdHandle(STD_OUTPUT_HANDLE);
    COORD pos = { 0, 0};
    DWORD written;
    CONSOLE_SCREEN_BUFFER_INFO screen_attr;
    unsigned size;

    GetConsoleScreenBufferInfo(screen, &screen_attr);

    size = screen_attr.dwSize.X * screen_attr.dwSize.Y;

    FillConsoleOutputCharacter( screen,attrib, size, pos, &written);
    SetConsoleCursorPosition(console, pos);
}

void update_generation(int old[ROWS][COLS], int new[ROWS][COLS])
{
      int i, j, count;

      for (i = 1; i <= ROWS; ++i)
      {
            for (j = 1; j <= COLS; ++j)
            {
                  count = old[(i + ROWS - 1) % ROWS][(j + COLS - 1) % COLS] + 
                        old[(i + ROWS - 1) % ROWS][j] +
                        old[(i + ROWS - 1) % ROWS][(j + 1) % COLS] +
                        old[i][(j + COLS - 1) % COLS] +
                        old[i][(j + 1) % COLS] +
                        old[(i + 1) % ROWS][(j + COLS - 1) % COLS] +
                        old[(i + 1) % ROWS][j] +
                        old[(i + 1) % ROWS][(j + 1) % COLS];

                  switch(count)
                  {
                  default:
                        new[i][j] = 0;
                        disp[i][j].Char.AsciiChar = ' ';
                        break;

                  case 2:
                        new[i][j] = old[i][j];
                        break;

                  case 3:
                        new[i][j] = 1;
                        disp[i][j].Char.AsciiChar = '*';
                        break;
                  }
            }
      }
      WriteConsoleOutput(console,disp, size, src, &dest);
}


void initialize(void)
{
      int i, j;

      ClrScrn(0x71);
      randomize();

      for (i = 1; i <= ROWS; ++i)
      {
            for (j = 1; j <= COLS; ++j)
            {
                  civ1[i][j] = random(2); 
                  disp[i][j].Char.AsciiChar = civ1[i][j] ? '*' : ' ';
                  disp[i][j].Attributes = 0x71;
            }
      }
      WriteConsoleOutput(console,disp, size, src, &dest);
      fill_edges(civ1);
}

void fill_edges(int civ1[ROWS+2][COLS+2]) {
    int i;

      for (i=1; i<ROWS; ++i) {
        civ1[i][0] = civ1[i][ROWS+1];
        civ1[i][ROWS+2] = civ[i][1];
      }
      for (j=1; j<COLS; ++j) {
        civ1[0][j] = civ1[COLS+1][j];
        civ1[COLS+2][j] = civ1[1][j];
      }
      civ1[0][0] = civ1[COLS+1][ROWS+1];
      civ1[COLS+2][ROWS+2] = civ1[1][1];
      civ1[COLS+2][0] = civ1[

}


int main(void)
{
      int i;

      console = (HANDLE)_get_osfhandle(_fileno(stdout));
      initialize();
      for (i = 0; i < GENERATIONS; ++i)
      {
            update_generation(civ1, civ2);
            update_generation(civ2, civ1);
      }
//  getch();
      return EXIT_SUCCESS;
}

答案 1 :(得分:0)

在您通过某种合理化证明其他情况之前,听起来您已经选择了一个链表,因为您之前已经听过这个名字。

至于屏幕闪烁,终端没有双重缓冲,所以它就像它一样,直到你使用像ncurses这样的库来移动光标覆盖位置< / em>而不是反复清洁屏幕并从头开始。