Шапка: https://hipolink.me/godothread
Предыдущий: >>1008211 (OP)
Архивный: >>1000909 (OP)
>суть.gif
>решение.gif
Ты троллишь? Это не имеет отношения к движку...
Лучше бы запостил прозрачный рендер с бликами.
Первый сделал игру? Первый пришел к успеху? Первый в топчартах стима?

Делайте игру.
>лучше какую нибудь симуляцию
Но симуляции это тоже игры...
https://en.wikipedia.org/wiki/Non-game
https://en.wikipedia.org/wiki/Simulation_video_game
Покажешь свои симуляции?
>в Годо есть встроенное решение для undo/redo!
Внезапно оно в самом же редакторе используется, так что это довольно очевидно.
С другой стороны, изобретение своего велосипеда помогает понять принципы и детали его работы.
>>4048
>Лучше бы запостил прозрачный рендер с бликами.
Или Jiggle-физику
>оно в самом же редакторе используется
И люто бесит. Когда ты нажимаешь ctrl+z, отмена происходит там, где ты сейчас сфокусировался... Например, если хочешь отменить удаление ноды - нажимаешь на дерево сцены, а если параметров материала - на инспектор материала. Дико бесит, особенно когда меняешь всё и сразу, понемногу.
Привык, что полагаться на undo/redo в Godot нельзя.
https://docs.godotengine.org/en/stable/classes/class_undoredo.html
>>4070
Это еще ладно. Бывает, что оно вообще перестает работать и начинает удалять какие-то рандомные строки кода вместо undo. Помогает только перезапуск редактора.
А ты историю изменений пробовал? В какой-то версии реализовали - по умолчанию там, где инспектор, вроде третья вкладка. По идее, глобальный откат/повтор, но лично я выключил это меню в настройках (кажется, тормозило, не помню уже; нужно ещё попробовать).
Впрочем, обычно ничего кроме одного ctrl+z не нужно.

1920x1080, 1:04
Нет, свои не покажу.

Баг древний, но его почему-то игнорируют:
https://github.com/godotengine/godot/issues/31186
Меня задолбало... Как оптимизировать структуру проекта, чтоб избежать этих лишних сохранений? Пробовал закрывать все вкладки сцен - пикрил...
Хз, сам не встречал этот баг, хотя гитом пользуюсь с 3.х. Думаю он не столько про замедление сколько про замусоривание лога гита.
Самый простой способ с переменной:
>var obj := get_some_object() as MyType
>if obj: obj.do_my_func()
Если объект не MyType, то в obj будет null.
Разница между is и as:
obj is T == true/false (bool)
obj as T == obj/null (T)
В условиях:
null == false
instance == true
freed_instance == false
Поэтому можно делать так:
>if obj: # если obj создан и пока существует...
Если другие типы недопустимы, лучше так:
>(get_some_object() as MyType).do_my_func()
Это упадёт с обращением к null если не MyType.
>>4119
>Симулятора алкоголика еще, вроде, не было.
Было уже несколько, это банальная идея...
Мне нравится когда в условии if создаётся локальная переменная и к ней подтягивается автодополнение редактора. Сделойти.
>в условии if создаётся локальная переменная
Это же просто синтаксический сахар, не более...
Если тебя волнует локальность - ты говнокодишь.
>подтягивается автодополнение
Здесь оно тоже подтягивается:
>var obj := get_some_object() as MyType
>if obj: obj.do_my_func()
И здесь тоже подтягивается:
>(get_some_object() as MyType).do_my_func()
Алсо, GDScript позволяет форматировать так:
>var obj := get_some_object() as MyType; if obj:
>_ obj.do_my_func()
Если очень надо, можно всё в одну строчку через ";".
>Сделойти
Делай сам. Но в основную версию вряд ли пустят.

> Но в основную версию вряд ли пустят.
Они уже очень много притянули из шарпа. Неужели я многого прошу ещё одну фичу притянуть. Из шарпа.
> @private @onready var something : String = "hurr durr"
Для обратной совместимости считать все переменные и функции публичными, но добавить аннотацию, которая задаёт режим:
> @private_default
> Что мешает написать так?
Очевидно, что мешает необходимость проверять несколько подтипов в цепочке наследования.
>модификаторы доступа
https://github.com/godotengine/godot/pull/103768
Ты серьёзно пишешь в своём коде такое?
>other_object._private_var = value
>other_object._private_func()
Это ж максимально неприятно выглядит ("._").
Естественно, что приватное начинается с "_".
>>4143
>проверять несколько подтипов в цепочке
https://ru.wikipedia.org/wiki/Проблема_XY
Конкретно зачем тебе это нужно?
Если в твоём коде часто случается такое:
>если а типа А, то...
>иначе если а типа Б, то...
>иначе если а типа В, то...
>иначе если а типа Г, то...
Тогда тебе нужно учить базу ООП.
https://ru.wikipedia.org/wiki/SOLID
Реальное решение будет выглядеть так:
>get_object().do_work() # никаких проверок
В каждом классе - свой личный do_work().
>has_method
Вроде бы можно так, и это даже будет побыстрее:
>if "do_work" in obj: obj.do_work()
Но это если у тебя obj может не иметь do_work().
Речь шла про ситуации, когда ты делаешь так (плохо!):
>if animal is Cat: animal.meow()
>elif animal is Dog: animal.bark()
>elif animal is Bird: animal.chirp()
>elif animal is Duck: animal.quack()
>elif animal is Human: animal.shout()
Вместо этого лучше сделать так:
>animal.make_sound()
Cat, Dog, Bird, Duck и Human сами решат, как им звучать.
Если у тебя есть Fish, то у неё тоже есть этот метод:
>class_name Fish extends Animal
>func make_sound() -> void: pass # fish can't make sound
Чтобы не было проверок типа "можешь ли ты звучать".
Суть в том, что ты ПРОСТО создаёшь новый класс:
>class_name Zombie extends Animal
И реализуешь ему все необходимые Animal методы:
>func make_sound() -> void: play_sound("Aaarghhhh!")
ВСЁ. Не нужно никуда добавлять "elif animal is Zombie..."
Для RayCast/ShapeCast/Area лучше всего настроить слои.
>has_method
Вроде бы можно так, и это даже будет побыстрее:
>if "do_work" in obj: obj.do_work()
Но это если у тебя obj может не иметь do_work().
Речь шла про ситуации, когда ты делаешь так (плохо!):
>if animal is Cat: animal.meow()
>elif animal is Dog: animal.bark()
>elif animal is Bird: animal.chirp()
>elif animal is Duck: animal.quack()
>elif animal is Human: animal.shout()
Вместо этого лучше сделать так:
>animal.make_sound()
Cat, Dog, Bird, Duck и Human сами решат, как им звучать.
Если у тебя есть Fish, то у неё тоже есть этот метод:
>class_name Fish extends Animal
>func make_sound() -> void: pass # fish can't make sound
Чтобы не было проверок типа "можешь ли ты звучать".
Суть в том, что ты ПРОСТО создаёшь новый класс:
>class_name Zombie extends Animal
И реализуешь ему все необходимые Animal методы:
>func make_sound() -> void: play_sound("Aaarghhhh!")
ВСЁ. Не нужно никуда добавлять "elif animal is Zombie..."
Для RayCast/ShapeCast/Area лучше всего настроить слои.
>>func make_sound() -> void: pass # fish can't make sound
Поправка: этот метод скорее всего есть у предка - Animal:
>class_name Animal extends...
>func make_sound() -> void: pass
Многие потомки Animal делают свою версию, но не Fish.
Таким образом любые потомки Animal могут "звучать".

>Думаю он не столько про замедление
У меня Godot начал зависать при сохранении.
Сохраняю один простой скрипт - жду секунд 10.
Почему это может быть? Как искать причину?
Чекай жёсткий диск. Походу пришло время, его время.
Это не соответствует парадигме duck typing. Используй has_method.
>>4141
Никогда не понимал, зачем это нужно. Ну ладно, в компилируемых языках, возможно, применяются какие-то оптимизации, которые могут добавить производительности, если правильно разграничить права доступа. Наверное. Но в гдскрипте-то это зачем? Почему нельзя написать коммент "## это приватный мембер" и просто не использовать его извне? Это ж никак не влияет на производительность. Зачем эти искусственные ограничения?
> Используй has_method(&"method_name")
У меня детская травма, я не люблю строковые литералы в коде. И даже то что Хуан сделал для таких как я стрингнеймы - не сильно помогает.

>просто не использовать его извне
КАЧАЕШЬ ПРИКОЛЬНЫЙ АДДОНЧИК
@
ОН ПОЧТИ ИДЕАЛЕН ДЛЯ ТВОЕЙ ИГРЫ
@
НАДО ЛИШЬ КОЕ-ЧТО ИЗВНЕ ПОПРАВИТЬ
@
НАХОДИШЬ ИНТЕРЕСНОЕ ПОЛЕ _ПЕРДЫХ
@
ДА ЭТО ЖЕ ЛУЧШАЯ ФИЧА ВСЕГО АДДОНА!
@
СКАЗАНО НЕ ИСПОЛЬЗОВАТЬ, НУ ДА ЛАДНО
@
НИКАКИХ ПОБОЧНЫХ ЭФФЕКТОВ НЕ ВИДНО
@
ОБМАЗЫВАЕШЬ ВСЮ ИГРУ ЭТИМ _ПЕРДЫХ
@
ВСЯ ИГРА СВИСТИТ И ПЕРДИТ - КРАСОТА!
@
ПРОХОДИТ ПАРА МЕСЯЦЕВ РАЗРАБОТКИ
@
ОБНОВЛЯЕШЬ АДДОН ДО ВЕРСИИ 1.0.1
@
ТАМ ФИКС КРИТИЧЕСКОГО ОБДРИСТА
@
БЕЗ НЕГО ИГРА РАСТЕКАЕТСЯ В ЛУЖИЦУ
@
ПРОВЕРЯЕШЬ, КАК ОНО ПОСЛЕ АПДЕЙТА
@
_ПЕРДЫХ ВЕДЁТ СЕБЯ КАК-ТО СТРАННО
@
ПРОЕКТ СЛОМАЛСЯ И БОЛЬШЕ НЕ ПЕРДИТ
@
ВСЯ ТВОЯ ИГРА БЫЛА ПРО ЭТОТ ПЕРДЁЖ
@
РЕШАЕШЬСЯ САМ ПОФИКСИТЬ _ПЕРДЫХ
@
В АДДОНЕ 100500 СТРОК ГОВНОКОДА...

>просто не использовать его извне
КАЧАЕШЬ ПРИКОЛЬНЫЙ АДДОНЧИК
@
ОН ПОЧТИ ИДЕАЛЕН ДЛЯ ТВОЕЙ ИГРЫ
@
НАДО ЛИШЬ КОЕ-ЧТО ИЗВНЕ ПОПРАВИТЬ
@
НАХОДИШЬ ИНТЕРЕСНОЕ ПОЛЕ _ПЕРДЫХ
@
ДА ЭТО ЖЕ ЛУЧШАЯ ФИЧА ВСЕГО АДДОНА!
@
СКАЗАНО НЕ ИСПОЛЬЗОВАТЬ, НУ ДА ЛАДНО
@
НИКАКИХ ПОБОЧНЫХ ЭФФЕКТОВ НЕ ВИДНО
@
ОБМАЗЫВАЕШЬ ВСЮ ИГРУ ЭТИМ _ПЕРДЫХ
@
ВСЯ ИГРА СВИСТИТ И ПЕРДИТ - КРАСОТА!
@
ПРОХОДИТ ПАРА МЕСЯЦЕВ РАЗРАБОТКИ
@
ОБНОВЛЯЕШЬ АДДОН ДО ВЕРСИИ 1.0.1
@
ТАМ ФИКС КРИТИЧЕСКОГО ОБДРИСТА
@
БЕЗ НЕГО ИГРА РАСТЕКАЕТСЯ В ЛУЖИЦУ
@
ПРОВЕРЯЕШЬ, КАК ОНО ПОСЛЕ АПДЕЙТА
@
_ПЕРДЫХ ВЕДЁТ СЕБЯ КАК-ТО СТРАННО
@
ПРОЕКТ СЛОМАЛСЯ И БОЛЬШЕ НЕ ПЕРДИТ
@
ВСЯ ТВОЯ ИГРА БЫЛА ПРО ЭТОТ ПЕРДЁЖ
@
РЕШАЕШЬСЯ САМ ПОФИКСИТЬ _ПЕРДЫХ
@
В АДДОНЕ 100500 СТРОК ГОВНОКОДА...
Как стану миллиардером и перееду на запад - обязательно буду переводить процентов 5% дохода.

Да действительно, блять, что же это такое? Давайте поможем Даше найти гугл, блять.
>Гит, бекапы
Каким образом гит/бэкап поможет тебе обновить посторонний аддон до новой версии, сохранив функциональность игры, которая опиралась на секретную (приватную) возможность, которую ты не должен был использовать и которая изменилась?
С приватными полями всё просто: редактор тебе автоматически по рукам бьёт и говорит "низя". Без приватных полей ты говнокодишь без ограничений.
Это как со слабой типизацией: да, МОЖНО хранить в одной и той же переменой любые данные. Но будут последствия для твоего психического здоровья, при условии, что код проживёт дольше одного вечера.
Ещё более наглядный пример - глобальные данные, синглтоны. Хочешь обмазаться лапшой и дрочить?
Писать говнокод слишком легко - нужен начальник, наказывающий тебя за говнокод автоматически.

> Ещё более наглядный пример - глобальные данные, синглтоны. Хочешь обмазаться лапшой и дрочить?
Обоже опять эти ужасные антипаттерны повылезали из под кровати.

>Давайте поможем Даше
Ты чё такой помогающий?
>>4243
>>стрингнеймы
>Это что такое?
https://docs.godotengine.org/en/stable/classes/class_stringname.html
Хорошо, делай синглтоны:
Sprite: уникальная аватарка для Player.
Player: принимает ввод и меняет Sprite.pos.
Health: выводит над Sprite.pos здоровье Player.
Enemy: движется к Sprite.pos, снижает Health.value.
Shield: копирует Sprite.pos, поднимает Health.value.
И так далее. Не смей избегать синглтонов в игре.
Потом расскажешь, какой это чудесный паттерн.
ПРОСТО откатишься на старую версию, когда все работало. Стремление всегда использовать последнее - болезнь мозга и подвид прокрастинации.
В версии 1.0 всё работает, но из-за бага компьютер игроков взламывается кулхацкером фалько и жжёт пердаки до температуры поверхности Солнца. Это обнаружили только спустя несколько месяцев.
В весии 1.0.1 баг пофиксили, но из-за него ты будешь вынужден изменить 100500 строчек в проекте. Но и релизить игру с багом из 1.0 тоже недопустимо.
Влошил 100500 трудочасов и теперь откатишь их?
А ты просто заюзал то, что мог, но не должен был...
>Ни разу не встречал.
Их реализовали только в 4.0 для оптимизации...
Начиная с 4.0, используют во многих API движка.
>Оно где-то под капотом работает?
Так-то да, но можно использовать вручную, но много непонятных нюансов. По идее StringName - это просто целое число, поэтому их очень легко сравнивать - нет необходимости проверять каждый символ строки. Но преобразование String в StringName занимает много времени, равно как и создание нового StringName... Поэтому лучше их создавать заранее как константы.
Перестань строить из себя клоуна. Синглтоны нужны там, где они нужны, на своих местах. Я не буду реализовывать приведённое тобой соломенное чучело, чучело.
>Синглтоны нужны там, где они нужны
Приведи примеры, где они обязательно нужны.
Не из API движка, а из твоей собственной игры.
Где ты никак не смог обойтись без синглтона?
Алсо, как новичок определит, где они нужны?

В редот коммитит примерно никто. Смотрю у них сил не осталось даже на таскание коммитов из годота.
Бля, а вони-то было.
> DialogueSingleton.start_dialogue(npc.get_current_lines(), WorldDataSingleton.get_dialogue_point(npc))
Данный код запрашивает у синглтонового менеджера диалогов старт диалога, первый параметр - ресурс со строками диалога в формате жсон, второй параметр - точка на которой был прерван диалог, точка входа. Берется из синглтонового менеджера управления данными для сохранения.

Уже год жду...
Не стоит. Пусть коммитит Хуану.
>DialogueSingleton.start_dialogue
>WorldDataSingleton.get_dialogue_point
Что не получится сделать из-за этих синглтонов:
1. Сплит-скрин мультиплеер: нужны от 2 до 4 диалогов.
2. Параллельный разговор с NPC: нужно от 2 диалогов и более.
3. Параллельные вселенные в игре: нужны разные ветки сохранения.
Без синглтонов подобное решается простым созданием экземпляров классов.
Почему ты решил сделать именно так, через очевидно не обязательные синглтоны?
Нет пусть остается.
Я здесь чтобы обсуждать какие-то фичи в движке, которые мне интересны.
>...Server..., IP, Input..., Native..., OS, Java..., GDExtension...
Может быть только одним - это прослойка перед железом/ОСью.
>ClassDB, Editor..., Engine..., Performance, Project..., Navigation...
Может быть только одним - это основное API движка, а он один.
Наш диалог:
Я: не делай сиденье синглтоном, в машине их обычно несколько.
Ты: а вот двигатель в машине один, значит и сиденье тоже одно!
Я: не делай дверь синглтоном, в машине их обычно несколько.
Ты: а вот руль в машине один, значит и дверь только одна!
Я: вообще, двигателей и рулей может быть несколько...
Ты: а вот в моём запорожце их по одной штуке!!!
Я: а если тебе нужно будет вездеход сделать?
Ты: ряяяя, в запорожце так, значит так!!!
Я: а почему ты так привязался к этому?
Ты: а я уже сказал - запорожец! так!
Не чувствуешь проблему?..
>AudioServer может быть только один
>Как же так, баги когда игрок переключается с динамика на Bluetooth
>DisplayServer может быть только один
>Годами приходится добавлять поддержку второго глаза для ВиАр или второй монитор со своим разрешением
>PhysicsServer может быть только один
>Приходится городить костыли когда нужно две разных физических симуляции (например одна для платформера, а вторая для инвентаря).
Смеюсь, показываю пальцем и фотографирую.
>СКАЗАНО НЕ ИСПОЛЬЗОВАТЬ, НУ ДА ЛАДНО
Вот здесь проблема. В кривых руках кодера, который полез нажимать красную кнопку, на которой написано не нажимать. Не зная, что под капотом эта кнопка делает, почему нажимать нельзя и какие могут быть скрытые последствия.
Это всё равно что засунуть посторонний металлический предмет в розетку, а потом жаловаться, что током ёбнуло - ну ты же смог его туда запихнуть, значит это было можно, да?
Это защита от случайного попадания предметов. От преднамеренного поможет только живительная эвтаназия.

С шейдером уже сделал. Теперь интересно без.
Да, без шейдеров. Оно использует draw_polygon() из https://docs.godotengine.org/en/stable/tutorials/2d/custom_drawing_in_2d.html
Работает же. Нахуя тогда вобще в яп добавляют условия?
поч не нравится? мне все нравится. главное не делать много этажей.
Так, важен не факт наличия шейдера, а тяжелость его вычислений.
Например шейдеры который лежит на godotshaders выглядит очень тяжелым.
Во первых там fragment(), это вычисления для каждого пикселя, а не для полигона. И они все с синусами. С нодой по идее один раз считается при повороте (ну может еще раза 4 для вершин прямоугольрника).
Во вторых там if, в шейдерах это насколько помню сбивает конвеер.
А clip, скорее всего, превращается во встроенную в opengl функцию отсечения.
>>4444
Мне игры делать неинтересно, писал же выше. А оптимизон под веб/мобилки интересно.
Не увидите, я анонимен.
Чего-то там про круелти сквад? Не интересует как жанр, но видел всплывало повсюду. Удачи ему.
>клипуем
>>4458
>вычисления для каждого пикселя
А ты знаешь, как реализован этот клипинг?
Не знаю, попиксельный ли клипинг или нет, но:
>Note: Clipping nodes cannot be nested or placed within CanvasGroups. If an ancestor of this node clips its children or is a CanvasGroup, then this node's clip mode should be set to CLIP_CHILDREN_DISABLED to avoid unexpected behavior.
>оптимизон под веб/мобилки интересно
Возможно, лучше использовать полигон:
https://docs.godotengine.org/en/stable/classes/class_polygon2d.html
И двигать одну из вершин.
Алсо, если тебя интересует оптимизация:
1. Реализуешь каждый вариант по отдельности.
2. Размещаешь десятки тысяч каждого варианта.
3. Собираешь статистику на реальном устройстве.
4. Смотришь, какой вариант тормозит меньше всего.
Всё остальное - бесполезное теоретизирование.
>Мне игры делать неинтересно
Ты симуляцию делать хотел, зачем прогресс-бар?
>кодера, который полез нажимать
>>4414
>От преднамеренного поможет только
Ты не понимаешь психологии человеческой.
Если что-то лежит в открытом виде, как оголённые провода под напряжением - кто-то когда-то за них обязательно схватится голыми руками. Не "дурак", а случайно, по ошибке, от усталости, от лени и т.д.
Если провода спрятаны в ящик, что нужно открыть, прежде чем коснуться провода - это сильно снижает вероятность случайных и ошибочных действий, но уставший, ленивый или забывчивый всё же может проигнорировать перчатки/отключение питания.
Если ящик с проводами физически нельзя открыть, сохранив питание цепи - это снижает вероятность в ситуации с усталостью/ленью - перчатки больше не нужны. Если ящик с проводами закрыт на замок, а ключик у ответственного контролёра - это снижает вероятность забывчивого/ленивого залезть внутрь.
Если человек действительно ХОЧЕТ схватиться за оголённые провода и получить удар током, тогда он обязательно найдёт способ это сделать. Но все эти "защиты от дурака" не против злоумышленников, а против случайных, ошибочных, непреднамеренных действий, которые допускают даже умные люди, особенно уставшие после долгой тяжёлой работы.
Так и с public/private полями. Да, ты всегда можешь забраться в исходники, заменить private на public и получить доступ к тому, к чему не следует. Но это потребует осознанных усилий, а не обычного кода снаружи класса, что получает доступ к чему-то. Т.е. предупреждение компилятора/интерпретатора о потенциально непреднамеренной ошибке более чем достаточно, чтоб избежать 99% проблем в будущем.
Комментарии тут не решают проблему, т.к. их нужно сознательно читать в исходниках. Предупреждение компилятора/интерпретатора выводится туда, где допускается потенциальная ошибка, в точку вызова.
Это просто удобнее. В том числе умным людям.

854x480, 1:48
У меня еще родилась идея сделать шейдер, только не фрагментный, а вершинный - рисовать полигон смещая вершину. Приду с прогулки попробую.
>CanvasGroups
Не пользуюсь пока, да и не помню есть ли в 3-ке.
>Ты симуляцию делать хотел, зачем прогресс-бар?
В смысле зачем? А если мне надо симуляцию с десятками тысяч прогресс баров? Как в CivIdle. Симуляцию сапера 10000х10000 тут уже делали, вроде.
>1. Реализуешь каждый вариант по отдельности.
>2. Размещаешь десятки тысяч каждого варианта.
>3. Собираешь статистику на реальном устройстве.
>4. Смотришь, какой вариант тормозит меньше всего.
>Всё остальное - бесполезное теоретизирование.
Это эксперимент, а эксперимент проверяет теорию. А ее сначала можно построить в голове, на основе знания, то есть представить цепочку как проходят операции, тоже в каком то смысле игра-паззл. Если результат эксперимента не совпадет с теорией, то теория корректируется. А поскольку я занимаюсь оптимизациями по работе много лет, то и ошибаюсь со временем реже. Вот прям практически гарантировано фрагментный шейдер с if- для каждого пикселя медленнее.
>фрагментный шейдер
Суть шейдера - нарисовать КРАСИВО. Если нужен переливающийся всеми цветами радуги градиент с интересными волнообразными колебаниями, твои оптимизации сразу идут лесом. И как следствие, потраченное на них время - потрачено впустую. Вот поэтому всегда говорят, что преждевременные оптимизации - корень всех зол, и нужно сначала состряпать рабочую систему/игру из того, что есть.
>эксперимент проверяет теорию
Теория может быть выведена из экспериментов. В геймдизайне ты мало что можешь предсказать теоретическими размышлениями об игроках. А оптимизации должны идти после геймдизайна. Т.е. стряпаешь сырой тормозной прототип, потом, если сработает дизайн, делаешь варианты оптимизации. Нодовая система Godot как раз на это заточена.
>если мне надо симуляцию с десятками тысяч
Тогда ты отображаешь максимум 100 таких баров, остальные скрываются за пределами экрана, ибо отображаются только когда камера приближена. И упрощаешь геометрию баров до прямоугольников. Заменяешь бары на тробберы. Объединяешь сотни отдельных юнитов в группы с одним баром. И т.п. Универсального решения нет, нужно смотреть игру.
>Как в CivIdle
На видео нет баров, там только тробберы:
https://en.wikipedia.org/wiki/Throbber
https://ru.wikipedia.org/wiki/Троббер
>есть ли в 3-ке
А, описанного выше клипинга в тройке вообще нет:
https://docs.godotengine.org/en/stable/classes/class_canvasitem.html#class-canvasitem-property-clip-children
В тройке раньше для этого юзали Light2D:
https://docs.godotengine.org/en/3.6/classes/class_light2d.html
Клипинг прямоугольников, как я понимаю, проще. Поэтому твой способ, в теории, может работать.
https://docs.godotengine.org/en/3.6/classes/class_control.html#class-control-property-rect-clip-content
В актуальной версии переименовали:
https://docs.godotengine.org/en/stable/classes/class_control.html#class-control-property-clip-contents
>вершинный
Вершинный шейдер будет эффективен только если регулярно меняешь позиции вершин. Если бар очень медленный, то вершинный шейдер тоже избыточен. Впрочем, разница наверняка минимальная.
Повторюсь, если нужен троббер - это отдельная тема. Вращающийся троббер равно вращающийся спрайт, особенно если без дополнительных эффектов.
У тебя что-нибудь играбельное есть?
Или ты пока делаешь компоненты?
>фрагментный шейдер
Суть шейдера - нарисовать КРАСИВО. Если нужен переливающийся всеми цветами радуги градиент с интересными волнообразными колебаниями, твои оптимизации сразу идут лесом. И как следствие, потраченное на них время - потрачено впустую. Вот поэтому всегда говорят, что преждевременные оптимизации - корень всех зол, и нужно сначала состряпать рабочую систему/игру из того, что есть.
>эксперимент проверяет теорию
Теория может быть выведена из экспериментов. В геймдизайне ты мало что можешь предсказать теоретическими размышлениями об игроках. А оптимизации должны идти после геймдизайна. Т.е. стряпаешь сырой тормозной прототип, потом, если сработает дизайн, делаешь варианты оптимизации. Нодовая система Godot как раз на это заточена.
>если мне надо симуляцию с десятками тысяч
Тогда ты отображаешь максимум 100 таких баров, остальные скрываются за пределами экрана, ибо отображаются только когда камера приближена. И упрощаешь геометрию баров до прямоугольников. Заменяешь бары на тробберы. Объединяешь сотни отдельных юнитов в группы с одним баром. И т.п. Универсального решения нет, нужно смотреть игру.
>Как в CivIdle
На видео нет баров, там только тробберы:
https://en.wikipedia.org/wiki/Throbber
https://ru.wikipedia.org/wiki/Троббер
>есть ли в 3-ке
А, описанного выше клипинга в тройке вообще нет:
https://docs.godotengine.org/en/stable/classes/class_canvasitem.html#class-canvasitem-property-clip-children
В тройке раньше для этого юзали Light2D:
https://docs.godotengine.org/en/3.6/classes/class_light2d.html
Клипинг прямоугольников, как я понимаю, проще. Поэтому твой способ, в теории, может работать.
https://docs.godotengine.org/en/3.6/classes/class_control.html#class-control-property-rect-clip-content
В актуальной версии переименовали:
https://docs.godotengine.org/en/stable/classes/class_control.html#class-control-property-clip-contents
>вершинный
Вершинный шейдер будет эффективен только если регулярно меняешь позиции вершин. Если бар очень медленный, то вершинный шейдер тоже избыточен. Впрочем, разница наверняка минимальная.
Повторюсь, если нужен троббер - это отдельная тема. Вращающийся троббер равно вращающийся спрайт, особенно если без дополнительных эффектов.
У тебя что-нибудь играбельное есть?
Или ты пока делаешь компоненты?

> Если нужен переливающийся всеми цветами радуги градиент с интересными волнообразными колебаниями, твои оптимизации сразу идут лесом.
А может не идут - градиент можно пустить и по моему квадрату и скорее всего он все еще будет быстрее.
>А оптимизации должны идти после геймдизайна
А у меня не должны.
>тробберы
Ну в принципе да можно замутить что-то наподобие радара из полупрозрачной текстуры. А может я захочу чтобы там кулдаун у каждого был независимый.
> упрощаешь геометрию баров до прямоугольников. Заменяешь бары на тробберы. Объединяешь сотни отдельных юнитов в группы с одним баром
А может это преждевременная оптимизация.
>А, описанного выше клипинга в тройке вообще нет:
Так у меня в примере и была 3-йка и рект клиппинг.
Если повернуть родительский объект, то клиппинг работает внутри нового bounding box, возможно этому можно придумать какие то применения для спецэффектов.
>У тебя что-нибудь играбельное есть?
>Геймдизайн, геймдизайн
Сказал же, мне это сейчас неинтересно. Может на Ludum dare сделаю что то за пару дней. Или до ТВГ подожду.
Я просто сохраняю всю сцену в packed scene, дальше загружаю и продолжаю. В рот ебал вручную все восстанавливать.
Это про диалоги? Ссылки на внутренние (внутри игры) кастомные ресурсы диалоговой очереди внутри сейва? Или для чего-то еще можно ресурсы уместно в данном контексте применить? Для сохранения прогресса я просто не представляю как их можно использовать. Это ведь те же самые були будут.
>>4559
Не знал, что так можно. А поля автолод классов такой подход затрагивает?
Используй силу ООП. Заведи во всех важных классах функции save и load. В save сохраняй только важное геймплейное об объекте. Например позицию, кулдауны итд. А не всякие там состояния анимационного дерева. И каждому объекту выдай уникальный ID, и при сохранении например выбранной врагом цели сохраняй не ссылку на врага, а этот ID. Потом при спавне соответственно функцией load располагаешь все на нужные места, инициализируешь стейтмашины в нужное состояние. Вообще какие то готовые аддоны на это есть, я не пробовал правда.
У меня все.
Я пошел еще дальше - даже не расписываю ничего. Что нравится, тем и занимаюсь. Правда, игру так и не доделал.
Тоже так делал, пока не застрял с сегодня лень выдумывать задачи, нужны готовые
У легких задач больший шанс оказаться выполненными, причем быстро. И остаются сложные длинные задачи в которых ты застреваешь, и мозг быстро зарезает весь бюджет допамина выделенный на эту затею. Конец.
Тебе нужно в первую очередь умение деребанить большие задачи на маленкие, и воспринимать их соответственно. Это главный скилл, который появляется с опытом. Чтобы получить этот скилл, нужно просто начать и делать, понимая что ошибки это часть процесса. Одновременно почитывая книжки по сабжу(системное мышление) и консультируясь с нейронкой. Плставив этот скилл на рельсы ты получаешь чит на неограниченный допамин для решения задач любой глубины.
>Как можно хранить прогрессию в игре-песочнице?
Если хочешь, чтоб игрок мог редактировать в Блокноте: JSON.
Если хочешь сжато/чтоб игрок не мог править: бинарные файлы.
Если много сложных данных: база данных, как упомянул >>4558
>Как из маркера прогресса доставать доступные диалоги и прочее?
Если ты про квесты/линейный сюжет, то это делается примерно так:
1. Есть глобальная последовательность ID (целые числа), которые переключаются друг за другом при достижении игроком определённых триггеров - например, завершение квестов. Это сюжет. Он может быть разветвлённым и нелинейным - главное, чтобы ID были уникальными для каждого этапа/эпизода/главы сюжета. Для простого наглядного примера (без графики и геймплея, чисто сюжет) - посмотри, как создаются и хранятся истории в https://twinery.org/ - его и в более сложных играх используют. "Профессиональные" инструменты отличаются только количеством дополнительных свистелок и тормозами.
2. Глобальная последовательность может делиться на линейки квестов. У каждой линейки квестов есть своя последовательность ID, свои квестодатели, свои условия перехода, свои награды и т.д. Т.е. игрок может проходить параллельно несколько независимых квестовых линеек - в сейве, соответственно, помимо/вместо одного глобального числа-ID будет набор из нескольких чисел. Они могут интегрироваться в глобальный сюжет, если он есть, например, "следующая глава начинается только если игрок завершил N-ное число побочных линеек квестов на текущей локации".
Также есть много плагинов с готовыми решениями - смотри сам, что нравится.
>>4557
>Ресурсы. Кастомные ресурсы.
>>4559
>сохраняю всю сцену в packed scene
Записывать и считывать ресурсы (.tres/.res и .tscn/.scn) на компьютере игрока из произвольного места на диске чревато заражением вирусом в худшем случае (т.к. Godot автоматически выполняет любые загруженные скрипты, а антивирусы эти скрипты никак не распознают, а игроки постоянно обмениваются сейвами; давно уже предлагали сделать песочницу/вырубить скрипты из этих файлов) или просто тяжёлой поломкой сейва в случае неудачного обновления игры (твои скрипты/сцены или какие-то изменения API в новой версии движка), что будет сложно восстановить автоматически и игроку придётся начинать игру с начала. Система ресурсов и сцен удобна только для данных, которые ты экспортируешь в .pck и не пересохраняешь на компе игрока.
Надёжнее хранить все сохраняемые данные в JSON/XML/INI/бинарных файлах/базе данных и заниматься сохранением и восстановлением вручную. Однако, XML избыточно сложный, а INI (ConfigFile) слишком ограниченный. Поэтому либо JSON/бинарные файлы, либо подключать СУБД на свой выбор.
Не надо бояться "ручного" сохранения/загрузки. Там всё легко абстрагируется и управляется.
>Как можно хранить прогрессию в игре-песочнице?
Если хочешь, чтоб игрок мог редактировать в Блокноте: JSON.
Если хочешь сжато/чтоб игрок не мог править: бинарные файлы.
Если много сложных данных: база данных, как упомянул >>4558
>Как из маркера прогресса доставать доступные диалоги и прочее?
Если ты про квесты/линейный сюжет, то это делается примерно так:
1. Есть глобальная последовательность ID (целые числа), которые переключаются друг за другом при достижении игроком определённых триггеров - например, завершение квестов. Это сюжет. Он может быть разветвлённым и нелинейным - главное, чтобы ID были уникальными для каждого этапа/эпизода/главы сюжета. Для простого наглядного примера (без графики и геймплея, чисто сюжет) - посмотри, как создаются и хранятся истории в https://twinery.org/ - его и в более сложных играх используют. "Профессиональные" инструменты отличаются только количеством дополнительных свистелок и тормозами.
2. Глобальная последовательность может делиться на линейки квестов. У каждой линейки квестов есть своя последовательность ID, свои квестодатели, свои условия перехода, свои награды и т.д. Т.е. игрок может проходить параллельно несколько независимых квестовых линеек - в сейве, соответственно, помимо/вместо одного глобального числа-ID будет набор из нескольких чисел. Они могут интегрироваться в глобальный сюжет, если он есть, например, "следующая глава начинается только если игрок завершил N-ное число побочных линеек квестов на текущей локации".
Также есть много плагинов с готовыми решениями - смотри сам, что нравится.
>>4557
>Ресурсы. Кастомные ресурсы.
>>4559
>сохраняю всю сцену в packed scene
Записывать и считывать ресурсы (.tres/.res и .tscn/.scn) на компьютере игрока из произвольного места на диске чревато заражением вирусом в худшем случае (т.к. Godot автоматически выполняет любые загруженные скрипты, а антивирусы эти скрипты никак не распознают, а игроки постоянно обмениваются сейвами; давно уже предлагали сделать песочницу/вырубить скрипты из этих файлов) или просто тяжёлой поломкой сейва в случае неудачного обновления игры (твои скрипты/сцены или какие-то изменения API в новой версии движка), что будет сложно восстановить автоматически и игроку придётся начинать игру с начала. Система ресурсов и сцен удобна только для данных, которые ты экспортируешь в .pck и не пересохраняешь на компе игрока.
Надёжнее хранить все сохраняемые данные в JSON/XML/INI/бинарных файлах/базе данных и заниматься сохранением и восстановлением вручную. Однако, XML избыточно сложный, а INI (ConfigFile) слишком ограниченный. Поэтому либо JSON/бинарные файлы, либо подключать СУБД на свой выбор.
Не надо бояться "ручного" сохранения/загрузки. Там всё легко абстрагируется и управляется.

Приведу пример, как это можно оформить в коде.
Допустим, есть три+ главы сюжета и квест "ограбление банка":
>bank.tscn / bank.gd
># save_data может быть локальным для этого экземпляра банка
>func load_state(save_data: SaveData) -> void:
>_ match save_data["story"].phase:
>_ _ 1: # первая глава: банк в норме (сюжет о чём-то другом идёт)
>_ _ _ spawn_default_state() # банк - всего лишь декорация
>_ _ 2: # вторая глава: игрок обнаружил, что банк грабят
>_ _ _ match save_data["bank"].phase:
>_ _ _ _ 1: spawn_bandits() # игрок поблизости - начато ограбление
>_ _ _ _ 2: spawn_cops(false) # приехали копы, игрок их не трогал
>_ _ _ _ 3: spawn_cops(true) # приехали копы, игрок в них пострелял
>_ _ 3: # третья глава: после ограбления
>_ _ _ match save_data["bank"].phase:
>_ _ _ _ 4: spawn_robbed_state() # банк ограблен и закрыт (3 -> 4)
>_ _ _ _ 5: spawn_with_cute_maid() # в банк ходит горничная (2 -> 5)
>_ _ _ _ 6: spawn_default_state() # игрок нанял горничную (5 -> 6)
>_ _ _: # все остальные главы после третьей
>_ _ _ spawn_default_state() # банк восстановлен или горничная ушла
Как триггерить каждый из этапов, что, как и где спавнить - дело твоё.
В больших ААА-играх плюс-минус такая же система используется...
>Записывать и считывать ресурсы (.tres/.res и .tscn/.scn) на компьютере игрока из произвольного места на диске чревато заражением вирусом в худшем случае
>а игроки постоянно обмениваются сейвами
Думал об этом, пришел к выводу что во-первых сам я так никогда не делал, а во-вторых что мне пофиг на людей, которые качают рандомное дерьмо из интернета. Таким везде соломки не подложишь, не сейвы так вирусный чит энжн скачают, а страдать с сейвами я ради них не хочу.
Аргумент с поломкой сейва актуален и для классических сейвов в JSON/XML/whatever. Знаем мы эти истории, когда разработчикам приходилось городить целую цепочку конверторов сейвов, от игры версии 1 до игры версии 9000, и все равно оно ломалось. А потом в чейнджлогах ААА игорь видишь "для фичи Х придется начать новую игру".
А у меня буквально 3 строки кода и идеально полное сохранение/загрузка всего.
>мне пофиг на людей, которые качают рандомное дерьмо из интернета
Вот только претензия "не качайте там вирус" будет прилетать именно к твоей игре.
Шизы любят раскидываться такими заявлениями. Одна моя игра вообще без сейвов получала такой отзыв. Поглядываю за бывшим мейнтейнером годота, Юрой Сизовым, он со своим саунд-редактором тоже подобного огреб, ныл потом в соцсетях. Конкретно в моей игре вирусов нет, а чего там пользователь понакачал хуй пойми откуда - меня не касается, я ему не мамка. В точности как вирусы в крякнутых ААА торрентах не касаются разработчиков ААА игр.
И если уж на то пошло, то модами обмениваются чаще чем сейвами, и говна туда напихать легче. Не вижу чтобы за вирусный мод прилетало разработчику игры.
Туториал на немецком.
https://www.youtube.com/watch?v=gwsAIawjMwE
Впрочем, 21 век, будущее наступило, ИИ переводит с немецкого и озвучивает.
>модами обмениваются
Моды качают "на свой страх и риск", т.е. все должны осознавать потенциальные риски и выбирать только проверенный источник (steamworks, например). А классический сейв - это как txt-файлик. Часто ли ты задумываешься в стиле "а вдруг в txt файле вирус"? Представь, качаешь txt-файл, открываешь на своём рабочем компе, а там какой-то скрипт выполняется. Подобное поведение игры обманывает ожидания, а обманутые ожидания игроков - главная причина для негатива в отзывах к твоей игре. И речь о нормисах, а не каких-то там красноглазых шизолинуксоидах.
TL;DR:
- вирус в ожидаемом месте - ладно
- вирус в неожиданном месте - пипец
Шизик /gd перешёл на годот?
Сейвы тоже качают на свой страх и риск. Причем в разы меньше чем моды. Он вот знает, когда качает, что это реально сейв-файл, а не говно под видом сейва? Ничего он не знает. Тем более если речь о нормисах, они вообще не ебут что где-то какие-то сейвы хранятся и ими можно обменяться.
Короче я думаю это надуманная проблема и твердо намерен релизнуть как есть. Если вылезут непредвиденные последствия - обязательно приду рассказать ИТТ.
>Аргумент с поломкой сейва актуален
Нет, ты не понимаешь сути проблемы.
В случае ресурсов:
1. Ты создал поле mob_amount.
2. Игрок сохранил игру в версии 0.1.
3. Ты переименовал mob_amount -> mob_count.
4. Игрок загружает сохранение в версии 0.2.
5. Godot БЕЗ ПРЕДУПРЕЖДЕНИЯ устанавливает в mob_count значение по умолчанию, а mob_amount игнорирует, и оно утратится после сохранения. В зависимости от предназначения поля, игровые последствия утраты могут быть от незаметных до полностью ломающих геймплей. Хуже всего, когда геймплей полностью ломается, но незаметно...
Godot даже в редакторе об этом никак не может предупредить и помочь сохранить утраченное; в результате приходится придумывать костыли, но в рантайме эти костыли будут намного сложнее.
В случае сцен:
1. Ты создал digger с нодой shovel.
2. Игрок сохранил игру в версии 0.1.
3. Ты поменял ноду shovel на pickaxe.
4. Игрок загрузил игру в версии 0.2.
5. Godot БЕЗ ПРЕДУПРЕЖДЕНИЯ ломается, т.к. не способен найти удалённую сцену shovel и даже не пытается добавить персонажу в руки pickaxe. В лучшем случае это будет мелкая проблема - чувак будет с пустыми руками бегать. В худшем случае игрок проиграет +50 часов и ВНЕЗАПНО обнаружит, что отсутствие кирки, необходимой для продвижения по сюжету, фиксится только началом игры с нуля.
В редакторе Godot иногда предупреждает о таких проблемах, но в рантайме такие проблемы будет значительно сложнее пофиксить автоматически. Текущая версия системы UID тут не помогает.
>городить целую цепочку конверторов сейвов
Во-первых, с кастомным форматом ты ИМЕЕШЬ ВОЗМОЖНОСТЬ написать эту цепочку конвертеров. Стандартные ресурсы в Godot ломаются часто и без предупреждения, формат записи у них сложный и встроенные инструменты конвертации недоступны. Задолбаешься парсить tres вручную в обход Godot.
Во-вторых, с кастомным форматом ты всегда чётко контролируешь состояние сейвов и того, как игра загружается, поэтому можешь не создавать лишние конвертеры из-за того, что ты что-то в игре поменял, обновил версию движка или какого-либо плагина. Контроль за сейвами остаётся в твоих руках и он значительно проще ковыряния в формате tres.
>А у меня буквально 3 строки кода
Ты просто ленивый ассетфлипер или вся твоя игра состоит из нескольких строчек кода, которые ты за один день написал. То, что нормально работает для настолько мелких игрушек, может быть опасно для серьёзных проектов - там, где кода больше 3 строк.
Никто тебя не заставляет делать по-другому... Просто учитывай, что твоя поделка попадает в категорию
>рандомное дерьмо из интернета.
Сразу отвечу на следующие аргументы:
>просто не меняй поля в tres
>просто не меняй ноды в tscn
>просто не обновляй аддоны
>просто не обновляй Godot
>просто не обновляй игру
Ответ: если твоя игра позволяет ничего в себе не обновлять, то ты флипнул ассеты за вечер и теперь называешь это игрой. Представь себе, некоторые игровые проекты обновляются более 25 лет, и они вынуждены вносить существенные изменения. Большинство поделок, конечно, так долго не живут, однако не путайте причину со следствием - если вы наговнокодили, разумеется, обновлять будет очень больно, даже если игра вдруг станет популярной, и множество проектов сдохли из-за говнокода (или потеряли в популярности/проиграли конкурентам).
>Аргумент с поломкой сейва актуален
Нет, ты не понимаешь сути проблемы.
В случае ресурсов:
1. Ты создал поле mob_amount.
2. Игрок сохранил игру в версии 0.1.
3. Ты переименовал mob_amount -> mob_count.
4. Игрок загружает сохранение в версии 0.2.
5. Godot БЕЗ ПРЕДУПРЕЖДЕНИЯ устанавливает в mob_count значение по умолчанию, а mob_amount игнорирует, и оно утратится после сохранения. В зависимости от предназначения поля, игровые последствия утраты могут быть от незаметных до полностью ломающих геймплей. Хуже всего, когда геймплей полностью ломается, но незаметно...
Godot даже в редакторе об этом никак не может предупредить и помочь сохранить утраченное; в результате приходится придумывать костыли, но в рантайме эти костыли будут намного сложнее.
В случае сцен:
1. Ты создал digger с нодой shovel.
2. Игрок сохранил игру в версии 0.1.
3. Ты поменял ноду shovel на pickaxe.
4. Игрок загрузил игру в версии 0.2.
5. Godot БЕЗ ПРЕДУПРЕЖДЕНИЯ ломается, т.к. не способен найти удалённую сцену shovel и даже не пытается добавить персонажу в руки pickaxe. В лучшем случае это будет мелкая проблема - чувак будет с пустыми руками бегать. В худшем случае игрок проиграет +50 часов и ВНЕЗАПНО обнаружит, что отсутствие кирки, необходимой для продвижения по сюжету, фиксится только началом игры с нуля.
В редакторе Godot иногда предупреждает о таких проблемах, но в рантайме такие проблемы будет значительно сложнее пофиксить автоматически. Текущая версия системы UID тут не помогает.
>городить целую цепочку конверторов сейвов
Во-первых, с кастомным форматом ты ИМЕЕШЬ ВОЗМОЖНОСТЬ написать эту цепочку конвертеров. Стандартные ресурсы в Godot ломаются часто и без предупреждения, формат записи у них сложный и встроенные инструменты конвертации недоступны. Задолбаешься парсить tres вручную в обход Godot.
Во-вторых, с кастомным форматом ты всегда чётко контролируешь состояние сейвов и того, как игра загружается, поэтому можешь не создавать лишние конвертеры из-за того, что ты что-то в игре поменял, обновил версию движка или какого-либо плагина. Контроль за сейвами остаётся в твоих руках и он значительно проще ковыряния в формате tres.
>А у меня буквально 3 строки кода
Ты просто ленивый ассетфлипер или вся твоя игра состоит из нескольких строчек кода, которые ты за один день написал. То, что нормально работает для настолько мелких игрушек, может быть опасно для серьёзных проектов - там, где кода больше 3 строк.
Никто тебя не заставляет делать по-другому... Просто учитывай, что твоя поделка попадает в категорию
>рандомное дерьмо из интернета.
Сразу отвечу на следующие аргументы:
>просто не меняй поля в tres
>просто не меняй ноды в tscn
>просто не обновляй аддоны
>просто не обновляй Godot
>просто не обновляй игру
Ответ: если твоя игра позволяет ничего в себе не обновлять, то ты флипнул ассеты за вечер и теперь называешь это игрой. Представь себе, некоторые игровые проекты обновляются более 25 лет, и они вынуждены вносить существенные изменения. Большинство поделок, конечно, так долго не живут, однако не путайте причину со следствием - если вы наговнокодили, разумеется, обновлять будет очень больно, даже если игра вдруг станет популярной, и множество проектов сдохли из-за говнокода (или потеряли в популярности/проиграли конкурентам).
Решение есть, просто не переименовывай, а помечай deprecated и добавляй новое поле.
Давай тут без своих корявых гаданий на кофейной гуще. Ассеты все делаю сам в 3д редакторе, 2д арт тоже, игра в разработке больше года. Решение для обновления старых .scn-сейвов на новые написано. Остальные твои аргументы меня не ебут, потому что они из разряда "а что если васян с крыши упадет, ты виноват ведь ты дом построил!11".
А я двачую этот пост. Всегда был сторонником кастомного формата. Как правило жсон.
>>4609
Большое спасибо! Особенно за пример. Я такую систему уже успел выдумать сам, только постеснялся здесь писать. Думал, что глупости совсем. Можно еще эти фазы оформлять как инт из битфлага, например, чтоб это не были числа из головы. Там, где это уместно, разумеется.
>чревато заражением вирусом
Годонирс, кажется, выпускал аддон, который пробегается по сейву и отменяет его чтение как ресурса, если в нем есть скриптовая часть. Но я тебя понял. На json формат перейду наверное, с tscn я уже намучился.
Эмбеддил кастомный ресурс в заэмбеженный кастомный ресурс внутрь кастомного ресурса сейва, каюсь.
>Если вылезут непредвиденные последствия - обязательно приду рассказать ИТТ.
Если вдруг из-за этого твоя дочь исчезнет из пространственно-временного континуума - обязательно расскажи.
Но вообще, сохранение состояния в словарь, а из него в жсон - это очень просто, хотя бы в следующем проекте крайне рекомендую освоить данную технологию. Она тебе в будущем пригодится там, где ты сейчас даже и предположить не можешь. Вот тебе пример из жизни. Я щас пишу софтину на плюсах (годот отложил пока) и написал сохранение в жсон. Использую библиотеку, с которой работа с жсон-объектом не отличается от работы с вложенными словарями в годоте. Так вот, когда дошло до написания гуя, я сначала очень расстроился, что слишком геморно для этого использовать Годот, как изначально планировалось, я обнаружил, что самый практичный способ общения между основой и гуём - это те самые жсон-объекты, которые я планировал использовать только для сохранения в файл.
И вообще, помни: разрабатывая игру, ты получаешь навыки и знания, которые пригодятя в самых разных прочих областях разработки.

>Решение для обновления старых .scn-сейвов на новые
Поделись же им с нами, раз ты так сильно рекомендуешь этот чудесный способ.
>а что если васян с крыши упадет, ты виноват ведь ты дом построил
Виноват, если ты сделал слабую крышу, что обвалилась под васяном, который эту крышу после тебя доделывал, или даже над васяном, который просто мимо стройки проходил. Нормальные строители ГОСТы соблюдают, а ещё есть УК РФ 216: "Нарушение правил безопасности при ведении строительных или иных работ". Будешь спорить и доказывать, что васян всё ещё сам виноват, что проходил мимо, когда твоя крыша обвалилась ему на голову?
К счастью, ты не строитель и крыши не строишь, поэтому твоя поделка на чью-то голову не упадёт. Но рекомендую ознакомиться с УК РФ 273: "Создание, использование и распространение вредоносных компьютерных программ". Оправдываться, что ты не знал об уязвимости и не пытался намеренно совершать сделанное, будешь уже перед другими людьми...
>Но вообще, сохранение состояния в словарь, а из него в жсон - это очень просто,
Покажешь? Для годота.
>Но вообще, сохранение состояния в словарь, а из него в жсон - это очень просто, хотя бы в следующем проекте крайне рекомендую освоить данную технологию.
Освоил в двух предыдущих играх, больше не хочу, спасибо. Чем комплексней структура проекта, чем больше взаимосвязей между объектами, тем больше мозгоебли.
>>4705
Какой ты унылый бюрократ. ГОСТ на обкладывание соломой еще принеси, и пригрози УК всем кто делает иначе.
> больше не хочу, спасибо. Чем комплексней структура проекта, чем больше взаимосвязей между объектами, тем больше мозгоебли
Главное - не тащить структуру проекта в сейв. Отношение к сейву должно быть как к таблице базы данных. И ЖСОН позволяет сделать структуру как таблица. Вот есть такой сайт жсон-редактор-онлайн. Так вот там есть возможность представить особым образом составленный жсон как таблицу. В чём состоит эта особость? В жсоне должен быть один или больше массив [] однотипных объектов {}, ключи из этих объектов становятся именами столбцов виртуальной таблицы, значения - значениями строк.
Необязательно юзать редакторы, но вышеприведённый редактор позволяет постигнуть эту идею.
Проще скринами показать. Допустим есть такой жсон (пикча1) включаем режим, выбираем таблицу и редактируем. А в движке соответственно делаем несложный код, который находит в файле таблицы и читает их последовательно, извлекая данные и определяя их по полю наподобие "type". Таким подходом частично решается и немного упрощается вышеописанная проблема смены формата. Ты не добавляешь в сейв произвольные данные, ты добавляешь структурированные данные, у которых есть тип, подтип, имя, значение, иные параметры. И когда ты начнёшь мыслить в этой парадигме (парадигме СУБД) тебе будет сложнее "случайно" вносить ломающие изменения в свои же форматы.

Обычно вот такие жсоны пихают в сейв, а потом жалуются, что их масштабировать сложно. Здесь только инвентарь в виде таблицы, остальное прибито гвоздями к внутренней реализации.
Сохраняем:
func to_dict() -> Dictionary:
. var dict = {
. . foo = foo, # int
. . bar = bar, # String
. . obj = obj.to_dict();
. . connections = {
. . . connected_node1.name, connected_node2.name
. . }
. }
. return dict
Загружаем:
func from_dict(dict: Dictionary)
. if dict.has("foo") and dict.foo is int: foo = dict.foo
. if dict.has("bar") and dict.bar is String: bar = dict.bar
. if dict.has("obj") and dict.obj is Dictionary:
. . obj = new Obj
. . obj.from_dict(dict.obj)
После восстановления всех нод восстанавливаем соединения
func connections_from_dict(dict: Dictionary)
. if not dict.has("connections") or not (dict.connections is Array): return
. for connection in dict.connections:
. . conn: Node = get_node(connection)
. . if is_instance_valid(node): restore_connection_with(node)
Всё. и так можно сохранить проект ЛЮБОЙ сложности.
>>4713
>Чем комплексней структура проекта, чем больше взаимосвязей между объектами
Вообще, это огромный редфлаг, обозначающий, что пора бы заняться рефакторингом. Энивей, см.выше.
Сохраняем:
func to_dict() -> Dictionary:
. var dict = {
. . foo = foo, # int
. . bar = bar, # String
. . obj = obj.to_dict();
. . connections = {
. . . connected_node1.name, connected_node2.name
. . }
. }
. return dict
Загружаем:
func from_dict(dict: Dictionary)
. if dict.has("foo") and dict.foo is int: foo = dict.foo
. if dict.has("bar") and dict.bar is String: bar = dict.bar
. if dict.has("obj") and dict.obj is Dictionary:
. . obj = new Obj
. . obj.from_dict(dict.obj)
После восстановления всех нод восстанавливаем соединения
func connections_from_dict(dict: Dictionary)
. if not dict.has("connections") or not (dict.connections is Array): return
. for connection in dict.connections:
. . conn: Node = get_node(connection)
. . if is_instance_valid(node): restore_connection_with(node)
Всё. и так можно сохранить проект ЛЮБОЙ сложности.
>>4713
>Чем комплексней структура проекта, чем больше взаимосвязей между объектами
Вообще, это огромный редфлаг, обозначающий, что пора бы заняться рефакторингом. Энивей, см.выше.
Интересно. А как ты, например, сохраняешь текущую анимацию, ее скорость, направление и позицию?
> if dict.has("foo") and dict.foo is int: foo
Вот эту хрень надо выносить в метод. Что-то типа
> func _cast_to_type(dict: Dictionary, key: String, type: int, default: Variant) -> Variant:
> > if dict.has(key) and type_of(dict[key]) == type:
> > > return dict[key]
> > return default
Ну и после этого уже элегантнее будет:
> foo = _cast_to_type(dict, "foo", TYPE_INT, foo)
> bar = _cast_to_type(dict, "bar", TYPE_STRING, bar)
Эх, в шарпе такие штуки ещё элегантнее пишутся, там caller member name выводится.
Я всё внимательно прочитал и попробовал этот онлайн-редактор, но не понял, как ты это предлагаешь использовать, если у тебя в проекте больше одного экземпляра объекта. И зачем нужны дублирующиеся поля? Ты собираешься это вручную читать? Если ты предлагаешь создавать SQL запросы к этому сейву, не проще ли будет сразу подключить СУБД к проекту, а не делать велосипед с квадратными колёсами (JSON)? Я не понимаю, чем твой способ будет лучше.
Твой способ, как я его понимаю:
>location.gd
>func load(data): # получаем все данные, ибо хрен разберёшь
>_ for line in data.world_data:
>_ _ if line.type == "location":
>_ _ _ match line.name:
>_ _ _ _ "name": name = line.value
>_ _ _ _ "state": state = line.value
>_ _ _ _ "weather": weather = line.value
>_ _ _ _ "time": time = line.value
Очень странно. Это будет долго и неэффективно.
Возможно, через SQL будет быстрее и эффективнее?..
Нормальный способ, который тебе чем-то не нравится (чем?):
>location.gd
>func load(data): # получаем кусочек данных от заботливого родителя
>_ name = data.name
>_ state = data.state
>_ weather = data.weather
>_ time = data.time
Легко и понятно. Никакого "прибивания гвоздями" (где?) тут нет.
Если у тебя изменится первый вариант:
>_ _ _ _ "state": status = line.value
Если у тебя изменится второй вариант:
>_ status = data.state
Как видишь, разницы в обратной совместимости нет.
>>4732
>if dict.has("foo") and dict.foo is int: foo = dict.foo
Проще так записать:
>foo = dict.get("foo", foo)
А если у тебя там тип неправильный, то всё уже сломалось.
>if not dict.has("connections") or not (dict.connections is Array):
Можно так записать:
>if "connections" not in dict or dict.connections is not Array:
>>4734
>сохраняешь текущую анимацию
О какой анимации речь? И нужно ли её вообще сохранять?
Сохраняй только то, что нельзя восстановить при загрузке.
Я всё внимательно прочитал и попробовал этот онлайн-редактор, но не понял, как ты это предлагаешь использовать, если у тебя в проекте больше одного экземпляра объекта. И зачем нужны дублирующиеся поля? Ты собираешься это вручную читать? Если ты предлагаешь создавать SQL запросы к этому сейву, не проще ли будет сразу подключить СУБД к проекту, а не делать велосипед с квадратными колёсами (JSON)? Я не понимаю, чем твой способ будет лучше.
Твой способ, как я его понимаю:
>location.gd
>func load(data): # получаем все данные, ибо хрен разберёшь
>_ for line in data.world_data:
>_ _ if line.type == "location":
>_ _ _ match line.name:
>_ _ _ _ "name": name = line.value
>_ _ _ _ "state": state = line.value
>_ _ _ _ "weather": weather = line.value
>_ _ _ _ "time": time = line.value
Очень странно. Это будет долго и неэффективно.
Возможно, через SQL будет быстрее и эффективнее?..
Нормальный способ, который тебе чем-то не нравится (чем?):
>location.gd
>func load(data): # получаем кусочек данных от заботливого родителя
>_ name = data.name
>_ state = data.state
>_ weather = data.weather
>_ time = data.time
Легко и понятно. Никакого "прибивания гвоздями" (где?) тут нет.
Если у тебя изменится первый вариант:
>_ _ _ _ "state": status = line.value
Если у тебя изменится второй вариант:
>_ status = data.state
Как видишь, разницы в обратной совместимости нет.
>>4732
>if dict.has("foo") and dict.foo is int: foo = dict.foo
Проще так записать:
>foo = dict.get("foo", foo)
А если у тебя там тип неправильный, то всё уже сломалось.
>if not dict.has("connections") or not (dict.connections is Array):
Можно так записать:
>if "connections" not in dict or dict.connections is not Array:
>>4734
>сохраняешь текущую анимацию
О какой анимации речь? И нужно ли её вообще сохранять?
Сохраняй только то, что нельзя восстановить при загрузке.
>О какой анимации речь?
У меня animation player и долгая анимация в нем. Иногда я ее запускаю задним ходом через play_backwards
А сверху мускуля обязательно прослойку с ORM, на случай если базу на полпути сменить придется.
И мультиплеерные кнопки непременно.

>долгая анимация в нем
Что за анимация-то?
Основные варианты:
1. Кат-сцена. Сохраняешься ПЕРЕД кат-сценой, а не во время.
2. Действие персонажа. Сохраняешься перед/после действия.
3. Состояние персонажа. Запускаешь анимацию с нуля/с конца.
В любом случае, анимации - обычно декорации, а не геймплей.
Что плохого в том, что декорации "неправильно" загрузятся?
То есть твой подход, который:
>и так можно сохранить проект ЛЮБОЙ сложности.
Разваливается как только я делаю шаг в сторону от банального менеджера инвентаря, и начинаются костыли-подпорки либо "нинужно". Представляю что будет если я захочу сохраниться во время скриптованной на твинах интерактивной нелинейной сцены, или если у меня физическая симуляция с _integrate_forces, или процедурное создание материалов, или ...
Страдать. Я не нашел универсального и удобного способа или готового решения, способного безболезненно сохранить любое состояние любой ноды/объекта/сцены/скрипта/анимации/диалога/физики/звука. Чем более нестандартный проект тем хуже. Поэтому всегда охуеваю с ваших советов уровня "просто используй жысон/ресурсы/sql", когда совсем не в них дело.
В этом плане приятно мобильные дрочильни делать, где ты сохраняешь int пройденных уровней и больше ничего.
Не ты один страдаешь. Заметил, что в подавляющем большинстве современных игор сохранения специально установленными чекпоинтами? То-то же. Игра набита под завязку рандомно генерирующимися эффектами постобработки и сохранить всё это барахло дороже, чем. Чем.
Алсо для анимационного плеера:
> current_animation
> current_animation_length
> current_animation_position
Сохраняй на здоровье.
Со звуком и физикой так же.
Просто ты заебёшься всё сохранять, а игроки этих трудов не оценят и будут обсирать тебя на форумах, что когда они траят босса, приходится по несколько минут ждать загрузки.
>Проще так записать
>Можно так записать
Не душни, суть-то не в этом
>>4734
>А как ты, например, сохраняешь текущую анимацию, ее скорость, направление и позицию?
dict = {
...
. anim_name = animation_player.assigned_animtion,
. anim_speed = animation_player.get_playing_speed(),
. anim_pos = animation_player.current_animation_position
...
}
Но, во-первых, нахуя, а во-вторых упаковкой сцены ты вроде эти вещи даже и не сохранишь.
>>4748
>скриптованной на твинах интерактивной нелинейной сцены, или
Опять же, чёрт его знает, как поведёт себя упаковка сцены с этим всем говном. А вот записать в словарь, что вот сейчас работает такой-то твин с такими-то параметрами, а при загрузке его перезапустить - фигня вопрос.
>физическая симуляция
Симулируется заново; параметры симуляции пишутся в словарь.
>процедурное создание
Сид пишется в словарь, и у тебя всё воссоздастся точно так же.
Ах да, ну и да, у меня случился эффект манделы, и я забыл, что встроенной функции преобразования словаря в жсон нету. Зато можно сделать var_to_str(dict) и получить сериализованный словарь, очень похожий на жсон. Ну и обратное str_to_var тоже работает.
Анимация действительно тут самое сложное; но если у тебя в игре присутствует прям реально длинная сложная анимация, которая ещё и влияет на геймплей, которую ещё и надо сохранять-загружать - значит где-то ты свернул не туда. Такие штуки - это бомбы замедленного действия, лучше сразу проектировать без них, чем на поздней стадии разработки понять, что теперь придётся всё переделывать.
> если у тебя в игре присутствует прям реально длинная сложная анимация, которая ещё и влияет на геймплей, которую ещё и надо сохранять-загружать - значит где-то ты свернул не туда
Я не он, но я помню шутеры 90х-2000х, когда сохраняешься с летящей в полёте пулей, а при загрузке пуля тебя застреливает. Это раздражало, но это была фича.
>Симулируется заново;
Физика не детерминирована, даже с Jolt'ом, и вот твой подход развалился. А может ты физический паззл делаешь. А может симуляция была долгой и важной, и сиди теперь пару минут жди чтобы вернуться туда где остановился.
>у тебя в игре присутствует прям реально длинная сложная анимация, которая ещё и влияет на геймплей, которую ещё и надо сохранять-загружать - значит где-то ты свернул не туда
Снова, чуть в сторону от менеджера инвентаря и все разваливается и слышь переделывай.
Сейвы, по сути, каждый раз одно и то же простое действие - запиши-прочитай - но каждый сука раз оно достаточно разное чтобы прыгать с бубном и тратить время на унылые обвязки-бойлерплейты. А напишут ли мне в отзывах что у меня охуенные сейвы? Нет, всем похуй, ведь это базовый функционал, а ты каждый раз ебись с ним. А мог бы потратить это время на что-то интересное.
> Физика не детерминирована, даже с Jolt'ом
В рамках одной платформы всё воспроизводимо, как раз таки с джолтом
https://github.com/godot-jolt/godot-jolt/discussions/548?ysclid=m8penlk9ee155947311
>я помню шутеры 90х-2000х, когда сохраняешься с летящей в полёте пулей, а при загрузке пуля тебя застреливает
Пулю сохранить просто, достаточно записать вид пули, положение в пространстве и скорость.
>>4763
>Физика не детерминирована
Не натягивай сову на глобус. Сохраняй текущее состояние - восстанавливайся с него и продолжай симуляцию. Если дальше события будут при каждой загрузке идти по-разному, то
а) это не проблема сейвов, а проблема физики,
б) игроки могут сейвскамить, и лучше вообще запретить сохраняться в такие моменты,
в) это никак не зависит от того, сохраняешь ты избранные параметры в словарь или же сразу упаковываешь всю сцену.
>Сейвы, по сути,
Ну тут да. Не помню, у кого из блогеров видел этот тезис (наверняка у GMTK), мол, в разработке игр есть fun part, когда ты делаешь непосредственно игру, а есть огромная куча всего, что сделать всё равно необходимо, но это скучная рутина, которую игрок даже не заметит. И это касается не только сейвов, это ещё настройки, логика работы гуя, всякие там стейт-машины и куча другого.
Ну, c'est la vie, чо.
>костыли-подпорки либо "нинужно"
Да, не нужно. Ты вообще в игры играешь? Ты часто замечаешь, в каком состоянии загружается игра? В каком состоянии находятся все анимации, физика? Большинство игроков невнимательны к деталям. Загрузка игры должна восстановить всё, что может потребоваться для прохождения игры на 100% - всё остальное может быть в произвольном состоянии.
>Представляю что будет если я захочу сохраниться во время скриптованной на твинах интерактивной нелинейной сцены, или если у меня физическая симуляция с _integrate_forces, или процедурное создание материалов, или ...
Зачем? Сохраняйся перед началом/после конца. В крайнем случае можешь загрузить сцену с начала и прокрутить симуляцию в ускоренном режиме, пока закрываешь весь экран непрозрачным затвором. Практического смысла в этом, правда, мало.
>>4756
>функции преобразования словаря в жсон нету
Кто тебе такой бред сказал? Всё есть и работает:
https://docs.godotengine.org/en/stable/classes/class_json.html#class-json-method-stringify
https://docs.godotengine.org/en/3.6/classes/class_json.html#class-json-method-print
>>4763
>>Симулируется заново;
>Физика не детерминирована
Главное, чтоб объекты не проваливались в пол.
>может ты физический паззл делаешь
Вот когда ты его сделаешь - тогда и поговорим.
>сиди теперь пару минут жди чтобы вернуться
В чём проблема подождать всего лишь 2 минуты?
>все разваливается и слышь переделывай
Это и есть разработка программного обеспечения.
>унылые обвязки-бойлерплейты
А ты делай весёлые обвязки.
>И это касается не только сейвов, это ещё настройки, логика работы гуя, всякие там стейт-машины и куча другого.
ГУЙ хотя бы стилизовать можно по-новому, а над UX интересно работать. Сейвы же просто подкапотная муть, которую никто не увидит.
>>4844
>не нужно
>не нужно
>не нужно яскозал
Не нужен тут только твой бесполезный коммент, сорян.
> Кто тебе такой бред сказал? Всё есть и работает:
Я кстати не в первый раз вижу длиннопосты с подобными воззрениями на движок. Складывается ощущение, что какой-то хуй, ни разу не открывавший годот, залез в тред и жирно набрасывает движкосрача на вентилятор.
>>4812
> мол, в разработке игр есть fun part, когда ты делаешь непосредственно игру, а есть огромная куча всего, что сделать всё равно необходимо, но это скучная рутина, которую игрок даже не заметит. И это касается не только сейвов, это ещё настройки, логика работы гуя, всякие там стейт-машины и куча другого.
> Ну, c'est la vie, чо.
Нужно поглядывать в ассетлиб, может оказаться, что множество бойлерплейтовых работ уже произведено, только скачивай да используй.
Вот, например, менеджер сохранений https://godotengine.org/asset-library/asset/3765 вряд ли присутствующие в треде напишут толковее (я проверил код).
>подкапотная муть, которую никто не увидит
Если сохраняешь в JSON, игроки могут залезть в сохранение и подправить значения руками. Может существенно упростить работу моддерам. Может упростить жизнь желающим "читерить" в сингле. Теоретически упрощает фикс багов игры игроком (например, когда важная вещь тупо деспавнулась).
В любом случае, некоторые игроки спасибо скажут.
>>не нужно яскозал
>Не нужен тут только твой
А что НУЖНОГО делаешь ты?
Опиши, что тебе не удаётся сейчас сохранить.
Покажи на видео, как оно сейчас загружается.
Покажи на видео, как оно должно загружаться.
Подумаем вместе, как решить твою проблему.
>менеджер сохранений
Какой-то бредовый плагин...
>In order to be able to manipulate those StorageAccessors, an autoload called GlobalStorageManager is defined when the plugin is activated. This is a singleton capable of collecting and sending data to all active StorageAccessors in the scene.
Что он предлагает? Насрать нодами в дерево? Так?
>игрок: CharacterBody3D
>_ сохранятор_игрока: StorageAccessor
>_ пистолет: Пуляло3D
>_ _ сохранятор_пистолета: StorageAccessor
>_ _ магазин: Node3D
>_ _ _ сохранятор_магазина: StorageAccessor
>_ портки: Портки3D
>_ _ сохранятор_портков: StorageAccessor
>_ _ шнурки: Шнурок3D
>_ _ _ сохранятор_шнурков: StorageAccessor
И, конечно, это всё обмазано синглтоном.
>В любом случае, некоторые игроки спасибо скажут.
Сколько тебе сказали спасибо за жсонные сохранения? Покажи на видео, где тебе говорят спасибо. Мне за мои предыдущие игры никто не сказал, сохранял в жсон, за сотни отзывов ноль про сейвы. Мне кажется править сейвы руками это еще более редкое чем обмен сейвами. В общем, все это - надуманные причины, чтобы страдать при каждой реализации сейвов. А от надуманных причин надо избавляться.
>In order to be able to manipulate those StorageAccessors, an autoload called GlobalStorageManager is defined when the plugin is activated.
Так что да, тот анон прав, это в каком то смысле "насрать"
>причины, чтобы страдать
https://ru.wikipedia.org/wiki/Технический_долг
>...накопленные в программном коде или архитектуре проблемы, связанные с пренебрежением качеством при разработке программного обеспечения и вызывающие дополнительные затраты труда в будущем. Технический долг обычно незаметен для конечных пользователей продукта, а связан с недостатками в сопровождаемости, тестируемости, понятности, модифицируемости, переносимости.
Вообще, я не понимаю, в чём твои "страдания"...
Какая у тебя скорость? Хотя бы 100 слов в минуту?
>>4870
Френдли фаер, ты не туда воюешь.
>>4875
Речь о том, что StorageAccessor автор этого аддона предлагает пихать везде, где нужно что-то хранить и загружать. Хрен с ним, с синглтоном - почему вместо
>MyAwesomeStorageSingletonAddon.save(id, data)
>data = MyAwesomeStorageSingletonAddon.load(id)
Автор предлагает пихать тыщи новых нод в дерево?
>Годот нодовый движок.
Да, но нодами не рекомендуется срать.
https://docs.godotengine.org/en/stable/tutorials/best_practices/node_alternatives.html
>Nodes are cheap to produce, but even they have their limits. A project may have tens of thousands of nodes all doing things. The more complex their behavior though, the larger the strain each one adds to a project's performance.
>Godot provides more lightweight objects for creating APIs which nodes use. Be sure to keep these in mind as options when designing how you wish to build your project's features.
И ещё есть эта статья, но немного про другое.
https://docs.godotengine.org/en/stable/tutorials/performance/using_servers.html
>Ноды используют аля компоненты.
Это имеет смысл только если у такого компонента специфические свойства, требующие находиться непосредственно в дереве сцены без посредников.
Проблема такой системы сохранения в том, что ты размазываешь игровой объект на несколько нод, совершенно без какой-либо практической пользы.
Смысл в том, что ты вообще не пишешь ни строчки кода (не создавая зависимость внутри .gd), а только вешаешь ноду на те объекты которые хочешь сохранять.
Аналогия - создавать MeshInstance нодами или создавать их из кода. Иногда удобнее так, иногда так.

material_surface_set
Есть два любопытных класса: ResourceFormatSaver и ResourceFormatLoader
От них наследуешься и реализуешь свой собственный формат файла.
Я днём попробовал - работает. Код не покажу, ибо на другой машине. Документация в помощь, там несложно.
Могу только сказать, у меня получилось формировать файл .save с ini-форматированием внутри. А потом я еще по другому закодил и получилось бинарное содержимое внутри.
>не создавая зависимость внутри .gd
Выше уже кидали код, который не создаёт зависимостей:
>func load(data: Dictionary): ...
>func save() -> Dictionary: return { ... }
Не нужно тут никаких дополнительных нод и синглтонов.
Просто всё происходит по иерархии:
>A # сохраняет/загружает B, пишет/читает в/из файл/а
>_ B # сохраняет/загружает C
>_ _ C # сохраняет/загружает D
>_ _ _ D # лист дерева сцены
Поток данных во время сохранения:
>файл <- A <- B <- C <- D
Поток данных во время загрузки:
>файл -> A -> B -> C -> D
Аргументируй, если считаешь это неправильным.
>ResourceFormatSaver и ResourceFormatLoader
>получилось формировать файл .save
Эти классы нужны только для интеграции с инспектором в редакторе сцен:
>Godot loads resources in the editor or in exported games using ResourceFormatLoaders.
Планируешь открывать свои .save-файлы в редакторе (как .tres)? Нет? Тогда зачем?
Основная проблема с сохранениями/загрузками не в том, какой формат использовать, а в том, что ты каждый раз бегаешь как охуевший по всей своей кодовой базе и выискиваешь какие значения у каких объектов нужно сохранить и как их потом восстановить. А куда сохранять - похуй вообще, хоть на забор записывай. Вы вообще не туда спорите, не улавливаете сути проблемы.
>ты каждый раз бегаешь как охуевший по всей своей кодовой базе и выискиваешь какие значения у каких объектов нужно сохранить и как их потом восстановить
Разве? Для примера, у тебя есть: персонаж, автомобиль, квартал города, город.
Что должен сохранять/загружать персонаж? Это персонаж сам решает. Он может, например, сохранять своё состояние: бодрый, сонный, спящий, пьяный. Может сохранять одежду и вещи в сумке, которая у него с собой. Может сохранять, куда он сейчас смотрит и куда хочет добраться.
Что должен сохранять/загружать автомобиль? Автомобиль сам это решает. Он может сохранять состояние двигателя, корпуса, дверей, количество топлива, износ покрышек и прочее. В каком направлении и с какой скоростью он сейчас движется. Но также он сохраняет, кто в нём сейчас находится. Он запрашивает у того, кто в нём сидит (персонажа), и передаёт результат наружу. Или получает данные извне и передаёт их тому, кто в нём должен сидеть (персонажу). Но ему нет дела до того, как и что делает с этими данными тот, кто в нём сидит - он знает только о местах (сиденьях).
Что должен сохранять район города? Персонажей и автомобили. Но персонажи в автомобилях сохраняются по той простой причине, что за их сохранение отвечает автомобиль. При этом району города не нужно знать ни о персонажах, ни об автомобилях, он просто расставляет то, что ему предложил расставить город. То есть район города только знает о местах размещения каких-то загружаемых или сохраняемых объектах.
Допустим, ты хочешь добавить новый объект в сохранение. Придётся ли тебе лезть в код персонажа и автомобиля? Нет, если этот объект их не касается и просто валяется на дороге города. Если он касается только персонажа (элемент одежды), то он будет затрагивать только код персонажа, а код автомобиля и района города не будет о нём знать. Если он касается только автомобиля (чемодан на крыше), то он будет затрагивать только код автомобиля, но не код персонажа и района города.
Так что не вижу причин бегать по всей кодовой базе из-за системы сохранений.
>ты каждый раз бегаешь как охуевший по всей своей кодовой базе и выискиваешь какие значения у каких объектов нужно сохранить и как их потом восстановить
Разве? Для примера, у тебя есть: персонаж, автомобиль, квартал города, город.
Что должен сохранять/загружать персонаж? Это персонаж сам решает. Он может, например, сохранять своё состояние: бодрый, сонный, спящий, пьяный. Может сохранять одежду и вещи в сумке, которая у него с собой. Может сохранять, куда он сейчас смотрит и куда хочет добраться.
Что должен сохранять/загружать автомобиль? Автомобиль сам это решает. Он может сохранять состояние двигателя, корпуса, дверей, количество топлива, износ покрышек и прочее. В каком направлении и с какой скоростью он сейчас движется. Но также он сохраняет, кто в нём сейчас находится. Он запрашивает у того, кто в нём сидит (персонажа), и передаёт результат наружу. Или получает данные извне и передаёт их тому, кто в нём должен сидеть (персонажу). Но ему нет дела до того, как и что делает с этими данными тот, кто в нём сидит - он знает только о местах (сиденьях).
Что должен сохранять район города? Персонажей и автомобили. Но персонажи в автомобилях сохраняются по той простой причине, что за их сохранение отвечает автомобиль. При этом району города не нужно знать ни о персонажах, ни об автомобилях, он просто расставляет то, что ему предложил расставить город. То есть район города только знает о местах размещения каких-то загружаемых или сохраняемых объектах.
Допустим, ты хочешь добавить новый объект в сохранение. Придётся ли тебе лезть в код персонажа и автомобиля? Нет, если этот объект их не касается и просто валяется на дороге города. Если он касается только персонажа (элемент одежды), то он будет затрагивать только код персонажа, а код автомобиля и района города не будет о нём знать. Если он касается только автомобиля (чемодан на крыше), то он будет затрагивать только код автомобиля, но не код персонажа и района города.
Так что не вижу причин бегать по всей кодовой базе из-за системы сохранений.
> не улавливаете сути проблемы
Улавливаем.
> каждый раз бегаешь как охуевший по всей своей кодовой базе и выискиваешь какие значения у каких объектов нужно сохранить и как их потом восстановить
Это всё зависит от игры. Чтобы не пиздеть голословно, давай определимся о какой игре речь? Судя по намёкам выше, про анимации, физику, звуки, речь идёт об убийце скайрима/ведьмака/ассасинов одновременно?
Итак, мы определились с тем, какие объекта какие поля хотят сохранять. Дальше-то что? Вот игрок нажал F5, что происходит после этого? Кем регистрируется нажатие F5? Какой код он начинает выполнять? Как он опрашивает персонажей и автомобили? Записывает на забор, тут мы выше определились.
Я не сказал что считаю это неправильным, такой код создает зависимость в виде load() save() и том что тебе надо будет при изменениях править код, а нода - создает аналогичную зависимость в дереве tscn и при изменениях тебе надо будет менять поля ноды. Вот и все.
Менеджер - перехватчих всех необработанных нажатий обнаруживает нажатие F5, вызывает в синглотоне менеджера сохранений функцию сохранений, та любым способом обходит ноды которые нужно сохранить (хоть рекурсивно все дерево от корня, хоть объекты которые хотят сохранятся могут регистрироваться у него в каком то линейном массиве). Паттерн Visitor кстати тебе что то говорит? Там как раз обратный подход - неважно какая структура и как ее обходить, хоть приставным шагом хоть вприсядку, ты нам главное дай функцию которую вызывать для каждого объекта.
Нет у тебя варианта без синглтона, потому что ты не можешь быть умнее разработчиков, которые вхуячили кучу синглтонов выполняющих свои задачи. Был бы ты умнее - ты бы тут не тралил.
> Input
- это синглтон, без него ты не перехватишь копку F5. На этом всё.
Я, конечно, имел в виду "не заводя свой синглтон-менеджер сейвов".
Но чисто формально, движок опенсор, и можно и Input подменить своим...
Такое может понадобиться для мультиплеерных кнопок например
>Чтобы не пиздеть голословно, давай определимся о какой игре речь? Судя по намёкам выше, про анимации, физику, звуки, речь идёт об убийце скайрима/ведьмака/ассасинов одновременно?
Речь идет об универсальном решении, пригодном для игры любого типа. Например у меня есть сбор игровой аналитики, написанный еще пару лет назад. Я его копипастом вставляю во все свои игры и все работает. С сейвами хуй так сделаешь, каждый раз переизобретенный велосипед приходится вкорячивать.
>Всё есть и работает:
Ничоси. А я ж вижел эти функции в доке ещё тогда, до выхода четвёрки, но придал значения именно из-за неочевидных названий.
Энивей, var_to_str и JSON.stringify дают схожие результаты и одинаково читаемы. Плюс есть ультимативное File.store_var для хранения того же самого в бинарном формате.

>надо будет менять поля ноды
Ты аддон видел? https://github.com/locker-godot/locker
На пикриле - то, что предлагает делать автор аддона.
Возможно, в каких-то ситуациях это имеет смысл...
>>4952
>Вот игрок нажал F5, что происходит после этого?
Самый простой вариант, рекурсивный брутфорс:
>func save() -> Dictionary:
>_ var data := {}
>_ for o in objects: data[o.id] = o.save()
>_ return data
Конечно, это будет тормозить в случае огромного объёма сохраняемых данных. Поэтому придётся как-то резать на части и кэшировать никак не меняющиеся результаты. Но это вроде как универсальное решение, работающее независимо от структуры игры и геймплея, пока ты следуешь установленной тобой иерархии.
>>4970
Разработчики сохраняют старое API, чтоб ты не мучился с обновлением игры на новую версию движка.
>>4987
>дают схожие результаты
Насколько я понимаю, JSON.stringify гарантирует соответствие общепринятому стандарту JSON и позволяет выводить сразу с красивым форматированием, а var_to_str - это чисто внутренняя фича Godot для каких-то внутренних дел, которая ничего не гарантирует и, вроде бы, загоняет всё в одну строку без переносов.
Вот уж теперь-то можно начинать делать игры
как же хорошо что я еще не начинал делать игру
Висит в памяти в течение всей игровой сессии.
Содержит в себе два словаря, мутабельный и иммутабельный.
Имеет четыре метода: create(key, value, update = false), read(key, default, write_default = false), update(key, value, create = false), delete(key, only_value = false)
Методы работают со встроенными словарями таким образом, что любые изменения вносятся в мутабельный словарь, а при чтении сначала опрашивается мутабельный словарь, если в нём не найден ключ, опрашивается иммутабельный, если и в нём не найден ключ, возвращается дефолтное значение. Если нужно дефолтное значение добавлять в мутабельный словарь, если не найден ключ, то юзаем настройку через аргумент.
Так же есть массив контрольных точек, которыми являются глубокие копии мутабельного словаря. Эти контрольные точки могут быть быстро загружены из массива для быстрой загрузки без поднятия сейвов из файловой системы.
Теперь внимание.
Иммутабельный словарь - это эталонные данные игрового мира, он создаётся один раз при старте игры. Если у игры есть моды/длц, то в момент старта приложения оно опрашивает зарегистрированные моды и они предоставляют свои фрагменты данных в иммутабельный словарь. Этот словарь может быть достаточно большим и его не нужно сохранять постоянно. Он сохраняется один раз, в игровом профиле, который создаёт игрок в начале. Сейв-файлы являются сохранённым мутабельным словарём, работают как инкремент к ворлд-файлу в профиле.
Таким образом менеджер сохранений управляет следующими файлами:
1) ворлд-файл, который сохраняется редко, при создании новой игры внутри профиля, либо при изменении списка модов/длц
2) сейв-файл, один или несколько в зависимости от нужд, сохраняется часто, имеет малый размер, поскольку содержит только изменения относительно эталонного набора данных, впрочем в зависимости от величины игры сейвы тоже могут раздуваться.
3) конфиг-файл профиля, в котором хранятся настройки всего приложения в целом
То есть, игрок может полностью переключиться на другой профиль, с другим миром, сгенерированным на других сидах. Сейвы не будут подходить к ворлду, что является дополнительной защитой от читеров.
Стратегии удаления неактуальных данных являются предметом конфигурации менеджера, можно удалять их, а можно хранить, а можно предоставить эту возможность игроку.
Как происходит процесс сохранения? Устанавливается режим read_only и просто записывается мутабельный словарь в сейв-файл.
Как происходит процесс чекпойнтирования перед боссом? Просто копируется мутабельный словарь в массив чекпойнтов.
Как происходит заполнение мутабельного словаря? А вот тут вступает в дело паттерн обсервер. Объекты, которым требуется сохранить данные о себе, подписываются на КРУД-методы менеджера сохранений и при изменении своих данных, синхронизируют их со словарём. Таким образом идёт "трудолюбивое" формирование сейв-файла для "ленивого" процесса сохранения.
Как происходит загрузка? Вне зависимости от источника загрузки, чекпойнт или файл, сначала устанавливается режим read_only, испускается сигнал начала загрузки, все кто подписан на сигнал, делают свои дела, например встают на паузу и ждут дальнейших указаний. Происходит загрузка и проверка данных, если на этом этапе происходят косяки, испускается сигнал отмены, и все задействованные ноды возобновляют свои дела. Новые данные копируются в мутабельный словарь. Испускается сигнал окончания загрузки. Ноды проверяют, должны ли они существовать и если оказывается, что не должны, они выгружаются, а если оказывается, что должны, то обновляют данные о себе (не сидел у костра, а стоял на скале, например). Затем основная нода игрового мира (слово на букву с), управляющая загрузкой-выгрузкой чанков, также опрашивает менеджер на наличие нод, которые должны быть и загружает их. Загруженные ноды опрашивают менеджер на предмет актуальных данных о себе и действуют. И так пока все не обновятся. Когда все подписанные ноды отчитались об обновлении, испускается сигнал окончания обновления.
Дополнительный плюс такой системы в том, что данные об объектах доступны всегда, таким образом, в рамках исполнения квестов игроком, возможно менять состояние объектов, которые в данный момент не загружены (спиздил статую Талоса в Вайтране, а в Рифтене об этом уже знают, например, вопрос скорости передачи данных решается отдельно, например созданием объекта-таймера в потомках к основному миру, который с... существует, кхм, всегда, и сохранять таймаут этого таймера, и по окончании таймаута он произведёт изменения в данных).
Вот такой прожект. Разьебите по пунктам, в чём я не прав?
Висит в памяти в течение всей игровой сессии.
Содержит в себе два словаря, мутабельный и иммутабельный.
Имеет четыре метода: create(key, value, update = false), read(key, default, write_default = false), update(key, value, create = false), delete(key, only_value = false)
Методы работают со встроенными словарями таким образом, что любые изменения вносятся в мутабельный словарь, а при чтении сначала опрашивается мутабельный словарь, если в нём не найден ключ, опрашивается иммутабельный, если и в нём не найден ключ, возвращается дефолтное значение. Если нужно дефолтное значение добавлять в мутабельный словарь, если не найден ключ, то юзаем настройку через аргумент.
Так же есть массив контрольных точек, которыми являются глубокие копии мутабельного словаря. Эти контрольные точки могут быть быстро загружены из массива для быстрой загрузки без поднятия сейвов из файловой системы.
Теперь внимание.
Иммутабельный словарь - это эталонные данные игрового мира, он создаётся один раз при старте игры. Если у игры есть моды/длц, то в момент старта приложения оно опрашивает зарегистрированные моды и они предоставляют свои фрагменты данных в иммутабельный словарь. Этот словарь может быть достаточно большим и его не нужно сохранять постоянно. Он сохраняется один раз, в игровом профиле, который создаёт игрок в начале. Сейв-файлы являются сохранённым мутабельным словарём, работают как инкремент к ворлд-файлу в профиле.
Таким образом менеджер сохранений управляет следующими файлами:
1) ворлд-файл, который сохраняется редко, при создании новой игры внутри профиля, либо при изменении списка модов/длц
2) сейв-файл, один или несколько в зависимости от нужд, сохраняется часто, имеет малый размер, поскольку содержит только изменения относительно эталонного набора данных, впрочем в зависимости от величины игры сейвы тоже могут раздуваться.
3) конфиг-файл профиля, в котором хранятся настройки всего приложения в целом
То есть, игрок может полностью переключиться на другой профиль, с другим миром, сгенерированным на других сидах. Сейвы не будут подходить к ворлду, что является дополнительной защитой от читеров.
Стратегии удаления неактуальных данных являются предметом конфигурации менеджера, можно удалять их, а можно хранить, а можно предоставить эту возможность игроку.
Как происходит процесс сохранения? Устанавливается режим read_only и просто записывается мутабельный словарь в сейв-файл.
Как происходит процесс чекпойнтирования перед боссом? Просто копируется мутабельный словарь в массив чекпойнтов.
Как происходит заполнение мутабельного словаря? А вот тут вступает в дело паттерн обсервер. Объекты, которым требуется сохранить данные о себе, подписываются на КРУД-методы менеджера сохранений и при изменении своих данных, синхронизируют их со словарём. Таким образом идёт "трудолюбивое" формирование сейв-файла для "ленивого" процесса сохранения.
Как происходит загрузка? Вне зависимости от источника загрузки, чекпойнт или файл, сначала устанавливается режим read_only, испускается сигнал начала загрузки, все кто подписан на сигнал, делают свои дела, например встают на паузу и ждут дальнейших указаний. Происходит загрузка и проверка данных, если на этом этапе происходят косяки, испускается сигнал отмены, и все задействованные ноды возобновляют свои дела. Новые данные копируются в мутабельный словарь. Испускается сигнал окончания загрузки. Ноды проверяют, должны ли они существовать и если оказывается, что не должны, они выгружаются, а если оказывается, что должны, то обновляют данные о себе (не сидел у костра, а стоял на скале, например). Затем основная нода игрового мира (слово на букву с), управляющая загрузкой-выгрузкой чанков, также опрашивает менеджер на наличие нод, которые должны быть и загружает их. Загруженные ноды опрашивают менеджер на предмет актуальных данных о себе и действуют. И так пока все не обновятся. Когда все подписанные ноды отчитались об обновлении, испускается сигнал окончания обновления.
Дополнительный плюс такой системы в том, что данные об объектах доступны всегда, таким образом, в рамках исполнения квестов игроком, возможно менять состояние объектов, которые в данный момент не загружены (спиздил статую Талоса в Вайтране, а в Рифтене об этом уже знают, например, вопрос скорости передачи данных решается отдельно, например созданием объекта-таймера в потомках к основному миру, который с... существует, кхм, всегда, и сохранять таймаут этого таймера, и по окончании таймаута он произведёт изменения в данных).
Вот такой прожект. Разьебите по пунктам, в чём я не прав?
Дубина! Ты сейчас нарвёшься, блин! Я думаешь не смогу тебя поколотить? Я смогу тебя поколотить, балда!
>Он сохраняется один раз, в игровом профиле, который создаёт игрок в начале.
Зачем? Может быть, лучше все 150 Гб из папки игры скопировать в другую папку?
>в чём я не прав
В том, что копируешь данные из res:// в user:// чтобы... чтобы ничего не делать?
перехэшируй
misc/compute_shader_heightmap: Not supported on the Compatibility rendering method (which the web platform always uses).
Видимо речь о том что надо WebGPU, а там WebGL, который на GL ES 2.0
Я не знаю, братан.

>документация по этому поводу ничего не говорит
https://docs.godotengine.org/en/stable/tutorials/shaders/compute_shaders.html
>Compute shaders can only be used from RenderingDevice-based renderers (the Forward+ or Mobile renderer).
https://docs.godotengine.org/en/stable/tutorials/rendering/renderers.html
>Choose Compatibility if:
>You are developing for web. In this case, Compatibility is the only choice.
https://www.youtube.com/watch?v=2HxKr0MVwQs
Справедливо, надо было повнимательнее прочитать и сделать логический вывод.
Интересно есть ли смысл нагородить, скажем, WebGPU загрузчик в js-части и коммуницировать с годотом. Так, наверное, можно и Compute Shaders в 3-ке запустить, но непонятно можно ли это вообще и не съест ли коммуницирование выгоду.
Ладно, webgpu пока сырой, на пека в фуррифоксе не работает, на мобилке ни в каком.
А для чего тебе вообще compute shader в веб-игре?
Что ты там считать собрался на видеокарте? Нейронки?
Да разные. Конкретно мне подходит для симуляции водички и boids. И некоторые шейдеры похоже выгоднее делать через компьют, а не через чтение вьюпортов. Все что выигрывает от параллельности.
Написал большой ответ, но стер. Суть в том что это вопрос больше выбора версии движка, и я могу сделать отдельно версию 4-десктоп-компьют для шоукейза, а в вебе все равно оставаться на 3-ке с вариантом помельче, потому что буста не будет.
Все хочу следующую игру на SpryTile замутить (аналог CrocoTile3d) или типа https://godotengine.org/asset-library/asset/2873

Чтобы симуляция была точнее, динамическим объектам следует быть:
размером от 0.1 до 10 метров,
иметь скорости от 0 до 500 м/c,
гравитация от 0 до 10 м/с^2.
Статическим объектам следует быть от 0.1 до 2000 метров длиной.
То есть не стоит пытаться симулировать молекулу скачущую по имперскому крейсеру.
>500 м/c
Ради интереса глянул, это 1000 узлов, 1800 км/ч, то есть дозвуковые самолеты.
Блин, получается что и у огнестрела (типа калаш, m-16), и у танковых снарядов еще времен второй мировой скорость обычно раза в 2 выше.
Скорость в играх обычно сильно ниже 500 м/с, но физические симуляции тут ни при чём - просто игре потребуется загружать очень много декораций для движения на такой скорости где-либо кроме чистого космоса. Для реалистичных снарядов используются рейкасты; кидать RigidBody3D рационально только в случае какой-нибудь гранаты/ракеты/шара плазмы. Вообще, если ты делаешь игру, а не симулятор, то заботиться тебе придётся совсем о другом. Игры постоянно используют уловки ради фана игрока.
Для примера, скорость машин в GTA 5 намного ниже реалистичной, а игровой спидометр завышает свои показания. Почему? Потому что даже на SSD игра не всегда успевает подгружать нужные чанки города, а удерживать их все в оперативной памяти не может. Однако, это техническое ограничение скорости не мешает миллионам игроков наслаждаться игрой.
Только не рейкастами, а вычислением баллистической траектории, а так да.
Можно сделать вывод проще - если игра мультяшная, то можно и медленные пульки ригидобдями, а если симулятор, то надо свою баллистику и аэродинамику.

Пик с айпада.
Лидер Mono, вроде, который трудновато было пропихивать на iOS (потому что у эппла был запрет на виртуальные машины в прогах - а то вдруг что то скачает в обход них и выполнит)


Ждём...
Недостаточно долго планировал.

852x480, 1:08
Игорь.

1280x720, 1:48
Такая ж хуйня.
А по поводу пикчи: на годоте у нас с тобой хоть недоделки есть, юнити я тоже скачивал, тогда ещё в далёком 2к18 и сразу такое оттржение "фунахуй", закрыл и удалил. Анрил4 дольше продержался, но из-за конпеляции шейдеров постоянной и он меня доебал.
А на годоте заебись, достаётся за полсекунды, в нищепекарне лежит как влитой.
>>5441
У вас скоп большой, гарантирую. Теряете интерес задолго до финального результата. Возьмите микроидею на неделю, она неизбежено распухнет до месяца, но месяца должно хватить на удержание интереса. Опубликуете первую полноценную игру - дальше легче пойдет.
Если конечно есть желание реально игры делать, а не играться в движке. Играться в движке тоже норм.
Да, скоп большой, хочется экшен-слешер в открытом мире с прокачкой, квестами, скиллчеками в диалогах. Но понимание объёма уже пришло.
Я делал мини-игры и доводил до играбельного состояния (тетрис, сапёр и т.п.) В общем-то сижу и играю. В общем-то цель достигнута. Ведь никто не требовал обязательно публиковать.
А игра мечты? Я уже говорил, ранее, просто сидишь у реки и ждёшь, пока по ней проплывёт релиз игры похожей на твою мечту. Потому что мы все в едином инфополе живём. Родилась у тебя мечта и полетела синхроимпульсом по резонансу Шумана в коллективное бессознательное, начала сниться людям, похожим на тебя. Если ты сам не захочешь реализовать её, то найдутся другие, да и неизвестно, твоя ли это была мечта, или она тоже приснилась тебе однажды.
>хочется экшен-слешер в открытом мире с прокачкой, квестами, скиллчеками в диалогах.
Хочется ААА студией быть. А нужно знать свою нишу. Инди ниша удобна, хороша и востребована, особенно сейчас. Делай странное, делай новое, делай маленькое. Пройти игру на час, которая оставит впечатление, может оказаться более ценным экспириенсом для игрока чем 600 часов дрочить вышки в очередном ассассине.
>у нас с тобой хоть недоделки есть
И то верно, но хотелось большего...
>>5444
>возможностью заходить в каждый дом
Технически ничего сложного, но для того, чтобы эта концепция была интересной, все эти домики должны существенно отличаться друг от друга внутри. Даже с процедурной генерацией это требует много контента, который сам по себе не доставляет удовольствия. Т.е. разработать этот контент я мог бы, но в чём его фан?
Сейчас вот думаю: может, стоило делать декорации, расставляя их как попало, авось вошёл бы во вкус и получилось бы что-то интересное. Когда на всю игру имеется 3.5 плейсхолдера, работать с ней интереса мало, прогресс совсем не ощущается. Да и навалить различного контента низкого качества несложно. Тут главное соблюдать один общий стиль/настроение. В реалистичных ААА унылое "серое" настроение.
>>5443
>У вас скоп большой
А как без этого? Должен быть высокий потанцевал.
>микроидею на неделю
Сделал за вечер твою микроидею - дальше что? В чём интерес публиковать эту микроидею, что 100500 раз реализована во всех цветах и размерах в Google Play? Выбирай любую версию, играй сколько влезет... А, не влезет, потому что микроидея == микроинтерес к ней, развод лоха на просмотр рекламы перед геймплеем. Разумеется, если ты не сливаешь 1000 часов в одну гиперказуалку с одной примитивной механикой...
Понимаю, есть люди, которые 1000 часов сливают в банальный Flappy Bird и обожают повторять его по туториалам, типа "любимый флаппи бёрд, но вместо птички самолётик", но это вообще отдельная тема, и подобным играм в принципе не нужен движок на том уровне, на котором сейчас находится Godot. Им там достаточно выводить PNG в <canvas> тег HTML5.
Какой потанцевал у флаппи бёрд? PNG заменить?
У условного "клона GTA" большой потанцевал, это ж практически свой собственный Garry's Mod, только с нормальным транспортом и сразу большой картой. Направление развития любое можно выбрать и надстраивать новые механики одну за другой.
>>5447
>хочется экшен-слешер
Легко: мобы прут по прямой, герой тупо вращается с гигантским супер-пупер гипер-мечом, VFX вспышки перекрывают 99% экрана. За вечер сделаешь базу, а остальное можно доделать как-нибудь попозже.
>в открытом мире
Понятие растяжимо, но сегодня "открытый мир" == гигантские пустыни, пустыри, пустые поляны и т.д. Следовательно, опенворлд == растянутый филлер. Реализуешь стандартный коридорный экшн, дальше заменяешь загрузочные экраны тупыми пустырями, заставляешь игрока удерживать W всю дорогу. Даже суперпопулярная GTA 5 на этом построена, с этим её дебильным шоссе на 10 км вдоль скучной пустыни. "Слешеры" вообще с камерой сверху вниз, поэтому и подгрузка чанков мира будет проще технически.
>с прокачкой
Это тоже растяжимое понятие, прокачка может быть банальным +1 к урону и всё, никто не ждёт от тебя S.P.E.C.I.A.L. в ноунейм индюшке от соло автора. Переусложнённое дерево прокачки на самом деле проще реализовать в коде, чем понять в игре (тоже филлерный контент, тебе +1 к урону или к защите?).
>квестами
"Подай-принеси" квесты делаются легко. Остальные возможные квесты практически не встречаются, ибо игрокам не нравится ломать голову над задачами, а плестись за NPC - вообще своего рода наказание.
>скиллчеками в диалогах
Опять же несложно, если сделать фреймворк под это.
>понимание объёма уже пришло
В связи с вышеперечисленным не вижу сложности. Физических взаимодействий нет, крафта нет, даже стрельбы как таковой нет (Area3D на меч повесь). Графоманить тексты только научиться и в путь. В графическом плане - прибей камеру к потолку.
Ты просто ищешь оправдания для безделья.
>проплывёт релиз игры похожей на твою мечту
Лично моя проблема с этим в том, что мне хочется собственную игру. Ты предлагаешь удочерить уже взрослого человека вместо воспитания своего - это совершенно разные действия с разным результатом. Естественно, если тебе хочется просто поиграть, тебе разницы никакой не будет, но объективно она есть.
Для примера, Vintage Story начиналась как мод для Minecraft (TerraFirmaCraft), но разрабам надоели все подводные камни Minecraft - запилили свою игру. Возникает вопрос, что им мешало просто играть в ванильный Minecraft, не делая свои модификации? Некоторым людям, видимо, хочется чего-то своего, несмотря на провальность концепции (притащили бесполезный реализм ради реализма - зачем?).
>>5464
>Пройти игру на час
Никогда не понимал подобного. Я в игру играю, чтоб расслабиться и отвлечься от реальности, а не чтобы почитать мысли автора в интерактивном формате... Увлекающая игра не должна обрываться через час.
>ААА студией быть
Много видел hack-n-slash от ААА? Это ж инди жанр. Единственные представители от условного АА+ - это франшизы родом из древних времён. Как понимаю, нишевые жанры не получают финансирования без достаточно широко известного имени франшизы.
>у нас с тобой хоть недоделки есть
И то верно, но хотелось большего...
>>5444
>возможностью заходить в каждый дом
Технически ничего сложного, но для того, чтобы эта концепция была интересной, все эти домики должны существенно отличаться друг от друга внутри. Даже с процедурной генерацией это требует много контента, который сам по себе не доставляет удовольствия. Т.е. разработать этот контент я мог бы, но в чём его фан?
Сейчас вот думаю: может, стоило делать декорации, расставляя их как попало, авось вошёл бы во вкус и получилось бы что-то интересное. Когда на всю игру имеется 3.5 плейсхолдера, работать с ней интереса мало, прогресс совсем не ощущается. Да и навалить различного контента низкого качества несложно. Тут главное соблюдать один общий стиль/настроение. В реалистичных ААА унылое "серое" настроение.
>>5443
>У вас скоп большой
А как без этого? Должен быть высокий потанцевал.
>микроидею на неделю
Сделал за вечер твою микроидею - дальше что? В чём интерес публиковать эту микроидею, что 100500 раз реализована во всех цветах и размерах в Google Play? Выбирай любую версию, играй сколько влезет... А, не влезет, потому что микроидея == микроинтерес к ней, развод лоха на просмотр рекламы перед геймплеем. Разумеется, если ты не сливаешь 1000 часов в одну гиперказуалку с одной примитивной механикой...
Понимаю, есть люди, которые 1000 часов сливают в банальный Flappy Bird и обожают повторять его по туториалам, типа "любимый флаппи бёрд, но вместо птички самолётик", но это вообще отдельная тема, и подобным играм в принципе не нужен движок на том уровне, на котором сейчас находится Godot. Им там достаточно выводить PNG в <canvas> тег HTML5.
Какой потанцевал у флаппи бёрд? PNG заменить?
У условного "клона GTA" большой потанцевал, это ж практически свой собственный Garry's Mod, только с нормальным транспортом и сразу большой картой. Направление развития любое можно выбрать и надстраивать новые механики одну за другой.
>>5447
>хочется экшен-слешер
Легко: мобы прут по прямой, герой тупо вращается с гигантским супер-пупер гипер-мечом, VFX вспышки перекрывают 99% экрана. За вечер сделаешь базу, а остальное можно доделать как-нибудь попозже.
>в открытом мире
Понятие растяжимо, но сегодня "открытый мир" == гигантские пустыни, пустыри, пустые поляны и т.д. Следовательно, опенворлд == растянутый филлер. Реализуешь стандартный коридорный экшн, дальше заменяешь загрузочные экраны тупыми пустырями, заставляешь игрока удерживать W всю дорогу. Даже суперпопулярная GTA 5 на этом построена, с этим её дебильным шоссе на 10 км вдоль скучной пустыни. "Слешеры" вообще с камерой сверху вниз, поэтому и подгрузка чанков мира будет проще технически.
>с прокачкой
Это тоже растяжимое понятие, прокачка может быть банальным +1 к урону и всё, никто не ждёт от тебя S.P.E.C.I.A.L. в ноунейм индюшке от соло автора. Переусложнённое дерево прокачки на самом деле проще реализовать в коде, чем понять в игре (тоже филлерный контент, тебе +1 к урону или к защите?).
>квестами
"Подай-принеси" квесты делаются легко. Остальные возможные квесты практически не встречаются, ибо игрокам не нравится ломать голову над задачами, а плестись за NPC - вообще своего рода наказание.
>скиллчеками в диалогах
Опять же несложно, если сделать фреймворк под это.
>понимание объёма уже пришло
В связи с вышеперечисленным не вижу сложности. Физических взаимодействий нет, крафта нет, даже стрельбы как таковой нет (Area3D на меч повесь). Графоманить тексты только научиться и в путь. В графическом плане - прибей камеру к потолку.
Ты просто ищешь оправдания для безделья.
>проплывёт релиз игры похожей на твою мечту
Лично моя проблема с этим в том, что мне хочется собственную игру. Ты предлагаешь удочерить уже взрослого человека вместо воспитания своего - это совершенно разные действия с разным результатом. Естественно, если тебе хочется просто поиграть, тебе разницы никакой не будет, но объективно она есть.
Для примера, Vintage Story начиналась как мод для Minecraft (TerraFirmaCraft), но разрабам надоели все подводные камни Minecraft - запилили свою игру. Возникает вопрос, что им мешало просто играть в ванильный Minecraft, не делая свои модификации? Некоторым людям, видимо, хочется чего-то своего, несмотря на провальность концепции (притащили бесполезный реализм ради реализма - зачем?).
>>5464
>Пройти игру на час
Никогда не понимал подобного. Я в игру играю, чтоб расслабиться и отвлечься от реальности, а не чтобы почитать мысли автора в интерактивном формате... Увлекающая игра не должна обрываться через час.
>ААА студией быть
Много видел hack-n-slash от ААА? Это ж инди жанр. Единственные представители от условного АА+ - это франшизы родом из древних времён. Как понимаю, нишевые жанры не получают финансирования без достаточно широко известного имени франшизы.

>Много видел hack-n-slash от ААА? Это ж инди жанр.
Так все вменяемые слешеры это ААА. Иначе и быть не может. Миллион уникальных анимаций для врагов индюк не потянет. А если все враги будут просто набигать на игрока, то это заебет уже через 5 минут.
Отличный гайд как всю жизнь что-то делать но так ничего и не сделать.
Нет.
Сбилдить сможешь.
Про ограничения сказать трудно.
Насколько я знаю, поддержка там лишь частичная (через Mono и bionic-linux). Так было в 4.2 и не попадалось чтобы это менялось в текущих или в ближайшем будущем
https://godotengine.org/article/platform-state-in-csharp-for-godot-4-2/#android
В этой статье было написано:
uses the linux-bionic Mono runtime, and only supports the arm64 and x64 architectures.
The linux-bionic runtime is a Linux runtime using the Android C library, so it’s basically Android but without the JNI. This means that the Android bindings are not available, so some APIs (such as SSL) will crash the game. Use the Godot APIs when possible to avoid these issues.
Using NativeAOT should also be supported in theory, but it requires using .NET 8.0 and some manual work.
Немного покопавшись, нашел такой PR
https://github.com/godotengine/godot/pull/88803
Соответственно 3 предыдущих пункта отменяются:
Android exports now use the android runtime identifier instead of linux-bionic, this removes the restrictions we previously had:
Adds support for all Android architectures (arm32, arm64, x32, and x64), previously only the 64-bit architectures were supported.
Loads System.Security.Cryptography.Native.Android (the .NET library that binds to the Android OS crypto functions).
For Android, I don't think there should be any more unsupported APIs (starting from Godot 4.4).
Состояние NativeAOT отслежвается тут https://github.com/dotnet/runtime/issues/106748
Честно говоря, я не до конца все это понял. Думаю что твой игровой C# код всегда работал и будет работать. C# либы скачанные через nuget - скорее всего будут. Какая то экзотика, типа c++ либ - скорее всего нет.
По дефолту будет работать какой то anroid экспорт, в котором ограничений меньше, а для неработавшей криптографии написали обертку. linux-bionic с ограничениями подрубится (только?) если ты включишь экспериментальный NativeAOT в настройках csproj. Дефолтный экспорт комиилит в IL, который потом на устройстве конвертируется JIT в программу. NativeAOT бы сразу компилировал в бинарник.
Один момент например, в linux-bionic нет JNI. Вроде бы это значит что нельзя вызывать никакое API JAVA Android. А всякая аналитика, инаппы, камера вроде через него делается?
Сам я не пользуюсь ни 4-кой, ни C#, и давно не делал отдельных андроид версий (делаю только вин и веб)
Сбилдить сможешь.
Про ограничения сказать трудно.
Насколько я знаю, поддержка там лишь частичная (через Mono и bionic-linux). Так было в 4.2 и не попадалось чтобы это менялось в текущих или в ближайшем будущем
https://godotengine.org/article/platform-state-in-csharp-for-godot-4-2/#android
В этой статье было написано:
uses the linux-bionic Mono runtime, and only supports the arm64 and x64 architectures.
The linux-bionic runtime is a Linux runtime using the Android C library, so it’s basically Android but without the JNI. This means that the Android bindings are not available, so some APIs (such as SSL) will crash the game. Use the Godot APIs when possible to avoid these issues.
Using NativeAOT should also be supported in theory, but it requires using .NET 8.0 and some manual work.
Немного покопавшись, нашел такой PR
https://github.com/godotengine/godot/pull/88803
Соответственно 3 предыдущих пункта отменяются:
Android exports now use the android runtime identifier instead of linux-bionic, this removes the restrictions we previously had:
Adds support for all Android architectures (arm32, arm64, x32, and x64), previously only the 64-bit architectures were supported.
Loads System.Security.Cryptography.Native.Android (the .NET library that binds to the Android OS crypto functions).
For Android, I don't think there should be any more unsupported APIs (starting from Godot 4.4).
Состояние NativeAOT отслежвается тут https://github.com/dotnet/runtime/issues/106748
Честно говоря, я не до конца все это понял. Думаю что твой игровой C# код всегда работал и будет работать. C# либы скачанные через nuget - скорее всего будут. Какая то экзотика, типа c++ либ - скорее всего нет.
По дефолту будет работать какой то anroid экспорт, в котором ограничений меньше, а для неработавшей криптографии написали обертку. linux-bionic с ограничениями подрубится (только?) если ты включишь экспериментальный NativeAOT в настройках csproj. Дефолтный экспорт комиилит в IL, который потом на устройстве конвертируется JIT в программу. NativeAOT бы сразу компилировал в бинарник.
Один момент например, в linux-bionic нет JNI. Вроде бы это значит что нельзя вызывать никакое API JAVA Android. А всякая аналитика, инаппы, камера вроде через него делается?
Сам я не пользуюсь ни 4-кой, ни C#, и давно не делал отдельных андроид версий (делаю только вин и веб)
Это только про факт что "теперь поддерживается не только 64 бит".
Везде, и в документации, и в issue указывают что C# в Android - экспериментальный.
Бля, как же ты заебал уже.
Всё. Аноны! Давайте на зло ему не делать игры! Не поддадимся на его наглые провокации!
Он пишет эти посты во время своих перерывов, делая игры. Пару тредов назад говорил. У тебя же нет игр, как у безыгорника. Покажи свои игры.
Движок-то для делания игор. Ну и приложений. Делай игру и/или приложение. Давай, раз-раз.

Многие говорят, дескать, ГДСкрипт похож на Питон, но я тут с утра произвёл изучения и оказалось, что ГДСкрипт намного больше похож на Нахе, а тот в свою очередь похож на доведённый до ума Паскаль скрещенный со скопами скобачьками из си.
Посмотрите.
Главное чтобы глаза не царапало как раст. А вообще я у мамы уже вайбкодер, так что пофиг на чем.