Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > C/C++ программирование > Общие вопросы C/C++
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 13.08.2019, 23:09   #1
Alexey96
 
Регистрация: 13.08.2019
Сообщений: 4
По умолчанию Реализация блоков тетриса на С (консольное приложение)

Реализовываю простой тетрис на С в консоли. "Стакан" делаю через двумерный массив фиксированной размерности, где цифрами обозначены стенки и дно, а пустое пространство заполнено 0. Фигуру загружаю также из двумерного массива размером поменьше(4х4). Управление осуществляется стрелками с клавиатуры, программа считывает шестнадцатеричный код нажатой клавиши.

Так вот, трудности возникли на этапе рализации движения блоков тетриса по "стакану". Грубо говоря, есть три возможных направления - вправо, влево и вниз (еще поворот блока, но его пока не учитываем).
Каким способом в обычном С можно реализовать "перемещение" одного массива по другому, с учетом необходимых ограничений (проверка на "стенки" и "пол")? И подходит ли такое решение вообще?
Пока что накидал простенький способ, который очевидно не подходит, но как шаблон пока оставил его. Согласно нему, программа проверяет, есть ли в массиве единицы (цифрами 1 обозначена падающая фигура), затем помещает в левый\правый\нижний от Arr[i][j] элемент единицу или ноль. Очевидно, что этот способ не работает, ну и плюс перемещает по одному элементу за нажатие клавиши, не всю фигуру.

В интернете лежит довольно много реализаций Тетриса на С++/С#, как правило, с использованием сторонних библиотек, но вот подходящего решения для С пока не нашел. Надеюсь на совет знающих людей.
Собственно, код:
Код:
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
void ShowGlass(int [16][10]);
void Controls(int [16][10],int [4][4]);
void main()
{int Fig[4][4]={0,0,1,0,
                0,1,1,1,
				0,0,0,0,
				0,0,0,0};
int i,j,k,l,s=0,Arr[16][10]={0};
for(i=0;i<16;i++) //Сперва загружаем основу-стакан с "полом" и "стенками"
 {for(j=0;j<10;j++)
   {if(i==15)
      Arr[i][j]=2;//Нижний ярус-пол обозначаем цифрой 2
    if(i!=0&&(j==0||j==9))
	  Arr[i][j]=3;//Левую и правую стенки обозначаем цифрой 3
	 }
 }

for(i=0;i<4;i++)
 {for(j=0;j<4;j++)
  {Arr[i][j+2]=Fig[i][j]; //Присваиваем большому массиву-стакану фигуру из маленького массива
	}
  }
while(1)//Игровой цикл
   {ShowGlass(Arr);
    Controls(Arr,Fig);
    system("cls");}//Стираем игровое поле, чтобы отрисовать его заного на следующем ходу цикла
system("pause"); 
}

void ShowGlass(int Arr[16][10])//Рисуем стакан с фигурой
{int i,j;
for(i=0;i<16;i++)
  {for(j=0;j<10;j++)
    {printf("%d ",Arr[i][j]);}
	putch('\n');
  }
}

void Controls(int Arr[16][10],int Fig[4][4])
{int i,j,k,l,Fig2[4][4];
button:switch(getch())//Считываем кнопки управления
  {case 0x4b://Для кнопки влево
  	   	{for(i=0;i<16;i++)
         {for(j=1;j<10;j++)
          {while((Arr[i][j-1]!=3)&&(Arr[i][j]==1)&&Arr[i+1][j]!=2)
            if(Arr[i][j+1]==1)
             {Arr[i][j-1]=1;Arr[i][j]=1;goto button;}
            else
             {Arr[i][j-1]=1;Arr[i][j]=0;goto button;}
          }
         }
        }
   case 0x4d://Для кнопки вправо
    	{for(i=0;i<16;i++)
         {for(j=1;j<9;j++)
          {while((Arr[i][j+1]!=3)&&(Arr[i][j]==1)&&Arr[i+1][j]!=2)
            if(Arr[i][j-1]==1)
             {Arr[i][j+1]=1;Arr[i][j]=1;goto button;}
            else
             {Arr[i][j+1]=1;Arr[i][j]=0;goto button;}
          }
         }
        }
    case 0x50://Для кнопки вниз
    	{for(i=1;i<16;i++)
         {for(j=0;j<10;j++)
          {while((Arr[i][j]==1)&&Arr[i+1][j]!=2)
            if(Arr[i-1][j]==1)
             {Arr[i+1][j]=1;Arr[i][j]=1;goto button;}
            else
             {Arr[i+1][j]=1;Arr[i][j]=0;goto button;}
          }
         }
        }
    case 0x9://Для поворота по часовой стрелке
    	 {for(k=0;k<4;k++)
           {for(l=0;l<4;l++)
            Fig2[k][l]=Fig[4-l-1][k];
           }
         }
		 {for(k=0;k<4;k++)
           {for(l=0;l<4;l++)
            Fig[k][l]=Fig2[k][l];
           }
         };
    default:;
  }
}
Alexey96 вне форума Ответить с цитированием
Старый 14.08.2019, 08:14   #2
WorldMaster
Старожил
 
Аватар для WorldMaster
 
Регистрация: 25.08.2011
Сообщений: 2,841
По умолчанию

Чего то сложно в коде разбираться но суть то простая. Чтобы переместить фигуру надо проверить состояние клеток вокруг фигуры.

По коду у вас просто дикость какая то. Надо упрощать код тогда может быть станет понятнее. А вообще начать надо с листочка бумаги в клеточку. Нарисовать стакан и фигуру и там описать логику поведения.
Skype - wmaster_s E-Mail - WorldMasters@gmail.com
Работаем по 3 критериям - быстро, качественно, недорого. Заказчик выбирает любые два.
WorldMaster вне форума Ответить с цитированием
Старый 14.08.2019, 12:51   #3
Alexey96
 
Регистрация: 13.08.2019
Сообщений: 4
По умолчанию

Цитата:
Сообщение от WorldMaster Посмотреть сообщение
Чего то сложно в коде разбираться но суть то простая. Чтобы переместить фигуру надо проверить состояние клеток вокруг фигуры.
Собственно, идея как раз в этом и состоит. По моему коду берутся клетки вокруг фигуры и происходит проверка. Если клетка - 0, тогда можно двигать в этом направлении. Если 3, то это стенка стакана и дальше двигаться нельзя. Если 2, то это дно стакана, в таком случае нужно забрать у игрока управление той фигурой, присвоить клеткам "упавшей" фигуры 2 вместо 1 и загрузить новую фигуру сверху стакана (модель с разными фигурами и загрузкой новой пока не реализовывал, у меня прототип чисто для того, чтобы разобраться с перемещением фигуры).

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

В моем коде для загрузки фигуры берется цикл по строкам и столбцам массива фигуры (т.е. 4 строки и 4 столбца), затем для этих i и j производится присваиваивание МассивСтакана[i][j]=МассивФигуры[i][j]. Тогда возникает ситуация, что для расположения фигуры посередине верхнего ряда стакана нужно добавить смещение элементов при присваивании, то есть: МассивСтакана[i][j+2]=МассивФигуры[i][j].
Я пробовал таким же смещением сделать движение фигуры, но тогда оно вообще не работает.
Изображения
Тип файла: png tetris_example.png (42.1 Кб, 55 просмотров)
Alexey96 вне форума Ответить с цитированием
Старый 14.08.2019, 14:09   #4
WorldMaster
Старожил
 
Аватар для WorldMaster
 
Регистрация: 25.08.2011
Сообщений: 2,841
По умолчанию

Ничего себе поле сделали ...
Ну вот короче пока обедал набросал рабочий вариант для одной фигуры.
)))
Не плюсы конечно но синтаксис очень похожий.
Вот так проверять надо можно ли двигаться в стороны.
Код:
enum Direction { Right, Left, Up, Down };

        bool TryMove(Direction dir)
        {
            for (int i = 0; i < figure.GetLength(0); i++)
                for (int j = 0; j < figure.GetLength(1); j++)
                {
                    if (figure[i, j] == 1)
                    {
                        switch (dir)
                        {
                            case Direction.Right:
                                if (i + xLoc + 1 >= playField.GetLength(0) || playField[i + xLoc + 1, j + yLoc] == 2)
                                {
                                    return false;
                                }
                                break;
                            case Direction.Left:
                                if (i + xLoc - 1 < 0 || playField[i + xLoc - 1, j + yLoc] == 2)
                                {
                                    return false;
                                }
                                break;

                            case Direction.Up:
                                if (j + yLoc - 1 < 0 || playField[i + xLoc, j + yLoc - 1] == 2)
                                {
                                    return false;
                                }
                                break;
                            case Direction.Down:
                                if (j + yLoc + 1 >= playField.GetLength(1) || playField[i + xLoc, j + yLoc + 1] == 2)
                                {
                                    return false;
                                }
                                break;
                        }
                    }
                }
            return true;
        }
Изображения
Тип файла: png Безымянный.png (23.5 Кб, 53 просмотров)
Skype - wmaster_s E-Mail - WorldMasters@gmail.com
Работаем по 3 критериям - быстро, качественно, недорого. Заказчик выбирает любые два.

Последний раз редактировалось WorldMaster; 14.08.2019 в 14:12.
WorldMaster вне форума Ответить с цитированием
Старый 14.08.2019, 17:40   #5
Alexey96
 
Регистрация: 13.08.2019
Сообщений: 4
По умолчанию

Цитата:
Сообщение от WorldMaster Посмотреть сообщение
Ничего себе поле сделали ...
Ну вот короче пока обедал набросал рабочий вариант для одной фигуры.
)))
Не плюсы конечно но синтаксис очень похожий.
Вот так проверять надо можно ли двигаться в стороны.
Спасибо. Пока не понимаю принцип движения фигуры, но буду разбираться. Кстати, за что в вашем коде отвечают xLoc и yLoc?

А поле взято из гугл картинок для примера, оно мне такое большое в реальности не нужно.
Alexey96 вне форума Ответить с цитированием
Старый 14.08.2019, 18:08   #6
WorldMaster
Старожил
 
Аватар для WorldMaster
 
Регистрация: 25.08.2011
Сообщений: 2,841
По умолчанию

Это координаты фигуры
Skype - wmaster_s E-Mail - WorldMasters@gmail.com
Работаем по 3 критериям - быстро, качественно, недорого. Заказчик выбирает любые два.
WorldMaster вне форума Ответить с цитированием
Старый 14.08.2019, 18:11   #7
waleri
Старожил
 
Регистрация: 13.07.2012
Сообщений: 6,493
По умолчанию

Я бы сделал фигуру массивом из 4 координат, для каждого квадратика фигуры отдельно. Тогда проверка движения это просто проверить для каждого квадратика в отдельности.
waleri вне форума Ответить с цитированием
Старый 14.08.2019, 18:51   #8
Alexey96
 
Регистрация: 13.08.2019
Сообщений: 4
По умолчанию

Цитата:
Сообщение от WorldMaster Посмотреть сообщение
Это координаты фигуры
Тогда i и j - координаты массива-"стакана"?
Alexey96 вне форума Ответить с цитированием
Старый 14.08.2019, 20:35   #9
WorldMaster
Старожил
 
Аватар для WorldMaster
 
Регистрация: 25.08.2011
Сообщений: 2,841
По умолчанию

Цитата:
Сообщение от Alexey96 Посмотреть сообщение
Тогда i и j - координаты массива-"стакана"?
Просто индексаторы. Проверяем точки из фигуры в отношени поля игрового
Skype - wmaster_s E-Mail - WorldMasters@gmail.com
Работаем по 3 критериям - быстро, качественно, недорого. Заказчик выбирает любые два.
WorldMaster вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Консольное приложение.. C# Serg94 Фриланс 3 21.04.2012 19:45
консольное приложение на С++ Kingstоn Помощь студентам 1 20.06.2011 21:00
Консольное приложение shock-in Общие вопросы Delphi 2 19.12.2009 22:03
Консольное приложение __Demon__ Общие вопросы C/C++ 8 23.10.2009 10:08
Консольное приложение eks-s Общие вопросы Delphi 17 25.01.2008 03:12