HLFX.Ru Forum Страницы (255): « Первая ... « 36 37 38 39 [40] 41 42 43 44 » ... Последняя »
Показать все 3825 сообщений этой темы на одной странице

HLFX.Ru Forum (https://hlfx.ru/forum/index.php)
- Наши проекты (https://hlfx.ru/forum/forumdisplay.php?forumid=1)
-- XashNT: блог разработчика (https://hlfx.ru/forum/showthread.php?threadid=5297)


Отправлено thambs 18-11-2019 в 23:45:

Мысли по поводу скриптовой системы #1: возможная структура и юзкейсы

Цитата:
послушаем, что Тхамбс предложит.


Буду исходить из того, что скриптовая система не должна заменять или ломать существующий набор сущностей, а призвана скорее её дополнить и расширить, сделав более гибкой. Вообще-то говоря, сущности — довольно удобная штука и в 90% (условно) игровых механик какие-то дополнительные движения не требуются. Проблемы же начинаются тогда, когда из этих сущностей приходится городить сложные цепочки, вводить "логические энтити" и пр чертовщину. По моему опыту, использование более чем 5 сущностей в одном механизме создаёт путанницу, и чем дальше тем хуже. Особенно неудобно бывает, когда одна и та же цепочка сущностей используется в разных местах карты — приходится вручную переименовывать ключи, что тоже приводит ошибкам. Отчасти, это решается с помощью пре-процессинга .map-файла, но это не то что бы сильно универсальное решение, да и к тому же не избавляет от необходимости писать эти цепочки в .ent-файле, который остаётся сильно многословным в сравнении с той же функциональностью, выраженной на любом императивном яп.

О зле. На мой взгляд, основной источник зла — это т.н. "логические энтити", а точнее черезмерное их использование. Игровая логика в doom или quake была довольно проста: расставил монстров, связал кнопку с дверью, а дверь с ключ-картой, триггер — с ловушкой, и готово. Более комплексные игровые механики привели к разрастанию и непомерному усложнению всей системы. И самая пакость связана с тем, что, помимо сложности, система стала фактически "write only" — из-за того что при редактировании работаешь с одной энтитей за раз, то отладка/изменение сценария напоминает работу с древним БАСИКом — тем самым, в котором строки нумеровались цифрами, и редактор позволял работать только с одной строкой. А ведь, зачастую, эти самые сущности на карте расположены в разных местах и совершенно не обязательно как-то логически упорядочены.

О команде fire. Кстати, ещё в sauerbraten видел интересную штуку, оно конечно только proof of concept, для реальных применений не годится, но тем не менее. Ведь там совсем небыло энтить, а для манипуляции игровой логики был внутренний скриптовый язык. Причём скрипты на нём могли быть как во внешних файлах, подключаемых к карте, так и вызываться непосредственно из консоли, с такими же результатами. Мне это напомнило команду fire из спирита/ксаша в связке с trigger_command и те совершенно невозможные штуки, которые с помощью них делал доктортресни. Одного fire, конечно маловато.

О интерфейсе.Команда fire и поле target, фактически, позволяют передать некоторые параметры/сигналы сущности, но с большими ограничениями. Ещё есть changetarget, changeparent, env_render и всё, собственно. Что бы наблюдать за состоянием энтить — multi_watcher, но ему тоже доступен весьма ограниченный набор параметров. Наверное, имело бы смысл некоторое универсальное API, позволяющее передавать и получать от энтить любые допустимые параметры и проводить с ними операции. Не ломая существующую систему, можно было бы, например, ввести вызовы:
C++ Source Code:
$set(*entity, key, value) -> status
$get(*entity, key) -> value
$find(*world, mask) -> [*entity]

Из названий понятно: $set — установить пару ключ-значение для сущности
*entity; вернуть статус или неудачу, $get — получить значение, $find — сформировать список указателей на сущности с именем/класснеймом таким-то маске или значению, а world -- указатель на текущую карту. Сами функции, естественно, не содержат внутренних состояний.
Предположим, теперь, что у нас есть какой-то механизм сохранения состояний и обычные языковые конструкции. Добавим функцию асинхронной задержки:
C++ Source Code:
$sleep(time)

Тогда эти 4-вызова, тогда позволяют полностью заменить мульти_манаджеры/вотчеры, реле, энв_рендеры и пр. Возможные примеры использования дам дальше, пока о памяти.

При работе с памятью видится несколько кейсов. Предполагается, что скрипт может быть или глобальным (в масштабах карты), или связанным с какой-либо сущностью. При этом, у последней получается свой локальный нэймспейс. Так-как хочется работать с чистыми функциями и использовать обычную систему сохранений, то хранить какие-то состояния наверное лучше всего было-бы в каком ни будь специальном поле внутри самой сущности. Но я, к сожалению, так и не разбирался как у тебя сериализация устроена, возможно-ли туда затолкать полиморфный, изменяемый объект? И, если в функции есть вызовы $sleep, то, видимо нужно будет сохранять весь её стек...

Что же касается низкоуровнего выделения/освобождения, то наверное, самым разумным было-бы использовать RAII: выделяем память под переменную в том случае, если она синтаксически связалась с литералом, освобождаем (по мере необходимости) как литерал вышел из поля видимости. Например, пустой вызов:
C++ Source Code:
$find(*world, "func_door:storage*")

Не делает ничего,
C++ Source Code:
lst = $find(*world, "func_door:storage*")

связывает литерал lst с результатом вызова и храним его пока он в области видимости, или пока не вызвали какой ни будь $del(lst). При этом, соответственно, синтаксис не должен позволять существование несвязанного литерала, а если литералу присвоено новое значение, то старое удаляется.

Вызовы. Есть ещё момент, когда нужно вызвать скрипт автоматически, по наступлении определённых условий. Наверное, тут было-бы удобно тогда добавить внешний обработчкик. Например, указать в корне скрипта
C++ Source Code:
1
//следим за условиями
2
watch(){
3
  if cond1 { ... }
4
    if cond2 { ... }
5
    }


Общая структура. Таким образом, вырисовывается какая-то такая структура скрипта:
C++ Source Code:
1
/* определяем сохраняемые поля */
2
@static var1 = ...
3
@static var2 = ...
4
/* определяем обработчики */
5
spawn(...)
6
watch(...)
7
call(...)
8
/* определяем всякие вспомогательные функции */
9
...


Юзкейс: поезд с колёсиками. Есть, например, префаб фанк_трейна, к нему приделаны колёсики, env_shake, фонарики, убивалки. Хочется, что бы колёсики синхронно вращались и частота тряски менялась в зависимости от скорости, фонарики красные зажигались на заднем ходу, дым там из трубы ну и всё такое. Пишем у поезда в строке скрипт имя скрипта а в самом нём что-то такое:
C++ Source Code:
1
@static wheels = $find(*world, $get(*this, "targetname")+"_wheels")
2
@const  radius = 6
3
watch(){
4
  v_old = $get(*this, "v_old");
5
  v_new = $get(*this, "v_new")
6
  if v_old neq v_new{
7
    for( wheel : wheels){
8
      $set(*wheel, "speed", v_new/radius)
9
    }
10
  }
11
}


Юзкейс: универсальная станция для поезда с дверкой. Поезд активирует скрипт станции, а станция узнаёт имя поезда, имя дверки, открывает её, закрывает e`, вносит поправки в расписание и пр.

Юзкейс: управление персоналом. Есть, например, некоторая зона, на которой расставлены scripted_sequence и бегают доктора. Хочется создать иллюзию жизни на этой локации. Каждая скриптед секвенция по завершению вызывает наш скрипт и передаёт локус доктора. Внутри выбираем что ему делать, куда идти и пр.

Юзкейс: диалоги. Цепочки из диалогов та ещё беда. По хорошему, всё это бы просто в команду $speak(*actor, *target, SENTENCE, time). Делаем какие угодно цепочки с каким угодно ветвлениями и рандомами, диалоговый скрипт можно привязать непосредственно к персонажу тем самым делая его уникальным.

Добавлено 19-11-2019 в 02:45:

Хм, да, сейчас понял, что семантика $find небезопасна, т.к. может возникнуть ситуация, когда в сохранении указатели на уже удалённые сущности. Значит этот момент надо по другому.

__________________
http://www.moddb.com/mods/monorail-quest


Отправлено Дядя Миша 19-11-2019 в 07:51:

Цитата:
thambs писал:
отладка/изменение сценария напоминает работу с древним БАСИКом

Да, это точное сравнение.

Цитата:
thambs писал:
когда в сохранении указатели на уже удалённые сущности.

ну это решено еще Вальвой. Нет такой проблемы.

Синтаксис конечно будет си-подобный, но основную мысль я понял - чтобы колёсики в такт тряслись поезду. Только вот поезд "перейдет" на другую карту, а как он там найдет этот скрипт?

__________________
My Projects: download page

F.A.Q по XashNT
Блог разработчика в телеграме

Цитата:

C:\DOCUME~1\C4C5~1\LOCALS~1\Temp\a33328if(72) : see declaration of 'size_t'


Отправлено thambs 19-11-2019 в 09:29:

Дядя Миша
Ну основная идея что скрипт намертво привязывается к сущности. Т.е. у неё есть, например, поле script, в котором ссылка на текстовик, который читаем при загрузке карты, и есть какое-то скрытое поле, хранящее стек скрипта. Соответственно, паровозик переходит с карты на карту вместе со всей своей требухой что в скрипте насчиталась.

ps: я ещё обдумываю семантику и возможные варианты.

__________________
http://www.moddb.com/mods/monorail-quest


Отправлено Crystallize 19-11-2019 в 10:17:

Цитата:
thambs писал:
Более комплексные игровые механики привели к разрастанию и непомерному усложнению всей системы.

И никто не смог её в полной мере заюзать кроме автора T.E.A. и нашего Доктора.

Цитата:
thambs писал:
то отладка/изменение сценария напоминает работу с древним БАСИКом

БАСИК должно быть даже удобнее чем энтити.

Цитата:
thambs писал:
$set(*entity, key, value) -> status
$get(*entity, key) -> value
$find(*world, mask) -> [*entity]

Тебе комфортно набивать все эти доллары и аст-ириски?


Отправлено thambs 19-11-2019 в 10:22:

Crystallize
Плевать на синтаксис, ДМ сделает как считает нужно. Давайте лучше семантику обсуждать.

Цитата:
кроме автора T.E.A. и нашего Доктора

Автор HC2 ещё, он правда совсем маньяк, но в основном использовал env_render -- следовал за авторами блю-шифта.

__________________
http://www.moddb.com/mods/monorail-quest


Отправлено XaeroX 19-11-2019 в 11:29:

Цитата:
Crystallize писал:
Тебе комфортно набивать все эти доллары и аст-ириски?

Всем похапешникам комфортно.

__________________

xaerox on Vivino


Отправлено FiEctro 19-11-2019 в 12:16:

>> $find(*world, "func_door:storage*")

Ну и дичь лютую вы удумали, писать скрипт под конкретную карту, для каждой сущности. Ещё и трахаться с ДЕБАЖИТЬ отладкой этих финдов.

Что мешает просто подгружать файл скрипта как отдельную сущность со своими полями? Написали какой нибудь trigger_butthurt.qc, если есть на карте он, то он подгрузился, если нет, то нет. Как во всех современных движках. А наследования в скриптах делать по классике, через объявление public/private и т.п.

__________________
У котёнка мокрый нос и гладенькая шерсть, у него забавный хвост и быстрых лапок шесть. Две задних, две средних и две передних лапы, такая многоножка получилася у папы.
Он ученый — папа мой — зверушек изучает, гуляет по помойкам, ловит крыс и чаек. Две крысы белокрылые и чайки две унылые покрытые пупырчатою кожей лягушат без пёрышек тоскуют и ускакать спешат.
А ещё есть муравей большой размером с гуся он пугает всех зверей, и я его боюся, когда он ковыляет на лапках на своих.
И в двери ударяет, и начинает стих: Я — муравей, воды налей! Не меньше ведра, напиться мне пора!


Отправлено nemyax 19-11-2019 в 12:30:

Цитата:
FiEctro писал:
писать скрипт под конкретную карту, для каждой сущности

Где ты увидел "для каждой"?


Отправлено thambs 19-11-2019 в 13:05:

FiEctro
Ответь, почему ты так нагло ПЕРЕВИРАЕШЬ то что я писал?

Цитата:
Написали какой нибудь trigger_butthurt.qc

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

__________________
http://www.moddb.com/mods/monorail-quest


Отправлено Дядя Миша 19-11-2019 в 14:37:

Сгенерил патчи на кутришной карте, ну вроде норм - язык пропал (на q3dm1), как корова в реке утопила. Да что за бред, начал разбираться.
Оптимизатор отключаешь - язык на месте, остальное в порядке. Ну где я мог накосячить? Очевидно нигде. Расковырял функцию оптимизатора - там ошибка. Это походу уже становится традицией.

Добавлено 19-11-2019 в 17:37:

ЗЫ. Оптимизатор из OverDose если что. Не из ку3.

__________________
My Projects: download page

F.A.Q по XashNT
Блог разработчика в телеграме

Цитата:

C:\DOCUME~1\C4C5~1\LOCALS~1\Temp\a33328if(72) : see declaration of 'size_t'


Отправлено ncuxonaT 19-11-2019 в 15:02:

Что оптимизирует оптимизатор?


Отправлено a1batross 19-11-2019 в 15:11:

Оптимизатор оптимизирует брашевые языки, вестимо.

__________________
Xash3D FWGS форк


Отправлено FiEctro 19-11-2019 в 15:39:

Цитата:
thambs писал:
FiEctro
Ответь, почему ты так нагло ПЕРЕВИРАЕШЬ то что я писал?


Да потому что это не интуитивно и запутанно. Что даже здесь я видимо не понял твоей полной задумки.

Цитата:
thambs писал:
FiEctro
А ведь, я вообще не писал о том что бы создавать новые сущности, только о том как мог бы выглядеть механизм более тонкого и настраиваемого взаимодействия между существующими.


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

__________________
У котёнка мокрый нос и гладенькая шерсть, у него забавный хвост и быстрых лапок шесть. Две задних, две средних и две передних лапы, такая многоножка получилася у папы.
Он ученый — папа мой — зверушек изучает, гуляет по помойкам, ловит крыс и чаек. Две крысы белокрылые и чайки две унылые покрытые пупырчатою кожей лягушат без пёрышек тоскуют и ускакать спешат.
А ещё есть муравей большой размером с гуся он пугает всех зверей, и я его боюся, когда он ковыляет на лапках на своих.
И в двери ударяет, и начинает стих: Я — муравей, воды налей! Не меньше ведра, напиться мне пора!


Отправлено Дядя Миша 19-11-2019 в 17:15:

Финальный результат.
Кутришные шейдеры прекрасно заменяются моей системой материалов, даже при отсутствии специализированных GLSL-шейдеров для кутришных заморочек. ну типа мигающих текстур, пидарасов, которые, как известно, ползут по трубам итак далее. Но всё это реализуется в пользовательской части, рендерер трогать не надо.
Для сравнения, тепичный кутришный шейдер, который ничего не делает, а просто заменяет путь к текстуре:

C++ Source Code:
1
textures/skin/surface8_trans
2
{
3
  qer_editorimage textures/skin/surface8.tga
4
  surfaceparm nonsolid
5
  {
6
    map $lightmap
7
    rgbGen identity
8
 
9
  }
10
  {
11
    map textures/skin/surface8.tga
12
    rgbGen identity
13
    blendFunc GL_DST_COLOR GL_ZERO
14
 
15
 
16
  }
17
}

И его аналог в моей системе материалов
C++ Source Code:
1
textures/skin/surface8_trans
2
{
3
  image u_ColorMap = "textures/skin/surface8.tga";
4
}

Если надо светящийся материал, то вот так
C++ Source Code:
1
textures/liquids/lavahellflat_400
2
{
3
  image u_ColorMap = "textures/liquids/lavahell.tga";
4
#define LIGHTING_FULLBRIGHT
5
}

причём сам этот дефайн - он тоже пользовательский. Движок про него не знает.

__________________
My Projects: download page

F.A.Q по XashNT
Блог разработчика в телеграме

Цитата:

C:\DOCUME~1\C4C5~1\LOCALS~1\Temp\a33328if(72) : see declaration of 'size_t'


Отправлено XaeroX 19-11-2019 в 17:22:

Дядя Миша
По трубам, я так понимаю, ползать никто под ксашем не будет? Или можно самому написать шейдер? Если да, то как это будет выглядеть?

__________________

xaerox on Vivino


Временная зона GMT. Текущее время 06:36. Страницы (255): « Первая ... « 36 37 38 39 [40] 41 42 43 44 » ... Последняя »
Показать все 3825 сообщений этой темы на одной странице

На основе vBulletin версии 2.3.0
Авторское право © Jelsoft Enterprises Limited 2000 - 2002.
Дизайн и программирование: Crystice Softworks © 2005 - 2024