Войти на сайт

Авторизация, ждите ...
×

ТЕМА: Метод отсчёта времени (на примере дня и ночи)

Метод отсчёта времени (на примере дня и ночи) 11 года 9 мес. назад #53450

  • Cerberus
  • Cerberus аватар
  • Вне сайта
  • Модератор
  • Собака злая
  • Сообщений: 2269
  • Спасибо получено: 1182
  • Победитель Сбитой кодировкиОрганизатор конкурсовПроект месяца 3 местоПроект месяца 2 место3 местоПрограммист JavaScript 2 место Сбитая кодировка2 место Писатель 3 местоПроект месяца 1 место
В играх на мэйкере нередко приходится отсчитывать время до какого-нибудь значимого события. Яркие примеры: пазл, ограниченный по времени; пауза между двумя событиями, во время которой игроку даётся свобода действий. Да, для всего этого есть специальные средства – таймер, команда Wait, - но я хочу предложить на ваш суд свой способ, отличающийся от всех виденных мной тем, что его практически в неизменном виде можно приспособить к любой подобной ситуации.
Рассказывать я буду на примере такой больной для некоторых проектов темы, как смена дня и ночи. Сразу оговорюсь, что как-либо осуждать решение, применённое AnnTenn’ой в её «Легенде» и описанное здесь, я не собираюсь: у него есть такие большие достоинства перед моим, как простота реализации и малые затраты системных ресурсов. Случай смены дня и ночи мне всего лишь кажется достаточно наглядной иллюстрацией идеи, и не более.
Итак, что нам потребуется:
- 1 common event – назовём его, не мудрствуя лукаво, «день и ночь».
- 3 переменные: одна – «время до действия» (т.е., до смены времени суток), другая – «скорость», и третья, наконец, собственно время суток. Что всё это значит – объясню по ходу работы.
- а также карта, иллюстрирующая работу данной системы.
Разумеется, соответствующий проект будет приложен к данной теме.

Часть 1. Настройка параллельного эвента.
В самом начале мы создаём common event, ставим ему условие запуска Parallel process. Галочку на дополнительные условия запуска не ставим: мы же хотим, чтобы смена дня и ночи происходила постоянно?
Теперь – что происходит внутри этого эвента.
image001.png

Первый шаг – собственно, смена времени суток. Она происходит тогда, когда переменная «Время до действия» обнуляется (точнее, становится неположительной). Обратите внимание, я использовал способ сравнения below, т.е. «меньше или равно», а не «равно»; такое условие необходимо для корректной работы на разных скоростях - об этом позже. После этого мы нехитрым ветвлением проверяем состояние переменной «время суток», в зависимости от него выставляем интервал до следующей смены и новое время суток. Интервал мы выставляем в десятых долях секунды, т.е. ночь (время суток = 3) длится всего 5 секунд. На практике, конечно же, применяются значения побольше – здесь сделано так просто для наглядности.
image006.PNG

Вторая часть ивента – непосредственно отсчёт времени. Обратите внимание, что из переменной «время до действия» вычитается не константа, а другая переменная – переменная «скорость». Так как параллельный процесс выполняется циклически, а все операции, проводимые в нём, тратят пренебрежимо меньше времени, чем одна десятая секунды, то время одного повторения задаётся командой wait, установленной как раз на паузу в одну десятую секунды. Следовательно, переменная «время до действия» будет уменьшаться десять раз в секунду, и перед каждым уменьшением следует проверка, не стала ли она меньше нуля.
Особо внимательные могли заметить, что переменную «скорость» я нигде не инициализировал. Это действительно так, работу с данной переменной я отложил до того момента, когда мы будем применять ивент к конкретной карте.
На этом первая часть – работа с common event – закончена. Мы ещё вернёмся к нему в третьей части, однако основа уже готова.

Часть 2. Настройка ивента на карте.
Итак, у вас в проекте есть некая карта. Для демонстрации я создал карту минимального размера – 20х15 – пока что даже не задавая на ней никакого ландшафта.
Что нам потребуется, чтобы использовать на практике только что сделанный ивент смены времени суток? Правильно, регулировать освещённость карты в соответствии с временем. Делается это с помощью параллельного ивента, устроенного следующим нехитрым образом.
image009.png

Этот ивент работает абсолютно прямолинейно, и заострять на этом внимание мне не хочется (тем более, что он по сути такой же, как и аналогичный ивент из уже упомянутой статьи AnnTenn’ы).
Рассмотрим более интересный момент со скоростью. Как я уже говорил, инициализировать эту переменную я намерен непосредственно на карте. Зачем это нужно? Самый очевидный пример. Рассмотрим две карты: карту мира и карту отдельной локации. Очевидно, что одна клетка на той и на другой карте – это абсолютно разные расстояния по меркам мира, однако они проходятся за одно и то же реальное время. Наиболее логичный способ проиллюстрировать разницу – сделать так, чтобы на глобальной карте игровое время шло быстрее, чем на локальной. В данном случае это делается абсолютно элементарно. На глобальной карте ставим ивент с условием запуска «Автостарт» и с двумя командами: скорость=10, erase event; на локальной – такой же, но скорость=1. Разумеется, можно сделать больше градаций различия, можно сделать их другими – это не более чем иллюстрация.
В данном случае у нас глобальной карты нет, поэтому мы просто ставим скорость, равную 1.
Внимательный читатель может спросить, почему этот ивент делается автостартом, а не параллельным. Для обычной ситуации разницы нет вообще. А вот если начать добавлять различные дополнительные возможности, с параллельным ивентом (если не ставить в нём команду erase event, конечно же, - иначе он ничем не отличается от auto start) могут возникнуть проблемы, поскольку он будет влезать тогда, когда его совершенно не просят. Можно, конечно, заводить для этого специальные свитчи… но стоит ли?
Собственно, на этом с механикой покончено. Фактически, смена дня и ночи уже работоспособна, остаётся только поставить стартовую позицию и наблюдать. Тем, кто не до конца разобрался в происходящем (ежели таковые найдутся), советую последить за состоянием переменных во время процесса – при запуске из мэйкера это можно сделать нажатием F9.

(продолжение - во втором посте)
Жуть болотная, на лапках, в тапках и с пулемётом...
Последнее редактирование: 11 года 9 мес. назад от AnnTenna. Причина: поменяла иконку
Администратор запретил публиковать записи гостям.
За этот пост поблагодарили: AnnTenna, Kolhe

Re: Метод отсчёта времени (на примере дня и ночи) 11 года 9 мес. назад #53451

  • Cerberus
  • Cerberus аватар
  • Вне сайта
  • Модератор
  • Собака злая
  • Сообщений: 2269
  • Спасибо получено: 1182
  • Победитель Сбитой кодировкиОрганизатор конкурсовПроект месяца 3 местоПроект месяца 2 место3 местоПрограммист JavaScript 2 место Сбитая кодировка2 место Писатель 3 местоПроект месяца 1 место
Часть 3. Оживляем карту.
Разумеется, на обычной водной глади смена дня и ночи выглядит не особо интересно. В принципе, я могу бы сейчас начать реализовывать целое микропоселение, каждый житель которого имеет свой распорядок дня, однако это уже достаточно хорошо сделала AnnTenna. Я же заострю внимание на нескольких фичах, которые относительно легко реализуются в данной механике.
Для начала, впрочем, есть смысл всё-таки сделать небольшой населённый пункт, в котором будут реализованы все эти возможности. Маппер из меня не ахти, так что в итоге получилось вот что.

Как видите, здесь имеются три НПЦ, каждый из которых реализует определённую возможность.
Самое простое – это девушка возле дома. Пообщавшись с ней, герой удалится вместе с ней в дом, после чего время пойдёт гораздо быстрее.

Что происходит в этом ивенте? Первая его страница активируется, когда герой подходит к девушке и заговаривает с ней (клавишей выбора), при этом активируется свитч №1, и вместе с ним запускается основная, вторая, страница.
На второй странице графика девушки и героя заменяется на прозрачную («ушли в дом»), после чего параметр «скорость» становится равным 5 и остаётся таковым до нажатия произвольной клавиши (Wait: ForKeyPress), после чего всё возвращается, как было изначально. Аналогичным образом можно реализовать и замедление времени – только тогда придётся изначально скорость ставить больше единицы, т.к. дробных значений в RM2k3 не предусмотрено.
Для реализации двух других особенностей потребуется немного подправить параллельный ивент. Рассмотрим сначала волшебницу в правом нижнем углу.

При разговоре с ней можно остановить или снова запустить время, а также сделать время суток таким, как тебе хочется. Заметьте, что время суток ставится не напрямую, а косвенно – через установку предыдущего времени суток и нулевого оставшегося времени. Если просто установить значение переменной «время суток» на нужное вам, то получится, что до конца нового, только что установленного времени суток останется столько же шагов параллельного эвента, сколько оставалось бы до конца имевшегося, что не всегда желательно (хотя, если с таким побочным эффектом можно смириться - может быть смысл делать "в лоб").
Для остановки, в свою очередь, требуется скорректировать параллельный эвент. Вся конструкция параллельного эвента теперь помещена под одно условие: если время не остановлено, т.е. если сброшен свитч номер 3, устанавливаемый в диалоге с волшебницей. Если же оно остановлено (свитч поставлен), то параллельный ивент исполняться не будет.
Внимательные читатели могут меня сейчас поправить – получается, что при остановленном времени предыдущий эвент с той же самой волшебницей, устанавливающий время суток, не будет работать корректно! Да, это действительно так, и я могу предложить два варианта решения. Первый – указанный выше – напрямую установить время суток при обращении к волшебнице, без работы с таймером. Второй, возможно, более изящный: поместить под условие «Время не остановлено» только сам таймер:

Если сделать таким образом, то времена суток будут меняться параллельным ивентом в любом случае при обнулении таймера, но, если стоит свитч «время остановлено», таймер не будет уменьшаться «своим ходом». В некоторых случаях есть смысл поступить наоборот: поместить под условие только действия при обнулении таймера. Тогда при снятии блокировки необходимое действие может произойти моментально.
Ещё один, возможно, даже более простой вариант остановки времени – банальная установка скорости на 0. В этом случае не потребуется никакой правки параллельного процесса, зато понадобится делать более разветвлённую конструкцию диалога с волшебницей, а именно, делить ветку «Остановить/запустить время» на две в зависимости от того, нулевой или ненулевой является скорость. Однако я предпочитаю такой вариант, какой указан здесь; почему – скажу чуть позже.
И третий ивент – с мужчиной у гексаграммы.
У самого мужчины я никаких действий не ставил – только вывод сообщения. Действие (причём совершенно элементарное) помещено непосредственно на гексаграмму:

а на клетки вокруг неё помещены ивенты, сбрасывающие этот свитч.
Теперь добавляем нехитрую конструкцию всё в тот же параллельный ивент:

Теперь, наступив на гексаграмму, мы услышим частые щелчки – если быть точным, десять раз в секунду, как и изменение таймера. Заметьте, что при остановленном времени, т.е. тогда, когда не работает таймер, нет и звукового эффекта – что вполне согласуется со словами мужчины о «звуке Небесных Часов», слышном с этого места. Сойдя же с гексаграммы, мы слышать эти щелчки перестанем, поскольку свитч будет сброшен. Таким же образом можно реализовать любые периодические события, привязанные к этому же таймеру – разумеется, с частотой не менее одной десятой секунды, поскольку меньше RM2k3 просто не поддерживает.
Но, допустим, нам нужно, чтобы что-то происходило не каждую десятую долю секунды, а реже. Оказывается, есть способ сделать событие, происходящее через любой интервал, на том же самом таймере. Для примера давайте сделаем Небесные часы посекундными.
Исправления потребует только параллельный процесс – правда, универсальное решение довольно-таки нетривиально.

Действует эта конструкция следующим образом. Переменная «кратность скорости» - это период между двумя событиями в десятых долях секунды при скорости 1, делённый на скорость. Именно здесь и может ждать очевидный подвох при остановке времени методом обнуления скорости. Далее текущее значение таймера (скопированное в переменную «доли секунды») делится с остатком на «кратность скорости» и берётся остаток (операция Mod), и этот остаток, в свою очередь, сверяется с нулём. Совпадение и означает требуемый шаг. В данном случае, правда, надо быть осторожным: если период события может не делиться на скорость (к примеру, если бы в доме время ускорялось не в 5, а в 3 раза), то большая часть периодических событий не сработает; и если период сброса счётчика (в данном случае – смены времени суток) не делится на частоту события, то при сбросе период между событиями будет меньше.
Если частота события не должна зависеть от скорости игрового времени, то изменение ещё больше упрощается: убирается переменная «кратность скорости», вместо неё в выражение с Mod подставляется необходимая константа.

Какие ещё возможны варианты? Например, если есть желание облегчить параллельный эвент, мало теряя в гибкости конструкции, можно сделать счётчик не по десятым долям секунды, а по секундам: для этого просто надо заменить Wait:0.1 sec на Wait:1.0 sec и соответствующим образом установить счётчики. Кроме того, аналогичную систему можно использовать для обратного отсчёта времени перед некоторым событием – для этого потребуется один эвент, построенный по рассмотренной можели, один свитч, запускающий этот эвент и вместе с ним обратный отсчёт, и счётчик, который перед запуском эвента можно инициализировать любым значением. После этого получившуюся конструкцию можно использовать в очень широком интервале возможных значений без каких-либо изменений; фактически, имеется эвентовая реализация таймера.
И ещё много-много случаев, когда нам могут не помешать собственноручно сконструированные часы :)

Ну и, наконец, обещанная демка.
narod.ru/disk/56032921001.8dcfbcc823b2ba...acca2/Clock.zip.html
Готов выслушать, где я был неправ :)
Жуть болотная, на лапках, в тапках и с пулемётом...
Последнее редактирование: 11 года 9 мес. назад от Cerberus. Причина: вроде выкрутился)))
Администратор запретил публиковать записи гостям.
За этот пост поблагодарили: Lekste, Kolhe

Re: Метод отсчёта времени (на примере дня и ночи) 11 года 9 мес. назад #53452

  • Lekste
  • Lekste аватар
  • Вне сайта
  • Светлый дракон
  • Сообщений: 911
  • Спасибо получено: 565
  • ОраторДаритель СтимкеяПрограммист JavaScript ВетеранПрограммист Ruby
Хороший урок. Думаю начинающим "мэйкеристам" он очень поможет.
Администратор запретил публиковать записи гостям.

Re: Метод отсчёта времени (на примере дня и ночи) 11 года 9 мес. назад #53459

  • AnnTenna
  • AnnTenna аватар
  • Вне сайта
  • Администратор
  • ловлю волны настроения
  • Сообщений: 4542
  • Спасибо получено: 4690
  • Коммерсант3 место2 место ГотвОрганизатор конкурсовПобедитель Сбитой кодировкиПроект года 2 местоПроект месяца 2 местоПроект месяца 1 местоРазработчикУчитель
Интересная статья. Жалко, что вложения не сработали и картинки..при том в первой сработали а во второй нет..и это странно. Известно, что форум не поддерживает вложения с русскими названиями, может, это из за этого. Ну в общем это нужно поправить. А там где идет отсылка на мою статью, то можно сделать ссылку при первом упоминании, чтобы людям было удобнее, если они захотят посмотреть не искать. :)

Администратор запретил публиковать записи гостям.
За этот пост поблагодарили: Cerberus

Re: Метод отсчёта времени (на примере дня и ночи) 11 года 9 мес. назад #53460

  • Cerberus
  • Cerberus аватар
  • Вне сайта
  • Модератор
  • Собака злая
  • Сообщений: 2269
  • Спасибо получено: 1182
  • Победитель Сбитой кодировкиОрганизатор конкурсовПроект месяца 3 местоПроект месяца 2 место3 местоПрограммист JavaScript 2 место Сбитая кодировка2 место Писатель 3 местоПроект месяца 1 место
Есть вроде ссылка... забыл, что ли? (на слове "здесь") За русские названия - спасибо, совсем забыл :) Хотя странно, почему бы из-за этого сервер выдавал ошибку 500 :unsure:
Жуть болотная, на лапках, в тапках и с пулемётом...
Администратор запретил публиковать записи гостям.

Re: Метод отсчёта времени (на примере дня и ночи) 11 года 9 мес. назад #53461

  • Lekste
  • Lekste аватар
  • Вне сайта
  • Светлый дракон
  • Сообщений: 911
  • Спасибо получено: 565
  • ОраторДаритель СтимкеяПрограммист JavaScript ВетеранПрограммист Ruby
Cerberus пишет:
Хотя странно, почему бы из-за этого сервер выдавал ошибку 500
Может по этой причине:
Скрипт возвращает HTTP-заголовки, которые веб-сервер не может распознать и не понимает как интерпретировать. ?
Или вот это: Также к ошибке иногда приводит использование инструкций от Russian Apache. :)
Последнее редактирование: 11 года 9 мес. назад от Lekste.
Администратор запретил публиковать записи гостям.

Re: Метод отсчёта времени (на примере дня и ночи) 11 года 9 мес. назад #53462

  • Cerberus
  • Cerberus аватар
  • Вне сайта
  • Модератор
  • Собака злая
  • Сообщений: 2269
  • Спасибо получено: 1182
  • Победитель Сбитой кодировкиОрганизатор конкурсовПроект месяца 3 местоПроект месяца 2 место3 местоПрограммист JavaScript 2 место Сбитая кодировка2 место Писатель 3 местоПроект месяца 1 место
Lekste, ну хз, я тут не мастер... Переименование не помогло, к слову, пришлось сторонними ресурсами воспользоваться.
Жуть болотная, на лапках, в тапках и с пулемётом...
Администратор запретил публиковать записи гостям.

Re: Метод отсчёта времени (на примере дня и ночи) 11 года 9 мес. назад #53478

  • Kolhe
  • Kolhe аватар
  • Вне сайта
  • Просветлённый
  • Сообщений: 348
  • Спасибо получено: 171
  • 2 место
Да делайте же вы уже освещение через панарамы, госпааади. Понимаю что урок не об этом, но смотрение на это ужастное желтое освещение, вырывает мои глаза...
Администратор запретил публиковать записи гостям.

Re: Метод отсчёта времени (на примере дня и ночи) 11 года 9 мес. назад #53488

  • Cerberus
  • Cerberus аватар
  • Вне сайта
  • Модератор
  • Собака злая
  • Сообщений: 2269
  • Спасибо получено: 1182
  • Победитель Сбитой кодировкиОрганизатор конкурсовПроект месяца 3 местоПроект месяца 2 место3 местоПрограммист JavaScript 2 место Сбитая кодировка2 место Писатель 3 местоПроект месяца 1 место
Kolhe, опс, а это как? (в RM2k3, если что, с новыми не особо работал)
Жуть болотная, на лапках, в тапках и с пулемётом...
Администратор запретил публиковать записи гостям.

Re: Метод отсчёта времени (на примере дня и ночи) 11 года 9 мес. назад #53491

  • Kolhe
  • Kolhe аватар
  • Вне сайта
  • Просветлённый
  • Сообщений: 348
  • Спасибо получено: 171
  • 2 место
Всмысле через картинки, опечатался.
Создаем карту, делаем скриншот, загружаем в фотошоп или любой другой аналогичный редактор.
На новом слое, кистью, с параметрами как на скриншоте, делаем мазки.
ВНИМАНИЕ: Спойлер! [ Нажмите, чтобы развернуть ]

У меня будет два предмета света - святой крест, и огонек. Делаю мазки на этих предметах, цветами на несколько тонов выше и непрозрачнее, чем хочу в результате. Лишнее, там где мазки зашли за стены, стираем.
ВНИМАНИЕ: Спойлер! [ Нажмите, чтобы развернуть ]

Слой с скриншотом карты заливаем цветом который будет общей гаммой освещения. Так моя карта - подземелье, я все заливаю черным, объеденяю слои, меняю колор мод и сохраняю в png.
Возвращаюсь в мейкер, импортирую изовбражение в Picture, создаю паралельное событие в котором вывожу наш свет ровно по центру, а также добавляю прозрачности.
ВНИМАНИЕ: Спойлер! [ Нажмите, чтобы развернуть ]

И, конечный результат:

Еще примеры:
ВНИМАНИЕ: Спойлер! [ Нажмите, чтобы развернуть ]
Последнее редактирование: 11 года 9 мес. назад от Kolhe.
Администратор запретил публиковать записи гостям.
За этот пост поблагодарили: Cerberus

Re: Метод отсчёта времени (на примере дня и ночи) 11 года 9 мес. назад #53492

  • Cerberus
  • Cerberus аватар
  • Вне сайта
  • Модератор
  • Собака злая
  • Сообщений: 2269
  • Спасибо получено: 1182
  • Победитель Сбитой кодировкиОрганизатор конкурсовПроект месяца 3 местоПроект месяца 2 место3 местоПрограммист JavaScript 2 место Сбитая кодировка2 место Писатель 3 местоПроект месяца 1 место
Хм, спасибо, об этом я даже и не задумывался :)
Жуть болотная, на лапках, в тапках и с пулемётом...
Администратор запретил публиковать записи гостям.
Время создания страницы: 0.248 секунд