Программирование для Haiku OS шаг за шагом: обработка сообщений и реализация логики работы программы
Содержание:
1. Добавление меню;
2.Обработка сообщений и реализация логики работы программы (Вы читаете данный раздел).
При щелчке по фишке (кнопке) происходит отправка уникального сообщения программе, которое должно быть обработано в функции MessageReceived(BMessage*) главного окна программы. Очевидно, что в качестве обработчика события (щелчка) должна выступать функция, принимающая адрес фишки -источника сообщения.
Добавим в декларацию и реализацию класса TMainForm закрытую функцию-член void Buttonclicked(TChip*). В будущем функция будет отвечать за логику игрового процесса, пока же оставим её пустой. Также добавим заготовки функций-обработчиков щелчков по пунктам меню: void GameNew() и void About(). Теперь мы можем переписать реализацию функции обработки сообщений главного окна (см. листинг 4).
Теперь перейдём к программированию собственно игры. Для «запоминания» местоположения пустой клетки понадобится переменная. Запишем в файле реализации класса TMainForm глобальную переменную int iEmpty = 4 (на момент начала игры пуста 4-я клетка). Понятно, что направление хода фишки вычисляется вычитанием её положения из положения пустой клетки. Значениями хода, при которых фишка ходит, как уже упоминалось выше, будут 1 и 2, взятые по модулю. Учитывая, что направление хода определяется цветом фишки, для чёрных фишек значения верного хода будут отрицательными (-1 и -2), а для белых - положительными.
При соблюдении всех этих условий можно делать ход. Вначале необходимо записать номер клетки ходящей фишки в переменную iEmpty (клетка освобождается). Позиция же фишки (номер занимаемой ею клетки) изменится на значение хода, т.е. для белой фишки увеличится, а для чёрной, наоборот, уменьшится. Запишем это программно (см. листинг 5).
Для изменения позиции фишки на игровой доске мы воспользовались функцией void MoveTo(float x, float y), которая перемещает верхний левый угол виджета в точку с координатами x и y в системе координат родительского виджета (у нас это панель, BBox* pPanel). Поскольку фишка перемещается по горизонтали, координата y не меняется и сохраняется равной отступу от границ игрового поля (5 пикселов). Изменение же координаты x равно приращению координаты левой границы фишки (pChip->Frame().left) на величину хода, умноженную на размеры самой фишки, т.е. 80.
Всё, теперь можно скомпилировать и запустить программу, пощёлкать по фишкам и убедиться, что они движутся так, как нам и надо. Однако у программы есть существенный недостаток. Она не делает проверку на выигрыш. Это легко исправить. Очевидно, что каждая из фишек, для того, чтобы попасть на выигрышную позицию, должна переместиться на 4 клетки (не забываем, что фишки движутся только в одном направле-нии). 4 х 3 = 12, т.е. для каждой из групп фишек (белые и чёрные) число ходов до выигрышной позиции должно составлять 12, а для всей партии - 24. Когда суммарное число ходов равно нулю, партия завершена успешно.
Приступим к программной реализации проверки на выигрыш. В файле TMainForm.cpp объявим глобальную переменную iWin, которой присвоим значение 24. После каждого перемещения фишки от значения переменной будем отнимать число хода фишки, взятое по модулю: iWin -= abs(pChip->iMove).
В конце функции void TMainForm::Buttonclicked(TChip* pChip) добавим проверку на выигрыш (см. листинг 6):
Для вывода информации о победе мы использовали класс BAlert, который создаёт стандартное диалоговое окно Haiku. В качестве параметров конструктор класса принимает строку заголовка окна, строку выводимого сообщения, три строки - текст кнопок окна (если кнопок меньше, чем 3, то для отсутствующих кнопок принимает NULL), а также флаги ширины окна (можно оставить значение по умолчанию B_WIDTH_AS_USUAL) и выводимого в окне значка:
Показ диалогового окна осуществляется вызовом метода Balert::Go(). Для придания нашей программе окончательной функциональности осталось добавить реализацию функций-обработчиков события щелчка по пункту меню. У меня они выглядят следующим образом (см. листинг 7).
Откомпилируйте программу и убедитесь, что при решении головоломки она сигнализирует о победе (см. рисунок выше). Теперь у вас есть каркас простого приложения Haiku, который может быть взят за основу для создания собственных программ.
В следующей части статьи планируется описать работу с ресурсами и добавление пиктограммы приложения.
1. Добавление меню;
2.
При щелчке по фишке (кнопке) происходит отправка уникального сообщения программе, которое должно быть обработано в функции MessageReceived(BMessage*) главного окна программы. Очевидно, что в качестве обработчика события (щелчка) должна выступать функция, принимающая адрес фишки -источника сообщения.
Добавим в декларацию и реализацию класса TMainForm закрытую функцию-член void Buttonclicked(TChip*). В будущем функция будет отвечать за логику игрового процесса, пока же оставим её пустой. Также добавим заготовки функций-обработчиков щелчков по пунктам меню: void GameNew() и void About(). Теперь мы можем переписать реализацию функции обработки сообщений главного окна (см. листинг 4).
Листинг 4
void TMainForm: :MessageReceived(BMessage* pMessage) {
switch(pMessage->what) {
case uiBTTN1 _ MSG:
Buttonclicked(pChip[0]); break;
case uiBTTN2 _MSG:
Buttonclicked(pChip[1]); break;
case uiBTTN3 _ MSG:
Buttonclicked(pChip[2]); break;
case uiBTTN4 _ MSG:
Buttonclicked(pChip[3]); break;
case uiBTTN5 _MSG:
Buttonclicked(pChip[4]); break;
case uiBTTN6 _ MSG:
Buttonclicked(pChip[5]); break;
case uiGAMENEW _ MSG:
GameNew(); break;
case uiABOUT _ MSG: About();
break;
default:
BWindow::MessageReceived(pMessage);
}
}
void TMainForm: :MessageReceived(BMessage* pMessage) {
switch(pMessage->what) {
case uiBTTN1 _ MSG:
Buttonclicked(pChip[0]); break;
case uiBTTN2 _MSG:
Buttonclicked(pChip[1]); break;
case uiBTTN3 _ MSG:
Buttonclicked(pChip[2]); break;
case uiBTTN4 _ MSG:
Buttonclicked(pChip[3]); break;
case uiBTTN5 _MSG:
Buttonclicked(pChip[4]); break;
case uiBTTN6 _ MSG:
Buttonclicked(pChip[5]); break;
case uiGAMENEW _ MSG:
GameNew(); break;
case uiABOUT _ MSG: About();
break;
default:
BWindow::MessageReceived(pMessage);
}
}
Теперь перейдём к программированию собственно игры. Для «запоминания» местоположения пустой клетки понадобится переменная. Запишем в файле реализации класса TMainForm глобальную переменную int iEmpty = 4 (на момент начала игры пуста 4-я клетка). Понятно, что направление хода фишки вычисляется вычитанием её положения из положения пустой клетки. Значениями хода, при которых фишка ходит, как уже упоминалось выше, будут 1 и 2, взятые по модулю. Учитывая, что направление хода определяется цветом фишки, для чёрных фишек значения верного хода будут отрицательными (-1 и -2), а для белых - положительными.
При соблюдении всех этих условий можно делать ход. Вначале необходимо записать номер клетки ходящей фишки в переменную iEmpty (клетка освобождается). Позиция же фишки (номер занимаемой ею клетки) изменится на значение хода, т.е. для белой фишки увеличится, а для чёрной, наоборот, уменьшится. Запишем это программно (см. листинг 5).
Листинг 5
void TMainForm: :Buttonclicked(TChip* pChip) {
pChip->iMove = iEmpty - pChip->iCell; // Вычисляем ход фишки
if(((pChip->Colour == WhiteChip) && J
(pChip->iMove == 1 || pChip->iMove == 2)) || ((pChip->Colour == BlackChip) && J
(pChip->iMove == -1 || pChip->iMove == -2)))
{
iEmpty = pChip->iCell; // Фишка освобождает клетку // Вычисляем новое положение фишки... pChip->iCell += pChip->iMove; // и перемещаем её на новую позицию
pChip->MoveTo((pChip->Frame().left + 80 * pChip->iMove), 5);
}
}
void TMainForm: :Buttonclicked(TChip* pChip) {
pChip->iMove = iEmpty - pChip->iCell; // Вычисляем ход фишки
if(((pChip->Colour == WhiteChip) && J
(pChip->iMove == 1 || pChip->iMove == 2)) || ((pChip->Colour == BlackChip) && J
(pChip->iMove == -1 || pChip->iMove == -2)))
{
iEmpty = pChip->iCell; // Фишка освобождает клетку // Вычисляем новое положение фишки... pChip->iCell += pChip->iMove; // и перемещаем её на новую позицию
pChip->MoveTo((pChip->Frame().left + 80 * pChip->iMove), 5);
}
}
Для изменения позиции фишки на игровой доске мы воспользовались функцией void MoveTo(float x, float y), которая перемещает верхний левый угол виджета в точку с координатами x и y в системе координат родительского виджета (у нас это панель, BBox* pPanel). Поскольку фишка перемещается по горизонтали, координата y не меняется и сохраняется равной отступу от границ игрового поля (5 пикселов). Изменение же координаты x равно приращению координаты левой границы фишки (pChip->Frame().left) на величину хода, умноженную на размеры самой фишки, т.е. 80.
Всё, теперь можно скомпилировать и запустить программу, пощёлкать по фишкам и убедиться, что они движутся так, как нам и надо. Однако у программы есть существенный недостаток. Она не делает проверку на выигрыш. Это легко исправить. Очевидно, что каждая из фишек, для того, чтобы попасть на выигрышную позицию, должна переместиться на 4 клетки (не забываем, что фишки движутся только в одном направле-нии). 4 х 3 = 12, т.е. для каждой из групп фишек (белые и чёрные) число ходов до выигрышной позиции должно составлять 12, а для всей партии - 24. Когда суммарное число ходов равно нулю, партия завершена успешно.
Приступим к программной реализации проверки на выигрыш. В файле TMainForm.cpp объявим глобальную переменную iWin, которой присвоим значение 24. После каждого перемещения фишки от значения переменной будем отнимать число хода фишки, взятое по модулю: iWin -= abs(pChip->iMove).
В конце функции void TMainForm::Buttonclicked(TChip* pChip) добавим проверку на выигрыш (см. листинг 6):
Листинг 6
if(iWin == 0) {
(new BAlert("Победа", "Победа!", "Да",
NULL, NULL, B _ WIDTH _ AS _ USUAL, B _ INFO _ ALERT))->Go() ;
}
if(iWin == 0) {
(new BAlert("Победа", "Победа!", "Да",
NULL, NULL, B _ WIDTH _ AS _ USUAL, B _ INFO _ ALERT))->Go() ;
}
Для вывода информации о победе мы использовали класс BAlert, который создаёт стандартное диалоговое окно Haiku. В качестве параметров конструктор класса принимает строку заголовка окна, строку выводимого сообщения, три строки - текст кнопок окна (если кнопок меньше, чем 3, то для отсутствующих кнопок принимает NULL), а также флаги ширины окна (можно оставить значение по умолчанию B_WIDTH_AS_USUAL) и выводимого в окне значка:
- B_EMPTY_ALERT - нет значка;
- B_INFO_ALERT - выводится изображение буквы «i»;
- B_IDEA_ALERT - выводится изображение горящей лампочки;
- B_WARNING_ALERT - выводится изображение восклицательного знака жёлтого цвета;
- B_STOP_ALERT - выводится изображение восклицательного знака красного цвета.
- B_INFO_ALERT - выводится изображение буквы «i»;
- B_IDEA_ALERT - выводится изображение горящей лампочки;
- B_WARNING_ALERT - выводится изображение восклицательного знака жёлтого цвета;
- B_STOP_ALERT - выводится изображение восклицательного знака красного цвета.
Показ диалогового окна осуществляется вызовом метода Balert::Go(). Для придания нашей программе окончательной функциональности осталось добавить реализацию функций-обработчиков события щелчка по пункту меню. У меня они выглядят следующим образом (см. листинг 7).
Листинг 7
// Начало новой игры void TMainForm::GameNew()
{
iEmpty = 4; iWin = 24;
int iX = 5;
for(int i = 0; i 3) {
j-- ; // Средняя ячейка свободна
}
pChip[j]->MoveTo(iX, fChipTop); pChip[j]->iCell = i + 1;
iX += 80; // Приращение координат последующих кнопок
}
}
}
// Вывод краткой информации о программе void TMainForm::About()
{
(new BAlert("0 программе", "Головоломка Y'Ji^biV'Ante) Андрей Кузнецов, 2010.", "Да", NULL, NULL, B _ WIDTH _ AS _ USUAL, B _ INFO _ ALERT))->Go();
}
// Начало новой игры void TMainForm::GameNew()
{
iEmpty = 4; iWin = 24;
int iX = 5;
for(int i = 0; i 3) {
j-- ; // Средняя ячейка свободна
}
pChip[j]->MoveTo(iX, fChipTop); pChip[j]->iCell = i + 1;
iX += 80; // Приращение координат последующих кнопок
}
}
}
// Вывод краткой информации о программе void TMainForm::About()
{
(new BAlert("0 программе", "Головоломка Y'Ji^biV'Ante) Андрей Кузнецов, 2010.", "Да", NULL, NULL, B _ WIDTH _ AS _ USUAL, B _ INFO _ ALERT))->Go();
}
Откомпилируйте программу и убедитесь, что при решении головоломки она сигнализирует о победе (см. рисунок выше). Теперь у вас есть каркас простого приложения Haiku, который может быть взят за основу для создания собственных программ.
В следующей части статьи планируется описать работу с ресурсами и добавление пиктограммы приложения.