Привет! Я преподаватель информатики и математики. В один прекрасный день осознал простую и важную вещь: дети (и взрослые) любят игры, а математику не любят. И с этим ничего нельзя сделать.
Начал размышлять, как бы геймифицировать учебный процесс. Увлекаюсь HTML, CSS, JavaScript, поэтому задумал написать игру, в которой сюжет продвигался бы за счёт решения задач — и написал. Но самое интересное не это, а вот что:
Трудно быть и продактом, и разработчиком — то бишь и визионером, и исполнителем — в одном лице. Точнее не столько трудно, сколько долго. Ведь в промежутках неплохо бы заниматься своей непосредственной работой — то есть вести уроки)) Нужна помощь — миньоны-разработчики.
Кто же поможет сам-себе-продакту в наш лихой век смены кодерской парадигмы? Правильно! Искусственный интеллект! Яндекс.Шедеврум, Mistral AI, ChatGPT-4o, Claude 3.5 и прочие миньончики. Ибо полноценный раб разраб мне не по карману.
Итак, в статье рассказываю о том, как писал свою первую обучающую игру на JS и половину работы, если не больше, делегировал ИИ.
Постановка задачи
Задача: браузерная игра, в которой сюжет продвигается вперёд за счёт решения задач уровня ОГЭ по математике. Нужны локации, персонажи, уникальные задачи, увлекательный сюжет. И, конечно же, код, реализующий смену локаций, прорисовку и адаптивность всех элементов, генерацию канвасов с задачами, проверку введённых ответов и тд.
Геймплей: попадаешь в локацию → читаешь диалоги → заводишь курсор в красный квадратик (в мобильной версии на этот квадратик нужно жмякнуть) → появляется задача → решаешь задачу. Если решил правильно — попадаешь в следующую локацию. Если нет — попадаешь в начало игры. Если прошёл все локации — вознаграждаешься ощущением своего могущества и возможностью задонатить автору))
Познакомьтесь с командой
Перед вами фотография моей команды разработчиков.
Справа-налево:
→ попугайчик — это Яндекс.Шедеврум. Суммарно за час-другой промптинга он нарисовал мне все локации и всех персонажей. Согласитесь, неплохо. Самой трудной работой было потом убрать с отдельных картинок фон и подготовить прозрачные png-шки персонажей.
→ манки-кодер — это я, продакт-менеджер, так сказать. И сценарист.
→ слон — это Mistral AI (и другие модели), неуклюжий, но горящий желанием помочь. Как-то так получилось, что у меня сложилось взаимопонимание именно с ним — баланс адекватности и доступности. Он (ну ладно, Claude 3.5 Sonnet тоже поучаствовал) написал добрую половину кода. Также он (и немножко ChatGPT-4o) сгенерировал условия всех используемых в игре задач, сразу сверстав и оформив их в готовом для вырезания виде. Генерация задач также потребовала моего чуткого научного руководства, потому что некоторые придуманные ИИ задачи снабжались неверными ответами. Некоторые были вовсе сформулированы некорректно и решения не имели. Например, Mistral AI считает, что диагональ произвольного параллелограмма можно найти через теорему Пифагора (скрин, к сожалению, потерял). Глаз за ним да глаз.
→ Питон — желанный гость на любой вечеринке, даже если на нём не написано ни строчки (а на нём в проекте и правда не написано ни строчки). Его задача — молчаливо быть. Когда-нибудь, когда обезьянка-кодер превратится в гориллу-программиста, мы обязательно напишем свой сервер. Но пока этот великий день не настал, Питон просто получает зарплату за то, что смотрит мемчики в соцсетях. Хоть бы день так пожить.
Что «мы» с самого начала сделали не так
Величайшая ошибка: увлёкся сюжетом и наделал квадратных артов. Позже осознал, что они будут коряво смотреться и на десктопе, и на мобилках, но визуальное повествование уже состоялось, переделывать было поздно (и лениво).
Величайшая проблема: организация данных игры. Я ещё не научился связываться через веб-запросы с JSON-файлами из JS-кода, а открыть JSON-файл напрямую из JS-кода как будто бы нельзя. Пытался с помощью Mistral AI пересобрать свои списки в объект, но с наскоку не получилось, так как потребовалось менять ещё и код. Глубоко вдохнул, вспомнил все известные мне нецензурные слова, заполнил километровые списки с диалогами, оставил всё как есть — громоздко, но работает. Приберегу прозрения для следующих работ, а пока довольствуюсь МВП. Может быть, мои поделки вообще никому не пригодятся, а я тут буду гуглить всуе — зачем?
Как кодит Mistral AI
Подобрались к самому главному — как устроен код, и что именно писал ИИ.
Совсем не включать голову не получится. Как только я начинал лениться и уходить от технических деталей, машина беззастенчиво лажала.
Такой промпт:
даст более надёжный результат, чем такой:
Во втором случае модель не заставила себя долго ждать и моментально выдала чушь. И это нормально. Без ТЗ результат — сами знаете что. Мысли читать она пока не научилась. Чтобы формулировать запрос на модификацию кода как можно чётче и в терминах используемых в коде конструкций, вам придётся читать созданный моделью код (и свой собственный тоже) и хорошо в нём ориентироваться.
Но даже в таком виде ИИ — огромное подспорье! Я, например, понятия не имел (и до сих пор не имею), как расположить два канваса один на другом с сохранением пропорций и поведения при смене разрешения экрана — модель это сделала ЗА МЕНЯ. Она же начала таскать отдельный канвас вместе с курсором мыши. Я бы потратил битый час, разбираясь, как правильно работает синтаксис обработки событий mousemove и как написать для него eventlistener.
Итак, золотая середина найдена: даю модели небольшие технические задачи, которые лень писать самому. Причём формулирую их в терминах тэгов, переменных, функций уже существующего кода (самой же машиной и созданного), который требуется оптимизировать.
Но давайте обо всём по порядку.
Обзор итогового кода шаг за шагом
Глобальные переменные игры:
→ canvas, ctx — пространство, в котором рисуем игру.
→ hero — канвас с небольшой иконкой героя, которая таскается за курсором мыши. На спрашивайте «зачем». Дезигн — наше фсё.
→ person — канвас, в котором происходит смена побочных персонажей.
→ hero_face — канвас с картинкой главного героя.
→ squareXStart, squareYStart, squareXEnd, squareYEnd — координаты левого верхнего и правого нижнего углов рандомного красного квадрата. Когда курсор попадает в этот квадрат, появляется условие задачи и поле для ответа.
→ scene — счётчик сцен, самая главная переменная игры.
→ start_flag — техническая переменная, позволяющая избавиться от дублирования красного квадрата в начале игры.
Функцию адаптивности resizeCanvas почти полностью написал Mistral AI (или кто-то из его товарищей, я жу не помню всех деталей):
Заходим в игру с такого кода:
Кликаем на кнопку «Начать» и попадаем в функцию startGame:
Далее отправляемся в функцию makeScene:
Эта функция отвечает за создание текущей сцены. Внутри неё живёт стыдобушка — огроменный блок «if-else if-else», который кастомит расположение и размеры героев на канвасе. Объекты фона не адаптивны, так что ничего умнее, кроме как вручную прописать параметры героев в каждой отдельной сцене, я придумать не смог. Отголосок тоски по хорошему JSON'у с данными игры...
Заканчиваем километровый «if-else if-else» и завершаем формирование сцены:
Мы вызывали функцию makeScene из функции startGame, поэтому по завершении первой снова оказываемся во второй. Там на очереди стоит функция set_random_rect, которая формирует рандомный (появляется в рандомном месте экрана) красный квадрат, взаимодействие с которым вызывает появление условия задачи.
set_random_rect — магия ИИ в действии. Почти полностью написана ИИ. Я вообще поначалу не вдумывался в жуткую математику высчитывания координат. Позже, однако, пришлось вручную расширить ассоциированную с квадратом область, в которой код будет реагировать на положение курсора.
И снова возвращаемся в startGame, где вслед за генерацией квадрата вызываем листенер курсора мыши с прикрученным к нему канвасом, в котором помещена картинка парнишки на доске:
Эта функция была написана ИИ. Я же вставил свои 30 пикселей (в прямом смысле слова) уже на этапе тестирования и причёсывания кода. Вообще не врубаюсь, что здесь происходит))
hero_search запускает механику появления картинки с текущей задачей, создание поля и кнопки подачи ответа, проверки ответа:
Приведённые выше функции фактически полностью написаны Mistral AI. Это ключевой момент игры: именно здесь живёт инкремент scene++, а также происходит проверка, не пора ли закончить игру. Если нарываемся на максимальный индекс сцены (56), то уходим на сценарий окончания игры. Ничего сверхумного в этом сценарии нет — выводим сообщение о победе, создаём и отображаем кнопки подписки на мой тг-канал и перехода к «Яндекс.Чаевым» для донатов. Не буду приводить этот код, он тоже написан Mistral AI, можете посмотреть интересующие детали в репозитории игры.
Если же переменная scene ещё не достигла 56, то мы снова ныряем в startGame, и всё начинается по кругу. Если же ответ и вовсе оказался неверным, то переменная scene обнуляется, и мы снова попадаем в начало игры:
Что вежливые мальчики и девочки говорят в конце? Правильно! «Спасибо!»
Чтобы не загромождать и без того раздобревшую статью, не стал приводить HTML и CSS коды. Mistral AI весьма успешно писал и их. Здесь — полный код игры для заинтересованных.
Вместо послесловия
«Мы» не самые опытные на свете разработчики, но непрерывно растём. Уважаемый читатель, прости «нам» невежество и наивность, с которыми ты, вероятно, неоднократно встретился в тексте статьи. Не взыщи, пойми, прости и отпусти. Можешь даже закрыть страницу и смачно плюнуть в монитор, мы не обидимся (монитор-то твой). А лучше поделись своими мыслями в комментариях. Возможно, некоторые путанные для «нас» вопросы на самом деле решаются в две строки.
Если интересно следить за дальнейшими приколами, взлетами и падениями моей мысли — подписывайтесь.
Вспомнить школьную математику и поиграть в игру можно здесь.
Автор: habaznya