Мы с моей тимой геймдевелоперов решили взяться за самый большой проект в нашей истории- 2Д платформер. Нет, мы не делали до этого какие-нибудь FlappyBird'ы или змейки, но объём работы в этом проекте просто сносил нам мозг. Для начала мы отказались от обычных, вертикальных лестниц, а взяли ступенчатые лестницы. Мы написали логику для дверей, которые можно было закрывать «на ключ» и прикрутили разрушаемые блоки. Наступил момент, когда надо было писать Искусственный Интеллект. Как самому опытному из нашей малоопытной команды скриптеру, честь писать ИИ выпала мне.
Этап 1: поиск пути и движение по пути
Этап 1.1: Поиск пути
Так как основные локации у нас будут не на открытом воздухе, а в зданиях, то нужно было сделать поиск маршрута среди десятков дверей, лестниц и комнат. Подумав, мы с тимлидом решили, что стоит сделать некую пародию на алгоритм A*, где у нас будут узлы, между которыми будет бегать бот. сделали тестовую сцену, поставили узлы, для наглядности повесили на них SprateRenderer'ы. А что делать дальше?
С этим вопросом в голове я ходил 3 дня. Пока один мой товарищ не предложил интересный алгоритм, когда узлы будут возбуждаться, подобно нейронам головного мозга.
Итак. Есть узел A, около которого стоит ИИ и узел Б, к которому ИИ должен прийти. выдали всем Узлам свой ID и пометили соединенные узлы, к которым они будут отправлять сигнал. У каждого узла была своя булевая переменная «isChecked» и переменная «triggeredBy», в котором хранился ID узла, который его «возбудил». Так, когда затронут узел Б, он пройдёт по цепочке к узлу А, узнавая все ID узлов, которые прошёл сигнал. Так я получал путь из ID узлов, которые должен пройти бот. Если вы вдруг не поняли, как это работает, то я расскажу вам сказку.
Однажды Ивану нечего было делать, и поэтому он решил составить своё фамильное древо. К несчастью у него не хватало информации для воплощения этой идеи в жизнь. Иван был так увлечён этой идеей, что решил, что добравшись до главного прародителя он сможет обнаружить своих неожиданных родственников. Иван знал, где он может встретиться со своим отцом, чтобы поговорить и направился туда. Отец рассказал ему, что деда Ивана звали Iван и рассказал, где его можно найти. Иван нашёл Iвана, и тот рассказал, что прадед Ивана мог знать этого прародителя лично, но он давно помер. Иван посветил половину жизни изучению тёмных искусств, но в итоге смог воскресить своего прадеда. Прадед сказал, что его прародитель является оборотнем и что зарыто его тело на опушке у трёх сосен. Иван пошёл туда и обнаружил, роющего могилу человек. Оказалось, что этот человек – двеннадцатиюродный брат Иван. Иван сильно удивился тому, что они пришли к одному месту, но брат оказался программистом и всё объяснил.Получился вот такой результат:
– Здесь работает принцип навигации из моей любимой игры *название*!
– И в чём же он заключается?
– От каждого наследника можно придти к общему родителю системы, если в этой системе каждый наследник знает лично своего родителя.
Это массив int-переменных, которые означают ID узлов, которые должен пройти юнит.
Этап 1.2.1: движение по пути
У меня есть список ID узлов, у меня есть бот. Что дальше? А дальше то, что надо двигать бота по этому пути.
Ну я прикинул такой вариант: дошёл бот до узла, поставил галочку, посмотрел, что там дальше, пошёл к следующему узлу. Сделал. Заработало. Я был рад… Но…
Этап 1.2.2: лестницы и их взаимодействие с ИИ
Как говорил один чёрно-белый герой: «Лестницы… мой главный враг..»
Нужно было определить, следующий узел находится над ИИ, под или на уровне. В зависимости от этой информации он будет проходить мимо лестницы(игнорировать коллизию), или забираться на неё(взаимодействовать с коллизией). Ох и много нервных клеток полегло на этой битве с движком… На форумах вычитал, что можно расставить всё по слоям и во вкладке Edit->Physics2D можно настроить игнорирование коллизий одного слоя и другого. Всё заработало!
Осталось только научить его открывать двери. Тут проблем не возникло.
Итог:
Этап 2: Эмоции и реплики
Этап 2.1: Эмоции
Да, мы решили приделать эмоции… И реплики.
Эмоции будут выделяться выражением лица и анимациями действий.
Реплики будут отображаться текстом над головой.
Эмоции я прикрутил на одном дыхании… Для этого я уже сделал переменную «emotionID», которая хранила в себе ID эмоции. А вот реплики…
Этап 2.2: Реплики
Для красоты сделал отдельный класс Phrases
[System.Serializable] //сериализуемый для красивого отображения в инспекторе
class Phrases
{
public string Name; //название эмоции, которой соответствуют реплики
public int byEmotionID; //для определения, с какой эмоцией это соединять
public string[] Phrases;//массив самих реплик
}
Сделал массив этого класса. Дальше просто в зависимости от emotionID ставил любую фразу из списка. Обновлял раз в N секунд.
Но я решил пойти дальше! Для каждого персонажа сделал файл с .phrs расширением, закодировал это с помощью того, что к байтовому числу каждого символа в файле прибавлял X байтов. Получался нечитаемый, не изменяемый текст. сделал что-то типа своей разметки, сделал алгоритм, который берёт и по этой разметке всё переводит в массив класса Phrases.
Отлично! Всё работает!
Хотел на чистом шарпе написать программку для заполнения такого файла, но тут мы переходим к концу истории.
Конец..?
От большой, неоплачиваемой работы мы быстро устали… Присоединение нового кодера не помогло… Команда развалилась… Код всё-ещё лежит на облаке Unity.
Конечно, не так давно начала зарождаться идея продолжить проект, но уже с дальнейшей монетизацией… Если что-то получится, то я, пожалуй, напишу всю историю разработки. Но на этом мой рассказ про начинающего скриптера и ИИ заканчивается.
Комментарии (25)
Igor_Sib
16.05.2019 21:09+2Прикольно, у меня есть подобная наработка AI, только более продвинутая (NPC лазит, спрыгивает, запрыгивает, земля любой геометрии из SpriteShapes, на движущихся платформах даже почти ездит (малость доделать надо :)), лестницы вот только вертикальные обычные). Тоже есть эммоции (обычный, агрессивный, паника, ...) и есть список потребностей (жажда, голод, нужда в деньгах и тп) и точек интереса (есть, пить, в туалет, работать, ...), в зависимости от этого перс принимает решение, идет в нужное место и делает что надо. Сейчас правда тоже подзабросил. Может гифку запосчу позже.
Чем не устроил A*? Отлично подходит для такого решения, простой и эффективный, не понял почему начали свой велосипед изобретать.MrKarton Автор
17.05.2019 07:08Хотелось сделать что-то своё, прикольное… да и мы не нашли способа интегрировать А* в 2Д платформер. Это же больше для рогаликов..(новички, что с нас взять?)
UncleJey
17.05.2019 10:04Поясните пожалуйста, в чём проявление термина ИИ в данном контесте? Почему не бот? В чём интеллектуальность то? Прост для хайпу?
GCU
17.05.2019 10:41A* — это уже достаточно интеллектуально :)
В контексте игр бот и есть ИИ.
Интеллектуальность ИИ в играх заключается в том, чтобы с ботами было интересно играть — и это достаточно сложная задача. Например для ботов не сложно идеально перемещаться и стрелять без промаха. Бот может всегда видеть и слышать игрока, но при этом должен вести себя так, чтобы игроку было интересно его побеждать.
ИИ, который всегда обыгрывает человека в шахматы — достижение чисто научное.
В контексте же развлекательных игр — бот, который попадает в голову игроку в движении из пистолета с 500 метров — это провал. Задача победить человека любой ценой там не стоит — она давно решена классическими методами. В играх задачи ИИ идут гораздо дальше чем просто победить :)UncleJey
17.05.2019 12:02A* это не интеллект. Не подменяйте понятия, пожалуйста.
мне казалось что ИИ как минимум подразумевает обучаемость, адаптивность, иттеративность. В статье же ещё один банальный алгоритм без какой бы то ни было изящности.MrKarton Автор
17.05.2019 12:30Это уже продвинутый ИИ, нейросети, машинное обучение и много других страшных слов. ИИ — понятие широкое
GCU
17.05.2019 13:08Увы, «интеллектуальность» зависит лишь от полученных результатов по сравнению с человеческими. В случае поставленной задачи нахождения пути — результат близок к человеческому, естественному. Да, можно сказать что сама задача не особо интеллектуальная, однако:
— алгоритм отмечает обработанные узлы (обучается)
— алгоритм работает на разных связных графах (адаптивность)
— итерации поиска по смежным узлам продолжаются до успеха (итеративность)
P.S. На нейросети тоже можно сказать «банальный алгоритм без какой-либо изящности» :)dimkss
17.05.2019 16:21На правах сарказма:
Т.е. если взять алгоритм сортировки чисел, и результат будет близок к человеческому, то это тоже будет «интеллектуальность»? :)GCU
17.05.2019 22:40Да! Вы можете предложить более интеллектуальный результат сортировки чисел? :)
Конкретно в игровом ИИ в результате сортировки ингда были бы ещё и ошибки для пущей «человечности» :)
dimkss
17.05.2019 16:20Эт-то вы еще не видели как светофоры, где время горения зеленого зависит от времени суток, называли интелектуальными.
Видать мода такая, хорошо хоть SQL скрипты пока не принято называть интеллектуальными.GCU
17.05.2019 23:00В контексте игр симуляция работы светофора тоже исторически относится к ИИ — это же конечный автомат всё-таки :)
Интеллектуально это или нет — можно легко определить просто поставив человека (как эталон интеллектуальности) в те же самые условия что и ИИ — и сравнить результат.
Такая разновидность теста Тьюринга — посадить человека в изолированную коробку-светофор и дать ему часы. Сравнить результаты. :)
Вот если кроме часов в светофоре ещё стоит камера или какие-то дополнительные датчики — то в таких условиях ИИ соревноваться с человеком сложнее.
P.S. Если SQL скрипт играет в шахматы/шашки/крестики-нолики не хуже среднестатистического обывателя, почему бы не назвать его интеллектуальным? :)
Hendalph
18.05.2019 12:08Просто подмена понятий, произошедшая со времен, когда под «ИИ» как раз и подразумевалось поведение компьютерного соперника/напарника. Это сейчас в этот термин вложили «обучаемость, адаптивность, итеративность» :)
fivehouse
17.05.2019 13:12Как хорошо, что в геймдеве кусочек кода из 3 вложенных цикла, 10 if-then-ов и пару хешей можно назвать Искусственным Интеллектом. А если об этом не знают лохи, которые читают заголовки статей, а потом тупят над статьей в поиске этого Искусственного Интеллекта, то на это они и лохи? Так ведь?
GCU
17.05.2019 13:28Да, чтобы называться Искусственным Интеллектом безусловно нужно больше циклов, условий и хешей :)
Первая статья по-моему хорошо получилась, с картинками. Поздравления автору!
GCU
17.05.2019 13:19Возможно стоит писать ИИИ — ru.wikipedia.org/wiki/Игровой_искусственный_интеллект, так как из заголовка не понятно что он игровой
GCU
А если граф не связный? :)
MrKarton Автор
Не совсем понял
GCU
Как работает алгоритм, если между узлами А и Б пути не существует?
Ещё из описания непонятно — это поиск в ширину, или в глубину.
MrKarton Автор
В условиях нашего проекта узлы будут существовать всегда