Заметки за 2022 год
Крестики-нолики
После 2004 года я очень долго не касался темы создания игр, полностью уйдя в вебдев. Хотя, пробовал всякие движки, но это были просто эксперименты не заслуживающие внимания.
В 2020 году, в самый разгар пандемии коронавируса, я решил закрыть гештальт по играм. Засел за «GameMaker Studio 2» от «YoYo Games». В результате появилась эта игра.

Возможно возникнет вопрос, почему в предыдущей заметке практически всё было написано на C++, а теперь такой шаг назад. Отвечу, мне не хотелось писать отрисовку, ввод и прочие сущности «движка». Я решил, что лучше будет сосредоточиться на игровой логике.
О игре
В начале игры случайным образом определяется кто будет первым ходить. Затем, в случае если первым ходит игрок, Вы при помощи мыши выбираете ячейку для своего хода и кликаете левой кнопкой мыши. Если же ходит компьютер, то ожидаем конца его хода до появления надписи «YOU TURN».
Ссылка на загрузку игры: OXO.zip
Код игры содержит всего два объекта obj_game и obj_tile. Девять скриптов поделённых на зоны ответственности для спрайтов, ИИ компьютера и игровой доски. А также ресурсы в виде восьми спрайтов и двух шрифтов.
Все ассеты видно на скриншоте ниже.

Объект obj_game является главным. Он обрабатывает события:
Create– ИнициализацияClean Up– Очистка данныхStep– Обработчик основного циклаDraw– Вывод UIKey Up– Нажатие клавиши
Для примера код обработки события Step в объекте obj_game. Здесь же вызываются скрипты scr_computer_turn и scr_test_board_to_win.
1/// @description Обработка ситуации
2
3// Если в игре
4if (in_game) {
5
6 // Если ход компьютера
7 if (turn == 1) {
8
9 message = "WAIT";
10
11 if (computer_awaiting < 1) {
12 // Ход компьютера
13 scr_computer_turn();
14
15 // Передаём ход игроку
16 turn = 0;
17 message = "YOU TURN";
18
19 // Проверяем победителя
20 scr_test_board_to_win();
21
22 computer_awaiting = room_speed;
23 }
24
25 computer_awaiting -= 1;
26 }
27
28}Второй объект obj_tile обрабатывает только клик мышкой по тайлу в событии Left Pressed. Это ход игрока:
1/// @description Клик по тайлу
2
3if (obj_game.turn == 0 && obj_game.in_game) {
4
5 if (self.sprite_index == spr_n) {
6 // Меняем спрайт на крестик
7 self.sprite_index = spr_x;
8
9 // Проставляем в таблице свой ход
10 grid_x = (self.x / 128) - 3;
11 grid_y = (self.y / 128) - 2;
12 ds_grid_set(obj_game.board, grid_x, grid_y, 1);
13
14 // Передаём ход компьютеру
15 obj_game.turn = 1;
16
17 with (obj_game) {
18 scr_test_board_to_win();
19 }
20 }
21
22}Так компьютер расчитывает куда ему сходить:
1function scr_computer_turn() {
2 // Попытка сходить в выигрышную позицию
3 pos = scr_computer_turn_win();
4
5 if (pos != false) {
6 scr_computer_make_turn(pos[0], pos[1]);
7 return;
8 }
9
10 // Попытка заблокировать выигрышную позицию игрока
11 pos = scr_computer_turn_block();
12
13 if (pos != false) {
14 scr_computer_make_turn(pos[0], pos[1]);
15 return;
16 }
17
18 // Ход в случайное пустое место
19 pos = scr_computer_get_random();
20
21 if (pos != false) {
22 scr_computer_make_turn(pos[0], pos[1]);
23 }
24}Поиск возможной выигрышной позиции:
1function scr_computer_turn_win() {
2 board_x = noone;
3 board_y = noone;
4
5 for(i = 0; i < 8; i++) {
6
7 line = obj_game.lines[i];
8
9 a = line[0];
10 b = line[1];
11 c = line[2];
12
13 av = ds_grid_get(obj_game.board, a[0], a[1]);
14 bv = ds_grid_get(obj_game.board, b[0], b[1]);
15 cv = ds_grid_get(obj_game.board, c[0], c[1]);
16
17 if (av == 1 || bv == 1 || cv == 1) { continue; }
18
19 count_c = 0;
20 count_e = 0;
21
22 if (av == 2) { count_c++; } else if (av == 0) { count_e++; board_x = a[0]; board_y = a[1] }
23 if (bv == 2) { count_c++; } else if (bv == 0) { count_e++; board_x = b[0]; board_y = b[1] }
24 if (cv == 2) { count_c++; } else if (cv == 0) { count_e++; board_x = c[0]; board_y = c[1] }
25
26 if (count_c == 2 && count_e == 1) {
27 return [board_x, board_y];
28 }
29 }
30
31 return false;
32}Приводить весь код я не вижу смысла, там всё достаточно просто.