Member 14785777 Ответов: 3

Змея игра с использованием C++ не будет отображать хвост должным образом


I wrote this simple snake game using c++, all was working fine until I added the tail functionality using double linked lists, the idea is I have a pointer head pointing on a node called body, when the head is in the same position as a fruit a new body is allocated with a pointer tail pointing on it and depending on what buttons are pressed to generate movement the coordinates are added as you can see in the logic function. Now, I don't see where the problem is but when I added the code to display the tail in the display function for some reason the program stops working right before the line to display the tail. What seems to be the issue ?

КОД:

<pre>#include<iostream>
#include<stdlib.h>
#include<windows.h>
#include<conio.h>
using namespace std;

bool gameover;
const int width=20;
const int height=20;
int fruitX, fruitY;
enum directions{STOP=0, LEFT, RIGHT, UP, DOWN};
enum directions dir;
int score;



struct body
{
int x;
int y;
body* next;
body* prev;
}*head=NULL;

body* t;
body* tail;
body* q=head;


void create()
{
gameover=false;

dir=STOP;

head=(body*)malloc(sizeof(body));
head->prev=NULL;
head->next=NULL;
head->x=(width/2)-1;
head->y=(height/2)-1;


fruitX=rand()%width;
fruitY=rand()%height;

score=0;
}

void display()
{
system("cls");

for(int i=0;i<width;i++)
    cout<<"x";
cout<<endl;

for(int j=0;j<height;j++)
{
    for(int i=0;i<width;i++)
    {
        if(i == 0 || i == width-1)
           cout<<"x";
        else if(i == head->x && j == head->y)
           cout<<char(254);
        else if(i == fruitX && j == fruitY)
           cout<<"*";
        else
        {
            bool printTail=false;

            while(q != head)
            {
                q=q->next;
            }
            if(i == q->x && j == q->y)
            {
                cout<<char(254);
                printTail=true;
            }
        if(!printTail)     
           cout<<" ";   
        }   
    }
    cout<<endl;
}
for(int i=0;i<width;i++)
    cout<<"x";
cout<<endl;
cout<<"Score:"<<score;
}

void logic()
{
switch(dir)
{
    case UP:head->y--;break;
    case DOWN:head->y++;break;
    case LEFT:head->x--;break;
    case RIGHT:head->x++;break;
}
if(fruitX == head->x && fruitY == head->y)
{
    fruitX=rand()%width;
    fruitY=rand()%height;
    score++;



    body* tail=(body*)malloc(sizeof(body));
    t=head;
    t->next=tail;
    tail->prev=t;
    t=tail;

    if(dir==RIGHT)
    {
        t->x=t->prev->x++;
        t->y=t->prev->y;
    }
    else if(dir==LEFT)
    {
        t->x=t->prev->x--;
        t->y=t->prev->y;
    }
    else if(dir==UP)
    {
        t->x=t->prev->x;
        t->y=t->prev->y++;
    }
    else if(dir==DOWN)
    {
        t->x=t->prev->x;
        t->y=t->prev->y--;
    }
}

if(head->x > width-1)
  head->x=0;
else if(head->x < 0)
  head->x=width-1;
else if(head->y > height)
  head->y=0;
else if(head->y < 0)
  head->y=height-1;


}

void input()
{
if(kbhit())
{
    switch(getch())
    {
        case 'w':dir=UP;break;
        case 's':dir=DOWN;break;
        case 'd':dir=RIGHT;break;
        case 'a':dir=LEFT;break;
        case 'p':gameover=true;break;
    }
}

}

int main()
{
create();

while(!gameover)
{
    display();
    input();
    logic();
    Sleep(100);
}
}


Что я уже пробовал:

Я попытался удалить код для отображения хвоста, он работал просто отлично, добавил его обратно, и происходит то же самое, так что, по-видимому, проблема заключается в отображении хвостовой линии, но я не могу понять, почему.

KarstenK

совет: сделайте структуру для своего глобальные переменные и использовать отладчик ;-)

3 Ответов

Рейтинг:
27

Patrice T

Не прямое решение, а совет о том, как действовать, чтобы понять, что на самом деле делает ваш код.

Цитата:
Я попытался удалить код для отображения хвоста, он работал просто отлично, добавил его обратно, и происходит то же самое, так что, по-видимому, проблема заключается в отображении хвостовой линии, но я не могу понять, почему.

Ваш код ведет себя не так, как вы ожидаете, или вы не понимаете, почему !

Существует почти универсальное решение: запускайте свой код на отладчике шаг за шагом, проверяйте переменные.
Отладчик здесь, чтобы показать вам, что делает ваш код, и ваша задача-сравнить с тем, что он должен делать.
В отладчике нет никакой магии, он не знает, что должен делать ваш код, он не находит ошибок, он просто помогает вам, показывая, что происходит. Когда код не делает того, что ожидается, вы близки к ошибке.
Чтобы увидеть, что делает ваш код: просто установите точку останова и посмотрите, как работает ваш код, отладчик позволит вам выполнять строки 1 на 1 и проверять переменные по мере их выполнения.

Отладчик - Википедия, свободная энциклопедия[^]

Освоение отладки в Visual Studio 2010 - руководство для начинающих[^]
Базовая отладка с помощью Visual Studio 2010 - YouTube[^]

1.11 — отладка программы (пошаговое выполнение и останова) | выучить C++[^]

Отладчик здесь только для того, чтобы показать вам, что делает ваш код, и ваша задача-сравнить его с тем, что он должен делать.
-----
Ваша программа выглядит как упрощенная версия SnakeByte (40 лет).
Советы и улучшения по этой игре:
- Вместо того, чтобы использовать стандартный вывод TTY, вы должны использовать вывод, который позволяет перемещать курсор так, как вам нужно, он позволяет обновлять только измененные части вместо того, чтобы каждый раз регенерировать весь экран.
- Проблема: при создании нового плода вы забыли проверить, находится ли новый плод на теле змеи.
- Проблема: когда змея движется, вы забыли проверить, пересекает ли голова тело.
- Совет: Вместо того чтобы использовать двойной связанный список для хранения змеи, я бы сделал 2D-карту игрового поля, хранящуюся в виде 2D-массива. Это упрощает Программирование игры.

Змеиный Байт - Википедия[^]
поиск Google или YouTube с помощью "snakebyte game apple" для получения дополнительной информации.


Рейтинг:
12

Rick York

Я не вижу никакого кода который отображает хвост но одна вещь которую я заметил это :

body* tail=(body*)malloc(sizeof(body));
и у вас также есть глобальная переменная под названием tail. Я всегда использую уровень предупреждения 4 в Visual Studio, и он сказал бы мне, что локальное определение скрывает глобальное, а предупреждения-это ошибки для меня. Я думаю, что если вы удалите часть body* из этого определения, то будет использоваться глобальная переменная, и это позволит логике, которая обращается к хвосту, работать правильно.

Еще одна вещь, я бы скорректировал объявления в верхней части, чтобы они выглядели так :
body * head = NULL;
body * tail = NULL;
body * t = NULL;
body * q = NULL;
и я бы избегал использования глобальных переменных с однобуквенными именами. Это ничего не говорит вам о том, для чего он используется, и это ОЧЕНЬ это важно для глобальных переменных, поскольку, как правило, их следует избегать.


Рейтинг:
1

phil.o

Поместите точку останова в начало нарушающего кода и запустите сеанс отладки. Выполните его построчно, наблюдая за значениями переменных, и сравните то, что они должны получить, с тем, что они на самом деле получили. Где-то должно быть какое-то несоответствие, вы просто должны исследовать и найти, где и почему.