WarCraft 3: Часть пятая. Функции: создание и использование

Создание простого (Melee) AI

9. Функции: Создание и использование

Функции... чем они хороши, для чего, почему мы используем их? Хорошо... мы хотим, чтобы кто-нибудь еще написал много хороших функций для нас, чтобы вызывать их, так что мы не должны создавать их сами. И мы хотим создать несколько их самим себе, так что мы можем использовать свой код, отличный от других. Разделяй и властвуй . Поделите ваш код в несколько функциий, и затем завоевывайте каждую функцию.
Давайте посмотрим на самую маленькую функцию:
function myFunc takes nothing returns nothing
endfunction
Эта функция совсем ничего не делает и ничего не даёт. Тем не менее, она содержит несколько частей, которые каждая функция должна иметь. Она начинается со слова function и заканчивается словом endfunction. После слова function идёт название функции, myFunc в данном случае. Следующим идёт слово takes и список всех аргументов, которые функция принимает. Эта функция ничего не принимает, {говоря иными словами, ей не нужно что-либо сообщать}. Она также ничего не возвращает. Что все это дает нам? Это дает нам функцию с именем myFunc, которое не берет никакие входные аргументы/параметры и не имеет обратную значение.
Давайте теперь попытаемся сделать функцию, которая делает что-то, принимает какие-либо аргументы и возвращает значение.
function add takes integer a, integer b returns // sum of a и b
  return a + b
endfunction
Сразу видно, что она делает, да? И не очень умно, мы могли бы просто использовать "+" в начале без функции. Давайте сделаем более полезную функцию, ту, которая убеждается, что все крестьяне убирают что-то.
function resourceManager takes goldPeasants returns nothing
  call ClearHarvestAI()   // Сначала перезапускаем менеджер сбора, __{то есть останавливаем сбор и начинаем новый}__ и
  call HarvestGold( 0, goldPeasants )   // затем сообщаем имеющимся работникам собирать золото.
  call HarvestWood( 0, GetUnitCountDone('hpea') - goldPeasants )   // и остальным собирать дерево.
Endfunctions
Эта функция берёт, как аргумент, как много крестьян, которым следует собирать золото (остальные собирают дерево). Она может быть вызвана из другой функции, похожей на это:
call resourceManager( 5 )
, которая сделается функцией, поместив туда 5 крестьян, работающих в шахте, а остальных в лесу. Используя эту функцию в предшествующих программах, мы могли бы заменить несколько строк кода из основной функции вызовом функции resourceManager. Программа из части второй - сбор урожая, может теперь быть написана похожей на это:
function resourceManager takes goldPeasants returns nothing
  call ClearHarvestAI()   // Сначала перезапускаем менеджер сбора, __{то есть останавливаем сбор и начинаем новый}__ и
  call HarvestGold( 0, goldPeasants )   // затем сообщаем имеющимся работникам собирать золото.
  call HarvestWood( 0, GetUnitCountDone('hpea') - goldPeasants )   // и остальным собирать дерево.
endfunctions

function main takes nothing returns nothing
    call Sleep( 1.0 )  // Ждать одну секунду
    call DisplayTextToPlayer( GetLocalPlayer(), 0.0, 0.0, "Script started" )

    loop   // начало вечного цикла
        call resourceManager( 4 )  // 4 крестьян в шахте, а остальные в лесу.
        call Sleep( 1.0 )  // Если мы никогда не спим, такой движок может убить нас.
    endloop

    call DisplayTextToPlayer( GetLocalPlayer(), 0.0, 0.0, "Script exiting" )
endfunction
Убедитесь, что полезная функция, та, которая быть названа, находится перед той, которая вызывает её. В противном случае WarCraft III думает вроде этого: “Что это за странная функция? Никогда не слышал об этом. Я лучше убью этот сценарий, он выглядит, как повреждённый.”
Другая полезная функция:
function print takes string message returns nothing
  call DisplayTimedTextToPlayer( GetLocalPlayer(), 0.0, 0.0, 3600, message )
endfunction
Хорошо, хорошо, скажете Вы... но эта функция не создаст для нас армию. Хорошо... скоро мы создадим несколько функций, которые помогут нам создать большую армию. Терпение, пожалуйста.
Сценарий для борьбы
Давайте сначала перезапишем код из части пятой - создание барака и подготовка нескольких солдат.
Чтобы увеличивать удобность для чтения и сделать управление кодом легче, сценарий разбит в другие разделы, которые оперируют ресурсами, подготовкой юнитов и строительством зданий.
function resourceManager takes nothing returns nothing 
  local integer goldPeasants = 5
  local integer peasantsDone = GetUnitCountDone('hpea')
  if peasantsDone < 6 then
    set goldPeasants = peasantsDone - 1
  endif

  call DisplayTextToPlayer(GetLocalPlayer(), 0.0, 0.0, "In manager")
  call ClearHarvestAI() // Сначала перезапускаем менеджер сбора, __{то есть останавливаем сбор и начинаем новый}__ и
  call HarvestGold( 0, goldPeasants ) // сообщаем
                           // рабочим группы goldPeasants собирать золото   
  call HarvestWood( 0, GetUnitCountDone('hpea') - goldPeasants )
                      // и остальным собирать дерево. 
endfunction 

function unitManager takes nothing returns nothing 
  if GetUnitCount('hpea') < 12 then
    call SetProduce(1, 'hpea', -1) // Тренировать одного крестьянина, где возможно
  endif
  call SetProduce(1, 'hfoo', -1) // Тренировать одного пехотинца, где возможно
endfunction 

function buildingManager takes nothing returns nothing 
  local integer produced = 12 + 6 * GetUnitCount('hhou') 
  local integer used = 1 * GetUnitCount('hpea') + 2 * GetUnitCount('hfoo')
  local integer foodSpace = produced - used 
  local integer barrack = GetUnitCount('hbar')

  if foodSpace < 6 then 
    call DisplayTextToPlayer(GetLocalPlayer(),0.0,0.0,"Building house") 
    call SetProduce(1,'hhou',-1) 
  endif

  if barrack < 1 then
    call SetProduce(1,'hbar',-1)     
  endif
endfunction 

function main takes nothing returns nothing 
  call Sleep( 1.0 )  // Sleep 1 second 
  call DisplayTextToPlayer(GetLocalPlayer(), 0.0, 0.0, "Script started") 

  loop   // начало вечного цикла
  call DisplayTextToPlayer(GetLocalPlayer(), 0.0, 0.0, "in loop") 
    call resourceManager() 
    call unitManager() 
    call buildingManager() 
    call Sleep( 1.0 ) //Если мы никогда не спим, такой движок может убить нас.      
  endloop 

  call DisplayTextToPlayer(GetLocalPlayer(), 0.0, 0.0, "Script exiting") 
endfunction
Этот код произведет отряд пехотинцев, который будет просто стоять и ничего не делать. Но об этом скоро позаботимся... Давайте начнём с создания AI, что произвольно бродит карте со своими пехотинцами. Надо надеяться, он найдет что-то, чтобы убить... Мы должны скоро также рассмотреть как встроенный в AI скрипт решает проблемы обманом...
globals  // variables that can be reached from all functions in the AI script.
  unit scoutUnit = null
  real scoutX = 0
  real scoutY = 0
  real scoutHealth
endglobals
//==================================================  =======
//  resourceManager
//
//  Сбор ресурсов путём подачи команд крестьянам
//==================================================  =======
function resourceManager takes nothing returns nothing 
  local integer goldPeasants = 5
  local integer peasantsDone = GetUnitCountDone('hpea')
  if peasantsDone < 6 then
    set goldPeasants = peasantsDone - 1
  endif

//  call DisplayTextToPlayer(GetLocalPlayer(), 0.0, 0.0, "In resourceManager")
  call ClearHarvestAI() // Сначала перезапускаем менеджер сбора, __{то есть останавливаем сбор и начинаем новый}__ и
  call HarvestGold( 0, goldPeasants ) // сообщаем
                           // рабочим группы goldPeasants собирать золото   
  call HarvestWood( 0, GetUnitCountDone('hpea') - goldPeasants )
                      // и остальным собирать дерево. 
endfunction 
//==================================================  =======
//  unitManager
//
//  Тренировка юнитов
//==================================================  =======
function unitManager takes nothing returns nothing 
  if GetUnitCount('hpea') < 12 then
    call SetProduce(1, 'hpea', -1) // Тренировать одного крестьянина, где возможно
  endif
  if GetUnitCount('hfoo') < 15 then
    call SetProduce(1, 'hfoo', -1) // Тренировать одного пехотинца, где возможно
  endif
endfunction 
//==================================================  =======
//  buildingManager
//
//  Строительство зданий
//==================================================  =======
function buildingManager takes nothing returns nothing 
  local integer produced = 12 + 6 * GetUnitCount('hhou') 
  local integer used = 1 * GetUnitCount('hpea') + 2 * GetUnitCount('hfoo')
  local integer foodSpace = produced - used 
  local integer barrack = GetUnitCount('hbar')

  if foodSpace < 6 then 
//    call DisplayTextToPlayer(GetLocalPlayer(),0.0,0.0,"Building house") 
    call SetProduce(1,'hhou',-1) 
  endif

  if barrack < 2 then
    call SetProduce(1,'hbar',-1)     
  endif
endfunction 
//==================================================  =======
//  allocateScout
//
//  Выбор какого-либо юнита разведчиком, чтобы он разведывал тропы
//==================================================  =======
function allocateScout takes nothing returns nothing
  local group grp = CreateGroup()
  call GroupEnumUnitsOfType(grp, "footman", null)
  set scoutUnit = FirstOfGroup(grp)
  call RemoveGuardPosition(scoutUnit)
  set scoutX = GetUnitX(scoutUnit)
  set scoutY = GetUnitY(scoutUnit)
  set scoutHealth = GetUnitState(scoutUnit, UNIT_STATE_LIFE)
endfunction
//==================================================  =======
//  init
//
//  Инициализация скрипта
//==================================================  =======
function init takes nothing returns nothing
endfunction
//==================================================  =======
//  walk
//
//  Приказывает юниту u двигаться в какое-то место.
//==================================================  =======
function walk takes unit u, real distance returns nothing
  local real dir = GetUnitFacing(u) * 3.14 / 180
  local real x = GetUnitX(u) + distance * Cos(dir)
  local real y = GetUnitY(u) + distance * Sin(dir)
  call IssuePointOrder( u, "move", x, y)
endfunction
//==================================================  =======
//  walk
//
//  Приказывает юниту u двигаться в каком-либо направлении.
//==================================================  =======
function walkDir takes unit u, real distance, real direction returns nothing
  local real dir = direction * 3.14 / 180
  local real x = GetUnitX(u) + distance * Cos(dir)
  local real y = GetUnitY(u) + distance * Sin(dir)
  call IssuePointOrder( u, "move", x, y)
endfunction
//==================================================  =======
//  helpScout
//
//  Посылает юнитов, которые будут следовать по дорогам разведчиков
//==================================================  =======
function helpScout takes nothing returns nothing
  local group grp = CreateGroup()
  local unit u
  call GroupEnumUnitsOfType(grp, "footman", null)
  set u = FirstOfGroup(grp)
  loop
    exitwhen u == null
    if u != scoutUnit then
      call IssuePointOrder( u, "attack", scoutX, scoutY)    
    endif
    call GroupRemoveUnit(grp, u)
    set u = FirstOfGroup(grp)
  endloop
  call DestroyGroup(grp)
endfunction
//==================================================  =======
//  scout
//
//  Контролирование скаута, которые бродит по карте.
//==================================================  =======
function scout takes nothing returns nothing
  local real R = 1024
  local real x = GetUnitX(scoutUnit)
  local real y = GetUnitY(scoutUnit)

  if scoutX == x и scoutY == y then
//    call DisplayTextToPlayer(GetLocalPlayer(),0.0,0.0,"== Bump ==")   
    call walkDir(scoutUnit, R, GetUnitFacing(scoutUnit) + GetRиomReal(90, 270))
  else
    set scoutX = x
    set scoutY = y
    call walk(scoutUnit, R)
  endif
endfunction
//==================================================  =======
//  combatManager
//
//  Контролирование армии, которая будет следовать за скаутом
//==================================================  =======
function combatManager takes nothing returns nothing
//  call DisplayTextToPlayer(GetLocalPlayer(), 0.0, 0.0, "In combatManager")
  if scoutUnit == null or not UnitAlive(scoutUnit) then
    call allocateScout()
  endif
  if GetUnitCountDone('hfoo') > 4 и scoutUnit != null then
    call scout()
    call helpScout()
  endif
endfunction
//==================================================  =======
//  main
//
//  Главная функция, запускающая AI
//==================================================  =======
function main takes nothing returns nothing 
  call Sleep( 1.0 )  // Sleep 1 second 
  call DisplayTextToPlayer(GetLocalPlayer(), 0.0, 0.0, "Script started") 
  call init()

  loop   // начало вечного цикла
//    call DisplayTextToPlayer(GetLocalPlayer(), 0.0, 0.0, "in loop") 
    call resourceManager() 
    call unitManager() 
    call buildingManager() 
    call combatManager()
    call Sleep( 5.0 ) //Если мы никогда не спим, такой движок может убить нас.      
  endloop 

  call DisplayTextToPlayer(GetLocalPlayer(), 0.0, 0.0, "Script exiting") 
endfunction
Попытайтесь создать несколько людей, борющихся друг с другом при помощи этого сценария…
Следующий код будет связан со сценарием AI, действующем на игрока 2.
local integer command = 42
local integer data = 6 * 9
call CommиAI(Player(1), commи, data)
Чтобы получать хранимую информацию из сценария AI, используйте следующее:
function ReadAICommи takes nothing returns nothing
  local integer commи
  local integer data
                                                                                            
  loop
    exitwhen commandsWaiting() > 0
    call Sleep(0.5)  // Если мы не спим, игровой движок может быть разрушен...
  endloop
                                                                                            
  set command = GetLastcommand()
  set data = GetLastData()
  call PopLastcommand()

  // do whatever with command и data. 
Endfunction
Это работает только для целых чисел, конечно...
Другие способы создать связь между Картой и сценарием AI включают в себя установку золота и лесоматериалов для некоторого игрока или установку собственной величины некоторому специфическому юниту. Это возможно также при использовании игрового кеша… не уверен, что это доступно из сценариев AI. Вот, собственно говоря, и всё.

Просмотров: 4 503

Комментарии пока отсутcтвуют