UnitName 1 doWatch UnitName 2



 

Эта команда заставляет юнит Unit1 следить за юнитом Unit2. То есть Unit1 всегда будет стараться смотреть на юнита Unit2. В предпоследней строчке вместо второго юнита стоит ключевое слово ObjNull . ObjNull – обозначает отсутствие объекта, то есть в нашей команде(смотри предпоследнюю строчку скрипта) использование ObjNull заставит юнита _unit следить не за юнитом игрока, а за “никем” (то есть вообще не за кем не следить ).

Итак, мы подошли к очень интересной команде, а именно playmove. Эта команда заставляет юнит (человека, а не технику) проигрывать выбранную анимацию. Команда имеет такой синтаксис:

 

UnitName playmove ”{название анимации}”

 

Команда Playmove с плавным переходом из предыдущего положения начинает проигрывать указанную анимацию. Вот несколько примеров:

 

_unit playmove "effectstandsalute"

_unit2 playmove "CombatToCrouch"

_unit3 playmove "Stand"

_unit4 playmove "EffectStandSitDown"

 

 

Однако существует одна проблема. Не все анимации работают с этой командой. В игре есть также другая команда для работы с анимацией. Это switchmove . Синтаксис у этой команды такой же, как и у предыдущей. Эта команда проигрывает анимацию сразу же (без плавного перехода). Некоторые анимации работают только с Playmove, другие только с switchmove, а также есть анимации работающие с обеими командами. Пример команды switchmove:

 

_unit1 switchMove "FXStandDip"

_unit2 switchmove "EffectStandSitDown"

_unit3 switchmove "CommandEngageAtWill"

 

Вообще эти команды довольно капризные. Иногда для проигрывания анимации, например, требуется установить юниту тип поведения (setbehaviour) “SAFE”. Для демонстрации различий между Playmove и Switchmove попробуйте обе эти команды (на разных юнитах) с анимацией EffectStandSitDown". При использовании switchMove юнит мгновенно окажется в положении сидя. При использовании playMove юнит повесит оружие за спину и плавно сядет на землю. Как определить с какой командой работает та или иная анимация? Да просто попробовать!

 

Итак что бы проверить скрипт ставим на карте два юнита: одного – игрока(можно без имени) а второго – солдата с именем Sold1. Игрок должен стоять более чем в 5 метрах от второго юнита иначе будет не интересно. Теперь в поле Initialization одного из юнитов пишем: [Sold1] exec “Salut.sqs”. Запускаем и подходим игроком ко второму юниту. Этот юнит должен повернуться к игроку(или не совсем к игроку – багги движка) и отдать честь! Этот скрипт пустяк, но как приятно когда играешь в миссию проходишь мимо солдата на базе, а он отдает тебе честь! Вот из-за таких, (и не только) вроде бы пустяшных скриптов, ваша миссия приобретает красоту и оригинальность.

 

    Если Вы играли в официальную кампанию (и не только) то Вы, наверное, замечали, что в некоторых миссиях Вы начинаете в одном месте, а потом (как правило, после скриптовой сцены) мгновенно появляются в другом. Это очень полезный прием. Например, в миссии главная задача - уничтожить базу противника. Зачем заставлять игрока ехать(лететь, ползти) с одного конца острова на другой, если можно его мгновенно переместить в нужную точку (конечно перемещение должно происходить как было замечено ранее в момент скриптового ролика). Именно для этих целей используются две команды: setpos и getpos . Эти команды работают с координатами. В ОФП координаты – массив такого типа [x,y,z]. Где х – координата по оси x, y – координата по оси y и z – координата по оси z.

 

 

Ось Y всегда направлена на север, а X на восток. Вы конечно видели карту в ОФП: она поделена на квадраты горизантальными и вертикальными линиями. Горизантальные – ось X, а вертикальные – ось Y. Высоту конечно на двухмерной карте показать сложно, но я думаю Вы сами догадаетесь где эта ось Z(высота).

    Для получения координат объекта используют команду getpos.

 

Getpos ObjectName

Эта команда возвращает вышеупомянутый массив координат. С этим массивом работают как и с любым другим(см. пример). Команда setpos используется для мгновенного перемещения объекта:

 

ObjectName setpos [ x , y , z ]

 

В обойх премерах ObjectName – любой объект в игре. Примеры использования этих команд:

 

_ posUnit = getpos _ unit 1 – получение координат объекта _ Unit и их сохранение в локальную переменную _posUnit.

posUnitx = _ posUnit select 0 – получение координаты X из массива координат _ posUnit и сохранение ее значения в глобальную переменную posUnitx .

posUnity = _posUnit select 1 – получение координаты Y

posUnitz = _ posUnit select 2 - получение координаты Я

Получить координаты можно и таким путем:

posUnitx = getpos _ unit 1 select 0 - получение координаты X объекта _ unit 1 и сохранение ее значения в глобальную переменную posUnitx .

Получение координат Y и Z :

posUnity = getpos _unit1 select 1

posUnitz = getpos _unit1 select 2

_ Unit 2 setpos [1234,1234,1234] – перемещения объекта _ Unit 2 в координаты [1234,1234,1234].

_ Unit 2 setpos getpos _ unit 1 - перемещения объекта _ Unit 2 в координаты объекта _ unit 1

_unit2 setpos [(getpos _unit1 select 1),( getpos _unit1 select 2), (getpos _unit1 select 1) + 10] - перемещения объекта _Unit2 в координаты объекта _unit1 и на 10 метров выше чем _unit1.

 

Если в массиве координат не указать высоту, то объект по умолчанию будет перемещен на нулевую высоту (будет стоять на земле).

Вот небольшой скрипт показывающий работу команд setpos и setpos.

 

“ Privazka . sqs ”


;Получение аргументов: _Privazka – объект который привязывается к объекту _Vedushii. ;_movex и _movey смещения координат объекта _Privazka по-отношению к координатам ;объекта _Vedushii.

_Privazka = _this select 0

_movex = _this select 1

_movey = _this select 2

_movez = _this select 3

_Vedushii = _this select 4

#loop

;Установка объекта _Privazka в координаты объекта _Vedushii с учетом смещения.

_Privazka setpos [(getpos _Vedushii select 0) + _movex, (getpos _Vedushii  select 1) + _movey, (getpos _Vedushii  select 2) + _movez]

;проверка здоровья объекта _Privazka. Если объект разрушен скрипт прекращает свое ;выполнение.

?(getdammage _Privazka == 1): exit

; необходимая – малая (что бы ведомый объект перемещался плавно за ведущим) пауза. ;Попробуйте изменить на 1 и увидите о чем я.

~0.003

goto "loop"

 

 


Этот скрипт привязывает один объект к другому. То есть если ведущий объект двигается то вместе с ним на определенном расстоянии двигается и ведомый объект. Для проверки скрипта создайте на карте два солдата одного игрока а другого с именем Sold1. Запустите скрипт (например из Initialization поля) так: [Sold1,10,10,1,player] exec “Privazka.sqs”. Теперь запустите миссию. Солдат двигается точно так же как и Вы только в 10 метрах спереди и в 10 метрах справа и на высоте в 1 метр!

 

Вот еще один скрипт также показывающий работу setpos. Этот скрипт позволяет делать выход юнитов из домов в которые заходить нельзя(например, казармы на базах).

 

“ Exitfromhome . sqs ”


;Получение аргументов: _Exitpoint – невидимый объект, точка выхода из дома ;  _group – ;группа которая будет выходить из дома.

_Exitpoint = _this select 0

_Group = _this select 1

; получение массива всех юнитов из группы _group и сохранение этого массива в переменную _units

_Units = units _Group

;получение количества юнитов в массиве _Units и сохранение значения в ;переменную _num

_num = count _Units

_i = 0

 

~10

#loop

; сохранение первого юнита (ссылки на первый юнит) в массиве в переменную _unit

_unit = _Units select _i

; перемещение юнита _unit в точку выхода из дома

_unit setpos (getpos _Exitpoint)

; увеличение значения переменной _i на единицу

_i = _i + 1

;проверка равенства значения переменной _i числу юнитов в массиве(переменная _num)

?(_i == _num ): goto "exit"

~1.5

goto "loop"

 

#exit

exit

 


Рассмотрим этот скрипт. Принцип действия прост. В качестве аргумента передается группа (название группы, а не массив юнитов) которая будет выходить из дома. Эта группа должна быть где-то, где игрок не сможет ее увидеть, например, на острове в океане.  Также в качестве аргумента передается невидимый объект (H(Invisible) или Game Logic) – точка выхода из дома. Этот объект ставится как можно ближе к нарисованному на казарме выходу. После получается (с помощью команды units) массив всех юнитов заданной группы. И затем каждый юнит из массива перемещается в точку выхода.

Новая команда:

 

Units GroupName

 

Эта команда возвращает массив всех юнитов группы. Теперь я расскажу об одном полезном и часто используемом приеме работы с массивом. В этом скрипте есть переменная _i равная 0. Зачем? Это своеобразный счетчик. В цикле присутствует строчка, которая увеличивает значение переменной _i на единицу. То есть после каждого выполнения действий в цикле значение этой переменной увеличивается на единицу. А так как изначально значение _i равно 0 то оно и будет показывать, сколько раз выполнились действия в цикле. Посмотрим на первую строчку в цикле. В этой строчке из массива _Units выбирается элемент, чей номер равен значению счетчика. То есть каждый раз при выполнении цикла будет выбираться  тот элемент, который идет за элементом, выбранным при предыдущем выполнении цикла. Но так как количество элементов в массиве ограничено, а при выборе несуществующего элемента (например, в массиве 10 элементов, а компьютер пытается выбрать 11) происходит ошибка, то нам следует ограничить выполнение цикла. Цикл должен выполниться столько раз, сколько и элементов в массиве. Для этого в цикле и установлено условие. Значение переменной _num – количество юнитов в массиве (получено с помощью команды count: _num = count _Units ). В условие проверяется равенство значения переменной _i (номер выбираемого из массива элемента или количество “проходов” цикла) значению переменной _num (количество элементов в массиве) и если переменные равны (то есть значение переменной _i – номер выбираемого элемента – равно числу элементов в массиве, то есть элемент номер _i - последний), то выполнение скрипта прекращается. Этот прием очень часто применяется, когда для всех элементов массива нужно выполнить какие-то одинаковые действия. В нашем случае это перемещение в точку выхода из дома.

    Для того чтобы посмотреть работу скрипта нужно найти какую-нибудь базу на карте, поставить в месте предполагаемого выхода Game Logic с именем Gl1. Поместить группу юнитов куда-нибудь подальше. В Initialization поле лидера группы прописать gr 1 = group this . Теперь создайте триггер с активацией по каналу радио Альфа и с запуском скрипта в поле OnActivation: [ gr 1, Gl 1] exec “ Exitfromhome . sqs ”.

Теперь запускаем миссию и нажимаем 0-0-1, вызывая радио. Да, не забудьте поставить самого игрока перед домом откуда выходит группа (игрок не в той группе которая выходит). Смотрим!

 

 

Вышеописанные команды перемещают объекты мгновенно из одной точки в другую, а как же быть, если нужно плавно за определенное время переместить объект из одной точки в другую? Зачем? Ну, мне лично однажды нужно было сделать движущиеся мишени, а применений собственно можно придумать множество (была бы фантазия, а в этом деле без нее никуда): самонаводящаяся ракета, красиво (а главное реалистично) взлетевшая после взрыва машина и т.д.… Так вот когда передо мною возникла эта проблема я, как и практически каждый окончивший среднюю школу человек начал размышлять над тригонометрическими выражениями: зная угол (определяется командой getdir: getdir ObjectName  - возвращает угол поворота в градусах) и гипотенузу – путь который должен пройти объект, в прямоугольном треугольнике нужно найти катеты – в игре смещения по оси X и Y.

 

 


Стрелка (дистанция) – путь, который должен пройти объект (гипотенуза), φ – известный (с помощью getdir) угол. Итак, формулы:

 

Смещение по оси X = Дистанция * Cos φ

Смещение по оси Y = Дистанция * Sin φ

 

Найдя смещения, разделим их не определенное количество маленьких частей-кусочков (чтобы движение было плавным), это количество зависит от дистанции и нужного времени перемещения. Получив длину одного кусочка для каждой из осей, будем в цикле прибавлять эти кусочки к текущим координатам (X и Y) объекта и в результате получится плавное движение. Такой прием (нахождение смещений с помощью дистанции и угла)  очень часто применяется в скриптах для нахождения смещений по осям, например, когда нужно найти координаты точки, находящейся в метре от юнита, но строго впереди него (если взять точку с координатами просто больше на один метр по оси Y относительно юнита, то не учитывается направление взгляда; то есть юнит, например, смотрит на юг, а точка всегда будет на севере). НО, во-первых, этот прием довольно громоздкий и сложный, а, во-вторых, ну …. многие просто не любят тригонометрию! Сейчас я предложу довольно интересный способ решения этой (плавное перемещение объекта) задачи, хотя и выше описанный способ иногда имеет место быть. Скажу также, что подобного я не в одних скриптах не встречал.

 

Небольшое вступление. Итак, Вы, наверное, знаете, что в ОФП можно создавать скриптовые сцены – что-то типа фильмов или роликов на движке игры. Помните, в кампании перед некоторыми миссиями или во время миссий у игрока отбиралась возможность управлять игрой, и начинался показ такого ролика. Создание таких роликов основано на управление (создание, перемещение, уничтожение и т.д. ) камерами. Если Вы еще не умеете делать скриптовые ролики, то уверен, что научитесь, так как это очень легко. Я не буду Вам объяснять, как именно создавать ролики, а всего лишь покажу один нестандартный способ использования камеры, но если Вы все же хотите научиться создавать ролики, то поищите на просторах Интернета руководства и учебники, уверяю Вас - они там есть. Итак, камеры. Для того чтобы создать камеру нужно написать в скрипте (или редакторе) подобную строчку:

 

CameraName = “camera” camcreate [x,y,z]

 

Где CameraName – имя переменной (глобальная или локальная) в которой будет храниться ссылка на камеру для дальнейшего управления. [x,y,z] – как Вы поняли координаты, в которых создается камера. Вместо массива координат можно, конечно же, написать что-то типа getpos SomeObject (получение координат объекта). Затем камере необходимо установит какой-либо эффект. Это делается с помощью команды cameraeffect . А именно:

 

CameraName cameraeffect [{“Эффект”},{“Позиция”}]

 

Значения различных эффектов (например “ZOOMIN” – в кавычках) и позиций Вы сможете узнать в специальных руководствах. В нашем же скрипте нам понадобится только эффект "terminate" (отключить эффекты) и позиция "back" (сзади). При установлении таких эффектов камера будет существовать, как некий объект в игре, но вид не будет переключен на эту камеру (то есть на экране останется вид “из глаз” и игрок может управлять своим юнитом). Камера создана, установлен эффект что дальше? А дальше, в этом вся фишка, эта камера будет использоваться для получения нужных координат. Например, заставив камеру двигаться по нужной траектории (об этом ниже) перемещать в цикле (с маленькой паузой) какой-либо объект по координатам камеры. Вот примеры использования команд управления камерой (только необходимые для нашего скрипта):

 


Примечание : предполагается, что используемые камеры созданы и для них установлены эффекты ["terminate","back"].

 

Устанавливает камеру в координаты [x,y,z]:

 

_cam camsetpos [x,y,z]

(или _cam camsetpos getpos SomeObject)

 

Устанавливает для камеры как цель объект SomeObject или точку с координатами [x,y,z] Камера всегда будет направлена на свою цель (если она указана). Цель можно менять:

 

_cam camsettarget SomeObject

(или _cam camsettarget [x,y,z])

 

Устанавливает камеру в координаты [x,y,z] относительно своей цели. Если цель не указана, команда верно не работает. Эту команду используют для нахождения координат относительно юнита с учетом направления его взгляда.

 

_cam camsetrelpos [x,y,z]

 

Важно: Все действия установленные этими командами вступают в силу только после команды camcommit:

 

{ Действия управления камерой }

_ cam camcommit {время за которое установится действие}

 

Например:

 

_cam camsetpos getpos SomeObject1 – камере дается указание перейти в координаты объекта SomeObject1

_ cam camcommit 0 – мгновенно (время - 0) устанавливает камеру в координаты объекта SomeObject 1

_ cam camsetpos SomeObject 2 - камере дается указание перейти в координаты объекта SomeObject 2

_ cam camcommit 10 – за 10 секунд плавно переносит камеру в координаты объекта SomeObject 2 из координат объекта SomeObject 1

 

 


Иногда, бывает полезна команда camcommitted. Эта команда возвращает значение True, если все изменения сделанные командами управления вступили в силу, и False, если еще не вступили.

 

@(camcommited _cam)

 

Такая строка приостановит выполнение скрипта до тех пор, пока изменения сделанные командами управления камерой не вступят в силу.

 

Но вернемся к скрипту, вот собственно и он:

 

“Move.sqs”


;получение аргументов.

;_target – объект, который перемещают

;_moveto – координаты, в которые перемещают объект, вместо координат можно передать ;получение координат getpos SomeObject (чаще всего получают координаты GameLogic’а (На ;усмотрение игры – в Буке) – или другого невидимого объекта)

;_time - время перемещения объекта.

 

_target = _this select 0

_moveto = _this select 1

_time = _this select 2

 

;создание и установка эффектов для камеры

_cam = "camera" camcreate [0,0,0]

_cam cameraeffect ["terminate", "back"]

 

;мгновенное перемещение камеры в координаты перемещаемого объекта

_cam camsetpos getpos _target

_cam camcommit 0

 

;плавное перемещение камеры в координаты объекта _moveto за время _time

_cam camsetpos _moveto

_cam camcommit (_time)

#loop

;пауза

~0.01

; перемещение объекта _target в координаты камеры _cam

_target setpos [getpos _cam select 0, getpos _cam select 1]

;проверка жив ли перемещаемый юнит, и если мертв то выход из скрипта

?(getdammage _target == 1): goto "exit"

goto "loop"

 

#exit

exit

 


Сразу после получения аргументов следуют строчки, в которых создается камера и ей устанавливается нужный эффект. В нашем случае, как уже говорилось раньше, эффекты отключены (["terminate", "back"]), так как не нужно переключать вид на эту камеру (при использовании для камеры других эффектов на экране Вы увидите вид именно из этой камеры). Далее камера мгновенно (так как время в команде camcommit приводящей изменения в силу установлено на 0) перемещается в координаты того объекта, который будет передвигаться. Затем камере дается указание двигаться в координаты _moveto, то есть в точку конечного назначения. Так как в команде camcommit время – значение переменной _time (время движения – передается в скрипт как аргумент, то есть устанавливается пользователем) то камера пройдет путь от начального положения перемещаемого объекта в конечную точку за время – значение переменной _time. Камера двигается, несмотря на продолжение скрипта. В цикле с паузой в 0.01 (для плавного движения) происходит постоянное перемещение объекта _target в координаты камеры. Так как камера движется во время выполнения цикла то и объект постоянно перемещается в новые координаты. Происходит примерно то же что и в скрипте “Privazka.sqs”, только объект “привязывается” к движущейся в нужную точку невидимой камере.

 

Для проверки поставьте двух солдат на карте (еще одного - игрока). Одного пусть зовут Sold1 а второго Sold2. Запустите скрипт так:

[Sold1, getpos Sold2, 20] exec “move.sqs”

Смотрим!

Если Вы заметили, при перемещении объекта в координаты камеры, не устанавливается высота (координата Z), и, следовательно, объект всегда будет двигаться по земле. Для того чтобы при перемещении использовалась координаты Z нужно в строчку изменения координат объекта добавить и координаты высоты камеры - getpos _cam select 2.

 

Эта строчка

_target setpos [getpos _cam select 0, getpos _cam select 1]

должна выглядеть так:

_target setpos [getpos _cam select 0, getpos _cam select 1, getpos _cam select 2].

 

Но такой способ изменения режима работы скрипта не очень удобен. Во-первых, нужно менять сам код скрипта, а во-вторых, человек не умеющий писать скрипты может просто не понять, что и где нужно изменить. Поэтому сейчас на примере этого скрипта покажу, как изменять режим работы скрипта через передачу аргумента. Итак, нам, например, нужно сделать три режима работы скрипта: “LAND”, “AIR”, “AUTO”. Где “LAND” – передвижения объекта по земле. “AIR” – передвижение объекта точно по траектории камеры, причем объект будет двигаться не только по земле и воздуху, но и под землей, если на пути движения будут горы и т.п. “AUTO” – передвижение объект либо по земле, либо по воздуху, но не под землей. Как это сделать? Просто нужно сделать получение еще одного аргумента, значение которого и будет режим работы скрипта. А в зависимости от полученного режима работы будет выполняться один из трех циклов. Смотрим:

“Move2.sqs”


;получение аргументов.

;_target – объект, который перемещают

;_moveto – координаты, в которые перемещают объект, вместо координат можно передать ;получение координат getpos SomeObject (чаще всего получают координаты GameLogic’а (На ;усмотрение игры – в Буке) – или другого невидимого объекта)

;_time - время перемещения объекта.

;_tip – режим выполнения скрипта. Возможные значения:“LAND”, “AIR”,”AUTO”(в кавычках)

 

_target = _this select 0

_moveto = _this select 1

_time = _this select 2

_tip = _this select 3

 

;создание, установка эффектов для камеры и мгновенное перемещение камеры в ;координаты перемещаемого объекта

_cam = "camera" camcreate [0,0,0]

_cam cameraeffect ["terminate", "back"]

_cam camsetpos getpos _target

_cam camcommit 0

 

;плавное перемещение камеры в координаты объекта _moveto за время _time

_cam camsetpos getpos _moveto

_cam camcommit (_time)

 

;выбор одного из режимов работы скрипта и переход к соответствующему циклу

?(_tip == "LAND"): goto "loopLAND"

?(_tip == "Air"): goto "loopAIR"

?(_tip == "AUTO"): goto "loopAUTO"

?((_tip != "AUTO") AND (_tip != "AIR") AND (_tip != "LAND")): hint "Zadan nevernyi regim raboti scripta"; goto "exit"

 

;цикл, который исполняется, если _tip равняется “LAND”

#loopLAND

~0.01

_target setpos [getpos _cam select 0, getpos _cam select 1 ]

?(getdammage _target == 1): goto "exit"

goto "loopLAND"

 

;цикл, который исполняется, если _tip равняется “AIR”

#loopAIR

~0.01

_target setpos [getpos _cam select 0, getpos _cam select 1, getpos _cam select 2]

?(getdammage _target == 1): goto "exit"

goto "loopAIR"

 

;цикл, который исполняется, если _tip равняется “AUTO”

#loopAUTO

~0.01

;расчеты координаты z

?((getpos _cam select 2) < 0): _posZ = 0

?((getpos _cam select 2) >= 0): _posZ = getpos _cam select 2

 

_target setpos [getpos _cam select 0, getpos _cam select 1, _posz ]

?(getdammage _target == 1): goto "exit"

goto "loopAUTO"

 

#exit

exit


Определение заданного режима работы скрипта и последующий выбор нужного цикла происходит в этих строчках(строчки пронумерованы):

 

1 - ?(_tip == "LAND"): goto "loopLAND"

2 - ?(_tip == "Air"): goto "loopAIR"

3 - ?(_tip == "AUTO"): goto "loopAUTO"

4 - ?((_tip != "AUTO") AND (_tip != "AIR") AND (_tip != "LAND")): hint "Zadan nevernyi regim raboti scripta"; goto "exit"

 

Все эти строчки – условия. В каждом из них проверяется значение переменной _tip , а значение этой переменной передается в скрипт как аргумент. В первом условии проверяется значение переменной _tip на равенство строке “LAND” и в случае равенства происходит переход к циклу “loopLAND”. В этом цикле объект _target устанавливается в координаты камеры _cam без учета координаты Z. То есть объект двигается только по земле. Если значение проверяемой переменной не равно “LAND”, то скрипт переходит к следующей строчке, а следующая строчка – очередное условие, проверяющее значение переменной _tip на равенство строке “AIR”. В случае верности условия происходит переход к циклу “loopAIR”. В этом цикле при перемещении объекта учитывается координата Z камеры. Так как эта координата может быть отрицательной то объект может двигаться под землей. В третьем цикле, который выполняется в случае верности условия _tip == "AUTO", перед перемещением объекта в координаты камеры происходит расчет координаты Z объекта. Вот это вычисление:

 

?((getpos _cam select 2) < 0): _posZ = 0

?((getpos _cam select 2) >= 0): _posZ = getpos _cam select 2

 

Это два условия. В них проверяется, положительна или отрицательна координата Z камеры. Если положительна, то эта координата и используется при перемещении объекта _target. Если отрицательна (камера двигается под землей) то при перемещении объекта _target координата Z равна 0. Значение координаты Z используемой при перемещении объекта хранится в переменной _posZ.

Мы еще не рассмотрели последнюю строчку из определения режима работы скрипта. Вот эта строчка:

 

?((_tip != "AUTO") AND (_tip != "AIR") AND (_tip != "LAND")): hint "Zadan nevernyi regim raboti scripta"; goto "exit"

 

Это условие проверяется только в том случае, если переменная _tip не равна ни “LAND”, ни “AIR”, ни “AUTO”. То есть если в скрипт передано неверное значение режима скрипта. В этом случае выводится подсказка (hint) которая и сообщает пользователю о том, что режим задан неверно, а затем выполнение скрипта прекращается. Вместо условия можно было просто поставить предупреждение-подсказку hint, так как до этой строчки скрипт дойдет, только если все три выше написанные условия будут неверны. Если хотя бы одно из условий будет верным, то скрипт перейдет к нужному циклу, а эта строчка будет пропущена (также как и нижеследующие условия). Если не совсем понятно смотрим:

 

 

Примечание: зеленая стрелка, если условие верно, а красная – если неверно.

 

 

?(_tip == "LAND"): goto "loopLAND"

 

?(_tip == "Air"): goto "loopAIR"

 

?(_tip == "AUTO"): goto "loopAUTO"

 

hint "Zadan nevernyi regim raboti scripta"; goto "exit"(выход из скрипта)

 

 

{Цикл если _tip равно “LAND”}

 

{Цикл если _tip равно “AIR”}

 

{Цикл если _tip равно “AUTO”}

 

Попробуйте походить (мысленно!) по этим стрелкам, и Вы сможете дойти до строчки hint, только если будите ходить по красным стрелка, а красные стрелки – только в случае неверности условия.

 

Для проверки скрипта, найдите на одном из островов горку повыше и поставьте по обе стороны от горки двух солдат, как и в скрипте “Move.sqs”. Запустите скрипт так:

  [Sold1, getpos Sold2, 20,”LAND”] exec “move.sqs”

Смотрим! Затем замените значение режима и посмотрите на результат. Ну как? Работает!?

 

 

Раз уж я начал говорить о камерах, то попробую рассказать все, что знаю о нестандартном их использовании. Итак, команда camcreate кроме основных своих функций – создания камеры  – служит также и для… создания объектов! Да именно для создания объектов, любых, или почти любых. Как? А вот так:

 

ObjectName = “{ Тип объекта }” camcreate [x,y,z]

 

Где NameOfObject – имя (переменная, значение которой - ссылка на объект) создаваемого объекта, с помощью этого имени можно будет управлять объектом (но об этом потом). {Тип объекта} – тип, или внутреигровое название типа объекта. То есть, например, мы хотим создать обычного солдата СССР. Так вот название типа простого русского солдата – SoldierEB. И следовательно чтобы создать такого солдата нужно использовать (в On(De)Activation, в скриптах и т.д.) такую строчку:

_ Sold = “SoldierEB” camcreate getpos Barrak

Теперь локальная (может быть и глобальная) переменная _Sold служит для управления созданным объектом. НО, созданный объект СТАТИЧНЫЙ! То есть, хоть это и солдат, ему можно давать команды только как для статических объектов (дома, ящики)! Это такие команды как setpos, setdir, switchmove и другие. Скажем так, у такого юнита нет интеллекта (искусственного): он не будет по Вам стрелять, не будет ходить, не будет исполнять приказы, НО может умереть! Именно с помощью такого использования этой команды создают взрывы в произвольном месте! Например, для артобстрела. Просто нужно создать в нужном месте снаряд от танка (например, Shell73) или другой боеприпас! Но учтите, что снаряды и пули, созданные в воздухе падают вниз и при контакте с землей взрываются (снаряды)! Ракеты же не падают, а летят вперед! Некоторые типы объектов Вы найдете в списка команд на английском.

 

    Очень важной и интересной является команда nearestobject . Важная, потому что, используя эту команду, можно сделать скрипты универсальными и “автономными”. Интересная, потому что открывает новые приемы  в написании скриптов. Как можно понять из названия (nearestObject – “ближайший объект”) эта команда служит для определения ближайшего объекта к данному объекту. Существует несколько способов использования этой команды:

 

1. nearestObject [ ObjectName , “{ тип объекта } "]

2. nearestObject [[x,y,z], “{ тип объекта }"]

3. nearestObject [x,y,z]

 

В первом случае команда возвращает ссылку на объект определенного типа находящейся ближе всего к объекту ObjectName. Например:

_ Lamp 1 = nearestObject [player, "StreetLamp"] – локальная переменная _ lamp 1   принимает значение ближайшего к игроку объекта типа “ StreetLamp” (фонарный столб)

Во втором случае команда возвращает ссылку на объект определенного типа находящейся ближе всего к точке с координатами [x,y,z]. Например:

_ Lamp 2 = nearestObject [[ x , y , z ], "StreetLamp"] – локальная переменная _ lamp 2   принимает значение ближайшего к точке с координатами [ x , y , z ]  объекта типа “ StreetLamp” (фонарный столб).

 

В третьем случае команда возвращает ссылку на объект находящейся ближе всего к точке с координатами [x,y,z]. В данном случае тип объекта не требуется. Например:

_ Lamp 3 = nearestObject [ x , y , z ] (или _ Lamp 3 = nearestObject getpos SomeObj 1) – локальная переменная _ lamp 3   принимает значение ближайшего к точке с координатами [ x , y , z ] объекта любого типа.

 

    Рассмотрим работу команды на примере одного скрипта. Этот скрипт немного улучшает AI (искусственный интеллект) снайперов.  Может быть, Вы замечали, что если снайпер замечен и по нему открыт огонь, то он все равно лежит на месте и пытается отстреливаться, даже если ему противостоит целая армия солдат. Настоящий снайпер после обнаружения срочно покидает позицию и отходит. Этот скрипт предназначен для улучшения действий снайпера при обнаружении. Теперь, когда снайпер замечен, то сначала он создает дымовую завесу, а потом в зависимости от переданных аргументов либо двигается по вейпоинтам, либо двигается в определенную точку. Смотрим скрипт:

“SniperAI.sqs”


;В качестве аргументов мы получаем юнит (_sniper), способ отхода или режим ;работы скрипта (_mode), координаты точки отхода (_posback), тип поведения при ;отходе (_behaviour), положение юнита при отходе (_unitpos), боевой режим юнита ;при отходе (_combatmode)

 

_sniper = _this select 0

_mode = _this select 1

_posback = _this select 2

_behaviour = _this select 3

_unitpos = _this select 4

_combatmode = _this select 5

 

SniperAIletmove = false

 

; проверка : снайпер человек иди нет

_checkarray = [_sniper]

?("Man" counttype _checkarray == 0): hint "SniperAI: Переданный юнит не человек"; exit

 

;нахождение первоначального значения здоровья и ближайшего к снайперу ;кратера

_oldcrater = nearestobject [_sniper,"crater"]

_olddammage = getdammage _sniper

;проверка правильности заданного режима работы скрипта

?((_mode != "POS") AND (_mode != "WP")): hint "SniperAI script: Неверно задан тип отхода (2ой аргумент)"; exit

 

;начало цикла

#loop

;проверка условия

?((((_sniper distance nearestobject [_sniper,"crater"]) < 20) AND (nearestobject [_sniper,"crater"] != _oldcrater)) OR ((getdammage _sniper) > _olddammage)): goto "loop2"

?(getdammage _sniper == 1): exit

;hint "Поиск"

~1

goto "loop"

 

#loop2

;hint "Есть кратер"

;проверка мертв ли снайпер

?(getdammage _sniper == 1): exit

;проигрывание анимации

_sniper switchmove "BinocLyingToLying"

~2

 

;нахождение координат точки находящейся в 0.8 метрах впереди от снайпера

_cam = "camera" camcreate [0,0,0]

_cam cameraeffect ["terminate", "back"]

_cam camsettarget _sniper

_cam camsetrelpos [0,0.8,0]

_cam camcommit 0

 

;создание рюкзака в найденных координатах

_somesmokething = "PipeBomb" camcreate [(getpos _cam select 0), (getpos _cam select 1),0]

;создание дымовой шашки в координатах рюкзака

_somesmoke = "SmokeShell" camcreate getpos _somesmokething

;уничтожение используемой для получения координат камеры

camdestroy _cam

;выбор режима работы скрипта

?(_mode == "WP"): goto "exitWP"

?(_mode == "POS"): _sniper setunitpos _unitpos

;установка поведения, режима боя и т.д. для снайпера

_sniper setcombatmode _combatmode

_sniper setbehaviour _behaviour

_sniper domove _posback

;hint "Снайпер отходит"

goto "exitPOS"

 

#exitWP

 

SniperAIletmove = true

 

#exitPOS

 

exit

 


Сначала я расскажу о новых для Вас командах.

 

“{ тип }” counttype { массив }

 

Эта команда определяет, сколько юнитов, указанных в заданном массиве, принадлежат к заданному типу. О разные типах юнитов Вы узнаете из списка команд на английском. Например:

_ soldiersnum = “ soldier ” counttype MyArray 1 – получение количества юнитов (элементов) типа “ soldier ” (солдаты) в массиве MyArray 1 и сохранение значения в локальную переменную _soldiersnum.

 

UnitName SetUnitPos {положение}

 

Эта команда заставляет юнита принять определенное положение. В дальнейшем юнит будет передвигаться только в заданном положении.  Доступные положения: “UP” – стоя , “DOWN” – лежа, “AUTO” - позволить юниту самому выбрать наилучшее положение. Например:

Unit 1 setunitpos “ UP ” – заставляет юнит передвигаться стоя.

Примечание: При использовании положения “UP” юнит переходит в боевое положение. То есть если юниту было задано поведение “SAFE”(оружие за спиной) и если юнита заставить передвигаться стоя, то он возьмет оружие в руки.

 

U nitName SetCombatMode {режим боя}

Эта команда устанавливает для юнита определенный режим боя. Доступные режимы боя: “BLUE” - никогда не стрелять, “GREEN” - не стрелять до приказа, “WHITE” - не стрелять до приказа, но атаковать врага в поле видимости, “YELLOW” - открыть огонь (с того места, где находится юнит), “RED” - открыть огонь, но оставаться рядом с командиром. Например:

Unit 1 SetCombatMode "GREEN" – устанавливает для юнита Unit 1 режим боя “ GREEN ”.

 

 

UnitName domove [x,y]

 

Эта команда заставляет юнит двигаться в точку с координатами [x,y]. Пример:

Unit 1 domove [3415,1355] - заставляет юнит Unit 1 двигаться в точку с координатами [3415,1355]

Unit 2 domove getpos Unit 3 - заставляет юнит Unit 2 двигаться в точку с координатами юнита Unit 3

    Похоже это все неизвестные Вам команды из этого скрипта. Приступим к рассмотрению кода. В качестве аргументов мы получаем юнит (_sniper), способ отхода или режим работы скрипта (_mode), координаты точки отхода (_posback), тип поведения при отходе (_behaviour), положение юнита при отходе (_unitpos), боевой режим юнита при отходе (_combatmode). Доступные способы работы скрипта: “WP” и “POS”. “WP” – отход по заранее установленным в редакторе вейпоинтам. Для правильной работы этого режима нужно в редакторе для снайпера поставить один вейпоинт (максимально близко к самому снайперу) с условием выполнения (Condition) : SniperAIletmove == true. А затем расставлять вейпоинты для отхода. Причем в них (в поле OnActivation или в свойствах самого вейпоинта) можно использовать команды для установки режима боя, положения (setunitpos) юнита и т.д. Например, в поле видимости врага передвигаться лежа и не стреляя (в свойствах вейпоинта: режим боя – не стрелять, этот режим нужно обязательно ставить иначе снайпер так и не прекратит огонь и не начнет отходить ), а потом стоя и с боевым режимом боя. Второй режим – “POS” – отход в координаты _posback. Причем юнит будет отходить в соответствии с режимами, переданными в скрипт в качестве аргументов:  _behaviour, _unitpos, _combatmode. Режим отхода по вейпоинтам более предпочтителен, так как он более “гибкий” и имеет гораздо больше возможностей чем режим “POS”. Режим

“POS” был добавлен в скрипт только лишь для еще одной иллюстрации возможности работы скрипта в разных режимах.

    Сразу же после получения аргументов следует проверка переданного в скрипт юнита на тип “Man” – то есть скрипт проверяет этот юнит человек или нет. Если нет, то выводится сообщение об ошибке и выполнение скрипта прекращается. Как происходит проверка? Мы знаем, что для проверки юнита на принадлежность к какому-либо типу используют команду counttype. Однако эта команда работает только с массивами, а у нас есть всего лишь один юнит. Все просто! Мы просто создаем массив, в котором содержится только один нужный нам юнит, и проверяем его тип командой counttype. В нашем случае если юнит принадлежит к типу “MAN” то команда counttype возвращает значение 1 - количество юнитов в массиве этого типа, если не принадлежит то значение 0. Возвращаемое значение и проверяется в условии: если 1 то скрипт выполняется дальше, если 0 – скрипт прекращает выполнение. Такой способ определения типа используется чаще всего для объектов полученных командой nearestobject или командой List (об этой команде читай в списке всех команд).

    Далее в скрипте происходит присвоение переменным _oldcrater и _olddammage значения ближайшего к снайперу кратера и значения здоровья снайпера соответственно. Кратер в игре – след от пули на земле или другом объекте (кратеры иногда не прорисовываются, но все же существуют как объекты). Для чего эти переменные? Представим, что снайпер занимает позицию и рядом с этой позицией уже есть кратер. Скрипт найдет этот кратер и заставит снайпера отступать. Значение здоровья понадобится для проверки ранен ли снайпер или нет (снайпер может занять позицию уже раненым). Проверка здоровья необходима, потому что при попадании пули в человека не создается объект кратер и, следовательно, при ранении снайпер не будет отступать.

    После присвоения значений переменным в скрипте идет проверка режима работы скрипта. Если заданный режим не предусмотрен, то выводится сообщение об ошибке.

Теперь рассмотрим цикл в скрипте. Вот первое проверяемое в скрипте условие:

 

?( ( ( (_sniper distance nearestobject [_sniper,"crater"]) < 20) AND

(nearestobject [_sniper,"crater"] != _oldcrater) ) OR

 ( (getdammage _sniper) > _olddammage) ): goto "loop2"

 

Довольно сложное для понимания условие, неправда ли? Для того чтобы Вам было легче понять, я отметил скобок разными цветами. То есть для какого-то выражения открывающая и закрывающая скобка одного цвета. Что же проверяется в условии? В условии проверяется расстояние от снайпера до ближайшего к нему кратера (_ sniper distance nearestobject [_ sniper ," crater "]). Однако одновременно этот кратер не должен быть равен кратеру _oldcrater (…. AND (nearestobject [_ sniper , " crater "] != _ oldcrater)). Если эти условия не верны одновременно, то проверяется, ранен снайпер или нет (…. OR ( (getdammage _ sniper) > _ olddammage)). Если одно из этих условий верно, то происходит переход на метку “loop2”. Также в цикле проверяется, мертв ли снайпер и если снайпер мертв, то выполнение скрипта заканчивается.

    При верности первого условия происходит переход к метке “loop2”. После этой метки происходит проверка: жив ли снайпер. Затем проигрывается анимация: кажется, что снайпер, что-то кладет на землю. И как раз в том месте, (примерно) куда он что-то кладет, появляется рюкзак (муляж – для вида) и в том же месте дымовая завеса. Для вычисления координат появления рюкзака и дымовой завесы используется камера. После этого выбирается способ отхода (режим работы скрипта) и в зависимости от него выполняются различные действия. При отходе по вейпоинтам глобальная переменная SniperAIletmove принимает значение True, а именно значение этой переменной должно является условием в первом вейпоинте отхода! При отходе в заданную точку (режим “POS”) снайперу устанавливается тип поведения, режим передвижения и т.д. Затем команда domove заставляет его передвигаться в точку отхода.

    Скрипт работает так: при запуске начинается поиск нового кратера (кратеры появятся, когда в снайпера будут стрелять), при нахождении такого кратера или при ранении снайпера начинается отход снайпера. Перед отходом ставится дымовая завеса, затрудняющая прицельную стрельбу. Отход происходит либо по вейпоинтам, либо просто в установленную точку.

    Теперь о том, как использовать этот скрипт. Создаем карту на Колгуеве. В квадрате Ff52 есть база; вот туда и ставим несколько пулеметчиков (одного из них называем hevygunnner1) и разворачиваем их на северо-запад – на склон горы. Недалеко от горы ставим снайпера с именем sniper1. Затем расставляем ему вейпоинтов до самого склона; в вейпоинтах можно (даже нужно) прописывать команды. Команда типа Sniper1 setunitpos “UP” приписанная в OnActivation вейпоинта начнет выполняться только со следующего вейпоинта. Итак, понаставили вейпоинтов до самого склона, теперь в поле OnActivation последнего вейпоинта прописываем запуск скрипта: [ sniper 1,"WP",getpos gl1,"CARELESS","down","BLUE"] exec "SniperAI.sqs"; sniper1 reveal hevygunnner 1; sniper1 dofire hevygunnner 1.  Команда reaveal заставляет один юнит узнать о другом. Нужно обязательно указать все аргументы скрипта (gl1 – Game Logic с именем Gl1) даже ненужные в данном режиме работы скрипта! Конечно, можно сделать так, чтобы ненужные аргументы не нужно было вводить. Но этим Вы займетесь сами, если захотите. Подсказка: нужно сначала определить режим работы скрипта(2-й аргумент), а затем уже получать остальные только нужные в зависимости от режима работы аргументы. К примеру, создаем метку, после которой идут аргументы необходимые для работы в режиме “ POS ”. В начале скрипта определяем, выбран ли этот режим работы, и если выбран, переходим к этой метке. В конце получения нужных аргументов ставим команду goto чтобы “перепрыгнуть” получение ненужных аргументов. Все это должно выглядеть примерно так я объяснил.  Вернемся к вейпоинтам. Рядом с последним вейпоинтом ставим еще один с условием (Condition) SniperAIletmove == True (или просто SniperAIletmove). После этого вейпоинта идут вейпоинты отхода. Вот и все!

    Конечно, этот скрипт не сильно “прибавит мозгов” снайперу- компьютеру, однако если его доработать.… Например, выбрать главную цель и, определяя какое оружие имеют рядом стоящие (опять nearestobject) бойцы, уничтожать их по-очереди в соответствии с типом их оружия (на дистанции M21 опаснее, чем M60; для определения оружия – команда hasWeapon (см. список команд)). Собственно имея хорошую фантазию и терпенье в ОФП с помощью скриптов можно сделать ВСЕ или почти все!

    Кажется, я рассказал обо всех основных приемах создания скриптов. Для начала хватит. Если же Вы хотите стать мастером в создании скриптов, то Вам поможет только терпенье и любопытство. Удачи.

Sanek

 

PS :

Если Вы хотите разместить это учебник на своем сайте, пожалуйста, черкните мне об этом на мыло. Напишите в письме о сайте (название и ссылка) и о Ваших впечатлениях об учебнике (понравился или нет и тд). Для меня это очень важно! =)

PSS :

Огромное спасибо Martini за помощь!

PSSS:

Нашли ошибки? Неточности? Опечатки? По всем вопросам пишите - Sanek <Sanek-Solo@yandex.ru>  . Или ICQ#77449483 .


Дата добавления: 2020-11-15; просмотров: 78; Мы поможем в написании вашей работы!

Поделиться с друзьями:






Мы поможем в написании ваших работ!