XGM Forum
Сайт - Статьи - Проекты - Ресурсы - Блоги

Форуме в режиме ТОЛЬКО ЧТЕНИЕ. Вы можете задать вопросы в Q/A на сайте, либо создать свой проект или ресурс.
Вернуться   XGM Forum > Warcraft> Академия: форум для вопросов> Желтая пресса: обучающие статьи
Ник
Пароль
Войти через VK в один клик
Сайт использует только имя.

 
Sargeras
Лидер "Двух Королевств"
offline
Опыт: 22,163
Активность:
Создание AI для любого количества героев
Вступление

Всё мы уже не раз прекрасно убеждались в ограниченных возможностях World Editor'a. И такой же ограниченностью выделяется AI Editor, то есть редактор искусственного интеллекта. Не спорю, что он прекрасно подходит для создания примитивного интеллекта компьютера, который будет всегда отправлять на вас по герою с 5 пехотинцами, но иногда возникают тяжёлые ситуации, когда нам нужно сделать более совершенный AI-скрипт. И тогда мы приходим к выводу, что стандартных средств World Editor'a, увы, недостаточно и что решение возникшей проблемы нужно искать в другом. В этой статье я коснусь лишь одного момента, касающегося AI-скрипта - это создание искусственного интеллекта, который смог бы выбирать не между тремя героями, а между большим количеством, и не обязательно, четырьмя. Данное руководство будет полезно для изучения начинающим AI-скриптерам. Должен признаться, что сам процесс редактирования AI-скрипта достаточно нуден, однако методы настолько примитивны, что с лихвой окупают это. Да и к тому же на современных рынках программного обеспечения полно текстовых редакторов, которые позволяют редактировать стандартные текстовые файлы (именно таковым и является AI-скрипт), применяя нестандартные методы. Но это уже дело вкуса. Ладно, вернёмся к статье.
Немного теории AI, касающейся героев

Прежде чем я подробнее расскажу, как изменять настройки героев, необходимо рассмотреть структуру функций, которые отвечают за героев. Для этого вы можете использовать любой AI-файл, не внося в него каких-либо изменений. Просто откройте AI-редактор, далее «Файл --> Экспорт кода» и сохраните его где-нибудь. Как только сделаете это, можете открывать в блокноте или другом текстовом редакторе и любоваться jass-скриптом.)
Изменение способностей героев

Jass-код этот разглядывать и изучать можно долго, конечно, но что это даст, если есть уже готовое руководтсво по изменению изучаемых навыков? В общем, вам, наверно, известно, что любой AI-скрипт, генерируемый редактором AI в World Editor’e, состоит из нескольких категорий. И, просмотрев открытый Вами файл, вы наверняка догадаетесь, что за героев отвечает одноимённая категория Heroes. Вот именно её-то мы и будем редактировать. Сначала предлагаю определиться сразу с героями, которых вы будете использовать в игре и писать для компьютерного игрока, управляющего ими, AI-скрипт. Прежде чем, что-то изменять, откройте редактор объектов в World Editor’е и также держите его открытым, так как вам понадобится информацию об id-кодах героев и их способностей, которые должны будут изучаться. Вернёмся к AI-файлу. Мы увидим, что категория Heroes состоит из нескольких подкатегорий. Нам придётся отредактировать все, только в соответствии с правилами редактирования jass-кодов.
Запомните: здесь синтаксические ошибки исключены, ибо игра у вас может просто не завестись, поэтому проверяйте каждый символ, прописанный в Jass-коде, потому что интерпретатора, как такового нет, а блокнот, как и любой другой текстовый таких возможностей тем более не предоставит, хотя, по-моему, на сайте были специальные для этих целей программы.
Итак, начнём редактирование. Функцию SetHero, а именно её содержание мы полностью стираем, так как там нет ничего полезного для нас, ибо мы будем писать свой собственный код. Пишем следующее:
Код:
if (order ==1) then
set hero_id = heroid

Имейте в виду, таких скриптов, где рассматривается значение переменной order у нас будет столько, сколько героев использует компьютерный игрок, и каждое следующее условие для героев будет повторяться также столько, сколько у нас героев:
Код:
if (heroid = ‘{id-код вашего первого героя}’) then

Id-коды должны точно соответствовать тем, что показываются в редакторе объектов. Но есть одно но: иногда мы создаём новых героев на основе каких-то других, а когда начинаем просматривать их id-код (Ctrl+D), то можем увидеть что-то вроде этого: “A00A: Hamg”. Вот в этом случае можно воспользоваться программой WC3ObjectMergeAPI от Netrat’а, которая способна заменить id-коды на свои собственные, а можно и не делать этого, написав только “A00A”, правда я советую первый способ. После того, как напишите это условие, можно приступать к написанию способностей, а точнее последовательности, согласно которой герой будет их изучать. Делается это следующим образом:
Код:
set skillsx[ 1] = '{id-код способности, которую будет изучать герой, находясь на первом уровне}'
set skillsx[ 2] = '{id-код способности, которую будет изучать герой, находясь на втором уровне}'
set skillsx[ 3] = '{id-код способности, которую будет изучать герой, находясь на третьем уровне}'
...

Хочу дать одно замечание. Вместо “x” в “skillsx” напишите значение переменной order, которое было объявлено в самом первом условии. Также хочу заметить, что количество уровней не играет какого-либо значения. Вы можете с лёгкостью продолжить присваивать элементам массива skillsx id-коды способностей, продвигаясь аж до 100 уровня. Предел неизвестен, однако если в вашей карте используется уровень героев больше 10, не забудьте отразить это в игровых константах. Бывают случаи, что герою вообще не нужно изучать какой-либо способности. Тогда пишем следующий код:
Код:
set skillsx [{уровень героя, на котором он не будет что-либо изучать}] = 0

Что же тогда будет делать герой? Просто когда он достигнет соответствующего уровня, он ничего не станет изучать, а в запасе будет 1 скилл-поинт.
Кстати, если максимальное количество способностей меньше, чем максимальный уровень героя, то вы можете не отражать это в коде, хотя лично я советую отразить тем же способом – вдруг когда-нибудь станете редактировать этот файл и измените планы относительно изучения способностей…
Кроме того, если вдруг окажется, что способность у героя вообще отсутствует, а ему «дан приказ» изучать её, то герой также получит дополнительный скилл-поинт, а игра будет продолжаться, не выдавая каких-либо ошибок.
Вернёмся к коду. После того, как закончите писать способности для первого героя, переходим к способностям второго героя, если таковой имеется. Делается это следующим способом:
Код:
elseif (heroid == '{id-код второго героя}') then
set skillsx[ 1] = '{id-код способности, которую будет изучать второй герой, находясь на первом уровне}'
 set skillsx[ 2] = '{ id-код способности, которую будет изучать второй герой, находясь на втором уровне }'
...

Синтаксис в принципе один и тот же. Однако здесь также есть одно но: skillsx, в котором “x” также будет равняться значению переменной order. Пока вы наконец-то не дойдёте до другого рассмотрения значения этой переменной, ни в коем случае не изменяйте этот “x”, а то у вас получится путаница. Используя этот синтаксис, вы должны рассмотреть всех своих героев, и указать порядок изучения способностей для каждого. Второе условие if, когда мы начинаем рассматривать чему равно heroid, следует закончить словом “endif”. Только после этого начинаем рассматривать значение order, равное 2. Делается это примерно таким же способом, только вместо if пишем elseif:
Код:
elseif (order == 2) then
        set hero_id2 = heroid
        if (heroid == ...

Обратите особое внимание на вторую строчку. Hero_id изменяется на hero_id2. Если оставить старую вторую строчку неизменной, то опять же получится путаница. После этих трёх строчек вам предстоит сделать точно такую же операцию с героями. Если вам лень придумывать какой-то другой порядок изучения способностей, то просто скопируйте всё из первого главного условия – зачем писать одно и тоже? Но обязательно напишите их, а то ваши герои просто не будут изучать способности из-за отсутствия скрипта. Почему – разберёмся позже. Вот именно таким образом мы прописываем все значения order, постепенно доходя до максимального... А теперь приведу пример скрипта, который представляется изучением 8 способностей для стандартного Архимага и Паладина:
Код:
function SetHero takes integer order, integer heroid returns nothing
if (order == 1) then
        set hero_id = heroid
        if (heroid == 'Hpal') then
set skills1[ 1] = 'AHhb'
set skills1[ 2] = 'AHds'
set skills1[ 3] = 'AHad'
set skills1[ 4] = 'AHhb'
set skills1[ 5] = 'AHds'
set skills1[ 6] = 'AHre'
set skills1[ 7] = 'AHad'
set skills1[ 8] = 'AHhb'
        elseif (heroid == 'Hamg') then
set skills1[ 1] = 'AHbz'
set skills1[ 2] = 'AHab'
set skills1[ 3] = 'AHwe'
set skills1[ 4] = 'AHbz'
set skills1[ 5] = 'AHab'
set skills1[ 6] = 'AHmt'
set skills1[ 7] = 'AHwe'
set skills1[ 8] = 'AHbz'
       endif
elseif (order == 2) then
        set hero_id2 = heroid
        if (heroid == 'Hpal') then
set skills2[ 1] = 'AHhb'
set skills2[ 2] = 'AHds'
set skills2[ 3] = 'AHad'
set skills2[ 4] = 'AHhb'
set skills2[ 5] = 'AHds'
set skills2[ 6] = 'AHre'
set skills2[ 7] = 'AHad'
set skills2[ 8] = 'AHhb'
        elseif (heroid == 'Hamg') then
set skills2[ 1] = 'AHbz'
set skills2[ 2] = 'AHab'
set skills2[ 3] = 'AHwe'
set skills2[ 4] = 'AHbz'
set skills2[ 5] = 'AHab'
set skills2[ 6] = 'AHmt'
set skills2[ 7] = 'AHwe'
set skills2[ 8] = 'AHbz'
endif
endif
endfunction

Код этот нестандартный. Во-первых, потому что рассматриваются способности для двух героев. Во-вторых, потому что герои будут изучать способности только 8 раз. В-третьих, потому что последовательности изучения одинаковые. Если вы внимательно читали статью, то поймёте, что и как здесь, и почему я так утверждаю. Пожалуй, с функцией SetHero закончили. Идём дальше.
Функция SelectHeroes. Ясное дело – из названия понятно, что выбирает героев. И, думаю, jass’еры сразу поймут, как она это делает – методом нахождения случайного значения целочисленной переменной и рассмотрения числовых промежутков, на которых находится полученное значение. Для начала определите вероятности «выпадения» героев в процентном соотношении. Например, возьмём того же паладина и того же архимага. Мне надо, чтобы из 50 раз, допустим Архимаг выпал 37 раз, а паладин – 20 раз. Как это реализовать? Да просто не нужно смотреть на число 50, а находить случайное значение в промежутке от самого малого до суммы выпадений. В нашем случае это будет выглядеть вот так:
Код:
function SelectHeroes takes nothing returns nothing
    local integer roll = GetRandomInt(1,57)
    if (roll <= 37) then // если roll меньше или равно 37
        call SetHero(1, 'Hamg')
        call SetHero(2, 'Hpal')
elseif (roll > 37) then // если roll больше 37 но меньше 57
        call SetHero(1, 'Hpal)
        call SetHero(2, 'Hamg')
endif
endfunction

В принципе, если у вас нестандартный скрипт, и вы не собираетесь выбирать максимальное значение героев при любом значении случайно выпавшего числа, то здесь иногда бывает сложно узнать, все ли вы комбинации рассмотрели. Здесь эффективна следующая формула:
Код:
A = n! / (n-m)!
,
где n! = 1*2*3*…*n, m! = 1*2*3*…*m
Здесь n – максимальное количество ваших героев, а m – число взятых героев. Ну а A – это максимальное количество возможных комбинаций. Если же вы собираетесь использовать всех героев, то здесь используется формула:
Код:
P = n!

Здесь P будет являться максимально возможным количеством комбинаций. Осталось только разобраться с остальными строчками, которые идут после рассмотрения промежутка значения roll:
Код:
call SetHero ({значение переменной order}, {герой, который будет создан order’овым по счёту})

Для не-jass’еров объясняю: запускается функция, которую мы писали до этого, то есть функция, которая определяет, в какой последовательности герои будут изучать свои навыки. Первый аргумент позволяет войти в одно из условий значения order, а второй аргумент указывает героя, способности которого будут рассматриваться. Здесь можно поэкспериментировать, но это выходит за рамки данного руководства.
Думаю, с этой функцией мы тоже разобрались. Приступим же к последней - ChooseHeroSkill. В ней особого редактирования не понадобится. Сотрите всё содержание функции и начинайте писать новое:
Код:
function ChooseHeroSkill takes nothing returns integer
    local integer curHero = GetHeroId()
    local integer level = GetHeroLevelAI()

    if (level > max_hero_level) then
        set max_hero_level = level
    endif

    if (curHero == hero_id) then
        return skills1[level]
    elseif (curHero == hero_id2) then
        return skills2[level]
...
    endif
    return 0
endfunction

Вы поняли, чем следует закрыть многоточие? Вы просто продолжаете прописывать функцию, исходя из следующего синтаксиса:
Код:
elseif (curHero == hero_idx) then
        return skillsx[level]

Здесь “x” – целое число. Вы продолжаете увеличивать “x” на один до тех пор, пока не дойдёте до значения, равного максимальному количеству героев. Вот на этом-то наше редактирование закончено.
И напоследок я приведу пример полного редактирования этих трёх функций, которое выбирает из четырёх героев людей 3, если максимальный уровень героя - 12:
Код:
function SetHero takes integer order, integer heroid returns nothing
if (order == 1) then
set hero_id = heroid
if (heroid == 'Hpal') then
set skills1[ 1] = 'AHhb'
set skills1[ 2] = 'AHds'
set skills1[ 3] = 'AHad'
set skills1[ 4] = 'AHhb'
set skills1[ 5] = 'AHds'
set skills1[ 6] = 'AHre'
set skills1[ 7] = 'AHad'
set skills1[ 8] = 'AHhb'
set skills1[ 9] = 'AHds'
set skills1[10] = 'AHad'
set skills1[11] = 0
set skills1[12] = 0
elseif (heroid == 'Hamg') then
set skills1[ 1] = 'AHbz'
set skills1[ 2] = 'AHab'
set skills1[ 3] = 'AHwe'
set skills1[ 4] = 'AHbz'
set skills1[ 5] = 'AHab'
set skills1[ 6] = 'AHmt'
set skills1[ 7] = 'AHwe'
set skills1[ 8] = 'AHbz'
set skills1[ 9] = 'AHab'
set skills1[10] = 'AHwe'
set skills1[11] = 0
set skills1[12] = 0
elseif (heroid == 'Hmkg') then
set skills1[ 1] = 'AHtc'
set skills1[ 2] = 'AHtb'
set skills1[ 3] = 'AHbh'
set skills1[ 4] = 'AHtc'
set skills1[ 5] = 'AHtb'
set skills1[ 6] = 'AHav'
set skills1[ 7] = 'AHbh'
set skills1[ 8] = 'AHtc'
set skills1[ 9] = 'AHtb'
set skills1[10] = 'AHbh'
set skills1[11] = 0
set skills1[12] = 0
elseif (heroid == 'Hblm') then
set skills1[ 1] = 'AHfs'
set skills1[ 2] = 'AHdr'
set skills1[ 3] = 'AHbn'
set skills1[ 4] = 'AHfs'
set skills1[ 5] = 'AHdr'
set skills1[ 6] = 'AHpx'
set skills1[ 7] = 'AHfs'
set skills1[ 8] = 'AHbn'
set skills1[ 9] = 'AHdr'
set skills1[10] = 'AHbn'
set skills1[11] = 0
set skills1[12] = 0
endif
elseif (order == 2) then
set hero_id2 = heroid
if (heroid == 'Hpal') then
set skills2[ 1] = 'AHhb'
set skills2[ 2] = 'AHds'
set skills2[ 3] = 'AHad'
set skills2[ 4] = 'AHhb'
set skills2[ 5] = 'AHds'
set skills2[ 6] = 'AHre'
set skills2[ 7] = 'AHad'
set skills2[ 8] = 'AHhb'
set skills2[ 9] = 'AHds'
set skills2[10] = 'AHad'
elseif (heroid == 'Hamg') then
set skills2[ 1] = 'AHbz'
set skills2[ 2] = 'AHab'
set skills2[ 3] = 'AHwe'
set skills2[ 4] = 'AHbz'
set skills2[ 5] = 'AHab'
set skills2[ 6] = 'AHmt'
set skills2[ 7] = 'AHwe'
set skills2[ 8] = 'AHbz'
set skills2[ 9] = 'AHab'
set skills2[10] = 'AHwe'
elseif (heroid == 'Hmkg') then
set skills2[ 1] = 'AHtc'
set skills2[ 2] = 'AHtb'
set skills2[ 3] = 'AHbh'
set skills2[ 4] = 'AHtc'
set skills2[ 5] = 'AHtb'
set skills2[ 6] = 'AHav'
set skills2[ 7] = 'AHbh'
set skills2[ 8] = 'AHtc'
set skills2[ 9] = 'AHtb'
set skills2[10] = 'AHbh'
elseif (heroid == 'Hblm') then
set skills2[ 1] = 'AHfs'
set skills2[ 2] = 'AHdr'
set skills2[ 3] = 'AHbn'
set skills2[ 4] = 'AHfs'
set skills2[ 5] = 'AHdr'
set skills2[ 6] = 'AHpx'
set skills2[ 7] = 'AHfs'
set skills2[ 8] = 'AHbn'
set skills2[ 9] = 'AHdr'
set skills2[10] = 'AHbn'
set skills2[11] = 0
set skills2[12] = 0
endif
elseif (order == 3) then
set hero_id3 = heroid
if (heroid == 'Hpal') then
set skills3[ 1] = 'AHhb'
set skills3[ 2] = 'AHds'
set skills3[ 3] = 'AHad'
set skills3[ 4] = 'AHhb'
set skills3[ 5] = 'AHds'
set skills3[ 6] = 'AHre'
set skills3[ 7] = 'AHad'
set skills3[ 8] = 'AHhb'
set skills3[ 9] = 'AHds'
set skills3[10] = 'AHad'
elseif (heroid == 'Hamg') then
set skills3[ 1] = 'AHbz'
set skills3[ 2] = 'AHab'
set skills3[ 3] = 'AHwe'
set skills3[ 4] = 'AHbz'
set skills3[ 5] = 'AHab'
set skills3[ 6] = 'AHmt'
set skills3[ 7] = 'AHwe'
set skills3[ 8] = 'AHbz'
set skills3[ 9] = 'AHab'
set skills3[10] = 'AHwe'
elseif (heroid == 'Hmkg') then
set skills3[ 1] = 'AHtc'
set skills3[ 2] = 'AHtb'
set skills3[ 3] = 'AHbh'
set skills3[ 4] = 'AHtc'
set skills3[ 5] = 'AHtb'
set skills3[ 6] = 'AHav'
set skills3[ 7] = 'AHbh'
set skills3[ 8] = 'AHtc'
set skills3[ 9] = 'AHtb'
set skills3[10] = 'AHbh'
elseif (heroid == 'Hblm') then
set skills3[ 1] = 'AHfs'
set skills3[ 2] = 'AHdr'
set skills3[ 3] = 'AHbn'
set skills3[ 4] = 'AHfs'
set skills3[ 5] = 'AHdr'
set skills3[ 6] = 'AHpx'
set skills3[ 7] = 'AHfs'
set skills3[ 8] = 'AHbn'
set skills3[ 9] = 'AHdr'
set skills3[10] = 'AHbn'
set skills3[11] = 0
set skills3[12] = 0
endif
endif
endfunction

//===========================================================================
// Selects hero IDs for three possible heroes
//===========================================================================
function SelectHeroes takes nothing returns nothing
    local integer roll = GetRandomInt(1,100)
    if (roll <= 33) then
        call SetHero( 1, 'Hpal' )
        call SetHero( 2, 'Hamg' )
        call SetHero( 3, 'Hmkg' )
    elseif ((roll > 33) and (roll <= 66)) then
        call SetHero( 1, 'Hpal' )
        call SetHero( 2, 'Hamg' )
        call SetHero( 3, 'Hblm' )
    elseif (roll >66) then
        call SetHero( 1, 'Hblm' )
        call SetHero( 2, 'Hamg' )
        call SetHero( 3, 'Hmkg' )
endif
endfunction

//===========================================================================
// Returns the hero skill for the given hero and level
//===========================================================================
function ChooseHeroSkill takes nothing returns integer
    local integer curHero = GetHeroId()
    local integer level = GetHeroLevelAI()

    if (level > max_hero_level) then
        set max_hero_level = level
    endif

    if (curHero == hero_id) then
        return skills1[level]
    elseif (curHero == hero_id2) then
        return skills2[level]
    elseif (curHero == hero_id3) then
        return skills3[level]
    endif
    return 0
endfunction

У вас могут появиться некоторые вопросы по этому примеру. Вот FAQ:
Вопрос: почему рассмотрено только 3 случая значения переменной order, если всего описано 4 героя?
Ответ: это своеобразное исключение из правил, которое происходит только в том случае, когда количество выбираемых героев меньше, чем количество максимальных. В нашем случае мы выбирали 3 героя. По сути, order будет иметь максимальное значение, равное количеству выбираемых героев. А по 4 героя для каждого случая я прописал, чтобы в будущем можно было без проблем изменить код.
Вопрос: исходя из второй функции я делаю вывод, что когда order равно 3, то третьим героем никогда не сможет стать архимаг или паладин. Можно ли убрать информацию о них в первой функции, когда рассматривается order, равный 3?
Ответ: если не собираетесь изменять скрипт в будущем, то, конечно же, можно. Тем самым вы уменьшите размер файла и произведёте что-то вроде оптимизации скрипта.
Старый 22.06.2007, 09:01
PlayerDark
Coraline
offline
Опыт: 10,569
Активность:
Ух ты ! круто !

PlayerDark добавил:
А пример ?
Старый 22.06.2007, 09:36
Sargeras
Лидер "Двух Королевств"
offline
Опыт: 22,163
Активность:
PlayerDark, он есть в самом конце статьи. И к нему, если вы читали, ещё и FAQ прилагается.
Старый 22.06.2007, 09:38
PlayerDark
Coraline
offline
Опыт: 10,569
Активность:
Sargeras аффтар пиши исчо, мне понравилось ! пишу АИ для своей арены.
Старый 22.06.2007, 09:39
Sargeras
Лидер "Двух Королевств"
offline
Опыт: 22,163
Активность:
PlayerDark, написать-то могу, главное, чтобы всем нравилось и помогало. Если хотите хоть чем-то помчь - предложите другие темы для статей.
Старый 22.06.2007, 09:48
Devi

offline
Опыт: 10
Активность:
Я зделал всё как описано но как применить это в карте не пойму как включить этот ИИ?
Импортировал в карту сделал тригер типа запустить этот АI для игрока2 (тоесть компьютерный протвиник).После компьютер в игре только собирает ресурсы и то только золото.Проверял несколько раз всё было написано правильно в блокноте.Пытался просто сделать чтобы комп учил скиллы которые я ему поставил.Не пойму в чём ошибка :(: ...

Отредактировано Devi, 01.02.2009 в 18:36.
Старый 28.12.2008, 20:32

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы можете скачивать файлы

BB-коды Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход



Часовой пояс GMT +3, время: 17:21.