C ++中的Snake不会连续两次转动

时间:2018-10-23 10:15:44

标签: c++ console-application

我最近才开始学习C ++。我决定编写一个在控制台上运行的小Snake游戏。它相对简单,看上去并不令人惊奇,但它确实是应该做的。
我唯一的问题是我的Snake不会连续转动两次。换句话说,您不能对其进行严格的掉头。但是,按下按钮后它将立即转动。 (除非你只是转过身来。)
我的代码长120行,因此它是:

首先我的包含和名称空间:

#include <iostream>
#include <vector>
#include <conio.h>
#include <windows.h>
#include <random>

using namespace std;

此函数在控制台中绘制整个字段:

void drawGrid(vector<vector<char>> &g, int height, int width, int score, int time)
{
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), { 0,0 });
    for (int r = 0; r < height; r++)
    {
        for (int c = 0; c < width; c++) std::cout << g[c][r] << " ";
        std::cout << '|' << endl;
    }
    std::cout << "Current score: " << score << "     ";
    std::cout << "\nCurrent speed: " << time << "      ";
}

此功能检查食物是否在蛇下:

bool foodSnake(vector<int> &f, vector<vector<int>> &t, int l)
{
    for (int i = 0; i < l; i++) 
        if (f[0] == t[i][0] && f[1] == t[i][1]) return true;
    return false;
}

这是个大笨蛋:

int main(void)
{
    int sleeptime = 1000;    // how long the break is between each frame
    bool foodExists = 0;
    int width = 20;    //width and height of the field
    int height = 15;
    mt19937_64 engine;    //random distributions for food generation
    uniform_int_distribution<int> heightDist(0, height - 1);
    uniform_int_distribution<int> widthDist(0, width - 1);
    int tailLengthstart = 4;
    int tailLength = tailLengthstart;
    char movementDirection = 'u';    //starts moving upwards
    char input;
    bool alive = 1;   //keeps the program running on death = 0
    vector<int> pos = { (width - 1) / 2,(height - 1) / 2 };    //starts in the middle of field
    vector<int> foodPos = pos;  // so that the food generates at the beginning
    vector<vector<int>> tail(tailLength, pos);
    vector<vector<char>> emptyGrid(width, vector<char>(height, ' '));
    vector<vector<char>> grid = emptyGrid;
    while (alive)  //runs main program until alive == 0
    {
        grid = emptyGrid; // clear grid
        grid[pos[0]][pos[1]] = 'Q';  //place head in grid
        if (!foodExists) //generates food if it was eaten
        {
            while (foodSnake(foodPos, tail, tailLength) || foodPos == pos)
            { // keeps regenerating until it isn't under the snake
                foodPos[0] = widthDist(engine);
                foodPos[1] = heightDist(engine);
            }
            foodExists = 1;
        }
        grid[foodPos[0]][foodPos[1]] = 'X'; //place food in grid
        for (int i = 0; i < tailLength; i++) grid[tail[i][0]][tail[i][1]] = 'O'; // place tail in grid
        drawGrid(grid, height, width, tailLength - tailLengthstart, sleeptime); //call above function to draw the grid
        input = '_';
        Sleep(sleeptime);
        if (_kbhit()) { //this was the best way I found to wait for input
            input = _getch();
            switch (input)
            { //disallows moving in opposite direction otherwise changes direction
                case 'w':
                    if (movementDirection == 'd') break;
                    movementDirection = 'u';
                    break;
                case 'a':
                    if (movementDirection == 'r') break;
                    movementDirection = 'l';
                    break;
                case 's':
                    if (movementDirection == 'u') break;
                    movementDirection = 'd';
                    break;
                case 'd':
                    if (movementDirection == 'l') break;
                    movementDirection = 'r';
                    break;
                case '_':
                    break;
            }
        }
        for (int i = tailLength - 1; i > 0; i--)
            tail[i] = tail[i - 1]; 
        tail[0] = pos; //move the tail along
        if (movementDirection == 'u') pos[1]--;
        if (movementDirection == 'l') pos[0]--;
        if (movementDirection == 'r') pos[0]++;
        if (movementDirection == 'd') pos[1]++; // move the head
        if (pos[0] < 0 || pos[0] > width - 1 || pos[1] < 0 || pos[1] > height - 1) 
            alive = 0; // if head is out of bounds -> dead
        for (int i = 0; i < tailLength; i++) 
            if (pos == tail[i]) 
                alive = 0; // if head is on tail -> dead
        if (foodPos == pos)
        { // if head is on food -> eat
            foodExists = 0; // food needs to be generated
            tail.push_back(tail[tailLength - 1]); //tail adds a link
            tailLength++; // tail is now longer
            if (tailLength % 5 == 0) sleeptime *= 0.75; // at certain lengths game speeds up
        }
    }

这下一部分发生在你死了还是活着== 0

    std::system("cls");
    std::cout << endl << endl << endl << endl << "\tYou have died" << endl << endl << endl << endl;

    std::cout << endl;
    std::system("pause");
    return 0;
}

因此,如果有人知道为什么它无法快速旋转,请提供帮助。或者也欢迎其他任何改进想法。

2 个答案:

答案 0 :(得分:0)

运动问题是由以下事实引起的:您前进尾巴,改变方向会导致头部立即前进。这意味着蛇实际上要走一步。

我所看到的状态已设置:

  1. 设置场景。
  2. 检查密钥。
  3. 如果按下按键并且与当前方向相反,则更改移动方向。
  4. 制作旧的头尾,并从旧头开始按设定方向添加头元素。
  5. 检查死亡
  6. 检查食物。
  7. 如果发现食物,则通过改变TailLength来长尾巴。
  8. 如果蛇的长度大于TailLength,请删除尾部元素,直到它们相等为止。
  9. 渲染场景
  10. 睡眠并转到2。

最好用列表而不是向量来表示蛇。更改大小或删除第一个元素时,都不会重新分配内存。

如果您的平台是Windows(显然,您使用的是Sleep()函数而不是usleep),则此问题的答案为密钥检测提供了更好的解决方案。 Get key press in windows console

POSIX平台也有类似的解决方案。

答案 1 :(得分:0)

有一个小问题,即使您按下了键,您也正在等待sleeptime

Sleep(sleeptime);

主周期可能类似于此伪代码

while (IsAlive())
{
   currtime = 0;
   DrawState();
   while (currtime++ < sleeptime)
   {
      if (CheckAndProcessKeyboardInput())
         break;
      SleepOneMilliSecond();
   }
}