Форум » » Продвинутые возможности QSP-языка » Ответить

Продвинутые возможности QSP-языка

luciofulci: Во-первых, хотелось бы поблагодарить создателя движка за отличную работу. Впечатляет, без смайлов! Но, во-вторых, к сожалению, бросается в глаза некоторая несбалансированность самого языка. Например, отсутствует поддержка функций, определенных пользователем (про объекты, которые значительно облегчают написание сколько-нибудь сложных игр я не говорю...). Эта ограниченность приводит к необходимости использовать обходные пути, использовать локации и инвентарь явно не по назначению и т.д., что в дальнейшем затрудняет понимание и редактирование собственного кода :( Разумеется, это объясняется тем, что язык рассчитан в идеале для людей, слабо разбирающих в программировании, но при этом присутствует такая продвинутая фича, как динамическая генерация кода, для адекватного использования которой требуется серьезный опыт кодинга. Хотелось бы задать вопрос - будет ли язык развиваться в плане добавления новых возможностей, таких как функции и классы? Заранее спасибо за ответ!

Ответов - 72, стр: 1 2 3 4 All

Byte: Функций и классов не будет, думаю. Конструкции вида [pre2] свойство1["предмет"]=56 $свойство2["предмет"]='sdsd' свойство1[$obj]=234[/pre2] позволяют легко обходиться без классов, предоставляя бОльшую гибкость. Функции добавят такое понятие, как "локальные переменные". Возможно, появятся оператор добавления значений на стек и ф-я получения значения со стека. Но, в абсолютном большинстве случаев, легко обойтись без локальных переменных, так что не вижу особого смысла их вводить.

luciofulci: Спасибо за ответ :) Обойтись можно, конечно :) Сейчас язык позволяет реализовать практически все, что только может в голову прийти :) ПыСы. А что, локальные переменные - это такое ЗЛО? :)

Nex: luciofulci локальные переменные заставят новичков печься о таких понятиях, как "область видимости", а это усложнит им жизнь => вредно. Если движок у игры "с хитростями", то поможет GOSUB, а если не поможет GOSUB, поможем мы, то есть этот форум. Новички - приоритет, и это всё решает.


luciofulci: Само введение функций, классов и т.д. не означает необходимость их использования. Например, динамическая генерация кода ("код как данные") - это концепция уровнем гораздо выше, чем область видимости, но тем не менее в QSP она есть и никому не мешает. Тот же объектно-ориентированный подход органично вписывается в разработку игр, так в них мы имеем дело с большим количеством объектов, таких как магазины, персонажи и т.д. Все это в рамках движка не предусмотришь. Повторюсь, сделать все это возможно и без классов с функциями, но вот реализация будет связана с трехэтажными хаками, write-only кодом и копипастом, когда чтобы поправить какую-то мелочь, нужно править ее в десятке мест. Проще ли это для новичков, чем локальные переменные? Не уверен.

Byte: я не понимаю, зачем нужны классы, когда есть более лёгкое в освоении и с не меньшими возможностями/удобством: [pre2] свойство1["предмет"]=56 $свойство2["предмет"]='sdsd' свойство1[$obj]=234[/pre2] любой класс можно описать через это, вместе с наследованием (насколько это возможно без локальных переменных). "объекты" передаются посредством их имени.

Byte: luciofulci пишет: Повторюсь, сделать все это возможно и без классов с функциями, но вот реализация будет связана с трехэтажными хаками, write-only кодом и копипастом, когда чтобы поправить какую-то мелочь, нужно править ее в десятке мест. Да нет здесь "трёхэтажных хаков". И копипаста можно успешно избежать :-)

luciofulci: В принципе, типы вполне можно реализовать через массивы со строковыми индексами. Классы используются именно для упрощения организации кода, когда, например, чтобы изменить поведение всех НПС определенного вида нужно изменить пару строк в определении этого вида, и все. Разумеется, для небольших проектов это абсолютно избыточная идея, да, но вот в более-менее сложных они серьезно облегчают жизнь. К тому же повторюсь, ООП - органично вписывается в написание игр, так, что с новичками проблем быть не должно, если в этом дело. Конечно, у меня нет никакого права никому ничего советовать, только размышлять об идеальном сферическом движке в вакууме :(. Хотя вот сейчас пишу игру на QSP, так вот по мере написания могу более четко сформулировать свои предложения - если это интересно, конечно.

Byte: А "функции" с параметрами, возможно, будут в QSP 5.5 :) Будет gs 'proc',2,3,4,'test',$sdsd При этом заполняется массив 'args' args[0]=2 args[1]=3 args[2]=4 $args[3]='test' $args[4]='fddfd' Функции - eval('proc',2,4) Результат из ф-и передаётся н-р через переменную $result

luciofulci: Поясню, что понимаю под хаком. Это когда элементы языка явно используются не по назначению. Например, в одной дружественной платформе локации используются для всего чего угодно - например, для организации циклов :) Это разрушает абстракцию и нарушает стройность дизайна. Локация - это локация. Это некоторое место, которое игрок посещает, а не просто несколько строк кода. В куспе добавлены метки и одна эта фича уже позволяет локациям избежать подобного "насилия". Ну, вот что-то в этом духе...

luciofulci: Byte пишет: А функции с параметрами, возможно, будут в QSP 5.5 :) Будет gs 'proc',2,3,4,'test',$sdsd При этом заполняется массив 'args' args[0]=2 args[1]=3 args[2]=4 $args[3]='test' $args[4]='fddfd' Круто При таком раскладе без классов вполне можно будет обойтись :)

Byte: Передать несколько параметров в gs и сейчас не сложно )

luciofulci: Ну, не сложно то не сложно, только геморно немного и выглядит довольно жутко. Да и использовать локацию в качестве функции,... гм. Кстати, не рассматривается возможность передачи DYNAMIC параметров в том же виде, что и GOSUB? В смысле что-то типа dynamic $code_block, arg1, arg2, arg3... соответственно с заполнением массива args?

HIman: Вы ребята что-то страшное решили сотворить на куспе... а на самом деле тех же локаций и переходов порой бывает достаточно для полноценной игры.

Byte: Сделал аргументы для GS. Правда, увидеть это можно будет только в след. версии.

Nex: Byte как насчёт передачи по ссылке?

luciofulci: HIman пишет: Вы ребята что-то страшное решили сотворить на куспе... Сейчас готовлю небольшой тутор для реализации классов на куспе, создание класса с полями и методами, создание экземпляров класса, наследованием :) Все это можно осуществить на нынешней версии QSP, правда код явно не для слабонервных Byte пишет: Сделал аргументы для GS. Правда, увидеть это можно будет только в след. версии. А нельзя ли поделиться development билдом?

Nex: Классы будут, функции будут, поля и методы, наследование будет, а игра-то будет? Или как всегда? Куча кода, игры нет?

luciofulci: Поменял название темы :) Допустим у меня есть множество игровых объектов, у которых есть несколько свойств: name, description, seen, а также метод show_description для вывода описания. Ничего особенного. Можно реализовать это в виде массива: $old_table['name'] = "Cтарый стол" old_table['seen'] = 0 $old_table['description'] = "Массивный стол с потрескавшейся лакировкой." $old_table['show_desc'] = "$old_table['seen'] = -1 & clear & p old_table['show_desc'] & goto $curloc" Теперь, например, можно добавить в окно описания локации следущий текст, не забыв где-то вначале активировать USEHTML: <a href="exec:dynamic $old_table['show_desc']">старый стол</a> Или добавить действие, в теле которого просто написать: dynamic $old_table['show_desc'] Когда игрок кликнет на эту ссылку или нажмет на кнопку действия, он увидит в окне дополнительного описания описание старого стола, а локация перезагрузится на тот, случай, если в ней, допустим, есть проверка на то, осмотрел ли игрок стол. Допустим, у меня в игре штук 20 таких объектов и меня возникает два естественных желания - упростить процесс их создания и, главное, иметь возможность контролировать формат вывода описания где-то в одном месте. Первое решается частично с учетом существующих возможностей языка (полностью - когда будет введена возможность передачи аргументов в gs), второе (и главное) уже сейчас решается полностью. Подробнее - в следующем сообщении.

luciofulci: Окей, вот как выглядит код локации-подпрограммы, создающей подобные объекты: $self = $args[0] dynamic "$<<$self>>['name'] = $args[1]" dynamic "$<<$self>>['desc'] = $args[2]" dynamic "<<$self>>['seen'] = 0" $show_desc = "<<$self>>['seen'] = -1 & clear & p $<<$self>>['desc'] & gt $curloc" dynamic "$<<$self>>['show_desc'] = $show_desc" $show_desc = "" & $self = "" Код, создающий локации в нынешней версии, выглядит так: $args[0] = "old_table" $args[1] = "Старый стол" $args[2] = "Массивный стол с потрескавшейся лакировкой." gs "make_item" В будующей версии все будет несколько проще: gs "make_item", "old_table", "Старый стол", "Массивный стол с потрескавшейся лакировкой." Допустим, я создал с десяток таких объектов и захотелось мне, чтобы show_desc включал в себя название объекта. Я беру код локации make_item и заменяю $show_desc = "<<$self>>['seen'] = -1 & clear & p $<<$self>>['desc'] & gt $curloc" на $show_desc = "<<$self>>['seen'] = -1 & clear & pl $<<$self>>['name'] & p $<<$self>>['desc'] & gt $curloc" То есть изменяю одну строку кода в одном месте, а не в десяти.

luciofulci: По поводу игры - для меня именно эта возможность стала узким местом, реализовать я ее сумел только после долгого, вдумчивого чтения хелпа и бесчеловечных опытов над dynamic'ом. Если кому интересно, могу пояснить, что вся эта тарабарщина значит и как самому делать подобные штуки, например, для генерации врагов и прочих неписей. До генерации локаций я еще не дошел - просто мне это на данный момент не нужно.

Byte: А не проще ли сделать так: #showDesc p $desc[$o] seen[$o]=-1 ! ... -- #makeObj $name[$o]=$o $desc[$o]=$d seen[$o]=0 -- Добавляем предметы так: $o='ящик' & $d='обычный ящик' & gs 'makeObj' Показываем описания через $o='ящик' & gs 'showDesc' То есть, зная имя предмета, можно вызвать единственный метод показа описания. Дублировать код показа также не нужно, он находится в одном месте для всех предметов.

luciofulci: Можно и так. Но мне просто не нравится множить служебные локации, так как с каждой функцией (методом) необходимо создавать новую локацию. Но это как кому нравится :)

Byte: Даже в этом случае [pre2] $self = $args[0] dynamic "$<<$self>>['name'] = $args[1]" dynamic "$<<$self>>['desc'] = $args[2]" dynamic "<<$self>>['seen'] = 0" $show_desc = "<<$self>>['seen'] = -1 & clear & p $<<$self>>['desc'] & gt $curloc" dynamic "$<<$self>>['show_desc'] = $show_desc" $show_desc = "" & $self = ""[/pre2] заменяется на более простое [pre2] $self=$args[0] $name[$self]=$args[1] $desc[$self]=$args[2] seen[$self]=0 $show_desc[$self]="seen['<<$self>>']=-1 & clear & p $desc['<<$self>>'] & gt $curloc"[/pre2] Вызов н-р dynamic $show_desc['стол'] или dynamic $show_desc[$obj]

luciofulci: Да, спасибо, так действительно лучше

Byte: Рады помочь :)

noname: luciofulci, в стиле ООП можно писать и на QSP. То есть изменяю одну строку кода в одном месте, а не в десяти. допустим, есть сотня столов разных цветов, форм, размеров, и имеющие различные атрибуты местонахождения. и есть локация "показать". и есть переменные арг1, арг2, арг3,... . тогда меняем реакцию локации "показать" в одном месте программы. а не в ста. всё. и все эти заморочки с динамиком и т п - лишние.Локация - это локация. Это некоторое место, которое игрок посещает, а не просто несколько строк кода. такой подход бывает крайне неудобен. пример: генерим мир 8х8 полей. получаем 64 локации. значит ли это, что в тексте программы должно появиться ещё 64-ре локации?? Например, в одной дружественной платформе локации используются для всего чего угодно - например, для организации цикловудивительно. не слыхал пока о платформах без меток. впрочем, нет- в РТАДС и ТОМ, вроде бы обходятся без них. UPD насчёт столов и служебных локаций: да, зря в урке и куспе это названо локациями. потому как реально это- никакие не локации. то, что называется в этих платформах локациями- скорее такие особые функции/подпрограммы/куски. короче, что угодно. и с 'локациями' игрового мира зря путаницу внесли.

luciofulci: noname пишет: luciofulci, в стиле ООП можно писать и на QSP. Кто же спорит?? noname пишет: допустим, есть сотня столов разных цветов, форм, размеров, и имеющие различные атрибуты местонахождения. и есть локация "показать". и есть переменные арг1, арг2, арг3,... . тогда меняем реакцию локации "показать" в одном месте программы. а не в ста. всё. и все эти заморочки с динамиком и т п - лишние. Да я понял уже эту фишку с show_desc. Правда метод show_desc для разного типа объектов может (и по идее должна) выполнять разные функции. И - если уж говорить об ООП - должна быть частью объекта. В моем примере - реализация практически чистого ООП. Код опять же можно упростить добавив локации-обработчики. Для меня просто удобнее писать dynamic $old_table['show_desc'], чем $o='old_table' & gs 'show_description' , не более того :) noname пишет: удивительно. не слыхал пока о платформах без меток. впрочем, нет- в РТАДС и ТОМ, вроде бы обходятся без них. Разумеется, в TADS и TOM обходятся без них -там они абсолютно не к месту. А вот в urql, допустим, метки и локации - одно и то же. По крайней мере в стандартной версии.

Byte: Например, в C++ методы классов являются самостоятельными функциями, просто первым "скрытым" аргументом в них передаётся адрес объекта (фактически, просто структуры с полями данных). Именно через этот адрес метод может получить доступ к полям структуры, для которой вызывался метод. В QSP таким "адресом структуры" может являться имя объекта, через которое мы можем получить доступ к свойствам объекта. код в сообщении http://qsp.borda.ru/?1-0-0-00000154-000-20-0#017 этой темы - тому пример.

ASBer: Извините меня, пожалуйста, но предмет вашей ученой беседы настолько интересен, что... ООП это стиль мысли а не язык. Можно писать на ассемлере объектно-ориентированный код, а можно в С++ наваять такого, что лучше бы классы вообще не трогать. Если же говорить о языках, то язык либо содержит СПЕЦИАЛЬНЫЕ средства, поддерживающие ООП, либо их там нет. Все ИМХО.

Byte: Здесь речь идёт не конкретно о языке, а о подходе, который можно реализовать на нём. Вот и всё.

noname: luciofulci пишет: А вот в urql, допустим, метки и локации - одно и то же. почти одно и то же. в куспе же введены некоторые искуственные ограничения для их пущего различия. хорошо, хоть цикл в пределах локации всё-таки и на нём можно сделать. писать в стиле ООП на куспе можно, но ИМХО можно найти более удобный в рамках этого языка подход. поэтому в моём предложении и не было оопа. впрочем, пока больше ничего писать сюда не буду, что бы не зафлудить тему...

luciofulci: Безусловно на куспе и урке удобнее писать по-другому. Но просто на определенном этапе хочется чуть большей организации и порядка, тогда ООП-подобный дизайн становится почти необходимостью, несмотря на определенные неудобства.

Nex: luciofulci милену смотрел? там всё что хошь для заядлого программера. и тебе циклы, и функции, и тырпыр.

luciofulci: Может, посмотрю... Просто на этот раз все-таки хотелось бы закончить игру. А то рано или поздно все вернется к старым заготовкам для python и вместо того, чтобы писать игру, буду долбить движок...

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

Byte: Теперь добавил и функцию EVAL: [pre2] #fact if args[0]=1: result=1 else result=args[0]*eval('fact',args[0]-1) end --[/pre2] вызываем как eval('fact',5) Думаю, возможно имеет смысл сменить название на FUNC ? UPD: Решил переименовать в FUNC. Ещё добавил функцию ARRSIZE($имя_массива) - возвращает число элементов массива.

luciofulci: Еще заметил в хелпе: Как проверить, был ли герой на какой-либо локации? 1) На той локации, которую нужно проверить, введите: set был_здесь=1 А на локации, где нужно это проверить: if был_здесь=1:[операторы] или: if был_здесь:[операторы] 2) Через массивы, с индексированием через строки: was_here[$curloc] = 1 Проверка: if was_here['башня']:[операторы] По поводу второго способа, можно добавить, что was_here[$curloc] = -1 можно написать в коде локации, установленной в переменной $onnewloc , тогда на was_here можно проверять любую локацию в игре.

Nex: luciofulci где-то здесь уже об этом писали... Но в хелп да, нужно добавить пример про $onnewloc.

Byte: Может, кто-нибудь возьмётся за доработку справки? А я вышлю альфу QSP 5.5

luciofulci: Может сделать что-то типа вики с возможностью загрузить снэпшот в архиве? А так я мог бы, конечно, обновлять справку по ходу работы с игрой. Альфу тоже протестировать не отказался бы

Byte: Кому интересно - http://qsp.su/misc/libqsp550a1.zip

Byte: Обновил - http://qsp.su/misc/libqsp550a2.zip

Byte: Добавил передачу аргументов ARGS для GT/XGT. В $ONNEWLOC передаются аргументы, с которыми был вызван GT/XGT. То есть: [pre2] #start $onnewloc='new' gt 'loc1',1,2 -- #loc1 gt 'loc2',3,4,5 -- #loc2 'Перешли в <<$curloc>>, аргументы <<args[0]>>, <<args[1]>>, <<args[2]>>' -- #new $curloc arrsize('args') args[0] args[1] args[2] --[/pre2] Скачать: http://qsp.su/misc/libqsp550a3.zip

elmortem: arrsize - вкусняшка... ^__^

luciofulci: Респект! А в меню, вызываемое через оператор menu, параметры добавить не планируется?

Byte: Нет :-)

luciofulci: Ок. В принципе, это и не особо нужно :) А после возвращения из gs, массив args "обнуляется"? Да, обнуляется, просто это у меня коде глюк, сорри

Byte: Не обнуляется, а "возвращаются" предыдущие значения.

Byte: Добавил необязательный параметр для NL/*NL и параметр у PL/*PL сделал необязательным. Теперь между NL/*NL и PL/*PL разница в том, что NL сначала делает перевод строки, потом выводит данные, а PL наоборот - сначала выводит данные, а затем делает перевод строки.

luciofulci: Byte пишет: Не обнуляется, а "возвращаются" предыдущие значения. А какие у них предыдущие значения? В общем, при переходе в локацию без параметров значение $args - пустые строки, а args - 0. Я это имел в виду. То есть в случае вызова gs 'some_loc', 'blah', -1 , локация получит: $args[0] = "blah", args[1]=-1. А при вызове gs 'some_loc', 'blah', значение args[1] всегда будет нулевым.

Byte: Предыдущие значения - значения на момент вызова. Если мы вызываем GS из локации, вызванной по GS, то после обработки локации предыдущие значения восстановятся.

luciofulci: Понял, спасибо.

Ajenta: Таак, оно конечно всем за всё спасибо, но всё-таки прошу не сильно усложнять. :) Сейчас действительно есть всё, что требуется, а то, чего нет можно через html реализовать :)

elmortem: Ajenta К сожалению, HTML поддерживается лишь на базовом уровне. Ну и все "усложнения" касаются лишь дополнений к уже имеющемуся. Т.е. справка, конечно, пухнет, но проблему быстрого "вхождения в QSP" сейчас легко решают уроки, а их скоро станет больше и они будут доступнее для понимания. Ну а уж коли понадобится что-то специфичное - можно будет и в справку глянуть. (:

luciofulci: Все изменения в релизе 5.5, насколько я в курсе, - это дополнения. То есть, переделывать ничего не придется, хотя, возможно, стоит, так как некоторые вещи стали намного проще, а не сложнее :)

Byte: luciofulci да

Ntropy: Byte пишет: Думаю, возможно имеет смысл сменить название на FUNC ? UPD: Решил переименовать в FUNC. Ещё добавил функцию ARRSIZE($имя_массива) - возвращает число элементов массива. Всё таки победил вариант dyneval?

Byte: DYNEVAL это из другой оперы (динамическое вычисление выражений). Для вызова пользовательских функций победил FUNC/$FUNC.

werewolf: Byte ты писал что добавление параметров в оператор menu не планируется - это принципиально ограничение или просто нежелание усложнять синтаксис? а то я наткнулся на ситуацию, где удобнее всего иcпользовать menu, но без параметров придется создавать кучу локаций, большая часть которых будет состоять из одной строчки - вызова функции

Byte: werewolf, объясни ситуацию - думаю, найдём простой выход без создания кучи локаций. Про MENU - это и усложнение синтаксиса, и несовместимость, и еще ряд факторов, касающихся реализации. Плюс к этому, хочется верить, что это можно вполне нормально обходить.

Ntropy: Нужно написать все эти мелкие локации и спрятать в отдельный файл, либу. Это решение не требует ничего в операторе не менять.

werewolf: Я сейчас думаю о переводе на qsp оной книги-игры, так там при получении любого предмета указвается смещение по параграфам (-10 или +50 например) при использовании этого предмета, поэтому хотелось к каждому предмету добавить меню из 2 пунктов "Осмотреть" и "Использовать". В этом случае с пунктом Использовать можно было обойтись одной локацией, где-бы просчитывалось такое смещение. Но в принципе с предметами ситуация обходима 2 путями - по клику на предмету выводить описание в окно доп описаний и туда же добавлять html ссылку которую сформировать проще или мне сейчас пришел в голову второй, более удобный - делать с menu, но добавлять команду unselect не в локацию обработчик выбора а в локации на которых обрабатываются пункты меню. Сложнее обойти второй момент который есть в книге - кроме предметов игрок получает информацию, опять же завязанную на смещении, вот здесь бы и хотелось использовать один предмет "Информация" и меню к нему, но как здесь обойтись одной локацией я не придумаю.

werewolf: Ntropy если все же создавать кучу локаций, то смысла выносить их в отдельный файл я не вижу, поскольку повторно их использовать скорее всего не придется

HIman: werewolf В твоем случае с параграфами можно совсем в лоб создавать столько локаций сколько параграфов и все переходы будут однозначны по GT Либо придется переработать книгу-игру и вначале куда нить на листочек выписать все свойства или описания предметов написаные в том-то параграфе чтобы их выводить опционно в окошке описания предметов и никуда не перемещаться с текущей локации.

Byte: werewolf так и сейчас это можно. Создаем таблицу "использований" предметов: [pre2] useobjs['палка']=23 useobjs['кольцо']=-43[/pre2] 23, -43 - смещения. На локации использования предмета смещение для выбранного предмета будет: [pre2]useobjs[$selobj][/pre2] В этом случае всё делается на одной локации для всех предметов.

werewolf: Да для предметов смещение реализовать проще, но как быть с информацией? есть предмет Информация при выборе которого игроку выводиться меню со списком известной ему информации, при выборе пункта пункта меню нужно просчитывать смещение и делать переход - здесь можно как-нибудь обойтись без создания отдельной локации на каждый пункт?

Byte: А список возможных пунктов меню ("меню со списком известной ему информации") для предметов большой? Обычно ведь это очень ограниченный набор возможных вариантов.

werewolf: В том то и дело что не маленький - я точно не считал, но где-то около 20 а то и больше.

Byte: Возможно аргумент для MENU добавится, неявный. Есть 2 варианта: 1) После вызова в ARGS[0] хранится индекс выбранного пункта меню. 2) После вызова в $ARGS[0] хранится название выбранного пункта меню. Вообще, 20 локаций - не так уж много)

werewolf: Byte пишет: Возможно аргумент для MENU добавится, неявный. Есть 2 варианта: 1) После вызова в ARGS[0] хранится индекс выбранного пункта меню. 2) После вызова в $ARGS[0] хранится название выбранного пункта меню. это будет просто отлично Byte пишет: Вообще, 20 локаций - не так уж много) Просто хотелось упростить себе жизнь, при большой нужде и 100 локаций добавить не проблема.

Nex: А если по команде MENU нужно будет вызвать пользовательскую функцию с параметрами? P.S. наверняка есть более простое решение.

Byte: Можно будет вызвать FUNC('моя ф-я',1,2,ARGS[0]) - оно будет нормально работать.



полная версия страницы