Доделать змейку так, работало на любой раскладке - C (СИ)
Формулировка задачи:
Как сделать так,чтобы фрукты не появлялись на хвосте у змейки?
Как сделать так,чтобы работало на любой раскладке (хоть китайской)?
Ссылка на код (чтобы не слетели комментарии):http://rgho.st/7ytBk6fSZ
//Змейка v3.0
#include <stdio.h>
#include <string.h>
#include <conio.h> //Для использования функции _kbhit, которая ждет нажатия клавиши с клавиатуры
#include <unistd.h> //Для usleep(). Аргумент usleep() - количество миллисекунд. usleep() - задержка на определенная кол-во миллисекунд
//Константа (ширина и высота "карты игры"):
#define len 21
//Глобальная переменная признака конца игры:
int gameOver;
//Координаты змейки и фрукта, переменная записи счета игрока:
int x,y,fruitX,fruitY,score;
//Информация о хвосте:
int tailX[333]={0,0},tailY[333]={0,0}; //Координаты хвоста по x и по y
int nTail=0; //Количество элементов в хвосте
//Флаг,используемый в вызове меню:
int f;
//Карта игры
char map[len][len];
//Перечисление возможных передвижений, записанных в перечисляемый тип enum:
enum eDirection {
STOP=0,
LEFT,
RIGHT,
UP,
DOWN
} dir;
//Функция вызова меню:
void Menu(void){
system("cls");
int n;
f=1;
printf("Menu:\n1.Start game\n2.Settings\n3.Exit\nInput: ");
scanf("%d",&n);
switch (n){
case 1:
return;
case 2:
system("cls");
printf("In the game:\nPress a to go left\nPress w to go up\nPress s to go down\nPress d to go right\nPress x to exit the game\nIn the settings menu:\nPress 1 to exit settings menu\nInput: ");
scanf("%d",&n);
if (n==1){
system("cls");
Menu();
}
break;
case 3:
f=0;
return;
}
}
//Функция настройки параметров
void Setup(void){
gameOver=0; //Игра только началась -> проиграть вы не могли
dir = STOP; //Змейка стоит на месте
//Начальные координаты змейки:
x=(len-1)/2;
y=x;
//Начальные координаты фрукта:
srand(7); //"Затравочное" значение (можно без этой команды)
fruitX=rand()%len;
while((fruitX==0) || (fruitX==20)){
fruitX=rand()%len;
}
fruitY=rand()%len;
while((fruitY==0) || (fruitY==20)){
fruitY=rand()%len;
}
score=0; //Изначально счет равен нулю
return;
}
//Функция для прорисовка "карты"
void Draw(void){
system("cls");
int i,j;
memset(map,32,441); //Заполнение массива пробелами
map[y][x]='0'; //Запись головы змейки
//Запись хвоста змейки:
for(i=0;i<nTail;i++){
map[tailY[i]][tailX[i]]='o';
}
//Запись фрукта:
map[fruitY][fruitX]='F';
//Запись границ поля:
for(i=0;i<len;i++){
map[i][0]='#';
map[i][len-1]='#';
map[0][i]='#';
map[len-1][i]='#';
}
//Отображение карты и счета:
for(i=0;i<len;i++){
for(j=0;j<len;j++){
printf("%c",map[i][j]);
}
printf("\n");
}
printf("Score: %d",score);
return;
}
//Функция отслеживания нажатий
void Input(void){
while (_kbhit()){ //Возвращает правду если пользователь нажал кнопку на клавиатуре
switch(getch()){
case 'a':
dir=LEFT;
break;
case 'd':
dir=RIGHT;
break;
case 'w':
dir=UP;
break;
case 's':
dir=DOWN;
break;
case 'x':
gameOver=1;
break;
}
}
return;
}
//Логика игры
void Logic(void){
int i,j;
int prevX=tailX[0]; //Предыдущая позиция хвоста по x
int prevY=tailY[0]; //Предыдущая позиция хвоста по y
int prev2X,prev2Y;
tailX[0]=x;
tailY[0]=y;
for(i=1;i<nTail;i++){
prev2X=tailX[i];
prev2Y=tailY[i];
tailX[i]=prevX;
tailY[i]=prevY;
prevX=prev2X;
prevY=prev2Y;
}
switch (dir){
case LEFT:
x--;
break;
case RIGHT:
x++;
break;
case UP:
y--;
break;
case DOWN:
y++;
break;
}
//if ((x>len-2) || (x<1) || (y>len-2) || (y<1)){ //Выходим из игры при касании стенки
//gameOver=1;
//}
//Альтернативный вариант: когда змейка касается стенки, то она выходит с другого края карты
if (x>len-2){
x=1;
}
else{
if (x<1){
x=len-2;
}
}
if (y>len-2){
y=1;
}
else{
if (y<1){
y=len-2;
}
}
//Если мы наткнулись на свой хвост, то игра закончена:
for(i=0;i<nTail;i++){
if ((tailX[i]==x) && (tailY[i]==y)){
gameOver=1;
}
}
//"Поедание" фрукта:
if ((x==fruitX) && (y==fruitY)){
score+=10; //За каждый фрукт +10 очков
//Новое расположение фрукта:
fruitX=rand()%len;
while((fruitX==0) || (fruitX==20)){
fruitX=rand()%len;
}
fruitY=rand()%len;
while((fruitY==0) || (fruitY==20)){
fruitY=rand()%len;
}
//Увеличивание хвоста:
nTail++;
}
return;
}
//Основная функция программы
int main(void){
system("chcp 1251>nul");
Menu();
if (f){
Setup();
while(!gameOver){
Draw();
Input();
Logic();
usleep(111111); //Зарержка на определенное количество миллисекунд
}
system("cls");
printf("GAME OVER\nYOUR SCORE: %d\n",score);
}
system("pause>nul");
return 0;
}Решение задачи: «Доделать змейку так, работало на любой раскладке»
textual
Листинг программы
while(1)
{
if(GetKeyState(VK_ESCAPE)&0x80) printf("Esc\n");
if(GetKeyState('A')&0x80) printf("A\n");
if(GetKeyState('W')&0x80) printf("W\n");
if(GetKeyState('S')&0x80) printf("S\n");
if(GetKeyState('D')&0x80) printf("D\n");
if(GetKeyState(VK_UP)&0x80) printf("%c\n",(char)24);
if(GetKeyState(VK_DOWN)&0x80) printf("%c\n",(char)25);
if(GetKeyState(VK_LEFT)&0x80) printf("%c\n",(char)27);
if(GetKeyState(VK_RIGHT)&0x80) printf("%c\n",(char)26);
Sleep(100);
}
Объяснение кода листинга программы
- Код представляет собой бесконечный цикл while(1), который выполняется до тех пор, пока пользователь не нажмет клавишу «ESC» (VK_ESCAPE).
- Внутри цикла, программа проверяет, нажаты ли клавиши 'A', 'W', 'S', 'D', 'UP', 'DOWN', 'LEFT' и 'RIGHT'.
- Если любая из этих клавиш нажата, программа выводит на экран соответствующее сообщение.
- После проверки всех клавиш, программа делает паузу в 100 миллисекунд с помощью функции Sleep(100).
- Программа начнет работать снова после завершения паузы и продолжит цикл, пока пользователь не нажмет клавишу «ESC».