Перейти к содержанию

Invire

Пользователь
  • Постов

    19
  • Зарегистрирован

  • Посещение

Посетители профиля

3 676 просмотров профиля

Достижения Invire

1

Репутация

  1. Да, если игрок съест предмет или тот исчезнет функцией RemoveItem, то исчезнет навсегда, а вместе с ним и скрипт, который прикреплен к нему (прекратив следовательно свое выполнение). В отличие, кстати, от функции disable - при ее вызове предмет не исчезает, а выключается из игрового мира, а скрипты на нем все еще продолжают выполняться! Я был удивлен, узнав это. В оригинальной игре есть скрипт SealedTreasuryReport на свитке с печатью, которую можно распечатать, а потом попытаться снова запечатать. Так вот, там в скрипте свиток просто дизейблится, а игроку в инвентарь добавляется новая копия. А я их выкладывал, брал обратно... Представляете, сколько теперь невидимых копий свитков болтается неизвестно где? И на каждой скрипт, который по прежнему продолжает выполняться! Пример того, как как неаккуратно написан скрипт. Чтобы полностью удалить копию объекта из игры следует использовать функцию setdelete. Как я понял, ее работа распространяется только на копии объектов, созданные во время самой игры, а не в редакторе, например, функцией PlaceItem. Функция setdelete всегда должна выполняться после того, как предмет был отключен функцией disable, и в том же скрипте одновременно с ней ничего больше не должно выполняться, а то игра вылетит. Поэтому ставим этот блок в начало, а в конце его слово return. Скрипт на объекте object: begin scr_delete_copy if ( GetDisabled == 1 ) setdelete 1;полное удаление старой копии return endif if ( onActivate == 1 ) PlaceAtMe, object, 1 0 0;создаем новую копию Disable;выключаем старую endif end Если же в редакторе была установлена хоть одна копия объекта, то удалить ее с помощью функции setdelete невозможно, даже если это и прописано в скрипте. И если создается новая копия, то игра по прежнему продолжает обращаться к старой, так как та является первой для нее.
  2. Функции deactivate в скриптовом языке ТЕС не существует, так что название темы - шутка (я решил назвать по аналогии с темой Скрипт с disable, созданной Deska). Есть пара функций enable-disable, отвечающая за включение-выключение присутствия объекта в игровом мире. Функция же activate тоже отвечает за включение, но другого рода - активацию, действие, выполняемое с объектом. Почему бы и ей не иметь своего антипода deactivate, деактивировать (я иногда путаю и пишу deactivate вместо disable). Если это дверь, контейнер или книга, то при клике на них они откроются, все остальные предметы помещается в инвентарь - все это работа функции activate. То есть момент помещения в инвентарь можно определить точно (для этого в скрипте вызываем условие onActivate == 1, внутри ставим нужной переменной нужное значение и функцию Activate). А момент выкладывания? Вот тут-то нам и поможет функция deactivate. Ну на самом деле такой функции нет)), так что мы сымитируем те действия, которые она должна выполнять, а именно определять момент выкладывания предмета из инвентаря (поскольку само выкладывание производим мы сами). Для этого необходимо прежде всего определить, что конкретный объект находится в инвентаре. Если копия объекта одна, то нет проблем ( Player -> GetItemCount, название == 1 ), а если копий несколько? Можно локальной переменной в скрипте каждой копии объекта присвоить свое уникальное значение, а можно поступить еще проще. Определить любую координату объекта (например, для координаты х это GetPos, x). Если объект находится в инвентаре, то любая его координата равна нулю. Однако тут следует иметь ввиду, что координата объекта, находящегося не в инвентаре (скажем так, в мире) на самом деле может быть равна нулю. В этом случае можно поставить проверку условия сразу на две координаты, что еще более уменьшит и без того малую вероятность совпадения координат, а еще лучше на все три - тогда в мире будет существовать всего лишь одна-единственная точка, начало координат, где координаты предмета в мире будут равны координатам объекта в инвентаре. В эту точку можно поставить камень, колонну, бочку - в общем любой неподвижный объект и перекрыть игроку доступ туда, или сделать локацию "в обход". Теперь, когда мы знаем, что предмет в инвентаре, можно обнаружить и момент выкладывания из инвентаря. Значение локальной переменной в скрипте объекта постоянно проверяется и когда при старом значении обнаруживается изменение координат с нуля на число, то значит предмет был выложен. Вот примерный скрипт: begin scr_deactivate short varBag if ( varBag == 0 );предмет в мире if ( GetPos, x == 0 ) if ( GetPos, y == 0 ) if ( GetPos, z == 0 ) set varBag to 1 endif endif endif else;предмет в инвентаре if ( GetPos, x != 0 ) if ( GetPos, y != 0 ) if ( GetPos, z != 0 ) MessageBox "Предмет выложен" set varBag to 0 endif endif endif endif end Этот скрипт запаздывает на 1 кадр, поскольку мы обнаруживаем "неладное" тогда, когда предмет уже имеет новые координаты, а значит был выложен. Однако момент взятия можно не упустить - переменной varBag можно присваивать значение 1, когда вызывается функция Activate if ( onActivate == 1 ) set varBag to 1 Activate endif но по скорости выполнения это хуже, так как в этом случае будет проверяться сразу два условия (второе, что varBag == 1 ), а не одно, как в верхнем скрипте, к тому же скрипт теряет свою красивую симметрию... Похожий принцип будет у скрипта, обнаруживающего момент выхода из режима меню (что может быть также полезно в некоторых случаях). begin scr_menu_out short varMenu if ( MenuMode == 1 ) if ( varMenu == 1 ) return else set varMenu to 1 endif else if ( varMenu == 0 ) return else MessageBox "Вы вышли из меню" set varMenu to 0 endif endif end
  3. Очень странная штука. Если два раза кликнешь на предмет который активируется, то выполняется действие, а потом, когда оно завершено, выполняется снова (если условия позволяют), как если бы ты снова кликнул на активатор. Но ты не кликал, ты в первый раз кликнул два раза и второй клик как бы получился отложенным во времени. Для третьего клика это уже не проходит. Т.е. к примеру так: дабл клик на дверь - она открывается и сразу же закрывается, как если бы ты на нее кликнул. Но для двери все нормально, а вот для некоторых активаторов нет. В чем тут дело? В написанном мной скрипте активатор кликом приводится в действие. Однако если быстро кликнуть два раза, то после завершения цепочки действий и установки переменной снова в 0, вся цепочка начинается заново, хотя ты не кликал. А по логике такого происходить не должно (onActivate = 0). Как будто второй клик запоминается и отсылается вперед во времени (причем как будто даже на любое время, именно на длительность цепочки) и в момент конца цепочки активируется. В общем мистика какая-то) Вот схематический вид скрипта. begin short var if ( var == 0 ) if ( onActivate == 1 ) set var to 1 endif endif ;далее цепочка действий if ( var == 1 ) rotate, x 10 set var to 2 endif if ( var == 2 ) move, z -10 set var to 3 endif if ( var == 3 ) set Other_object.var to 1 set var to 0 endif endТ.е. совершенно ничего особенного, движение предметов, установка флаговых переменных в других объектах - ничего связанного с анимацией персонажей. Наверное это связано с движком, но все же у меня возник вопрос, может где-то тут есть ошибка, которую я не уловил? Наконец-то я понял в чем дело!!! (год спустя, см. дату предыдущего поста))) Если, скажем так, к условию onActivate доступ ограничен, тогда запрос этого условия как бы откладывается на время, до тех пор, пока проверка этого условия снова не станет доступна. Вот, например, есть активатор и по умолчанию он бездействует, ждет, пока мы на него кликнем. Но вот мы кликнули на него, и он начал что-то делать, но пока еще не закончил и не вернулся к своему обычному положению, а мы уже снова кликнули. Этот второй клик не найдет в данный момент условия onActivate, хотя в скрипте оно есть, и в результате клик как бы отложится в память, будет ждать того момента, когда это условие снова станет доступным, и тогда-то отложенный клик сработает мгновенно. В игре это выражается в том, что мы кликнули, заработало, мы снова кликнули, ничего естественно не произошло, так как и не должно, а вот как только прекратилась работа, то сразу же начинается снова, хотя мы не кликали. Неприятная штука. Для большей ясности вот скрипт. begin scr_test short State if ( State == 0 );первый клик разумеется здесь if ( onActivate == 1 ) set State to 1 endif elseif ( State == 1 ) ;...тут какие-то действия активатора, но потом значение State снова станет равно 0 ;второй раз кликнули тут (нам достаточно времени, пока работает активатор) ;но здесь нет условия onActivate, и запрос условия как бы запоминается endif endВот как это можно исправить. Конечно, если самосрабатывание активатора не особенно тревожит, можно и не париться. Но все же. begin scr_test short State if ( State == 0 );первый клик разумеется здесь if ( onActivate == 1 ) set State to 1 endif else if ( onActivate == 1 ) ;условие есть и тут, но оно пустое ;запрос найдет его, но ничего не произойдет ;в результате повторного срабатывания не будет endif if ( State == 1 ) ;...действия активатора endif endif endПроблему можно решить и поменяв местами уровни State и onActivate, но тогда цепочка if-elseif для State разрывается... begin scr_test short State if ( onActivate == 1 ) if ( State == 0 ) set State to 1 endif endif if ( State == 1 ) ;...действия активатора endif endИ еще хочу отметить, что, к счастью, запросы, не находящие условия onActivate, не выстраиваются в очереди. Т.е. нет такого, что 3 раза кликнул когда State == 1, а потом 3 раза на автомате сработало. К счастью, только 1 раз.
×
×
  • Создать...