Нужна помощь с консольной игрой [закрыт]

207
27 мая 2018, 15:10

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

#include <iostream> 
#include <string.h> 
#include <time.h> 
#include <conio.h> 
#include <windows.h> 
using namespace std; 

enum Direction 
{ 
STOP = 0, LEFT = 1, RIGHT = 2, UP = 3, DOWN = 4 //Движение 
}; 
struct BadCar 
{ 
struct { 
int x; 
int y; // Машина которая двигается вниз автоматом (ЕЩЕ НЕ СДЕЛАНО) 
}head; 
}; 
struct Cars 
{ 
struct { 
int x; 
int y; 
}head; 
Direction dir; 
}; 
struct Filed 
{ 
const int width = 20; 
const int height = 20; 
}; 
void StartGame(Filed &filed, Cars &car) 
{ 
car.dir = STOP; 
car.head.x = filed.width / 2; 
car.head.y = filed.height / 2; 

} 
void BadCarGame(Filed &filed, BadCar BadCar) 
{ 
BadCar.head.x = filed.width / 2; 
BadCar.head.y = filed.height / 2; 
} 
void IzField(Filed &filed, Cars &car) 
{ 
car.head.x = STOP; 
} 
void PrintFiled(Filed filed, Cars car,BadCar BadCar) 
{ 
system("cls"); 
cout « (char)218; 
for (int i = 1; i < filed.width + 1; i++) 
{ 
cout « (char)196; 
} 
cout « (char)191 « "\n"; 
for (int i = 0; i < filed.height + 2; i++) 
{ 
for (int j = 0; j < filed.width + 2; j++) 
{ 
if (j == 0) 
{ 
cout « (char)179; 
} 
if (car.head.x == j && car.head.y == i) 
{ 
cout « '*'; 
} 
if (BadCar.head.x == j && BadCar.head.y == i) 
{ 
cout « "="; 
} 
else 
{ 
bool IsPrintTail = false; 
if (!IsPrintTail) 
{ 
cout « " "; 
} 
} 
if (j == filed.width - 1) 
{ 
cout « (char)179; 
} 
} 
cout « "\n"; 
} 
cout « (char)192; 
for (int i = 1; i < filed.width + 1; i++) 
{ 
cout « (char)196; 
} 
cout « (char)217; 
cout « "\n"; 
} 
void KeyPressEvent(Cars &car) 
{ 
if (_kbhit()) 
{ 
switch (_getch()) 
{ 
case 75: 
car.dir = LEFT; 
break; 
case 77: 
car.dir = RIGHT; 
break; 
case 80: 
car.dir = DOWN; 
break; 
case 72: 
car.dir = UP; 
break; 
case 27: 
exit(0); 
} 
} 
} 
void move(Filed &filed, Cars &car) 
{ 
switch (car.dir) 
{ 
case LEFT: car.head.x--; 
break; 
case RIGHT: car.head.x++; 
break; 
case UP: car.head.y--; 
break; 
case DOWN: car.head.y++; 
break; 
} 
} 

bool IsField(Filed &filed, Cars &car) 
{ 
if (car.head.x == -1 || car.head.y == -1 || car.head.x == filed.width || car.head.y == filed.height + 1) 
{ 
IzField(filed, car); 
} 
return false; 
} 
void main() 
{ 
srand(time(NULL)); 
Cars car; 
BadCar BadCar; 
Filed filed; 
StartGame(filed, car); 
while (true) { 
PrintFiled(filed, car, BadCar); 
KeyPressEvent(car); 
move(filed, car); 
if (IsField(filed, car)) 
{ 
break; 
} 
Sleep(200); 
} 

}
Answer 1

Так, поехали)
1) "если заезжает за правую сторону карты, выезжает с слевой, а если к левой едит, то просто прижимается"
Проерка движения у вас сделана в функции IsField(...), если развернуть вложенную функцию IzField(), то получим следующие проверки движения:

bool IsField(Filed &filed, Cars &car)
{
    if (car.head.x == -1 || car.head.y == -1 || car.head.x == filed.width || car.head.y == filed.height + 1)
    {
        IzField(filed, car);  // car.head.x = STOP;
    }
}

словами: если координаты машины выходят за границы поля, то в функции IzField мы присваиваем координате х значение STOP, равное 0.
Таким образом получается, что когда машина доезжает до правой рамки, её координата становится 0 и она продолжает движение с этой координаты, что выглядит как будто она заехала справа и выехала слева игрового поля.
Я не знаю, какое поведение вы закладывали, возможно там должно быть

car.dir = STOP

Тогда при достижении границ машина будет останавливаться.

Если же хоите,чтобы машина ездила как пакман, то можно написать так:

bool IsField(Filed &filed, Cars &car)
{
    if (car.head.x == -1)
        car.head.x = filed.width - 1;
    else
    if (car.head.x == filed.width)
        car.head.x = 0;
    if (car.head.y == -1)
        car.head.y = filed.height - 1;
    else
    if (car.head.y == filed.width)
        car.head.y = 0;
    return false;
}

Тогда машина по достижении какой-либо из границ будет продолжать движение с другой стороны.

2) вызов system("cls"); вызывает адское мерцание, чтобы немного его уменьшить надо вместо system("cls"); использовать вот эту команду SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), COORD{0, 0}); Вкратце, system("cls"); очень неэффективная функция. Вам для отрисовки поля нет нужды каждый раз очищать консоль, можно просто выводить символы поверх предыдущих, а чтобы отрисовывалось нормально необходимо каждый раз перед отрисовкой помещать курсор консоли в начальную позицию. Именно это и делает команда SetConsoleCursorPosition
На самом деле существуют и более изощренные техники отрисовки, полностью исключающие мерцание, гуглите сами.

3) Отрисовка.
Алгоритм отрисовки немного кривой и получается непонятное поле с выбоиной в том месте, где находится игрок.

   for (int i = 0; i < filed.height/* + 2*/; i++)
    {
        for (int j = 0; j < filed.width/* + 2*/; j++)
        {
            if (j == 0)
            {
                cout <<(char)179;
            }
            if (car.head.x == j && car.head.y == i)
            {
                cout << '*';
                continue; // Вот тут!
            }
            if (_BadCar.head.x == j && _BadCar.head.y == i)
            {
                cout << "=";
            }
            else
            {
                bool IsPrintTail = false;
                if (!IsPrintTail)
                {
                    cout << " ";
                }
            }
            if (j == filed.width - 1)
            {
                cout <<(char)179;
            }
        }
        cout << "\n";
    }

Выбоина в поле получалась из-за того, что при отрисовке строки с игроком вы в этой строке отрисовывали и игрока и символ пробела, что в итоге делало размер этой строки больше на 1 символ, чем необходимо, дополнительно я убрал +2, хз зачем оно)

READ ALSO
Идеально сбалансированное дерево-C++ [закрыт]

Идеально сбалансированное дерево-C++ [закрыт]

Нужно определить высоту узлаДумаю, нужно при помощи функции обхода дерева подсчитать высоту, вот только с реализацией проблемы

190
Запись и чтение вектора объектов класса в файл

Запись и чтение вектора объектов класса в файл

Возникла проблемаЯ изучил абсолютно все, что смог найти

216
QML. Repeater. Как узнать ID каждого элемента Repeater?

QML. Repeater. Как узнать ID каждого элемента Repeater?

Определенное количество кнопок создается с помощью Repeater(ListModel)Как обратится к определенной кнопки и узнать ее параметры(X, Y)? main

184