Издательский дом ООО "Гейм Лэнд"СПЕЦВЫПУСК ЖУРНАЛА ХАКЕР #64, МАРТ 2006 г.

строим двухмерное счастье

ПАЛАГИН АНТОН

Спецвыпуск: Хакер, номер #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.

Назад на стр. 064-076-4  Содержание  Вперед на стр. 064-076-6