9. Функции: Создание и использование
Функции... чем они хороши, для чего, почему мы используем их? Хорошо... мы
хотим, чтобы кто-нибудь еще написал много хороших функций для нас, чтобы
вызывать их, так что мы не должны создавать их сами. И мы хотим создать
несколько их самим себе, так что мы можем использовать свой код, отличный от
других. Разделяй и властвуй . Поделите ваш код в несколько функциий, и затем
завоевывайте каждую функцию.
Давайте посмотрим на самую маленькую функцию:
function myFunc takes nothing returns nothing
endfunction
Эта функция совсем ничего не делает и ничего не даёт. Тем не менее, она
содержит несколько частей, которые каждая функция должна иметь. Она начинается
со слова function и заканчивается словом endfunction. После слова function идёт
название функции, myFunc в данном случае. Следующим идёт слово takes и список
всех аргументов, которые функция принимает. Эта функция ничего не принимает,
{говоря иными словами, ей не нужно что-либо сообщать}. Она также ничего
не возвращает. Что все это дает нам? Это дает нам функцию с именем myFunc,
которое не берет никакие входные аргументы/параметры и не имеет обратную
значение.
Давайте теперь попытаемся сделать функцию, которая делает что-то, принимает
какие-либо аргументы и возвращает значение.
function add takes integer a, integer b returns
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 )
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 )
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 )
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
unit scoutUnit = null
real scoutX = 0
real scoutY = 0
real scoutHealth
endglobals
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 ClearHarvestAI()
call HarvestGold( 0, 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
if GetUnitCount('hfoo') < 15 then
call SetProduce(1, 'hfoo', -1)
endif
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 SetProduce(1,'hhou',-1)
endif
if barrack < 2 then
call SetProduce(1,'hbar',-1)
endif
endfunction
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
function init takes nothing returns nothing
endfunction
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
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
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
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 walkDir(scoutUnit, R, GetUnitFacing(scoutUnit) + GetRиomReal(90, 270))
else
set scoutX = x
set scoutY = y
call walk(scoutUnit, R)
endif
endfunction
function combatManager takes nothing returns nothing
if scoutUnit == null or not UnitAlive(scoutUnit) then
call allocateScout()
endif
if GetUnitCountDone('hfoo') > 4 и scoutUnit != null then
call scout()
call helpScout()
endif
endfunction
function main takes nothing returns nothing
call Sleep( 1.0 )
call DisplayTextToPlayer(GetLocalPlayer(), 0.0, 0.0, "Script started")
call init()
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()
Endfunction
|
Это работает только для целых чисел, конечно...
Другие способы создать
связь между Картой и сценарием AI включают в себя установку золота и
лесоматериалов для некоторого игрока или установку собственной величины
некоторому специфическому юниту. Это возможно также при использовании игрового
кеша… не уверен, что это доступно из сценариев AI. Вот, собственно говоря, и
всё.