在我的第一个C++程序中需要一些帮助(简单)



我从沉重的C背景开始C++。这是我的第一个程序,我将其用作学习体验。一个简单的贪吃蛇游戏。一切都进行得很顺利,唯一的问题是,无论我做什么,在玩家得分达到 4 分后,下一点食物总是在墙内生成,在左下角(从底部向上 1 行(。遇到它=游戏结束。

这是在 Linux 服务器上运行的。我尝试弄乱边框参数,但我很难弄清楚要更改什么,因为在我看来一切都很好。(显然有些东西不是。 我将整个程序粘贴到下面。它很短。我只需要你们中的一位大师通读/运行该程序,并带我去学校学习一些可能是简单修复的事情。请原谅过多的评论。我用这些来教(我对 pastebin 有一个追随者,就像这么说的那样奇怪(

/* 
Snake Game - Tragedy
My First Program In C++
I'm Using This Much As A Learning Experience For Myself
And Would Like To Help Those Reading The Code For This Goofy Game
Understand C++ A Bit Better Too
Therefore I'm Trying To Explain As Much As Possible In Real Time
*/
#include <iostream> //Standard
#include <stdlib.h> //Standard
#include <unistd.h> //For POSIX Access
#include <sys/ioctl.h> //For Display Window, TTY Window (Console Window) 
#include <termios.h> //For Line Buffering - See Below
#include <stdio.h> //Old Friend
#define CLRSCR "e[1;1He[2J" //Command To Clear Terminal Screen - Change Accordingly
using namespace std; /* 
A NameSpace Is Used As Additional Information 
To Differentiate Between Similar Functions/Variables
That Have The Same Name In Different Libraries
Using 'namespace' You Can Define The Context
In Which Names Are Defined
Withoug Using The STD NameSpace, The Computer Will Try
To Call cout Or cin As If It Weren't Defined In A NameSpace
Trying To Call Something That Doesn't Exist = Error
So, Without Using namespace std; When You Write For Example:
'cout << value;' You'd Have To Write 'std::cout << value;''
*/
//Create Boundaries
const int width = 50;
const int height = 25;
const char block = 'o';
void ClearScreen(void)
{
cout << CLRSCR;
}
//Global Arrays For Data Records
int background[height][width]; // Background
int snake[50][2];              // Max Snake Length
int food[2] = {0,0};             // Snake Food
int score = 0;                 // Score
int snakelen = 3;              // Snake Starting Length
int snakespeedx = 1;           // Horizontal Speed
int snakespeedy = 1;           // Vertical Speed
int lap = 200;                   // Waiting Time Betweeen Frames

//Declaring Global Temporary Variables To Save Memory
int px, py, nx, ny; //Postions
char k;
int h, w;
int x, y;
int movementx = snakespeedx;      //Snake Movement
int movementy = 0;                //Snake Movement
//Check For Keyboard Press 
/*
Reference Link:
https://www.quora.com/With-which-function-can-I-replace-kbhit-in-C++-because-the-header-conio-h-doesnt-exist-in-linux
Ubuntu Users:
sudo apt-get install libncurses5-dev libncursesw5-dev
Life Saver:
http://www.flipcode.com/archives/_kbhit_for_Linux.shtml
*/
int bytesWaiting, i;
int _kbhit()
{
static const int STDIN = 0;
static bool initialized = false; //The Boolean Data Type Is Used To Declare A Variable Whose Value Will Be Set As True (1) Or False (0)
if (! initialized)
{
//Use Termios To Turn Off Line Buffering
termios term;
tcgetattr(STDIN, &term);
term.c_lflag &= ~ICANON;
tcsetattr(STDIN, TCSANOW, &term);
setbuf(stdin, NULL);
initialized = true;
}
ioctl(STDIN, FIONREAD, &bytesWaiting);
return bytesWaiting;
}
//Initialise background borders Onto Array
void initialise_background(void)
{
//int i;
// Insert Top Border
for(i=0; i<width; i++)
{
background[0][i]=1;
}
//Insert Left Border
for(i=0; i<height; i++)
{
background[i][0]=1;
}
//Insert Right Border
for(i=0; i<height; i++)
{
background[i][width-1]=1;
}
//Insert Bottom Border
for(i=0; i<width; i++)
{
background[height-1][i]=1;
}
}
//Initialise Snake Coordinates
void initialise_snake(void)
{
snake[0][0]=3; //Coordinates X
snake[0][1]=3; //Coordinates Y
snake[1][0]=3+1; //Coordinates X
snake[1][1]=3; //Coordinates Y
snake[2][0]=3+2; //Coordinates X
snake[2][1]=3; //Coordinates Y
snake[3][0]=3+3; //Coordinates X
snake[3][1]=3; //Coordinates Y
snake[4][0]=3+4; //Coordinates X
snake[4][1]=3; //Coordinates Y
}
//Update Snake
void update_snake_coordination(void)
{
//int px,py,nx, ny;
px = snake[0][0];
py = snake[0][1];
snake[0][0] = px + movementx;
snake[0][1] = py + movementy;
nx = snake[0][0];
ny = snake[0][1];
for(i=1; i<snakelen; i++)
{
nx = snake[i][0];
ny = snake[i][1];
snake[i][0] = px;
snake[i][1] = py;
px = nx;
py = ny;
}
}
//Install Snake Coordinates Into Background Array = ( 1 To Draw And 0 To Erase)
void draw_snake_in_background(const int rev)
{
//int x, y;
for(i = 0; i<snakelen; i++)
{
x = snake[i][0];
y = snake[i][1];
if((x!=0)&&(y!=0))
{
background[y][x] = rev;
}
}
}
//Print Array Frame
void print_array_frame(void)
{
for(h=0; h<height; h++)
{
for(w=0; w<width; w++)
{
i=background[h][w];
if(i==1)
{
cout << block;
}
else if (i == 2)
{
cout << "+";
}
else
{
cout << " ";
}
}
cout << endl;
}
}
//Update Loop
void mainloop(void)
{
ClearScreen();
draw_snake_in_background(1); // Install Snake
print_array_frame();         // Print Frame
draw_snake_in_background(0); // Uninstall Snake
}
//Waiting Function
void sleepcp(int milliseconds) // Cross-Platform Sleep Function
{
clock_t time_end;
time_end = clock() + milliseconds * CLOCKS_PER_SEC/1000;
while (clock() < time_end)
{
//
}
}
//Reaction To Keyboard Press
void reaction_on_keyboard(const char k)
{
if(k=='d'||k=='6')
{
//Right Turn
movementx = snakespeedx;
movementy = 0;
}
else if(k=='a'||k=='4')
{
//Left Turn
movementx = -snakespeedx;
movementy = 0;
}
else if(k=='w'||k=='8')
{
//Turn Up
movementx = 0;
movementy = -snakespeedy;
}
else if(k=='s'||k=='2')
{
//Turn Down
movementx = 0;
movementy = snakespeedy;
}
else if(k=='q'||k=='z'||k=='c')
{
cout << "[+] Exit Safely [+]"<<endl;
exit(0);
}
}
//Create Snake Food
void cook_food(void)
{
if (food[0]==0)
{
x = rand() % width + 1;
y = rand() % height + 1;
food[0] = x;
food[1] = y;
background[y][x] = 2;
}
}
//Check Snake & Food Status
void capture_food(void)
{
x = food[0];
y = food[1];
if ((x==snake[0][0])&&(y==snake[0][1]))
{
background[y][x] = 0;
food[0] = 0;
score ++;
snakelen ++;
cook_food();
}
}
//Check Snake is Not Touching Boundary
void check_over_lapping(void)
{
//int px,py;
px = snake[0][0];
py = snake[0][1];
if((px==0)||(px==(width-1))||(py==0)||(py==(height-1)))
{
cout << "[+]        Game Over           [+]" << endl;
exit(0);
}
}
//Loop
void loop(void)
{
int frame = 0;
x = 0;
y = 0;
while(x<500)
{
sleepcp(lap);
if(_kbhit())   //If Keyboard Pressed
{
cin >> k; //Character
reaction_on_keyboard(k);
}
mainloop();                 //RUn Main Loop FUnction
update_snake_coordination();//Update Snake Coordinates
check_over_lapping();       //Check Snake Status
cook_food();                //Make Sure Food is Available
capture_food();             //Snake Eaten Food?
cout << "[ Frame : " << frame << "  | Score  : " << score << " ] "<< endl; //Print Status
frame ++;
}
}
//Main Trigger Function
main()
{
initialise_background(); //Install All Variables
initialise_snake();      //Install Snake data
loop();                  //Run Update Loop
}

这是运行游戏时发生的情况:

oooooooooooooooooooooooooooooooooooooooooooooooooo
o                                                o
o                                                o
o                                                o
o                                                o
o                                                o
o                                                o
o                                                o
o                                                o
o                                                o
o                                                o
o                                                o
o                                                o
o                                                o
o                                                o
o                                                o
o                                                o
o                                                o
o                                                o
o                       ooooooo                  o
o                                                o
o                                                o
o                                                o
+<---Places Here Every Time                      o
oooooooooooooooooooooooooooooooooooooooooooooooooo
[ Frame : 169  | Score  : 4 ]

任何帮助或意见将不胜感激!

您的背景数组是高度 * 宽度。当您将食物放入数组中时,将其放置在rand() % width + 1rand() % height + 1,它们的范围分别为 1 到宽度和 1 到高度。如果您在宽度的 x 坐标或高度的 y 坐标处生成食物,您将在背景数组的边界之外读取。正在发生的事情是,您的程序初始化的种子正在宽度的x位置生成食物,并且由于内存的布局方式与background[y + 1][0]相同的数组位置。

您可能希望更改cook_food,如下所示:

void cook_food(void)
{
if (food[0]==0)
{
x = rand() % (width - 1) + 1;
y = rand() % (height - 1) + 1;
food[0] = x;
food[1] = y;
background[y][x] = 2;
}
}

我要指出的是,无论您用什么编译它,这都不是一个真正的C++程序。您使用的是非常 C 的样式,以 C 方式存储数据,并调用 C 标准库函数。您可能想阅读isocpp C++常见问题解答,其中为学习C++的人提供了一些资源。

C++实现可能希望在标准库中使用 std::uniform_int_distribution 类,这样可以更清楚地了解食物 X 和 Y 坐标的最小值和最大值。您还将拥有跟踪其 X 和 Y 坐标的"食物"和"蛇"对象,而不是将这些值存储在您直接使用的数组中。

编辑:您一直在评论中提出一些关于蛇碰撞检测的问题。我相信这种方法会根据上面的代码检测蛇与蛇的碰撞:

bool is_snake_touching_itself() {
for (std::size_t i = 1; i < snakelen; ++i) {
if (snake[0][0] == snake[i][0] && snake[0][1] == snake[i][1]) {
return true;
}
}
return false;
}

最新更新