Пишем простую игру в 1С на встроенном языке

· 9 мин

Содержание

Игру на платформе 1С:Предприятие создают в Конфигураторе: делают обработку, рисуют поле на табличном документе или в поле HTML, а движение фигур задают обработчиком ожидания — это и есть игровой цикл. Встроенного языка 1С для этого хватает: массивы, циклы и работа с координатами здесь ровно те же, что в учётных задачах.

Платформа не игровой движок, поэтому подход выбирают заранее. Для пошаговых и сеточных игр — змейка, 2048, тетрис, крестики-нолики — достаточно «родных» средств 1С. Для плавной графики, звука и управления с клавиатуры удобнее встроить HTML5-canvas в поле HTML, а 1С оставить роль оболочки и хранилища рекордов.

С чего начать: обработка и объекты метаданных

Основу игры удобно держать в обработке. Два варианта:

  • 🧩 Внешняя обработка (.epf) — отдельный файл. Ничего не меняет в основной конфигурации, легко передать коллеге. Запускается через Файл → Открыть в режиме 1С:Предприятие.
  • 🗂 Обработка в составе конфигурации — встроена в прикладное решение, доступна из командного интерфейса. Нужна, если игра — часть большого решения.

Для эксперимента берите внешнюю обработку : быстрее итерации, не нужно обновлять конфигурацию базы после каждой правки. Выбор способа зависит от жанра: сеточные игры (змейка, тетрис, 2048, сапёр) целиком собираются на табличном документе и чистом коде 1С; аркады с плавным движением и спрайтами разумнее вести в поле HTML.

Внутри обработки создают одну управляемую форму. На форму добавляют реквизиты:

  • реквизит типа ТабличныйДокумент — если рисуете поле ячейками;
  • числовые реквизиты Счёт, Рекорд, координаты активной фигуры;
  • служебные флаги ИграИдёт, Пауза.

Отдельные объекты метаданных (справочники, регистры) для самой игры не нужны. Они понадобятся только под таблицу рекордов — об этом ниже.

Учебная версия платформы для таких экспериментов подходит: разработка в Конфигураторе доступна, ограничение — размер базы и отсутствие клиент-серверного режима. Для игры этого достаточно.

Минимальный набор для игры в 1С
Выполнено: 0 / 5

Игровое поле: на чём рисовать картинку

Готового холста в 1С нет, поэтому поле собирают из того, что есть. Два рабочих способа.

Способ 1. Табличный документ. Поле — это сетка ячеек. Каждую клетку красят через свойство ЦветФона, а состояние хранят в двумерном массиве. Перед игрой у документа скрывают сетку и заголовки и включают «только просмотр», чтобы читатель не правил ячейки.

&НаКлиенте
Процедура Перерисовать()
    ПолеИгры.Очистить();
    ПолеИгры.ОтображатьСетку = Ложь;
    ПолеИгры.ОтображатьЗаголовки = Ложь;
    Для Стр = 1 По ВысотаПоля Цикл
        Для Кол = 1 По ШиринаПоля Цикл
            Клетка = ПолеИгры.Область(Стр, Кол, Стр, Кол);
            Клетка.ВысотаСтроки = 12;
            Клетка.ШиринаКолонки = 2;
            Если Поле[Стр][Кол] = 1 Тогда
                Клетка.ЦветФона = WebЦвета.Синий;
            Иначе
                Клетка.ЦветФона = WebЦвета.Белый;
            КонецЕсли;
        КонецЦикла;
    КонецЦикла;
КонецПроцедуры

Чтобы клетки выглядели квадратными, подбирают высоту строки и ширину колонки опытным путём — единицы у них разные. Палитру берут из WebЦвета: так не придётся задавать цвет числовыми кодами. Поле 20×20 ячеек рисуется мгновенно, 100×100 уже заметно задумается при полной перерисовке — размер подбирайте под жанр.

Способ 2. Поле HTML. В реквизит типа «Строка» кладут HTML-страницу с тегом <canvas>, а всю отрисовку ведёт JavaScript внутри поля. 1С только задаёт начальную разметку и принимает обратно счёт. Способ даёт плавную анимацию и не упирается в ограничения табличного документа.

Способ отрисовкиКогда выбратьЧем неудобен
Табличный документСеточные и пошаговые игры, чистый код на 1СГрубая «пиксельная» картинка, нет плавности
Поле HTML + canvasНужны анимация, звук, клавиатураЛогика уходит в JS, сложнее отлаживать

Управление в управляемой форме проще всего сделать экранными кнопками «Влево», «Вправо», «Вверх», «Вниз». Полноценный перехват стрелок клавиатуры в управляемой форме ограничен — если он критичен, ведите ввод в поле HTML.

Игровой цикл: обработчик ожидания вместо таймера

Отдельного таймера в 1С нет — его роль играет обработчик ожидания. Метод ПодключитьОбработчикОжидания раз за разом вызывает вашу клиентскую процедуру через заданный интервал. В ней вы двигаете объекты, проверяете столкновения и перерисовываете поле.

&НаКлиенте
Процедура ПриОткрытии(Отказ)
    ВысотаПоля = 20;
    ШиринаПоля = 20;
    СоздатьПоле();
    ПодключитьОбработчикОжидания("ШагИгры", 0.3);
КонецПроцедуры

&НаКлиенте
Процедура ШагИгры()
    Если Не ИграИдёт Тогда
        Возврат;
    КонецЕсли;
    ДвигатьОбъект();
    ПроверитьСтолкновения();
    Перерисовать();
КонецПроцедуры

Интервал задают в секундах, для динамики ставят небольшое значение. В старых релизах минимум был около секунды, в актуальных платформах допускается дробный интервал. Если нужен темп выше, чем успевает обработчик, делайте несколько шагов логики за один вызов или переносите цикл в поле HTML.

Остановить игру — ОтключитьОбработчикОжидания("ШагИгры"). Скорость меняют так: отключили старый обработчик и подключили заново с меньшим интервалом. На этом же приёме делают постепенное ускорение — за каждые N очков уменьшаете интервал на долю секунды и переподключаете обработчик.

Паузу делают флагом Пауза: обработчик продолжает тикать, но в начале ШагИгры вы выходите по Возврат, пока пауза включена. Это надёжнее, чем отключать и включать обработчик по кнопке.

Обработчик ожидания работает на клиенте. Не вызывайте внутри него серверные процедуры на каждом шаге — обращение к сервере каждый тик заметно тормозит игру. Всю логику движения держите в клиентском коде.

Движение объектов и проверка столкновений

Состояние поля удобно хранить в массиве массивов: Поле[Строка][Колонка], где 0 — пусто, 1 — занято. Координаты активной фигуры — в отдельных реквизитах.

Движение — это смена координат на каждом шаге. Перед тем как применить ход, проверяют, свободна ли целевая клетка и не вышла ли фигура за границы.

&НаКлиенте
Функция КлеткаСвободна(Стр, Кол)
    Если Стр < 1 ИЛИ Стр > ВысотаПоля
        ИЛИ Кол < 1 ИЛИ Кол > ШиринаПоля Тогда
        Возврат Ложь; // вышли за поле
    КонецЕсли;
    Возврат Поле[Стр][Кол] = 0;
КонецФункции

&НаКлиенте
Процедура ДвигатьОбъект()
    НовСтр = ТекСтрока + СмещениеСтр;
    НовКол = ТекКолонка + СмещениеКол;
    Если КлеткаСвободна(НовСтр, НовКол) Тогда
        Поле[ТекСтрока][ТекКолонка] = 0;
        ТекСтрока = НовСтр;
        ТекКолонка = НовКол;
        Поле[ТекСтрока][ТекКолонка] = 1;
    Иначе
        ОбработатьСтолкновение();
    КонецЕсли;
КонецПроцедуры

Столкновения в большинстве игр сводятся к двум проверкам: граница поля и занятая клетка. От типа игры зависит реакция: змейка на стену — конец партии, тетрис-фигура упёрлась в дно — фиксируется, а на её месте появляется новая.

Механика конкретных игр ложится на этот же каркас:

  • 🐍 Змейка. Тело — очередь координат. На каждом шаге добавляете клетку спереди и убираете сзади. Съели цель — заднюю клетку не убираете, змейка растёт. Столкновение с собственным телом ищется проверкой, не занята ли новая клетка головой же.
  • 🧱 Тетрис. Фигура — набор из четырёх координат. Падение вниз на шаг, поворот — пересчёт координат вокруг центра. После фиксации проверяете заполненные строки и сдвигаете поле вниз.
  • 🔢 2048. Сетка чисел. Нажатие сдвигает все плитки в одну сторону, одинаковые соседние — складываются. Поле хранит не 0/1, а само число в клетке.

Кнопки управления меняют не координаты напрямую, а вектор смещения СмещениеСтр / СмещениеКол. Тогда объект продолжает двигаться сам, а игрок лишь задаёт направление. Командам кнопок можно назначить горячую клавишу в свойствах команды формы — это ускоряет управление, когда стрелки недоступны.

Звук и мультимедиа: честно о возможностях

Здесь у платформы слабое место. Универсального средства проиграть произвольный звуковой файл в тонком и веб-клиенте нет. Поэтому:

  • 🔇 Способ 1 на табличном документе звук, как правило, оставляют без звука — это нормально для учебной игры.
  • 🔊 Способ 2 через поле HTML звук решается штатно: внутри HTML используют тег <audio> и проигрывают его из JavaScript при событиях игры (съел яблоко, собрал линию).

Картинки спрайтов проще всего тоже держать в поле HTML. Если остаётесь на табличном документе, роль «графики» выполняет цвет ячеек — для сеточных игр этого достаточно. Иконки и мелкие картинки (цель, бонус) можно выводить отдельным полем картинки на форме, подгружая изображение из макета или библиотеки картинок конфигурации.

Не закладывайтесь на тяжёлое мультимедиа: платформа оптимизирована под учётные задачи, а не под рендер. Чем больше анимации и звука нужно — тем сильнее аргумент в пользу поля HTML с canvas.

Сохранение счёта и таблицы рекордов

Личный рекорд одного пользователя хранят в хранилище общих настроек — отдельные объекты метаданных не нужны:

&НаСервере
Процедура СохранитьРекордНаСервере(Значение)
    ХранилищеОбщихНастроек.Сохранить("Игра", "Рекорд", Значение);
КонецПроцедуры

&НаСервере
Функция ПрочитатьРекордНаСервере()
    Возврат ХранилищеОбщихНастроек.Загрузить("Игра", "Рекорд");
КонецФункции

Если нужна общая таблица рекордов для всех игроков, заведите справочник или регистр сведений с полями: имя игрока, очки, дата. После партии добавляете запись, а для экрана рекордов строите запрос с сортировкой по очкам по убыванию и ограничением ПЕРВЫЕ 10. Регистр сведений удобен, когда на одного игрока нужен один лучший результат: периодичность не ставьте, ключом сделайте имя игрока и перезаписывайте запись, если новый счёт выше.

Для одиночной игры хранилище настроек проще и не требует менять конфигурацию. Таблица рекордов оправдана, когда в базе несколько пользователей и есть смысл соревноваться.

Сохранять счёт логично в конце партии, а не на каждом шаге — иначе снова упрётесь в лишние обращения к серверу. Проверьте, что Загрузить возвращает пустое значение при первом запуске — иначе арифметика с рекордом упадёт на Неопределено.

Отладка и публикация готовой игры

Отлаживают игру штатными средствами Конфигуратора:

  1. Запуск под отладчиком — F5 (запускает 1С:Предприятие с подключённой отладкой).
  2. Точки останова — F9 на нужной строке, выполнение встанет на ней.
  3. Табло — Shift+F9, чтобы посмотреть значения координат и массива поля на каждом шаге.
  4. Пошаговое выполнение — F11 (с заходом в процедуру) и F10 (без захода).

Удобный приём: временно увеличьте интервал обработчика до нескольких секунд — успеете разглядеть каждый шаг цикла в отладчике. Частая ошибка начинающих — ставить точку останова внутри цикла перерисовки: отладчик будет останавливаться на каждой клетке. Ставьте её в начало ШагИгры, а массив поля смотрите целиком в Табло.

Распространяют игру тремя путями:

  • 📁 Файлом .epf — отдаёте обработку, пользователь открывает её через Файл → Открыть. В прикладном решении открытие внешних обработок должно быть разрешено настройками.
  • 🧩 В составе конфигурации — добавляете обработку в основную конфигурацию, выводите команду в интерфейс и обновляете конфигурацию базы.
  • 🌐 Публикацией на веб-сервере — Администрирование → Публикация на веб-сервере в Конфигураторе (нужен Apache или IIS). После этого игра открывается в браузере через веб-клиент.

Веб-публикация особенно уместна для варианта с полем HTML: canvas и звук в браузере работают предсказуемо.

Частые ошибки при разработке игры

Разберём промахи, которые не видны из пошаговой инструкции.

Диагностика: выберите симптом

Ещё одна типичная причина «тормозов» — перерисовка всего поля целиком, когда изменились одна-две клетки. На больших полях перекрашивайте только затронутые ячейки.

Частые вопросы

Нужна ли платная лицензия, чтобы написать игру в 1С?
Для экспериментов подойдёт учебная версия платформы: разработка в Конфигураторе доступна. Ограничения учебной версии (размер базы, отсутствие клиент-серверного режима) на простую игру не влияют.
Можно ли сделать игру без Конфигуратора?
Нет. Код встроенного языка, формы и объекты метаданных создаются только в Конфигураторе. В режиме 1С:Предприятие игра лишь запускается.
Будет ли игра работать в веб-клиенте?
Да, если опубликовать базу на веб-сервере. Вариант с полем HTML в браузере ведёт себя стабильнее, чем табличный документ с частой перерисовкой.
Насколько быстрый игровой цикл можно сделать на обработчике ожидания?
Для сеточных игр интервала в доли секунды достаточно. Если нужна настоящая плавная анимация, переносите цикл в canvas внутри поля HTML — там частота кадров не ограничена платформой.
Как потом отдать игру другому человеку?
Проще всего — файлом внешней обработки .epf. Получателю нужно, чтобы в его базе было разрешено открытие внешних обработок, иначе файл не запустится.