我最近才开始学习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;
}
因此,如果有人知道为什么它无法快速旋转,请提供帮助。或者也欢迎其他任何改进想法。
答案 0 :(得分:0)
运动问题是由以下事实引起的:您前进尾巴,改变方向会导致头部立即前进。这意味着蛇实际上要走一步。
我所看到的状态已设置:
最好用列表而不是向量来表示蛇。更改大小或删除第一个元素时,都不会重新分配内存。
如果您的平台是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();
}
}