Raseri | Дата: Воскресенье, 10.11.2013, 18:16 | Сообщение # 1 |
Темный Клинок
Группа: Добрый Модератор
Сообщений: 756
Награды: 23 +
Статус: Offline
| Всем привет Перечитав прошлые части статьи, я заметил, что до сих пор ничего не рассказал вам про такие важные в создании миссии штуки, как условные операторы и таймеры И, чтобы рассказать вам об этом, да ещё и на интересных примерах, я поведаю в этой статье о том, как сделать периодичную высадку вражеских подкреплений.
Для начала взглянем на код миссии, на функцию Breakthrough:UpdateActivity()
Именно в этой функции мы и будем писать код периодичного спавна врагов. Но для начала, нам нужно сделать кое-какие приготовления.
Во-первых, сбрасывать десант нужно не абы куда, а над базой врага (и лучше всего прямо внутрь бункера, через шахту), так что мы должны каким-либо образом получить координаты появления кораблей. Можно это сделать тем способом, который давался во второй части статьи.
Во-вторых, если у противника будет командир, то логично, что его будут пытаться всеми силами защитить, что хотя бы часть войск будет направлена вниз, к его комнате. Для этого нам потребуется расставить в коридорах и комнатах несколько зон, которые солдаты будут занимать. Как размещать зоны, написано тоже во второй части
Немножко покопавшись с редакторами сцен и зон, я получил координаты вражеского корабля (Х == 1000) и расставил зоны следующим образом:
Как вы могли заметить, одной зоне соответствует несколько прямоугольников. Выбрав название зоны, я просто добавлял и добавлял новые "боксы", пока ими не оказались покрыты все подходящие места. Также, я окружил зоной комнату с командиром:
Если игрок подберётся тем или иным образом достаточно близко к вражескому командиру, то ВСЕ вражеские войска получат приказ ломануться вниз, на выручку.
В StartActivity присваиваю зоны переменным и под комментарием указываю координату (чтоб не забыть), также я решил сразу создать таймер:
Код -- присваиваем переменным зоны self.ZoneOutpost = SceneMan.Scene:GetArea("Outpost"); self.ZoneAlarm = SceneMan.Scene:GetArea("ZoneAlarm"); -- зона для проверки проникновения войск игрока вглубь базы self.DefPosTop = SceneMan.Scene:GetArea("DefPosTop"); -- позиции для прибывших подкреплений self.DefPosDown = SceneMan.Scene:GetArea("DefPosDown"); self.TimerReinf = Timer(); -- создаём таймер self.TimerReinf:Reset(); -- сбрасываем, начиная отсчёт
В UpdateActivity начинаю прописывать код спавна. Вот, кстати, полная форма условного оператора:
Код function Breakthrough:UpdateActivity()
self:ClearObjectivePoints(); if self.TimerReinf:IsPastSimMS(30000) and (MovableMan:GetMOIDCount() < 200) then -- создаём корабль for i = 1,3 do -- создаём трёх солдат коалиции, даём им оружие и суём в корабль end -- спавним корабль -- сбрасываем таймер (если это не сделать, корабли будут спавнится бесконечной лавиной) end self:YSortObjectivePoints(); end Важное замечание: Если на карте единовременно окажется слишком много акторов, ИИ начнёт жестоко лагать. Чтобы такого не происходило, в условие спавна добавляется "MovableMan:GetMOIDCount() < 200". В том случае, если на игровом уровне находится и без того достаточно войск, код просто "подождёт", пока их количество не убудет. |
А вот как я написал код спавна:
Код function Breakthrough:UpdateActivity()
self:ClearObjectivePoints(); if self.TimerReinf:IsPastSimMS(30000) and (MovableMan:GetMOIDCount() < 200) then -- создаём корабль local ship = CreateACDropShip("Drop Ship MK1" , "Base.rte"); ship.Pos = Vector (1000, -20); ship.Team = 1; ship:SetControllerMode(Controller.CIM_AI, -1); -- создаём трёх солдат коалиции, даём им оружие и суём в корабль for i = 1,3 do local soldier = CreateAHuman("Soldier Light","Coalition.rte"); soldier.Team = 1; soldier:AddInventoryItem(CreateHDFirearm("Compact Assault Rifle","Coalition.rte")); ship:AddInventoryItem(soldier); end -- спавним корабль MovableMan:AddActor(ship); -- сбрасываем таймер self.TimerReinf:Reset(); end self:YSortObjectivePoints(); end
Единственное, что тут ещё не указано, это режим ИИ для вражеских солдат. Решил его организовать я так (кстати, можете посмотреть здесь на вложенные условия):
Код function Breakthrough:UpdateActivity()
self:ClearObjectivePoints(); if self.TimerReinf:IsPastSimMS(30000) and (MovableMan:GetMOIDCount() < 200) then -- создаём корабль local ship = CreateACDropShip("Drop Ship MK1" , "Base.rte"); ship.Pos = Vector (1000, -20); ship.Team = 1; ship:SetControllerMode(Controller.CIM_AI, -1); -- создаём трёх солдат коалиции, даём им оружие и суём в корабль for i = 1,3 do local soldier = CreateAHuman("Soldier Light","Coalition.rte"); soldier.Team = 1; soldier:AddInventoryItem(CreateHDFirearm("Compact Assault Rifle","Coalition.rte")); local AI; AI = math.random(); -- переменной AI присваивается случайное значение от 0 до 1 (в виде дроби)
if AI >= 0.5 then -- в половине случаев охотится за мозгом игрока soldier.AIMode = Actor.AIMODE_BRAINHUNT; elseif AI > 0.25 then -- в четверти случаев занимает позиции вверху soldier.AIMode = Actor.AIMODE_GOTO; soldier:ClearAIWaypoints(); soldier:AddAISceneWaypoint(Vector(self.DefPosTop:GetRandomPoint().X , self.DefPosTop:GetRandomPoint().Y)); else -- в четверти случаев занимает позиции внизу soldier.AIMode = Actor.AIMODE_GOTO; soldier:ClearAIWaypoints(); soldier:AddAISceneWaypoint(Vector(self.DefPosDown:GetRandomPoint().X , self.DefPosDown:GetRandomPoint().Y)); end ship:AddInventoryItem(soldier); end -- спавним корабль MovableMan:AddActor(ship); -- сбрасываем таймер self.TimerReinf:Reset(); end self:YSortObjectivePoints(); end Теперь, нам нужно сделать так, чтобы при вторжении солдат игрока в self.AlarmZone, все вражеские войска направились вниз, на выручку.
Немного отступив от кода периодичного спавна, я пишу: Код local actor; for actor in MovableMan.Actors do -- перебираем всех акторов (солдат, крабов, корабли, т.д.) if (actor.Team == 0) and self.ZoneAlarm:IsInside(actor.Pos) then -- если принадлежит игроку и пересекает зону --приказываем двигаться вниз end end Теперь подробнее распишу код, в котором мы прикажем всем врагам тащиться вниз. Во-первых, с помощью "for actor in MovableMan.Actors" нам снова нужно перебрать всех акторов (чтобы найти тех, кто принадлежит врагу). Во-вторых, всем им нужно приказать идти в точку... мм... ну, скажем, ту самую, где стоял в самом начале дрон коалиции, т.е. по координатам (1100, 854).
Получаем: Код local actor; for actor in MovableMan.Actors do -- перебираем всех акторов (солдат, крабов, корабли, т.д.) if (actor.Team == 0) and self.ZoneAlarm:IsInside(actor.Pos) then -- если принадлежит игроку и пересекает зону local actor for actor in MovableMan.Actors do if actor.Team == 1 then actor.AIMode = Actor.AIMODE_GOTO; actor:ClearAIWaypoints(); actor:AddAISceneWaypoint(Vector(1100, 854)); end end break; -- прерываем внешний цикл, продолжать поиск вторгнувшихся войск игрока нет смысла end end Хорошо, теперь нам нужно сделать ещё две вещи с этим многострадальным кусочком кода.
Во-первых, нам нужно запретить выполнение этого кода после того, как он будет один раз уже выполнен. Ну, вы понимаете, если мы это не сделаем, то каждый раз, как какой-то солдат игрока окажется в зоне, каждые несколько миллисекунд все враги снова и снова будут получать приказ двигаться вниз. Нам это не надо.
Во-вторых, проверка по всем акторам штука весьма ресурсоёмкая, поэтому проводить ещё слишком часто было бы нерационально. Из-за этого мы добавим таймер, который будет запускать проверку... скажем, раз в полторы секунды.
В StartActivities прописываем новую переменную и таймер: Код self.Alarm = 0; -- "0" позволяет проводить проверку; "1" - эту проверку отключает self.AlarmTimer = Timer(); self.AlarmTimer:Reset(); А код тревоги дополняем таким образом:
Код if self.Alarm == 0 then if self.AlarmTimer:IsPastSimMS(1500) then local actor; for actor in MovableMan.Actors do -- перебираем всех акторов (солдат, крабов, корабли, т.д.) if (actor.Team == 0) and self.ZoneAlarm:IsInside(actor.Pos) then -- если принадлежит игроку и пересекает зону for actor in MovableMan.Actors do if actor.Team == 1 then actor.AIMode = Actor.AIMODE_GOTO; actor:ClearAIWaypoints(); actor:AddAISceneWaypoint(Vector(1100, 854)); end end self.Alarm = 1; -- прекращаем выполнение куска кода break; -- прерываем внешний цикл, продолжать поиск вторгнувшихся войск игрока нет смысла end end self.AlarmTimer:Reset(); end end
Надеюсь, я не слишком запутал и запугал вас этими горами текста Мне показалось, что несколько этапов написания кода помогут вам получше разобраться, что тут к чему
Возможно, это покажется вам самой сложной частью статьи, но это, пожалуй, и одна из самых важных её частей. Разобравшись и освоив то, про что тут идёт речь, вы уже сможете с лёгкостью программировать "сюжет" миссии, который сможет включать в себя передвижение войск и создание в нужных местах нужных акторов (в том числе и десантных кораблей с десантом), также из этой статьи можно выдернуть режим ИИ, позволяющий приказать охотится за вражеским мозгом.
К посту снова прикрепляю миссию - смотрите, разбирайтесь, задавайте в комментариях вопросы
Если потребуется помощь, вы можете выложить сюда свою миссию и обрисовать характер затруднения - я запрограммирую вам нужную часть (дав к коду подробные комментарии) или помогу исправить ошибки.
Мне очень важно, выглядят ли мои объяснения здесь, в статье, достаточно понятными, поэтому прошу отписаться и рассказать, как вам показалась "на вкус" эта часть
|
|
| |
puksus | Дата: Воскресенье, 10.11.2013, 22:41 | Сообщение # 2 |
Пукс
Группа: Модераторы
Сообщений: 987
Награды: 0 +
Статус: Offline
| Идея о том, что если один пересекает область, то и все шпарят туда, мне очень понравилась.Также, можно уничтожать лежащее на поле боя оружие в случае, если количество моидов зашкаливает (оружие ведь относится к моидам, да?) И вопрос: как поведёт себя солдат, который во время перестрелки с противником получил приказ валить вниз? Забудет про соперника и будет игнорировать его стрельбу до первого попадания(или вообще всё будет игнорировать?) или сначала убьёт(если убьёт) соперника и уже потом пойдёт вниз?
Статья отличная, хватило ж терпения всё разжовывать до мелочей...
https://vk.com/beezoya
|
|
| |
Raseri | Дата: Понедельник, 11.11.2013, 00:08 | Сообщение # 3 |
Темный Клинок
Группа: Добрый Модератор
Сообщений: 756
Награды: 23 +
Статус: Offline
| >>как поведёт себя солдат, который во время перестрелки с противником получил приказ валить вниз? Сначала рыпнется выполнять новый приказ, потом увидит врага / услышит выстрел и вернётся к своему прежнему занятию, а после победы (если победит, конечно) продолжит движение
>>Также, можно уничтожать лежащее на поле боя оружие в случае, если количество моидов зашкаливает Эмм... ну да, в принципе можно, но я так никогда не делал )) Мне кажется, было бы довольно печально потерять таким образом крутые пушки, выпадающие со своих или вражеских солдат. Вполне вроде хватает ограничения по десанту для врагов.
НО если это реквест, то я напишу скрипт, мне не сложно
|
|
| |