Ил-2 Штурмовик: Битва за Британию. Скрипты. Скрипты для чайников. Часть 3 - Загрузка подмиссий
- Автор: FG28_Kodiak
- Ссылка: Перейти (перевод Google)
Скачать оригиналы миссий:
Скачать примеры с Sukhoi.ru:
В предыдущих двух миссиях мы загружали под-миссии после начала миссии-хоста. В этой части мы научимся контролировать загрузку миссиий при помощи метода public virtual void OnTickGame ()
public override void OnTickGame()
Метод OnTickGame() направляет вызовы с частотой 34 тика в секунду, в зависимости от компьютера может быть больше или меньше времени.
Например:
using System; using maddox.game; using maddox.game.world; public class Mission : AMission { public override void OnTickGame() { double WievielSekunden = 0; if (Time.tickCounter() == 334) { WievielSekunden = Time.TicksToSecs(Time.tickCounter()); GamePlay.gpLogServer (null, "Meldung nach: {0} Ticks das sind {1} sek.\n", new object [] {Time.tickCounter(), WievielSekunden}); } if (Time.tickCounter() == 667) { WievielSekunden = Time.TicksToSecs(Time.tickCounter()); GamePlay.gpLogServer (null, "Meldung nach: {0} Ticks das sind {1} sek.\n", new object [] {Time.tickCounter(), WievielSekunden}); } if (Time.tickCounter() == 1000) { WievielSekunden = Time.TicksToSecs(Time.tickCounter()); GamePlay.gpLogServer (null, "Meldung nach: {0} Ticks das sind {1} sek.\n", new object [] {Time.tickCounter(), WievielSekunden}); } } }
Данный пример ничего не делает, кроме как отправляет сообщение в чат сервера каждые 10, 20, 30 секунд.
Time.tickCounter() - содержит количество тиков, прошедших с момента начала мисиии Time.TicksToSecs - переводит такты в секунды
Далее выводим сообщение на экран:
GamePlay.gpLogServer (null, "Meldung nach: {0} Ticks das sind {1} sek.\n", new object [] {Time.tickCounter(), WievielSekunden});
В игре это будет выглядеть так:
Также вы можете использовать OnTickGame() для задания циклов, зависящих от времени, например:
using System; using maddox.game; using maddox.game.world; public class Mission : AMission { public override void OnTickGame() { double WievielSekunden = 0; if (Time.tickCounter() % 334 == 0) { WievielSekunden = Time.TicksToSecs(Time.tickCounter()); GamePlay.gpLogServer (null, "Erste Meldung: {0} Ticks = {1} sek.\n", new object [] {Time.tickCounter(), WievielSekunden}); } if (Time.tickCounter() % 509 == 0) { WievielSekunden = Time.TicksToSecs(Time.tickCounter()); GamePlay.gpLogServer (null, "Zweite Meldung: {0} Ticks = {1} sek.\n", new object [] {Time.tickCounter(), WievielSekunden}); } } }
Для вычисления остатка при целочисленном делении в языке С# используется оператор деления по модулю %. Он применяется таким же образом, что и оператор деления, но в результате вычисляется не частное, а остаток.
3%3 результат: 0 3%2 результат: 1 5%3 результат: 2
- Подробнее можно прочитать здесь: Деление с остатком )
Условие Time.tickCounter() % 334 == 0 всегда выполняется когда значениеtickCounter() равно 334 тика (то есть остаток от деления 334%334 равен нулю и отправляет сообщения в чат через каждые 10 секунд.
Условие Time.tickCounter() % 509 == 0 всегда выполняется когда значениеtickCounter() равно 509 тиков (то есть остаток от деления 509%509 равен нулю и отправляет сообщения в чат через каждые 15 секунд.
Если вы не хотите выводить сообщение в начале миссии, можете использовать задержку изменив ноль в предыдущем примере на значение меньше, чем делитель. Вот примеры неправильных условий:
if (Time.tickCounter() % 334 == 334) if (Time.tickCounter() % 334 == 335) Эти условия никогда не будут выполнены и сообщение не появится на экране.
Зададим конкретное время вывода сообщения:
using System; using maddox.game; using maddox.game.world; public class Mission : AMission { public override void OnTickGame() { double WievielSekunden = 0; if (Time.tickCounter() % 334 == 333) { WievielSekunden = Time.TicksToSecs(Time.tickCounter()); GamePlay.gpLogServer (null, "Erste Meldung: {0} Ticks = {1} sek.\n", new object [] {Time.tickCounter(), WievielSekunden}); } if (Time.tickCounter() % 509 == 508) { WievielSekunden = Time.TicksToSecs(Time.tickCounter()); GamePlay.gpLogServer (null, "Zweite Meldung: {0} Ticks = {1} sek.\n", new object [] {Time.tickCounter(), WievielSekunden}); } } }
Результат:
В основную миссию два добавим камуфляжную палатку, она появится перед исчезновением и скроет технику.
Далее нам необходима подмиссия. В ней будет один автомобиль, который проедет от одного конца ВПП до другого.
Подмиссия будет загружаться скажем каждые 30 секунд, так мы создадим колонну грузовиков, которые будут курсировать по ВПП и станут для нас отличной мишенью. Транспортные средства будут двигаться на некотором расстоянии друг от друга. В нашей миссии автомобили буду исчезать через 75 секунд - это время, которое понадобится им, чтобы достичь конечной точки пути. Игрок должен уничтожить как можно больше автомобилей. Количество машин (точнее под-миссий) будет равно 10. В этот раз мы не будем использовать триггеры, зачет результатов атаки и сведения о поврежденной технике будут содержаться в коде скрипта.
Код с тестовыми сообщениями:
using System; using maddox.game; using maddox.game.world; using System.Collections.Generic; public class Mission : AMission { AiAircraft PlayerPlane; const int MaxAnzahlWellen = 10; int AnzahlWellen = 0; int ZerstoerteZiele = 0; public override void OnBattleStarted() { base.OnBattleStarted(); MissionNumberListener = -1; PlayerPlane = (AiAircraft)GamePlay.gpPlayer().Place(); } private void serverMessage(string msg) { GamePlay.gpLogServer (null, msg, new object [] {msg}); } public override void OnTickGame() { if (Time.tickCounter() % 1000 == 0 && (AnzahlWellen < MaxAnzahlWellen)) //ca. alle 30sek die Karte laden { GamePlay.gpPostMissionLoad("missions\\Single\\Samples\\TestSubmissions\\MissionNachladen5Sub1.mis"); AnzahlWellen++; GamePlay.gpLogServer (null, "{0} nach {1} sek.\n", new object [] {AnzahlWellen, Time.TicksToSecs(Time.tickCounter())});//Testmeldung } if (Time.tickCounter() % 11500 == 0) { GamePlay.gpLogServer (null, "{0} nach {1} sek.\n", new object [] {AnzahlWellen, Time.TicksToSecs(Time.tickCounter())});//Testmeldung GamePlay.gpHUDLogCenter("Sie haben "+ ZerstoerteZiele.ToString() + " von " + AnzahlWellen.ToString() + " Fahrzeugen zerstört" ); } } public override void OnActorCreated(int missionNumber, string shortName, AiActor actor) { base.OnActorCreated(missionNumber, shortName, actor); if (actor is AiGroundActor) { Timeout(75, () => { if (actor != null) { (actor as AiGroundActor).Destroy(); } }); } } public override void OnActorDead(int missionNumber, string shortName, AiActor actor, System.Collections.Generic.List<DamagerScore> damages) { base.OnActorDead(missionNumber, shortName, actor, damages); string KilledName; KilledName = missionNumber.ToString()+ ":0_Chief"; if ((damages.Count != 0) && (PlayerPlane.Name().Equals(damages[0].initiator.Actor.Name())) && KilledName.Equals(actor.Name())) { ZerstoerteZiele++; serverMessage(ZerstoerteZiele.ToString()); } } }
Разберем код нашего скрипта. Во-первых мы используем новый метод:
using System.Collections.Generic;
В скрипте нам понадобятся следующие переменные:
AiAircraft PlayerPlane; - AiAircraft класс, в котором содержатся все доступные самолеты в игре, все самолеты за пределами этой группы являются статическими.
const int MaxAnzahlWellen = 10; - количество запусков под-миссий, в нашем случае равно кол-ву грузовиков (целей) int AnzahlWellen = 0; - кол-во уже запущенных под-миссий int ZerstoerteZiele; - количество уничтоженных целей
public override void OnBattleStarted() { base.OnBattleStarted(); MissionNumberListener = -1; PlayerPlane = (AiAircraft)GamePlay.gpPlayer().Place(); }
В методе OnBattleStarted установим MissionNumberListener = -1, чтобы иметь доступ к объектам под-миссий.
PlayerPlane = (AiAircraft)GamePlay.gpPlayer().Place(); - определяем самолет игрока. Используем для этого класс IGamePlay, в котором есть метод gpPlayer(). Указываем нужный нам класс (AiAircraft) куда входит игрок (так же он присутствует в классах AiActor, AiCart, AiAircraft..). Place() определяет текущее положение игрока. Метод gpPlayer используется только в одиночных миссиях, для мультиплеера нужно использовать метод gpRemotePlayers.
public override void OnTickGame() { if (Time.tickCounter() % 1000 == 0 && (AnzahlWellen < MaxAnzahlWellen)) //ca. alle 30sek die Karte laden { GamePlay.gpPostMissionLoad("missions\\Single\\Samples\\TestSubmissions\\MissionNachladen5Sub1.mis"); AnzahlWellen++; GamePlay.gpLogServer (null, "{0} nach {1} sek.\n", new object [] {AnzahlWellen, Time.TicksToSecs(Time.tickCounter())});//Testmeldung } if (Time.tickCounter() == 11500) { GamePlay.gpLogServer (null, "{0} nach {1} sek.\n", new object [] {AnzahlWellen, Time.TicksToSecs(Time.tickCounter())});//Testmeldung GamePlay.gpHUDLogCenter("Sie haben "+ ZerstoerteZiele.ToString() + " von " + AnzahlWellen.ToString() + " Fahrzeugen zerstört" ); MissionAbgeschlossen = true; } }
OnTickGame ()
if (Time.tickCounter() % 1000 == 0 && (AnzahlWellen < MaxAnzahlWellen)) - условие, которое загружает под-миссию, если прошло 30 секунд И (оператор &&) и номер текущей подмиссии меньше переменной const int MaxAnzahlWellen.
if (Time.tickCounter() == 11500) - если прошло 11500 тиков (то есть время, выделенное на выполнение задания - выводится итоговый результат по количеству уничтоженных целей)
public override void OnActorCreated(int missionNumber, string shortName, AiActor actor) { base.OnActorCreated(missionNumber, shortName, actor);
if (actor is AiGroundActor) { Timeout(75, () => { if (actor != null) { (actor as AiGroundActor).Destroy(); } }); } }
OnActorCreated(int missionNumber, string shortName, AiActor actor) - метод вызывается каждый раз, когда создается новый Actor.
if (actor is AiGroundActor) - проверяем, принадлежит ли Actor к классу AiGroundActor в котором содержатся все "живые" наземные объекты: автомобили, танки, корабли, артиллерия. Если условие равно TRUE выполняется соответствующий код.
Timeout(75, () => { Anweisungen }); - "отсчитываем" 75 секунд после создания Actor, далее проверяем существует ли он еще - if (actor != null). Если условия выполняются - указываем, что объект должен рассматриваться как AiGroundActor и уничтожаем объект командой .Destroy();.
.Destroy() - удаляет объект из мисии (с карты он исчезает).
public override void OnActorDead(int missionNumber, string shortName, AiActor actor, System.Collections.Generic.List<DamagerScore> damages) { base.OnActorDead(missionNumber, shortName, actor, damages); string KilledName; KilledName = missionNumber.ToString()+ ":0_Chief"; if ((damages.Count != 0) && (PlayerPlane.Name().Equals(damages[0].initiator.Actor.Name())) && KilledName.Equals(actor.Name())) { ZerstoerteZiele++; serverMessage(ZerstoerteZiele.ToString()); //Testmeldung } }
Чтобы зарегистрировать уничтоженный объект в статистике переопределим метод OnActorDead(..).
public override void OnActorDead(int missionNumber, string shortName, AiActor actor, System.Collections.Generic.List<DamagerScore> damages)
Этот метод вызывается при нанесении объекту повреждений, причем два раза - первый раз для техники, второй - для экипажа. Так как мы будем считать только уничтоженные грузовики введем переменную KilledName. Переменная будет состоять из номера миссии и имени уничтоженного объекта. Имя объекта можно найти в файле мисиии .mis:
[Chiefs] 0_Chief Vehicle.Austin_10_Tilly gb
if ((damages.Count != 0) && (PlayerPlane.Name().Equals(damages[0].initiator.Actor.Name())) && KilledName.Equals(actor.Name()))
- условие в котором определяется, что игрок уничтожил объект. Если выполняется - прибавляем к счетчику уничтоженных грузовиков еще один и выводим сообщение сервреа об этом.
- Для установки миссий-примеров скопируйте их в папку:
..\Documents\1C SoftClub\il-2 sturmovik cliffs of dover\missions\Single
Загрузка подмиссий (автор FG28_Kodiak)
Оригинальные темы см. на форуме sturmovik.de(перевод от Google):