Контент Malandrinus - Страница 57 - AMK Team
Перейти к контенту

Malandrinus

Жители
  • Число публикаций

    1 930
  • Регистрация

  • Последнее посещение

  • Дней в топе

    13
  • AMKoin

    180 [Подарить AMKoin]

Весь контент пользователя Malandrinus

  1. lekzd, кроме того, что таб - это неудобно, он ещё и занят кучей других модов. Надо искать другие способы. Опять же остаётся проблема определения того, что перед тобой лежит предмет. На локации объектов довольно много, перебирать их все в момент нажатия - плохой вариант.
  2. lekzd, я как-то думал про гравипушку. Когда с физикой развлекался, то это первое, что пришло на ум. Но там масса мелких вопросов. Первое. Вот лежит перед тобой предмет, и тебе надо его подцепить. Как ты узнаешь, что он перед тобой лежит и ты на него нацелился? Дальше. Допустим, ты сделал некий девайс, вероятно на основе обычного ствола. Тебе нужны три действия: поднять, отпустить и кинуть. Значит надо определять нажатость на курок (левая кнопка) и как-то ещё нажатость правой кнопки для кидания. Насколько я знаю, отдельный выстрел пока никому отследить не удалось, особенно, если патронов нет =) Остальное по сути дело техники: уравновесить гравитацию для предмета, подтащить его, держать перед актором и дать ему пинка. Это всё нудно, но реализуемо наверняка, а вот те проблемы - без понятия как сделать, особенно с управлением.
  3. lekzd, если уж подтащить удалось, то пусть висит перед актором сам предмет. Зачем его удалять? Так и как определять предмет под курсором? Из примитивных способов на ум приходит перебор всех онлайновых с определением того, что попадает в конус взгляда.
  4. Monnoroch, если надо просто пнуть предмет, то лучше пользоваться не хитом, а методами класса physics_shell. Импульс в параметрах хита хоть и есть, но действовать на живых не будет, поскольку они под анимацией. Импульс вроде как подействует только тогда, когда хит будет смертельный и начнёт действовать регдолл анимация (собственно физика). Впрочем не уверен, надо проверить. В любом случае для тушек и физических объектов смысла заморачиваться с хитом нет - что им до химического или "кусачего" урона? А через физическую оболочку можно так: obj:get_physics_shell():apply_force(x,y,z) здесь метод хоть и называется "приложить силу", но на самом деле имеет смысл "добавить импульс", т.е. тот-же смысл, что и параметр impulse класса hit. Чтобы изменить скорость объекта на V надо приложить импульс, равный m*V. m - масса. Физическую массу можно узнать методом mass. Чтобы пнуть предмет в вертикальном направлении со скоростью 10 м/с делаем так obj:get_physics_shell():apply_force(0,obj:mass()*10,0) Только учтите, что наличие оболочки надо обязательно проверять. Вспомнил вот. Хит тоже можно использовать, поскольку он даёт возможность пнуть в произвольную кость, что с помощью оболочки не сделать. Я так пытался управлять вращением объекта, пинал в две разных кости в противоположном направлении с равным импульсом =)
  5. Monnoroch, Gonarh, злые вы =) По поводу "сначала учи, потом пиши". Рекомендую взглянуть, как реализована (разработчиками) функция _g.IsMonster в ТЧ и как она же в ЗП. Увидели? Следуя озвученному правилу, им бы следовало застрелиться, а не выпускать такое в свет. Насчёт оффтопа. Ну не здесь про скрипты, допустим. А где тогда? На форуме есть более адекватное место?
  6. Голосую всеми конечностями. Ещё бы всё программеры взяли за правило прилично оформлять свой код. Впрочем, думаю коммунизм наступит раньше =) Насколько мне известно, в случае индексации от единицы и без разрывов хеш-таблицы вообще не используются, а значения хранятся просто как массив. Впрочем, это только внутренняя оптимизация. Ничто не мешает и в этом случае считать таблицу Lua ассоциативным массивом общего вида. Ничто из этого =) Поскольку это формат файла, т.е. способ интерпретации непрерывной последовательности байтов. Когда ты читаешь эти данные из файла, то просто выбираешь для их хранения наиболее удобную структуру. На мой взгляд что-то вроде такого: ini_data = { [<имя секции 1>] = {[<ключ 1>] = <значение 1>, [<ключ 2>] = <значение 2>, [<ключ 3>] = <значение 3>, }, [<имя секции 2>] = {[<ключ 4>] = <значение 4>, [<ключ 5>] = <значение 5>}, -- и т.д. } Т.е. как видишь не одна таблица, а их комбинация. Хотя на кой надо хранить в программе все данные из внешнего файла? Кроме того, формат файла допускает и отступление от такого вида. Как ты верно заметил, внутри секции можно получать данные не по ключу, а по номеру строки. Это надо главным образом для того, чтобы читать секции такого вида: [some_section] value1 value2 value3 ; и т.д. т.е. в этом случае вид "ключ/значение" не соблюдается. Используется это в частности для обхода ограничения, которое не позволяет получить список секций в файле. Я могу завести специальную секцию, в которой таким образом перечисляю идущие далее секции, как бы регистирую их. В этом случае, адекватной структурой данных для этой секции будет список, массив или множество. Можно задать и направление и импульс. Вроде как пример был в "справочнике" в этом посте.
  7. Garry_Galler, Внесу небольшое уточнение насчёт порядка расположения объявлений в модуле. В принципе, порядок не должен быть так важен. Дело в том, что последовательность работы с модулем следующая: При первом обращении модуль загружается и компилируется. При этом происходит выполнение операторов, которые находятся в глобальной области. Объявления таблиц и функций - это по сути своей выполняемые операторы, поэтому в этот момент (при загрузке модуля) важно, чтобы объявление А, которое использует объект Б, стояло бы после объявления объекта Б. Когда загрузка модуля закончена, то все задекларированные объекты - это по сути записи в таблице и как такового порядка уже не имеют. Поэтому после загрузки модуля уже не важно, в каком порядке таблицы и функции расположены в файле - они могут ссылаться друг на друга без проблем. Вот иллюстрация сказанного. Пусть это будет файл my_module.script: local a = 1 local b = a * 2 local t = {} t.a1 = b -- объявления a, b, t должны быть строго в таком порядке, поскольку выполняются последовательно при загрузке модуля function fun1() fun2() -- можно ссылаться на ещё не созданную функцию end function fun2() end -- если я вызываю fun1 снаружи, то вызов my_module.fun1() должен сработать без проблем -- поскольку сначала произойдет загрузка модуля и создадутся и fun1 и fun2, -- а только потом произойдёт собственно вызов -- а вот так нельзя, поэтому дальше закомментировано --[[ function fun11() fun22() end fun11() -- этот вызов произойдёт при загрузке модуля до объявления функции fun22, поэтому будет сбой function fun22() end ]] Хотя конечно в любом случае не стоит превращать код в малочитаемую кашу и всё-таки надо как-то упорядочивать объявления.
  8. Нет. То, что я сейчас описал - это голый Lua. Будет работать где угодно. Luabind естественно опирается на эти синтаксические возможности. Добавляет к этому предопределённые конструкторы/деструкторы, глобальную функция создания, наследование. Ну в принципе это и средствами Lua тоже можно сделать, но там это просто готовое есть. Кроме того, если здесь строится на базе таблицы, то в Luabind - на базе пользовательского объекта. Естественно, в основном он нужен для экспорта сишных классов. "Просто классы" Luabind как бы приводит к своему стандарту оформления.
  9. Monnoroch, Конструкция вида: function <имя_класса/таблицы>:<имя_функции/метода>(<список_аргументов>) <тело функции> end это на самом деле комбинация из двух синтаксических украшений. Приведённый код эквивалентен следующей конструкции: <имя_класса/таблицы>.<имя_функции/метода> = function(self, <список_аргументов>)<тело функции>end Или иными словами в таблицу просто добавляется ещё одна пара с ключом <имя_функции/метода> и значением типа "function". Сама функция при вызове подразумевает наличие первого скрытого аргумента self. В случае использования при вызове нотации с двоеточием: t:fun(<список_аргументов>) это в свою очередь эквивалентно записи t.fun(t, <список_аргументов>) Т.е. при вызове таблица/объект подставляется в качестве первого неявного аргумента, который соответственно станет неявным аргументов self в объявлении выше. Короче да, самопальный класс =)
  10. Monnoroch, нет конечно. И вообще смысл колбека - не вызывать что-то, а напротив быть вызванным чем-то, чтобы дать в этот момент что-то сделать дополнительное. Поэтому меня и удивило немного, что on_death вызывает смерть. Однако работает, а kill_entity не работает, я только что проверил. Кстати, в ЗП для серверного класса добавили метод kill, видимо как раз для решения этой проблемы.
  11. Garry_Galler, это как бы не специальный метод для убиения, а коллбек серверного объекта на смерть. Т.е. он автоматом вызывается при смерти непися. Весьма неожиданно, что он сам по себе вызывает смерть неписей. Я не пробовал, но может быть можно использовать метод kill_entity класса alife_simulator.
  12. Зачем здесь функция вообще? release либо удалит либо вылетит, так что что-то там возвращать смысла нет. Здесь более уместны аналогии с STL. Там строки - это объекты класса и сравниваются по содержимому.
  13. Ray, стиль дурной, согласен. Но к ошибке в данном случае это не приведёт, поскольку как обычно локальные переменные перекрывают глобальные. Сама функция внутри себя становится недоступна, но в данном случае рекурсия не нужна. ЗЫ: Это индикатор =) К концу недели способность рожать "длинные мнемоничные идентификаторы" сильно снижается.
  14. Приведи ссылку плиз.
  15. Ray, совершенно согласен насчёт читабельности. Но я чего завёлся-то, такой код стимулирует по аналогии писать в вырожденном случае кошмарную конструкцию вида: if <лог. выр.> then return true else return false end Посему я бы написал тот фрагмент так: function has_info() local has_info = db.actor:has_info("info") if has_info then ................. end return has_info end Что в вырожденном случае (при отсутствии действия по условию) приводит к более вразумительному коду.
  16. Garry_Galler, Правильно. Ещё вариант, проверять оставшееся место перед каждым оператором записи. вопрос не по теме - как подключать в SCITE библиотеку классов? вроде require (classlib") - только куда это вписать и надо ли модуль создавать...и саму библиотечку куда лучше положить. Вписать в начале головного модуля. Библиотеку клади рядом с выполняемым файлом. А что за классы? Luabind же в SCITE недоступен.
  17. Было бы там чего изучать, особенно для вывода строк. text = string.format("%s %s %s %s %s.%s.", obj_name, verb, adjective, substantive, str, habar) Стоит проверка на запас в 180 байт. Потом пишутся все данные функцией taynik_rnd.message_save. Ты бы привёл её код, а то так не понять. Что за число 180? Какое отношение имеет к записываемым данным? Где твои 45-50 сообщений?
  18. Интересно, почему так? Реально выдаётся при следующем апдейте? Думаю, надо делать это в netspawn. По идее, что переход на другой уровень, что загрузка игры происходят одинаково. При этом актор переходит в онлайн и однократно срабатывает netspawn биндера.
  19. Ключом может быть любая переменная, кроме значения nil: числа, строки, булевские, таблицы, функции и пользовательские объекты. Вопрос некорректно поставлен. Какую-то нагрузку несёт любое шевеление. Другое дело, какую нагрузку несёт этот вариант по сравнению с каким-то другим. С чем ты его сравниваешь? Если замутили таки функцию и надо вернуть true/false, то довольно часто можно обойтись без возврата false. Если ничего не возвращать, то это эквивалентно возврату nil. А nil в свою очередь в логических выражениях однозначно интерпретируется как false (согласно синтаксису языка). Впрочем, в данном случае это будет скорее трюкачеством.
  20. Про список геймвертексов я здесь писал. Или, как верно говорят, используй ggtool.pl. Левелвертексы можно для текущего уровня перебрать с помошью функции level.vertex_position(i). только так не узнать, сколько их, и это только для текущего. Можно пробежаться по уровням и перебирать до вылета. Если совсем сильно надо, то смотрим исходники Бардака, и разбираем ручками файл level.ai нужного уровня. Только в самом деле зачем нужен список из миллионов левелвертексов? Кроме того, от мода к моду списки гейм и левел вертексов меняются. P.S.: Комрады, а зацените, какая нынче мОлодежь пошла. Не как узнать, не какой функцией, не где посмотреть... Дай ему, вынь да положь =)
  21. Garry_Galler, уф... ну давай поговорим о базовых понятиях ООП. То, что написано в файле биндера и то, что указывается в секции - это класс. Класс - это не объект, это описание объекта, тип, если угодно (хотя здесь это не совсем тип). Когда создаётся онлайновый объект, то создаётся объект класса. И к онлайновому объекту прицеплен именно объект. Потому кстати и биндер (binder), что от слова bind (привязывать, присоединять). Ещё раз: у каждого клиентского объекта свой объект биндера, даже если эти объекты одного класса. С точки зрения синтаксиса дилемма "один класс / много объектов" решается просто. У каждого метода есть скрытый первый аргумент self, в котором методу передаётся ссылка на конкретный объект. Таким образом один и тот-же метод может обслуживать множество объектов. Это достаточно типичный подход, используемый в большинстве современных языков. Таким образом self - это всегда текущий объект биндера. self.object - это соответственно клиентский объект, к которому этот биндер прицеплен. С нетпакетами ситуация такая. У каждого объекта есть буфер на 8кб, в котором объект хранит своё состояние. Это не нетпакет, а просто буфер. Нетпакет - это просто средство получать и записывать туда информацию. Сам по себе нетпакет - это обычный объект, которой можно создать и который автоматом удалится сборщиком мусора. Ещё раз, данные сохраняются в объекте, через нетпакет они просто туда передаются, для чего имеются методы класса биндера. Если уж быть корректным до конца, то в биндере на чтение используется не нетпакет, а почему-то reader. На практике терминология постоянно смешивается. Биндером называют и класс и объекты, говорят "сохранить в нетпакете", "сохранить в биндере" и т.п. Это и понятно, трудно в обычном разговоре постоянно сохранять предельную точность. По поводу стиля сохранения. Таки желательно придерживаться верной стратегии: 1. Сохранять минимум информации 2. Сохранять там, где надо. По первому пункту самая общая рекомендация - избегайте избыточности. Если конкретнее: - если есть строка, выбираемая из заранее известного набора, то лучше сохранять её номер, а не целиком строку - если можно что-то вычислить на основе другого, то лучше вычислить - для логических переменных можно использовать двоичные флажки Отдельного разговора заслуживают строки. Вообще нужда сохранять именно строки возникает не так уж часто. Между тем, как я заметил, народ почему-то весьма злоупотребляет строками. Как-то видел сохранение массива с переводом его в строку вида "a,b,c,d", сохранением в виде строки, а при чтении элементы распарсивались обратно. Ужас! Нет как правило никакой необходимости сохранять не строковые данные в виде текста. Они при этом занимают больше места и тратится существенно больше времени. Особенно при чтении как в случае с массивом выше, где фактически использовались регулярные выражения (!). Дополнительная неприятность - что место под хранение нужно заранее непредсказуемого размера, что делает невозможным предварительную оценку свободного места в буфере. Насчёт второго пункта соображения простые. Если данные относятся к конкретному объекту, то в нём и надо сохранять ("в его биндере"). Точнее здесь не скажешь. В конкретном случае надо включать мозг и думать, где и как сохранить.
  22. В данном случае индексы указывать не надо. Автонумерация от единицы и так получится. Т.е. достаточно как-то так: local funcs = { fun1, fun2, fun3, ... } Зато конструкция вида: local funcs = { [<ключ1>] = function1, [<ключ2>] = function2, [<ключ3>] = function3, ... } вполне заменяет недостающий оператор switch. Это может радикально ускорить выполнение некоторых фрагментов, если заменить этим убогие километровые списки из if - else. Что касается неподходящей темы, то я с этим не согласен. Не помню, говорил или нет, но желание было замутить здесь статейку другую по "advanced Lua", где в том числе обсуждались бы и такие вопросы. Потому что смотреть на код порой просто больно. Теми же таблицами похоже что сами разработчики научились пользоваться только в ЗП =) Добавлено через 13 мин.: Раз пошла такая пьянка. Комрады, не пишите плиз соединение нескольких строк так: res = a..b..c..d..e Это очень медленно, поскольку на каждую операцию конкатенации приходится вычисление суммарной длины и выделение памяти под новую строку. Вместо этого используйте string.format: res = string.format("%s%s%s%s%s",a,b,c,d,e) При таком способе вычисление суммарной длины и выделение новой памяти происходит всего один раз. Кроме того, статичные фрагменты можно разместить прямо в строке формата. Опять же, дополнительные возможности по форматированию. Способ первый даёт N^2 время вычисления, где N - число соединяемых строк. Способ второй - N. Регрессия производительности может быть совершенно чудовищная. Не говоря уже о фрагментации памяти. Так можно соединять и заранее неизвестное число строк. Если надо, напишу как именно.
  23. Garry_Galler, полагаю, что придётся думать о куда более серъёзной экономии, нежели 30-50%. Нетпакет актора в некоторых глобальных модах занят почти полностью. Мне просто интересно, что же там такое сохраняется такого размера. Не мог бы привести пример одного твоего сохраняемого сообщения?
  24. Garry_Galler, я имел в виду сомнительность с технической точки зрения =) Что-то явно не так, если каждая строка занимает по четверть килобайта. Даже теоретически их можно в этом случае записать всего около 30-и. Может записывать не в виде строк, а виде бинарных данных? Может что-то можно не записывать, а хранить постоянно в конфигах? Например часто можно вместо строк записывать их номера. А многие данные можно получить на ходу из других. Например по id объекта можно получить его имя, описание и пр. Значит всё это можно не хранить, а сохранить только id (два байта).
  25. Ой смотри, весь нетпакет - 8 кб. А в акторовском ещё всего до фига. Какую-то сомнительную идею ты пытаешься реализовать. Данные не в нетпакете хранятся, а в объекте. Какая разница, два уровня или десять? Главное, читать в том же порядке, что и записывал. Перед записью переменного числа элементов записываешь их количество. Вот и все секреты. Ещё раз, сохраняется не нетпакет сам по себе, а объект и вместе с ним то, что было в его нетпакет записано. В актора пишут только потому, что он всегда доступен. Ничто не мешает записывать дополнительные данные в другие объекты. Собственно в их биндерах это и делается повсеместно. Хм. Дарю идею. Сам как-то хотел сделать, но руки не доходят. Можно завести специальных объектов, которые никак в игре не участвуют, а используются только для хранения данных. Такие можно сделать на связке cse_alife_object - CGameObject. А может это был cse_alife_dynamic_object, не помню точно какой объект был минимально создаваемым. Запретить переход в онлайн, по созданию объект регистрировать, при недостаче места создавать новый, наращивая таким образом объём хранимых данных. Будет отличная альтернатива пстору актора.
×
×
  • Создать...