Forum.iFiction.Ru

iFiction.Ru · ifHub · FAQ · IFWiki · QSP · URQ · INSTEAD · AXMA

форум об interactive fiction, текстовых приключенческих играх и всём таком...

Вы не зашли.

   #26
02.09.2018 21:54

Антон Ласточкин
Участник (+243, -5)
Зарегистрирован: 18.09.2015
Сообщений: 117

Re: Игра пример

kepra, не читал всю переписку, но хочу немного поделиться по поводу крайнего вопроса. TADS далеко не СИ, хотя синтаксис похож. Обработчик глагола (doAction) и верификатор (verDoAction) проверяются системой, если в системе определён соответсвующий глагол (надо почитать главу "Создание новых команд" http://rtads.org/man/TADSADV.HTM#usingpredef). Посмотрим на глагол take, в advr.t есть определение:

Код:

takeVerb: deepverb
     ...
     doAction = 'Take'

Это значит, что во всех объектах сцены будет сначала проверяться прямой верификатор, со строгим синтаксисом -
verDoTake(actor) и если он не выдаёт строки, то будет срабатывать метод doTake(actor).
Аргумент actor подставляет сама система. Например, ты вводишь команду "взять череп", тогда подставляется вместо actor объект главного героя Me. Если написать "пьедестал, возьми череп", то тогда (если бы он был живым и разрешалось командовать), вместо actor подставился бы этот объект.
Все это к чему, надо понимать глагол какого типа используется и какой синтаксис верификаторов и реакций применять, иначе движок может отвалиться или проигнорирует объявление метода.

Неактивен

   #27
02.09.2018 22:46

Nikita
Модератор (+321, -105)
Зарегистрирован: 29.10.2016
Сообщений: 104

Re: Игра пример

Kephra написал:

Мне понятно, что первый аргумент в doTake это actor (смотрел код doTake в advr.t), но разве мы вот таким способом передаём???

Я ещё раз повторяю, в doTake разработчик игры ничего не передаёт, он вообще не контролирует этот процесс. Разработчик всего лишь переопределяет метод, для которого есть установленный интерфейс вызова, отхождение от которого приведёт к неизбежной ошибке.

В стандартной библиотеке объявлен объект "глагола" (действия) с названием Take, в результате чего движок во всех объектах игрового мира ожидает встретить два метода: verDoTake для верификации возможности действия и doTake для осуществления действия в случаи положительной верификации. При вызове этих методов в объекте предмета, к которому пытаются применить данный "глагол", движок передаёт им в аргументе объект персонажа, выполняющего это действие. В стандартном случае это объект главного героя по умолчанию, то есть Me, в нестандартном случае любой другой персонаж, если в игре это специальным образом реализовано.

Методы verDoTake и doTake наследуются объектами от своих родителей. TADS - это язык с суперклассами, так что в объекте и его прямом родителе в явном виде какого-то метода может не быть, а работать будет метод у родителя через несколько уровней наследования, где он определён явным образом. Существует общий класс thing, от которого наследованы практически все классы и объекты стандартной библиотеки для моделирования мира (базовый класс ещё выше - object, но в моделировании мира он напрямую не применяется). В отдельных классах verDoTake и doTake явно переопределены, чтобы изменить поведение по умолчанию, например, в классе fixeditem, предназначенном для создания фиксированных объектов, типа стены или дома. Там на уровне verDoTake блокируется попытка взять такой фиксированный предмет.

Когда вы в черепе начинаете работать с verDoTake или doTake, равно как и с любым наследованным методом, вы всего лишь переопределяете его тело, то есть тот код, который будет выполняться при его вызове. Интерфейс вызова вы никак не переопределяете, вернее не должны переопределять, если не хотите получить ошибки. Движок как ожидал, что в любом объекте метод действия будет готов от него принять объект персонажа, так и ожидает, с учётом чего и вызывает doTake с одним аргументом, в который передаёт объект персонажа

Код:

class printer: object
    print(msg) =
    {
        say(msg);
    }
;

messager: printer
;

Если для такого кода вызвать messager.print('Hello World!'), то сработает метод print, определённый в его родителе. В этом и суть ООП, что нам не нужно явно определять методы и свойства объектов, если они уже определены у их родителей и не требуют модификации. Мы можем явно переопределить метод print в объекте messager, чтобы, например, не просто печатать текст, а печатать его курсивом, но если вся система заточена на интерфейс вызова из одного аргумента в виде строки, то менять его в переопределённом методе не нужно, чтобы ничего не поломать, можно просто менять процедуры обработки внутри метода.

Проще говоря, работая с doTake в любом объекте мира, вы должны писать

Код:

doTake(actor) =
{
    // ...
}

И всё, просто на текущем этапе примите это как данность, если пока нет полного понимания. Можете делать разные дополнительные вещи внутри метода, типа проверки условий на поражение, но интерфейс вызова не трогайте. Если сильно хочется, вы можете вместо actor написать другой локальный идентификатор, но объект, который будет доступен по этому идентификатору внутри блока doTake, вы всем этим никак не измените. Все остальные попытки шаманить с аргументами doTake ни к чему хорошему не приведут.

Чтобы создать условия, когда в метод действия будет приходить какой-то другой объект, а не Me, нужно проделать довольно большую предварительную работу. Для этого либо нужно создать дополнительного персонажа игры, который через метод actorAction в своём объекте будет принимать от вас приказы и их исполнять, вызывая соответствующие методы действий в объектах мира, типа "слуга, возьми череп", либо же также создать ещё одного персонажа, а потом через функцию switchPlayer() реализовать переключение игры между стандартным Me и этим вторым персонажем по какой-то команде или событию, чтобы можно было играть сначала за одного, а потом за другого (например, есть игра "Комбикорм", где прохождение как раз осуществляется от лица трёх персонажей, между которыми надо переключаться). Вот в этих случаях в doTake начнёт движком передаваться другой объект, но не потому, что вы что-то измените в объявлении данного метода, а потому, что реально действие будет выполняться иным персонажем.

Лучше чётко опишите то, что именно вы хотите реализовать в игре, пытаясь шаманить с аргументами методов действий. Вам просто объяснят, как именно это сделать правильно, и это будет намного продуктивнее и нагляднее.

Неактивен

   #28
02.09.2018 23:31

Kephra
Участник (+1, -1)
Откуда: Украина
Зарегистрирован: 04.04.2011
Сообщений: 46

Re: Игра пример

То есть, даже если я захочу передать в doTake другой объект вместо актёра, например камень, (smallRock), просто вписав его в аргументы doTake, то это не произойдёт? Система создаст локальную переменную/объект smallRock в которой всё равно будут данные объекта персонажа, поскольку таков шаблон в advr.t. Собственно, чтобы doTake принимал отличный от actor аргумент/ты, надо править этот шаблон и его родителя. Я не собираюсь пока подобным заниматься. Но это даёт мне понимание, — как устроена логика языка. От того, я и пробую игрушку на вкус, на прочность, в общем делаю всякие на первый взгляд бестолковые вещи.

Лучше чётко опишите то, что именно вы хотите реализовать в игре, пытаясь шаманить с аргументами методов действий. Вам просто объяснят, как именно это сделать правильно, и это будет намного продуктивнее и нагляднее.

Мы пока учимся, а о замыслах — потом.

Отредактировано Kephra (03.09.2018 01:39)

Неактивен

   #29
03.09.2018 01:27

Nikita
Модератор (+321, -105)
Зарегистрирован: 29.10.2016
Сообщений: 104

Re: Игра пример

Kephra написал:

То есть, даже если я захочу передать в doTake другой объект вместо актёра, например камень, (smallRock), просто вписав его в аргументы doTake, то это не произойдёт? Система создаст локальную переменную/объект smallRock в которой всё равно будут данные объекта персонажа, поскольку таков шаблон.

Да, именно так. Как создать условия для передачи иного персонажа я написал в предыдущем сообщении.

В общих чертах под капотом происходит следующее:

Движок принимает из интерфейса интерпретатора команду "взять череп", раскладывает её на лексемы, определяет, что нужно выполнить действие, у которого есть название "взять" в отношении объекта, у которого есть название "череп". После этого движок смотрит, какое внутреннее название у действия "взять" и выясняет, что это Take. Затем в объекте с названием "череп" из текущей локации движок вызывает метод verDoTake, отправляя ему в качестве аргумента объект текущего персонажа. Если при вызове verDoTake в объекте с названием "череп" ничего не происходит, а именно вывода на экран, то движок считает, что выполнению действия ничего не мешает, так что вызывает уже doTake, также отправляя ему в качестве аргумента объект текущего персонажа.

Можно, например, в череп вписать такое:

Код:

verDoTake(actor) =
{
    "А морда у <<actor.rdesc)>> не треснет? ";
}

Здесь мы модифицируем метод-верификатор, который теперь будет выводить текст, а значит блокировать выполнения действия взятия. Если посмотреть в код класса fixeditem, то именно по такому принципу и реализована невозможность взять пьедестал вместе с черепом.

Если у вас в игре два персонажа, у одного из которого не треснет, а у другого таки да, может треснуть, то как раз передаваемый actor позволит нам проверить, кто из них вызывает действие и либо разрешить, либо запретить. На этот случай движок и построен таким образом, чтобы всегда в метод действия передавать персонажа. Ну или просто по объекту персонажа можно дотянуться до его содержимого. Например, если бы у нас в игре был щит, то можно было бы по actor внутри doTake проверить инвентарь персонажа и, если есть, то увести на ветку pass, а если нет, то на ветку die().

Важно понять, что объявление метода не является его вызовом.

Код:

test: object
    message(string) =
    {
        say(string);
    }
;

Здесь объявляется метод message, но не вызывается. Вызов - это строка с функцией say(), но она выполнится только если где-то кто-то вызовет метод как test.message('Hello World!').

Вы, вероятно, путаете объявление метода с его вызовом. Если опустить некоторые нюансы, то вызов метода или функции может происходить только внутри блоков, очерченных фигурными скобками, а то, что само создаёт блок с фигурными скобками - это не вызов, а объявление, то есть создание возможности вызвать.

Объявляя внутри объекта метод doTake(actor), вы всего лишь говорите: "Ну OK! Если кто-нибудь захочет в этом объекте вызвать метод с названием doTake, то я в принципе готов это обработать, ну а то, что вы мне в него передадите, я внутри этого метода буду называть actor".

Неактивен

Powered by PunBB
© copyright 2001–2018 iFiction.Ru