Тема: створення комп’ютерної гри з двома об’єктами, управління одним з яких здійснює людина, а управління іншими здійснюється автоматично за допомогою комп’ютера мовою програмування C++.
Мета: сформувати предметні компетенції щодо технологій імітації руху та моделювання гри.
Учень повинен пояснювати:
Обладнання: комп'ютери зі встановленими ОС, браузером, середовищем CodeBlocks для програмування мовою С++ з використанням бібліотеки wxWidgets, (дана) інструкція.
Структура уроку
Хід уроку
1. Організаційний момент
Вітання з класом. Перевірка присутності і готовності учнів до уроку. Перевірка виконання домашнього завдання.
2. Актуалізація опорних знань
Протлумачити дію вказівок мовою С++
srand(time(NULL)); return rand()%N; wxPaintDC z(Panel1); z.SetBrush(wxColor(255,0,0)); z.SetPen(wxPen(wxColor(255,0,0),1)); z.DrawRectangle(x,y,W,H); z.DrawCircle(wxPoint(x,y),r); wxFont font1(14,wxFONTFAMILY_DEFAULT,wxFONTSTYLE_NORMAL,wxFONTWEIGHT_BOLD,false,"Ubuntu Calibri"); z.SetFont(font1); z.SetTextForeground(wxColor(255,0,0)); z.SetBackgroundMode(wxTRANSPARENT); wxString s=wxT("");
і порівняти з очікуваними відповідями.
srand(time(NULL)); — ініціалізація генератора випадкових чисел;
return rand()%N; — повертає випадкове ціле число, що менше N;
wxPaintDC z(Panel1); — опис об'єкта для малювання, нащадка Panel1;
z.SetBrush(wxColor(255,0,0)); — встановлення червоного кольору заповнення;
z.SetPen(wxPen(wxColor(255,0,0),1)); — встановлення червоного кольору для контура ширини 1 піксель;
z.DrawRectangle(x,y,W,H); — зображення прямокутника ширини W й висоти H, верхній лівий кут (ВЛК) якого має координати (x, y);
z.DrawCircle(wxPoint(x,y),r); — зображення круга з центром у точці (x, y) і радіусом r;
wxFont font1( // опис шрифту 14, // розмір wxFONTFAMILY_DEFAULT,// родина wxFONTSTYLE_NORMAL, // стиль написання wxFONTWEIGHT_BOLD, // наповнення false, // підкреслити? "Ubuntu Calibri"); // гарнітура
z.SetFont(font1); — призначення властивостей шрифту для виведення;
z.SetTextForeground(wxColor(255,0,0)); — задання червоного кольору шрифту;
z.SetBackgroundMode(wxTRANSPARENT); — задання прозорого тла для виведення тексту;
wxString s=wxT(""); — ініціалізація порожнього рядка wxWidgets;
z.DrawText(s,x,y); — виведення рядка wxString s у точку з координатами (x, y).
3. Вивчення нового матеріалу
Події від клавіатури подано класом wxKeyEvent. У бібліотеці wxWidgets є такі типи повідомлень:
Макроси подій wxKeyEvent
EVT_KEY_DOWN (функція) — опрацьовує подію wxEVT_KEY_DOWN — будь-яку клавішу було натиснуто. Якщо цю подію опрацьовано і не пропущено, wxEVT_CHAR взагалі не буде породжено для цього натискання клавіші, але wxEVT_KEY_UP буде.
EVT_KEY_UP (функція) — опрацьовує подію wxEVT_KEY_UP — будь-яку клавішу було відпущено.
EVT_CHAR (функція) — опрацьовує подію wxEVT_CHAR.
EVT_CHAR_HOOK (функція) — опрацьовує подію wxEVT_CHAR_HOOK, що виникає перед довільною іншою головною подією.
На відміну від усіх інших головних подій, ця повідомлення про подію поширюється вгору ієрархією вікон, що дозволяє перехоплювати її у батьківському вікні того вікна з фокусом, на яке його відправлено спочатку. Якщо немає такого вікна з фокусом, це повідомлення буде надіслано глобальному об'єкту wxApp. Те, що ця подія виникає перед довільною іншою головною подією, дає батьківському вікну можливість змінювати опрацювання клавіатури своїх нащадків. Наприклад, це використовують для перехоплення натисканням клавіші Esc у будь-якому дочірньому вікні діалогу і уникнути передчасного закриття вікна самого діалогу. Як усталено, якщо цю подію опрацьовують, тобто обробник не викликає wxEvent :: Skip, не будуть створені ні wxEVT_KEY_DOWN, ні wxEVT_CHAR, хоча wxEVT_KEY_UP буде породжено. Однак, звернувшись до спеціального методу DoAllowNextEvent, можна опрацювати wxEVT_CHAR_HOOK і дозволити породження головних подій. Це може знадобитися, якщо потрібно не допустити запуску батьківського обробника wxEVT_CHAR_HOOK без придушення головних подій. Ця подія не породжується при захопленні миші, бо вважають, що вікно, яке її захопило, також повинно отримувати всі події клавіатури, не дозволяючи своєму батьківському wxTopLevelWindow втручатися в їх опрацювання.
Якщо натиснути на клавішу і через певний час її відпустити, то, як правило, буде породжено багато подій натискання і лише одна — відпускання.
Щоб отримувати події від клавіатури, вікно програми має перебувати у фокусі. Його можна примусово отримати, викликавши метод wxWindow :: SetFocus. Наприклад, після натискання клавіші миші.
Для отримання коду ASCII введеного символа використовують функцію GetKeyCode. Для отримання введеного символа у кодуванні Unicode використовують GetUnicodeKey.
Для перевірки, чи було натиснуто певну клавішу-модифікатор, використовують функції AltDown, MetaDown, ControlDown або ShiftDown. Функція HasModifiers повертає значення true, якщо клавішу Control або Alt було натиснуто під час породження повідомлення про натискання / відпускання клавіші (але не Shift або Meta).
Замість використання функцій ControlDown або MetaDown краще використовувати CmdDown, яка викликає MetaDown на Mac OS X і ControlDown на інших платформах.
Функція GetPosition повертає позицію покажчика миші в координатах клієнтської області під час отримання відповідних подій.
Примітка. Якщо подію натискання клавіші захоплено, а її обробник не викликав метод event.Skip, то цю подію не буде передано наступним обробникам. Якщо не викликано event.Skip для подій, які не опрацьовано, то на деяких платформах можуть перестати працювати гарячі клавіші.
Не перетворюваний код натискання або відпускання для алфавітно-цифрової клавіші завжди відповідає значенню верхнього регістра. Для решти клавіш це значення виду WXK_XXX з таблиці кодів символів. Наприклад, якщо натиснути клавішу А (латиниця), то код події натискання дорівнює коду А з таблиці ASCII (65), але код події введення — символу а в ASCII (97). Але, якщо натиснуто А + Shift, код події натискання як і раніше буде А, в той час як код клавіші події введення символу тепер також стане А. З іншого боку, при натисканні клавіш Ctrl + А подія натискання передає код А, але подія введення символу матиме код 1.
Завдання 1 (для учителя при наявності проектора у класі, інакше — для учнів). Вибірково дослідити роботу клавіш, запустивши приклад wxWidgets*/samples/keyboard і понатискавши різні клавіші. Код аналізувати не потрібно.
Після натискання й відпускання клавіш у такій послідовності: A, Shift + A, Ctrl + A, ↓, ↑ можна отримати такий результат.
Клавіші-модифікатори в ОС Windows — це Control і Alt, а також клавіша Windows, яка працює як Meta. В ОС Linux, клавішу, що працює як Meta, налаштовують. Щоб дізнатися, як налаштовано систему, достатньо використати утиліту xmodmap і отримати щось, схоже на таке.
Якщо клавішу NumLock налаштовано як Meta, функція HasModifiers не повертає значення true при утриманої клавіші Meta при нормальному опрацюванні натискання клавіш з включеним NumLock.
У Mac OS X клавіша Command (з символом Apple) виконує функції Meta, а Option — функції Alt. При Mac OS X клавішу Command використовують з тією самою метою, що й Control на інших платформах, тому можна використовувати функцію CmdDown об'єкта wxKeyEvent замість ControlDown або MetaDown.
Перевірка того, чи натиснуто клавішу в обробнику події, породженою не клавіатурою — за допомогою функції wxGetKeyState, що набуває булевоого значення і аргументом якої є назва клавіші — див. перелік в алфавітному порядку. Це використовують, наприклад, при програмуванні гри з використанням таймера в обробнику породженої ним події, як у поданому далі завданні 3.
4. Інструктаж з ТБ
5. Вироблення практичних навичок
Завдання 2. Cтворити проєкт, який повідомлятиме код ASCII введеного символа і сам введений символ, виводячи рядок wxString s за допомогою функції wxMessageBox(s).
У середовищі CodeBlocks у вказаній учителем теці створити проєкт key з використанням бібліотеки wxWidgets з такими параметрами:
Видалити об'єкти: MenuBar1 і StatusBar1, виділивши їхні зображення (клацнувши на них лівою кнопкою миші) над зображенням форми і натиснувши клавішу Delete.
Надати властивості Title форми значення Press any key.
Створити обробник подій введеня символа EVT_CHAR:
підтвердити створення обробника OnPanel1Char, натиснувши кнопку з написом Гаразд.
Повідомити вчителя про завершення роботи над проектом.
Завдання 3. Cтворити гру Пінг-Понг з відбиванням м'яча від бокових меж ігрового поля, у якій однією ракеткою (червоного кольору) керує людина, а іншою (жовтого кольору) — програма.
Вказівки до виконання завдання
(словесний опис кроків 8−10 бажано отримати конкурсом ідей)
У середовищі CodeBlocks у вказаній учителем теці створити проєкт PingPong з використанням бібліотеки wxWidgets з такими параметрами:
Видалити об'єкти: MenuBar1 і StatusBar1, виділивши їхні зображення (клацнувши на них лівою кнопкою миші) над зображенням форми і натиснувши клавішу Delete.
Надати властивостям форми значення (тут і нижче у тексті вказано лише ті властивості, значення яких потрібно змінити):
X | 0 |
Y | 0 |
Width | 780 |
Height | 400 |
Розташувати на панелі користувацький віджет Custom з такими значеннями властивостей:
Creating code | $(THIS) = new $(CLASS)($(PARENT)); |
Include file | wx/dcclient.h |
Var name | z |
Class name | wxPaintDC |
X | 0 |
Y | 0 |
Width | 780 |
Height | 400 |
Щоб змінити значення Creating code (коду породження), потрібно клацнути лівою кнопкою миші праворуч від відповідного значення
і у вікні діалогу Creating code вилучити зайві символи, після чого натиснути на кнопку Гаразд.
Виставити на панель таймер з вкладення Tools і виставити проміжок між вмиканнями 50 мілісекунд, що відповідає частоті 20 кадрів на секунду.
Створити обробник події вмикання таймера:
виділити таймер, клацнувши на ній лівою кнопкою миші, і перейти до розгляду подій, натиснувши кнопку із зображенням фігурних дужок {};
навести вказівник миші на рядок з написом None (Жодного) праворуч від напису EVT_BUTTON, клацнути лівою кнопкою миші і з випадного меню вибрати Add new handler (Додати новий обробник);
підтвердити створення події OnTimer1Trigger вмикання таймера, натиснувши кнопку з написом Гаразд у вікні діалогу New hadler (Новий обробник);
Описати глобальні змінні — параметри математичної моделі гри:
int j=0, t[2]={0,0}, H=400, W=780, r=8, w=5, h=50, yy=0, yr=0, dyr=8, xr=W-w, Nx=50, Ny=20; double x,y,dx,dy, dxmin=15, dxmax=20, dymax=10; wxString s;з таким тлумаченням:
Програмно втілити математичну модель гри у тілі функції OnTimer1Trigger коду PingPongMain.cpp — обробника події вмикання таймера, передбачивши таке:
зміна yy — ординати ВЛК жовтого прямокутника — таким чином, щоб його центр мав ту саму ординату, що й центр білого круга, якщо це можливо. Інакше кажучи:
— «ракетка» комп'ютера відстежує рух «м'яча» із запізненням час між вмиканнями таймера;
при виході частини білого круга за горизонтальні межі ігрового поля — зміна ординати його центра таким чином, ніби до цього відбувся пружний удар об горизонтальну межу, протягом якого dy — приріст ординати між вмиканнями таймера — змінив значення на протилежне;
Порівняти створене з очікуваним.
Програмно втілити унаочнення процесу гри наприкінці тіла функції OnTimer1Trigger коду PingPongMain.cpp — обробника події вмикання таймера, передбачивши таке:
заповнення об'єкта для малювання темно зеленим кольором — (0, 128, 0) моделі RGB;
зображення лінія поділу ігрового поля на половини і меж поля — вертикальних ліній білого кольору товщини 1 піксель;
зображення об'єктів для поточного стану гри:
Порівняти створене з очікуваним.
Повідомити вчителя про завершення роботи над проектом.
6. Підбиття підсумків уроку
Обговорення проблем виконання завдання. Виставлення оцінок.
7. Домашнє завдання
У разі потреби доробити завдання. Удосконалити проект (достатньо одним з перелічених нижче шляхів):
створити інтерфейс: зберігши початкові розміри ігрового поля, збільшити висоту форми і у нижній частині форми розташувати написи і поля введення для глобальних змінних, які необхідно ініціалізувати. Передбачити можливість зміни розмірів форми й ігрового поля;
змінити ту частину коду обробника події OnTimer1Trigger, що описує відбивання м'яча ракетками, передбачивши незначну випадкову зміну напряму й величини швидкості у результаті відбивання.
Текст упорядкував Олександр Рудик.