строим двухмерное счастье ПАЛАГИН АНТОН Спецвыпуск: Хакер, номер #064, стр. 064-076-5 { bottom = i; count++; } else count++; } else //Прерываем цикл поиска, если найдена хотя бы одна заполненная линия if(count != 0) break; } } void Playfield::RemoveRows(SquareCoord bottom, SquareCoord count) { //Проверяем, не наблудили ли наши шаловливые ручки assert(bottom>=0 && bottom<m_rows.size()); assert(count>=1 && count<=4); assert(bottom-count>0 && bottom-count<=m_rows.size()); SquareCoord i; //Итерируемся по заполненным линиям for(i = bottom; i > bottom-count; --i) { //Удаляемая линия должна быть полной assert( m_rows[i].IsFull() ); //Удаляем ее содержимое m_rows[i].Reset(); } //Сдвигаем верхние линии вниз на места удаленных линий for(i = bottom; i != 4; --i ) { m_rows[i] = m_rows[i-count]; } } Сначала требуется определить, есть ли заполненные линии, — это делается в функции GetFullRows(). Если такие линии есть, грохнем их и опустим все верхние линии вниз на столько линий, сколько только что было удалено, — вытворяем это в функции RemoveRows(). Конфигурации новых фигур создаются случайным образом в функции ThrowNextBlock. Листинг «Генерация нового блока» void GameDriver::ThrowNextBlock() { //Если игра не поставлена на паузу if( !m_isPaused ) { assert(m_current==0); //Текущий блок становится будущим блоком m_block = m_nextBlock; //Создаем будущий блок m_nextBlock = TetrisBlock(); //Случайным образом задаем его конфигурацию for(int i = 0; i < rand()%4; ++i ) m_nextBlock.Rotate(); //Задаем начальное положение в стакане нового блока m_current = &m_block; m_currentX = 3; m_currentY = -2; //Задаем скорость блока if(m_pushedSpeed>0) { m_gameLogic.m_levelInfo.m_speed = m_pushedSpeed; m_pushedSpeed = 0; } } } отделяй котлеты от мух Как видишь, архитектурно код тетриса разделен на три части. Одна часть отвечает за отображение пользовательского интерфейса на экране и прием команд от пользователя. Этот код инициализирует виджеты и обрабатывает события, генерируемые ими. Другая часть кода отвечает за игровую логику, причем идет четкое разделение на код, рисующий игровые объекты, обновления игровых объектов, подсчета статистики, анализа правил игры и рисования «спецэффектов». Вся игровая область (стакан) описывается игровой сеткой. Тетрисные фигуры двигаются строго по этой сетке, причем код логики оперирует только координатами фигур на игровой сетке — перевод в экранные координаты осуществляется только на этапе рисования каждой фигуры. Старайся разбивать программный код на функциональные блоки, используй рекурсию. Пусть у тебя будет множество методов в классах, зато ты не запутаешься в гигантских циклах и непонятных присваиваниях. Давай переменным говорящие имена, только не злоупотребляй! Читать сочинения на языке программирования — весьма сомнительное удовольствие. И комментируй, комментируй и еще сто тысяч раз комментируй. Готов поспорить, что через неделю ты посмотришь на свои 20 000 строк кода — и не поймешь, что там написано, если неделю назад не откомментировал. откажись от указателей Использование указателей на объекты классов и данные в памяти несет в себе потенциальную опасность. Ты можешь забыть удалить выделенную память, переписать значение указателя и потом будешь тратить сутки на поиски тривиальных ошибок. Старайся использовать по максимуму статическую компоновку данных, механизм ссылок, контейнеры STL и Boost. Если нельзя обойтись без указателя, то воспользуйся умными указателями, например shared_ptr из библиотеки Boost. |