Это копия, сохраненная 4 марта в 07:45.
Скачать тред: только с превью, с превью и прикрепленными файлами.
Второй вариант может долго скачиваться. Файлы будут только в живых или недавно утонувших тредах. Подробнее
Если вам полезен архив М.Двача, пожертвуйте на оплату сервера.
Краткий гайд по вкату в движок:
1. Читать документацию.
2. Качать примеры.
3. ПРОФИТ!
Ссылки
Новости движка: https://godotengine.org/news/
Скачать движок: https://godotengine.org/download/ или http://store.steampowered.com/app/404790/Godot_Engine/
Играть в игродела онлайн без регистрации: https://editor.godotengine.org/releases/3.4.rc1/godot.tools.html с дивана нельзя.
FAQ: https://docs.godotengine.org/ru/latest/about/faq.html
Документация: https://docs.godotengine.org/ru/latest/ https://docs.godotengine.org/en/stable/
Примеры качаются прямо в движке через свой магазин в отдельной вкладке AssetLib. Там есть всё - от платформера до чата.
Игры, созданные глобальными кириллами: https://steamdb.info/tech/Engine/Godot/ https://steamcommunity.com/app/404790/discussions/0/412448792354265655/
Изумительный Годот: https://github.com/Calinou/awesome-godot https://github.com/godotengine/awesome-godot - подборка дополнений, модулей и минишоукейc.
Аддон для диалоговой системы: https://godotengine.org/asset-library/asset/833
Прекомпилер шейдеров: https://godotengine.org/asset-library/asset/977
Библиотека готовых шейдеров: https://godotshaders.com
Майндмаппинг проектов не отходя от кассы: https://godotengine.org/asset-library/asset/879
SmartShape для рисования 2D-террейнов без задней мысли: https://godotengine.org/asset-library/asset/715
Конвертор кваковских карт для ностальгирующих дидов: https://godotengine.org/asset-library/asset/446
Конвертер блендеровских моделей в формат сцен: https://docs.godotengine.org/en/stable/getting_started/workflow/assets/escn_exporter/index.html
Конвертер блендеровских файлов прямо в движок: https://github.com/V-Sekai/godot-blender Надо только в настройках проекта путь к blender.exe указать. Потом просто закидываешь .blend в папку и импортируется.
Книги
Книги в 21 веке всё равно никто не читает, поэтому вот вам две рандомные из гугла:
https://play.google.com/store/books/details/Godot_Engine_Game_Development_in_24_Hours_Sams_Tea
https://play.google.com/store/books/details/Chris_Bradfield_Godot_Engine_Game_Development_Proj
Для любителей пощекотать конпеляцию
Бинды LUA: https://github.com/perbone/luascript
Бинды JS: https://github.com/GodotExplorer/ECMAScript
Годнота от анона
- Для приверженцев опенсорца существует возможность распространять проекты в незапакованном формате. Просто скачай темплейт с оф.сайта и положи экзешник/эльфешник в папку с проектом, этого достаточно. Имя файлу можно задать любое. Дополнительно можешь вшить свою иконку в экзешник. После этого, запустившийся файл темплейта обнаружит рядом с собой файл project.godot и начнет грузить проект из него и из файлов, лежащих в распакованном виде в той же директории. Для запущенного таким образом проекта папка res:// становится доступна для записи (если это не ограничено правами доступа в системе).
- В версии 3.2 появилась возможность прикреплять pck к бинарнику. Не появилась, а вернулась - 2.х умел. Бриллиант для любителей однофайлового продукта!
- Редактор персонажей на основе makehuman: https://github.com/Lexpartizan/Go_MakeHuman_dot
- Тест-бенчмарк:
- - Веб-версия - https://govdot.herokuapp.com
- - Вишмастер для винды - https://govdot.herokuapp.com/4Anon.rar
Предыдущий: >>785715 (OP)
Архивный: https://arhivach.ng/thread/746886/
включил sdfgi и хуйнул rotate_y на light detection, или как-то иначе все это должно быть реализовано?
Конец 2022, начало 2023.
Я вообще эту нумерацию не понимаю. 3 - это март?
>>792918
>SDFGI
Что это и зачем?
Кстати, а как вообще отражения включить? Всё перепробовал, у меня кроме бликов и теней ничего нет на 3.4.2 GLES3.
>>792902 →
>velocity = (position - old_pos) / delta
>И среди всех возможных решений НЕТУ моего варианта. Естественно закрадывается подозрение, что я что-то делаю не так. Но всё ж работает.
Не знаю, а какие бывают другие решения? По-моему твоё решение нормальное, вычисляет скорость в единицах в секунду же? Проблема скорее всего в том, что редактор пишет предупреждение "функция возвращает значение", и пользователь воспринимает это как призыв к действию - использованию этого значения, даже если оно ошибочно.
Алсо есть некоторые сомнения не счёт точности position, поскольку, например, позиции ригидбоди зачастую неактуальны, вдруг с кинематик боди такая же фигня...
1920x1080, 0:39
Переписываю код кирпичей. Теперь я могу задавать им размер прямо в редакторе. Коллизии обновятся вместе со спрайтами.
Какая-же tool-скрипты все-таки годнота
Так и не понял, как рендерить скайбокс в панорамную текстуру неба, поэтому удалил sky и вьюпорт, делаю всё в одном мире - нужно будет только копировать позицию активной камеры и эффект будет такой же, что и от труъ скайбокса (надеюсь)...
>>793040
>Reflection Probe
У меня не заработала. Наверное, она только для статичных уровней, но даже в режиме "обновлять постоянно" ничего не изменилось, кроме появления сильных лагов. Где-то прочитал, что рефлексы вообще не предназначены для опенворлда, а как тогда отражения на автомобилях во всяких ГТА делают? Ну то есть фейковые отражения, конечно, настоящие отражения в играх только в плоских зеркалах бывают, там где рендеринг в текстуру со стороны зеркала.
[2D] Имеем:
1. кинематик двигается через move_and_slide_with_snap.
2. Все наклонные плоскости не более 45 градусов, а в функции указывается чуть больший угол.
3. Вектор снапа указан верно.
И вообще. Всё правильно работает, персонаж снапится к земле, правильно проходит все изгибы. Кроме одного. Вот такого подъём в горку, затем плато, а затем резкий 90 градусов обрыв. Что происходит? Знающие люди знают: персонаж поднимается в горку, добегает до обрыва и без команды подпрыгивает. Если мониторить велосити, то можно обнаружить, что после горки её вектор направлен под углом к горизонту и почему-то не приходит в горизонтальный, даже несмотря на то, что заснапленный персонаж движется ровно по горизонтали.
Я думал, думал. И пришёл к простому решению:
var old_pos = position
move_and_slide_with_snap(.....)
velocity = (position - old_pos) / delta
И всё! Пока что ни одного бага, который мог бы появиться от неправильного использования кинематиков, не замечено. Ну типа, я ожидаю от move_ans_slide_with_snap, что оно вернёт мне велосити с поправкой на снап; оно не возвращает, но я получаю самостоятельно, в результате поведение выходит как раз как я ожидаю.
Но вот что меня смущает. Я предварительно хорошенько прогуглил эту проблему. И среди всех возможных решений НЕТУ моего варианта. Естественно закрадывается подозрение, что я что-то делаю не так. Но всё ж работает. Тогда зачем народ пляшет с бубном и ищет сложные решения? Непонятно. Что думаете?
[2D] Имеем:
1. кинематик двигается через move_and_slide_with_snap.
2. Все наклонные плоскости не более 45 градусов, а в функции указывается чуть больший угол.
3. Вектор снапа указан верно.
И вообще. Всё правильно работает, персонаж снапится к земле, правильно проходит все изгибы. Кроме одного. Вот такого подъём в горку, затем плато, а затем резкий 90 градусов обрыв. Что происходит? Знающие люди знают: персонаж поднимается в горку, добегает до обрыва и без команды подпрыгивает. Если мониторить велосити, то можно обнаружить, что после горки её вектор направлен под углом к горизонту и почему-то не приходит в горизонтальный, даже несмотря на то, что заснапленный персонаж движется ровно по горизонтали.
Я думал, думал. И пришёл к простому решению:
var old_pos = position
move_and_slide_with_snap(.....)
velocity = (position - old_pos) / delta
И всё! Пока что ни одного бага, который мог бы появиться от неправильного использования кинематиков, не замечено. Ну типа, я ожидаю от move_ans_slide_with_snap, что оно вернёт мне велосити с поправкой на снап; оно не возвращает, но я получаю самостоятельно, в результате поведение выходит как раз как я ожидаю.
Но вот что меня смущает. Я предварительно хорошенько прогуглил эту проблему. И среди всех возможных решений НЕТУ моего варианта. Естественно закрадывается подозрение, что я что-то делаю не так. Но всё ж работает. Тогда зачем народ пляшет с бубном и ищет сложные решения? Непонятно. Что думаете?
Я тебе в прошлом треде ответил. У тебя с гравитацией проблемы, поэтому вектор скорости не возвращается в горизонтальное направление. Скорее всего ты интегрируешь гравитацию только если !is_on_floor, что неправильно
блин. Случайно вышло. Мне двощ сказал, что отправка сообщения отменена.
>>793150
Гравитация появляется только в стейтах прыжка и падения. Если добавить её в других стейтах, то
а) Появляются проблемы на горках: вниз персонаж движется сильно быстрее, чем вверх.
б) Это НЕ исправляет вектор скорости после горки (проверял). Да, через некоторое время он выравнивается, но если идёт горка, потом короткая горизонтальная поверхность, а потом обрыв - на краю обрыва персонаж подпрыгнет, потому что его велосити была направлена чуть вверх, и единственное, что его удерживало от прыжка, это снап.
в) Есть ещё стейты лазания по лестницам и плавания в воде, там гравитация другая.
velocity = (position - old_pos) / delta попробуй заменить на velocity = velocity.slide(get_floor_normal)
Вроде как это само собой напрашивается. Если будешь высчитывать Velocity из позиции, можешь столкнуться с некоторыми траблами в будущем. Например, некорректно будут работать движущиеся платформы
1920x1080, 0:32
Пора бы уже переставать срать в движкотреде, а заводить свой.
Вот такие кирпичи получились. Могу к ним прицеплять любые другие штуки. Джамппады, шипы, вращающиеся вокруг кирпича пилы.
Писал пост и придумал, что можно чуть-чуть отредачить код и появится возможность цеплять на кирпичи другие кирпичи, чтобы они двигались по своей траектории вокруг главного. Сколько уровней можно с этим придумать
Очень круто получается, создавай свой тред! Я уже сам начал некоторые фичи из твоих постов брать :D
Стильно! Хоспаде, как же стильно!
Тряска камеры дезориентирует. Обычно рекомендуется вообщене использовать её, если событие, инициирующее тряску, происходит слишком часто.
>Пора бы уже переставать срать в движкотреде, а заводить свой.
Я тебе это пол-треда назад говорил
>попробуй заменить на velocity = velocity.slide(get_floor_normal)
Уже даже не попробовав вижу, как персонаж будет в полтора раза ускоряться при переходе с горки на плато при таком ходе.
Вообще, вопрос был не "что делать?", а "я сделал, всё работает, почему так не делают другие?".
>персонаж будет в полтора раза ускоряться
Не будет. При переходе с горки на плато скорость не изменится. По сути эта штука занулит тебе velocity.y (Первый пример на пикриле)
При переходе с плато на горку замедления/ускорения опять же не произойдет. Вектор движения просто будет направлен вдоль горки. (Второй пример. Подьем с плато на горку в 45 градусов)
Твоя проблема в том что ты отключаешь гравитацию если персонаж на полу. В таком случае move_and_slide не учитывает коллизии с полом. Если бы ты не убирал гравитацию, все эти вычисления проводились бы внутри move_and_slide.
Чтобы персонаж не менял скорость в зависимости от наклона горки в move_and_slide передавай stop_on_slope = true
960x540, 1:25
>набросал звёзды
Вот они.
Совет: если вам нужно реализовать в коде какую-то формулу, сначала эту формулу будет лучше спроектировать на специальном калькуляторе, который строит графики. Найти такие легко в интернете, работают в том числе в браузере. Я вот долго ломал голову над формулами прибавления и убавления энергии солнца и окружения, пока не догадался нарисовать график. С графиком стало всё просто, даже ветвление не потребовалось.
Также неочевидный момент, вдруг кому пригодится: SpotLight нельзя помещать параллельно освещаемым плоскостям, из-за этого на 3.x получается некрасивая решётка наподобие Z-fighting. Т.е. лучше повернуть на несколько градусов. А ещё можно выбрать reverse cull faces и поставить bias на -0.01 или около того, проблема решается (но тогда свет будет немного протекать в щели). В 4.0, говорят, уже пофиксили...
>проблема в том
что move_and_slide_with_snap возвращает не ту велосити, которая фактически получается со снапом, а ту, которая получалась бы без снапа, но перемещает персонажа всё равно со снапом. То есть, фактическое перемещение персонажа не совпадает с возвращаемой скоростью. Этот баг давно известен и закрыт, потому что не баг, а фича.
>В таком случае move_and_slide не учитывает коллизии с полом
Всё оно прекрасно учитывает, потому что это move_and_slide_with_snap.
>Вектор движения просто будет направлен вдоль горки.
он уже перенаправляется внутри функции, а ты предлагаешь повторить это ещё раз снаружи.
Всё, что я делаю, это получаю фактическую скорость, исходя из реального перемещения персонажа.
окей, насчёт velocity.slide ты был прав. Ща в тестовом проекте прогнал - нашёл случай, при котором мой вариант с position - old_pos выдаёт странное, а твой работает нормально, в том числе на переходе с горки на плато и обратно.
А вот гравитацию таки надо выключать при is_on_floor(). Потому что смотри что получается:
velocity.y += GRAVITY
# теперь вектор скорости направлен куда-то вниз
velocity = move_and_slide_with_snap(velocity, Vector2.DOWN * snap_size, Vector2.UP, true, 4, SLOPE_ANGLE, false)
# обращаю внимание: stop_on_slope == true
velocity = velocity.slide(get_floor_normal())
# тадам, наш вектор гравитации только что превратился в вектор скольжения.
>комменты на русском
Бож, дурачок. Тебе русским языком сказано было. Либо гравитация, либо velocity.slide(get_floor_normal())
>Всё оно прекрасно учитывает, потому что это move_and_slide_with_snap.
Не учитывает и это легко проверить при помощи get_last_slide_collision() . Зачем ты тут воняешь, если даже документацию открыть не в состоянии?
>integrate_forces, а что в ней делать-то?
Интегрировать силы, очевидно же.
>Примеры с add_force не вызывают доверия, это же добавляется каждый раз еще сила. Это что же, мне вычитать предыдущую и добавлять новую?
Нет. Вызывать add_force() можно и нужно каждый тик, пока данная сила действует на объект. А вот apply_impulse() вызывать каждый кадр нельзя, эта функция предназначена только для одноразового толчка объекта. Разница в том, что импульс не учитывает дельту физического тика, а add_force() по идее учитывает дельту.
_integrate_forces() нужно, по сути, только с одной целью: безопасно читать и модифицировать физическое состояние объекта, когда он готов это состояние менять. Т.е. это аналог _physics_process, только вызывается на определённом этапе работы физического сервера и даёт доступ к дополнительным физическим свойствам.
Хотя я сам не использовал _integrate_forces(), не знаю, чем отличается безопасный доступ от небезопасного... Типа, глюков меньше?
Делаешь самолёт на базе VehicleBody? Эта нода официально признаётся недоделанной и с кучей проблем, и вообще предназначена для наземного транспорта. Говорят, лучше на базовом RigidBody делать или вообще на KinematicBody, если не нужно взаимодействие с другими RigidBody...
Я тоже хотел/хочу самолёт замутить, пробовал сделать на базе RigidBody, но для строгой симуляции нужен чёткий дизайн с пропеллером на одной линии с центром масс, либо придётся обманывать игрока и делать тягу в центре масс, а не в пропеллере, что выглядит нереалистично. Пичаль, но ничего не поделаешь, это физика, её знать нужно.
>Похоже это фича буллета сбрасывать каждый тик.
Попробуй переключиться на GodotPhysics. По-моему, там точно такая же интеграция сил, серьёзное отличие только в положении центра масс (в буллет оно фиксированное, в годо зависит от количества и положения коллиженшейпов).
>>793373
>даже если домножать на дельту, то результаты немного расходятся
Это может быть связано с неточностью вещественных чисел или с тем, что у физического движка своя дельта времени, отличающаяся от той, которую ты получаешь в своих скриптах.
Кстати, часто замечаю, что мой персонаж, каким бы способом я его ни делал, падает не с той скоростью, с которой падают ригидбоди. Т.е. он либо быстрее, либо медленнее, хотя в теории скорости должны совпадать, если нет симуляции сопротивления воздуха. Это напрягает, хочется предсказуемых результатов... Скорее всего проблема та же - разные дельты у физики и скриптов.
>Думаю насчет кинематика, просто придется силы и шасси самому написать.
Можно к ригидбоди колёсики через джойнты прицепить, я видел на гитхабе проекты с такой реализацией машин. Либо просто посадить на рейкасты, как это делает VehicleBody.
Анончики, я запустил свой тред. Теперь буду постить все обновления и девлоги там:
>>793516 (OP)
От души
а) отскалить как canvas_item - скейл не работает на партиклях;
б) поставить отрицательный скейл в процесс-материале - не ставится меньше нуля, как ни старайся;
в) выставить direction.x = -1 в том же процесс-материале - это влияет лишь на направление полёта, но не на саму текстуру.
Я чёт в тупике. Неужели придётся тупо делать два эмиттера частиц с зеркально отражёнными текстурами? Это как-то тупо. Наверняка как-то можно флипнуть, пацаны, выручайте.
1280x720, 1:57
Не унывайте, годаны!
ты конкретно текстуру в партикле хочешь флипнуть? через вьюпорт подобное можно сделать.
потому что сам партикл флипается спокойно
У меня тоже была такая проблема. Никак, но есть несколько вариантов. Либо загонять партиклы под канвас лейер и флипать его, либо менять параметры непосредственно в ParticleMaterial, либо использовать Particle Shader
>>793565
Не дочитал твой вопрос и высрал хуйню. Ты же можешь менять текстуру партиклам на лету
$Particles2D.texture = mytexture
Ну в этом случае тоже покостылить придется, потому что как я понимаю, текстура заменится и на уже выпущенных партиклах
А на твоем месте я бы разбил партиклы на левый и правый эмиттер и включал бы их по-отдельности
Лучше бы кинул ссылку на стабильную 3.4.3, это важнее альфы.
https://godotengine.org/article/maintenance-release-godot-3-4-3
Потому что их нет
848x464, 0:10
>Туториалы - хуйня, к сожалению, в большинстве случаев
Просто вообще все так пишут.
>Учи общее программирование
Кстати вот тематические книги по геймдеву вообще есть? Шоб на торрентах там и т.д
>Война, ёпт
Дык не у нас, а у хохлов, че у нас то лагает, будто трафик сильно вырос, полтора анона как сидела, так и сидит.
> хотя бы раз голову включал
Ну вот я включил позавчера и запасся НЗ на недельку, чтобы переждать пока курсы и цены бешенно скакать будут. Даром не пропадёт.
ЦИПСО спок.
> А какое мнение должно быть, чтобы это было не лахтой?
Мнение должно быть особым, как особый режим несения боевого дежурства сил ядерного сдерживания РФ.
960x540, 1:27
>Вместо этого, почему никто не использует сигналы и таймеры? Это ведь производительней в разы. Какое-то дурновкусие у тех же туториалов, по которых я и обучаюсь.
Не всякое производительное решение легко объяснить, особенно ньюфагу. Если сигналы и таймеры объясняются на каком-то определённом уроке - до этого урока всё будут делать более примитивным кодом, которого в реальном проекте быть не должно. Это не ошибка, это просто последовательное объяснение сложных тем полным новичкам, с расчётом на то, что они пройдут весь курс от начала до конца не пропуская и не перескакивая главы.
Сравни это с преподаванием в обычных школах. Первокласснику не пихают в голову знания старшей школы лишь потому, что они оптимальнее или нужнее во взрослой жизни. Сначала учат писать "печатными буквами", да ещё и каждую букву своим цветом (типа согласные синей ручкой, гласные красной, ещё какие-то зелёной), что дико неэффективно, но помогает научиться (или должно помогать по замыслу педагогов). Или учат считать на каких-нибудь яблоках, на пальцах, палочки по парте раскладывать, какие-то закорючки в тетради, что взрослый человек делать никогда в жизни не будет. Учат читать сначала по буквам, потом по слогам, потом проговаривая каждое слово, а не бегло просматривая текст по диагонали. И так далее. Если ты не вылетишь из школы во втором классе, то всё будет нормально. Проблема с онлайн-туториалами в том, что никто не может заставить тебя внимательно прочитать весь курс туториалов от начала до конца, а иногда и сам автор не успевает доделать этот курс до конца или забрасывает работу над ним.
Раз уж ты знаешь такие сложные темы, как сигналы, то тебе будет лучше изучать Годо по официальному руководству:
https://docs.godotengine.org/en/stable/index.html
На русский там почти ничего не переведено, но ничего сложного там нет, это не художественная литература. А сторонние туториалы толку не имеют, они в большинстве своём пересказывают официальное руководство и ничего нового не добавляют, если только не касаются каких-то сторонних аддонов.
>Вместо этого, почему никто не использует сигналы и таймеры? Это ведь производительней в разы. Какое-то дурновкусие у тех же туториалов, по которых я и обучаюсь.
Не всякое производительное решение легко объяснить, особенно ньюфагу. Если сигналы и таймеры объясняются на каком-то определённом уроке - до этого урока всё будут делать более примитивным кодом, которого в реальном проекте быть не должно. Это не ошибка, это просто последовательное объяснение сложных тем полным новичкам, с расчётом на то, что они пройдут весь курс от начала до конца не пропуская и не перескакивая главы.
Сравни это с преподаванием в обычных школах. Первокласснику не пихают в голову знания старшей школы лишь потому, что они оптимальнее или нужнее во взрослой жизни. Сначала учат писать "печатными буквами", да ещё и каждую букву своим цветом (типа согласные синей ручкой, гласные красной, ещё какие-то зелёной), что дико неэффективно, но помогает научиться (или должно помогать по замыслу педагогов). Или учат считать на каких-нибудь яблоках, на пальцах, палочки по парте раскладывать, какие-то закорючки в тетради, что взрослый человек делать никогда в жизни не будет. Учат читать сначала по буквам, потом по слогам, потом проговаривая каждое слово, а не бегло просматривая текст по диагонали. И так далее. Если ты не вылетишь из школы во втором классе, то всё будет нормально. Проблема с онлайн-туториалами в том, что никто не может заставить тебя внимательно прочитать весь курс туториалов от начала до конца, а иногда и сам автор не успевает доделать этот курс до конца или забрасывает работу над ним.
Раз уж ты знаешь такие сложные темы, как сигналы, то тебе будет лучше изучать Годо по официальному руководству:
https://docs.godotengine.org/en/stable/index.html
На русский там почти ничего не переведено, но ничего сложного там нет, это не художественная литература. А сторонние туториалы толку не имеют, они в большинстве своём пересказывают официальное руководство и ничего нового не добавляют, если только не касаются каких-то сторонних аддонов.
>лучше изучать Годо по официальному руководству
Поддвачну.
Годо научил меня читать доки. Начинал с русских видео-туторов, быстро переключился на английские, а там и до чтения апи дошло.
В доках не сказано, а тайлмапа не является наследником CollisionObject2D, и физика у неё странная.
Или можно походу изучать gdscript?
Что посоветуете?
Конечно, по ходу изучать гскрипт
Гдскрипт только внешне похож на пайтон. Форматированием отступами. Больше ничем знание пайтона там не поможет. Но замечательная новость в том, что гдскрипт феноменально простой! Учится за неделю.
Всё равно не поможет.
Я тут в прошлом году хотел написать плагин для одного софта, не связанного с играми, написанного на пайтоне, и плагины у него пайтоновские. Я подумал, вроде гдскрипт знаю, щас быстро сварганю. Ага. ЩАЗЗ. До сих пор не могу разобрать эту тарабарщину.
>Можно ли при использовании add_collision_exception_with(body) в качестве body указать тайлмапу?
Читаем документацию:
>PhysicsBody is an abstract base class for implementing a physics body. All *Body types inherit from it.
>void add_collision_exception_with ( Node body )
>Adds a body to the list of bodies that this body can't collide with.
Каким местом тайлмап/гридмап может быть боди, если они не являются дочерними от PhysicsBody?
Внутри тайлмап/гридмап обращаются к серверу физики, чтобы создавать соответствующие физические объекты и шейпы. Т.е. в теории можно было бы найти RID физического объекта тайлмапы/гридмапы, чтобы затем вызвать это:
>void body_add_collision_exception ( RID body, RID excepted_body )
>Adds a body to the list of bodies exempt from collisions.
Потому что именно это вызывается, когда ты обращаешься к соответствующей функции PhysicsBody. Но делать такое с тайлмапой/гридмапой не рекомендую, т.к. сами они необходимые RID не предоставляют, а искать подходящие RID вручную чревато неуловимыми ошибками из-за того, что ты не знаешь, как внутри устроен тайлмап/гридмап. А потом со следующей версией движка они могут измениться и придётся переделывать костыли.
Короч, рекомендую обратиться в godotengine/godot-proposals и предложить либо введение метода "добавить исключение", либо вывод наружу соответствующих физических RID, по которым можно было бы добавлять исключение вручную. А пока лучше пользоваться слоями, это намного проще, если у тебя не более 32 физических объектов.
>для вката в Годо стоит ли сперва изучить Пайтон?
Нет, питон тебе не нужен, изучай сразу GDScript.
>>793856
>Больше ничем знание пайтона там не поможет.
Так-то знание ЛЮБОГО императивного ЯП поможет в изучении GDScript, как и любого другого императивного ЯП. Знаешь один императивный ЯП - считай, знаешь все остальные, достаточно только прочитать про особенности синтаксиса, например, как выглядит знак присваивания и какие типы принимает знак деления.
Другое дело что можно своим первым языком осваивать GDScript, а уже потом с него переходить на любой другой ЯП, если потребуется. Т.е. изучать питон для Годо вообще не нужно.
>>793858
>Я подумал, вроде гдскрипт знаю, щас быстро сварганю. Ага. ЩАЗЗ. До сих пор не могу разобрать эту тарабарщину.
Лол, открываешь официальную документацию по питону, смотришь, что означают те или иные особенности синтаксиса и быстро разбираешься. Это же императивный ЯП, а не какая-нибудь там функциональщина.
> Лол, открываешь официальную документацию по питону, смотришь
Ты меня раскусил)) Я не особо-то и старался тот аддон написать. Не вышло и пох.
>Каким местом тайлмап/гридмап может быть боди, если они не являются дочерними от PhysicsBody?
А где в документации сказано, что боди должно быть дочерним от физиксбоди?
>void add_collision_exception_with ( Node body )
Если бы функция принимала на вход только физиков, почему бы тип не указать соответствующий?
>Короч, рекомендую обратиться в godotengine/godot-proposals и предложить либо введение метода "добавить исключение"
Ты загоняешься. Я уже всё сделал через слои. А для каких таких задач требуется добавлять в исключения целую тайлмапу, а не отдельные плитки, я чёт не могу придумать пока что. Конечно, ковыряться с плитками всё ещё такое себе удовольствие, но тут уж посмотрим, как оно в четвёрке будет.
Каким местом тайлмап/гридмап может быть боди, если они не являются дочерними от PhysicsBody?
Обычным. Тайлмап можно сделать body двумя способами:
1) Установить ему галку collision/use_parent и сделать его дочерней нодой kinematicbody/staticbody/rigidbody (С area2d тоже срабатывыает). По сути в данном случае тайлмап будет играть роль collisionshape2d
2) Установить ему галку collision/use_kinematic. Тогда для физ.сервера тайлмап станет kinematicBody
>>793827
Читай выше, должно помочь
Ты лучше гречку, соль, спички качай.
Сяп, котаны.
Ничего не знаю о Годоте, а самому разбираться сложна. Есть несколько вопросов.
1. Можно ли на Годоте скриптить только на C# или только на Cpp?
2. Есть ли в редакторе рантайм режим, чтобы сразу проверять, как что работает?
3. Будет ли он нормально работать на слабом компухтере?
1. Можно.
2. Есть. Режим tool в искаробочном gdscript. На шарпе я не интересовался таким режимом, скорее всего нет, а на плюсах тебе вообще редактор будет недоступен во время написания модуля, с которым тебе придётся потом движок пересобрать. Но ты же сишник, тебе всё это легко. Легко же? Нет? А нахуй ты в кресты лезешь?
3. Будет. Но не ожидай от некропеки кинематографичного графона.
Да я о другом. Домен хк лёг. А у меня на нём плашка ОПа осталась. В общем-то, перенести не проблема. Потом займусь. Если домен не вернётся.
А у меня лег. Пишу с .life
Ну значит проблема в моих ДНС. Ну штош, значит к утру поправят. Зря перенервничал.
1280x720, 0:16
Спрошу тогда свой вопрос. Кто-то мультипоток реализовал в своей игре? Как вы это сделали? Можете рассказать? Скриншоты покидать и т.д, если можно. Чета мало инфы об этом, как именно в играх реализовывают мультипоток, где его юзають лучше и как.
вебмрандом
>Кто-то мультипоток реализовал в своей игре?
Я юзал для динамичческой подгрузки комнат.
>>793682 →
В принципе ничего сложного нет, если понимать как работают потоки и thread-safe код.
Спасибо анончик, за пояснения. Как я понял, даже в обсуждениях не любят много поток, потому что даже дебагинга нет и старые неуловимые баги присутствуют, из-за которых непонятно как, непонятно когда крашется аж до синего экрана. Проблема все же еще в том, что если никто не использует потоки, некому и багрепортить и фиксить, печаль короче.
Но подгрузка уровня, загрузка мультимешей конечно только в параллельном потоке, это самое собой, слишком уж пропукивается иначе все. Вообще я сейчас плотно взялся за создаение прототипа, уже есть подвижки, в этом, я все равно буду ковырять многопоток, иначе хули никто ничего не делает в этой стези, мейби что-то расскажу в будущем, слишком уж мало инфы об этом.
>Вчера скачал 1000 ассетов по свежести, все шейдеры с godotshaders и все репозитории arlez80. Качал godotforums, скачал около 5000 свежих тредов, но потом вылетел свет, повторно ставить не будут. Никуда ничего не стухнет.
Ух бля, а разве со включенным впном невозможно чищо зайти будет? Да и инфа про гитхаб и бесплатное ПО фейки оказались, гитхаб не будет никого блокировать. Правда сейчас от Лондонского тырнета нас отрезали, теперь все потоки через китай, тырнеты еще медленейстали, но работают хотяб
>>794945
Как я понял, все юзают потоки только для подгрузки контентыча, любопытно, где еще его кто-то юзал, мейби тех же нпс реализовывал и как успехи в этом были. В интернете чета вообще нихуя нет контента, даже примеров реальных, кроме подгрузки уровней.
Приходит в голову AI или навигация пересчитываемая в фоне
> не любят много поток
Я понимаю, что многопоток - круто, но до сих пор не могу мыслить тредсейфово.
мимо
Когда ты используешь process или phisic_process, у тебя эта функция не может быть перезагружена заново так как используется одним источником. В то же время, если ты создашь функцию, которую можно будет запускать из разных источников при каком то событии, то, по крайней мере в godot, она у тебя может быть вызвана повторно даже не дойдя до конца(то есть перезагружена(извиняюсь, я не программист)).
Теперь другой вопрос: почему JSON файл в игре виден на пк, но не виден на ведре?
> почему JSON файл в игре виден на пк, но не виден на ведре?
Потому что на ведре ты только с папкой user:// можешь работать. А твой файл наверняка лежит в res://
> этот способ сработал
Значит я таки телепат. Всё верно угадал.
…Ведь при отправке проекта на андроид фактически происходит его экспорт, а это значит, что годот берёт все известные ему файлы ресурсов в папке с проектом и пакует их в ПАК-файл. Поскольку у тебя файл ЖСОН, он не является известным годоту файлом ресурсов, не смотря на то, что сам формат ЖСОН годоту прекрасно известен. Поэтому нужно принудительно прописать необходимые расширения в инклюды. Воот.\
>>795195
Если по доброму, то пусть немножко сренькает. Мы ж с тобой сами такие были. Плюс, не забывай, когда излагаешь свои мысли текстом, они лучше структурируются. Он пару раз напишет вот такое, а потом пойдёт в документацию, чтобы правильными терминами переписать написанное. Тут то в него знания и польются.
Таймеры кстати в годоте супербыстрые, на крестах написанные, вроде как без посредников работают по типу питона прокладки и т.д, на чистых крестах тащемта
>>795207
>>795210
А я походу понял, он хочет засунуть текстуру в партикл, а эта текстура должна отображать то, что он намалявал в тайлмапе, по сути сделать скриншот этого участка и засунуть в текстуру и применить после в партикле, если это так, то могу пояснить как сделать через стрим текстуру
>Если по доброму, то пусть немножко сренькает.
Намедни у GamesFromScratch вышел видос о плюсах и минусах линукса как платформы (и в том видосе он вроде как излагает свои мысли, а не просто зачитывает текст с какого-нибудь сайта; хотя хз, может, зачитывает, просто не показывает). И он верно заметил: линуксовое сообщество ужасно токсичное, несмотря на, казалось бы, всю гуманистичность изначальной идеи опенсурса. И как же на контрасте с этим выглядит Годо-сообщество, я не первый год удивляюсь, какая тут доброта. Даже телепаты в отпуск приезжают сюда как на курорт.
Хули тогда так донатов мало? Давай раскупоривай кубышку, Хуан не справляется
> линуксовое сообщество ужасно токсичное
А ты не был бы токсичным, если бы пилил бесплатно код, тратил время и талант, не получая зарплаты? Только редкие донаты. Какая-то мелочь с рекламных баннеров. Рано или поздно приходит осознание, что опенсорц не подходит для капиталистической реальности. Но врождённая честность не позволяет перейти на закрытые лицензии и обдирать людей как липку. И всё это приводит к постоянному жесточайшему стрессу.
Да, конечно, есть поддерживаемый корпорациями опенсорц. Но там как раз 90% это корпоративные кодеры на зарплате. Но это исключение. Большинство опенсорца раздаётся за спасибо.
>А где в документации сказано, что боди должно быть дочерним от физиксбоди?
Но ведь это логично? Под телом подразумевается физическое тело, а для физических тел есть один общий класс.
>Если бы функция принимала на вход только физиков, почему бы тип не указать соответствующий?
Меня это тоже смущает. Возможно, это для того, чтобы не было ошибок типов при передаче результатов get_node(), get_parent() и т.п., которые выдают Node. Для новичков это проще, меньше кода писать, в противном случае пришлось бы обмазываться проверками и приведением типов.
>>794064
>Тайлмап можно сделать body
Нет, тайлмап останется тайлмапом. Физическое тело будет создано на физическом сервере, но ссылка на него скрыта где-то в недрах тайлмапа и ты не можешь получить её.
>Установить ему галку collision/use_parent
1. Эта галка есть только у тайлмапы, кстати, почему у гридмапы такой функциональности нет?
2. Окей, тайлмапа создаёт колижн ШЕЙП для твоего боди, которого ты сам должен создать родителем этой тайлмапы. Т.е. тайлмапа как была тайлмапой, так и остаётся, а боди ты создаёшь отдельной нодой. Да, звучит как решение проблемы, по крайней мере для 2D.
Я думаю, речь всё же о пользователях линукса, а не его разработчиках. Во всех этих "ламповых сообществах Годо" большинство участников - простые пользователи, а не разработчики движка. То, что мы пишем какие-то скрипты или даже выкладываем их бесплатно, не причисляет нас к разработчикам движка. Так и пользователь линукса, даже если что-то там сидит ковыряет в системе, не разработчик, но вот визжать на форумах он может очень громко и очень противно. Потом все эти срачи между пользователями сборок линукса, как будто им мало срачей за линукс, всё визжат и смеются над своими собратьями по разуму. Срачи между отдельными альтернативными программами под линукс. Срачи "текстовый режим или графический интерфейс" и т.д.
Что же касается разработчиков опенсурса, то они не могут быть токсичными, потому что им некогда общаться на форумах за пределами сухих ответов на вопросы по разрабатываемому софту. Никто не будет сраться с тобой и вываливать на тебя стены оскорблений. Если тебе что-то не нравится - не пользуйся, ведь ты ничего не покупал, либо сделай по-своему в форке. Может и бывают токсичные разработчики опенсурса, но такие вряд ли задерживаются в больших командах/проектах, и вряд ли способны потянуть в соло достойный проект (потому что всё время уходит на срачи, оскорбления, проявление ненависти и т.д.).
Я лично предполагаю, что аудитория Годо такая дружелюбная только потому что движок непопулярный. Стоит Годо распиариться и токсичных пользователей станет многократно больше. Думаю, с выходом релизной 4.0 можно будет забыть о ламповости, т.к. активизируются спящие ждуны и нахлынет поток новичков...
>эта функция не может быть перезагружена заново так как используется одним источником
Возможно, ты путаешь с термином "перегрузка функций"? В GDScript нет перегрузки функций. Или ты путаешь с "переопределение методов"? Хотя, судя по следующему тексту ты вообще путаешь с порядком выполнения/многопоточностью:
>может быть вызвана повторно даже не дойдя до конца
Не может такого случиться, если только не использовать yield в самой функции. Godot по умолчанию делает всё в одном потоке и GDScript тоже выполняется в одном потоке. Есть API для создания потоков, но одновременное обращение из разных потоков к одному объекту небезопасно, этого следует избегать, иначе потом будет сложно найти причину, по которой данные в памяти портятся или программа зависает или падает.
>то есть перезагружена
Нет такого термина, и никакой "перезагрузки" не происходит, во всяком случае в GDScript. Если с помощью yield приостановить выполнение функции и затем сразу запустить эту функцию снова, это не будет "перезагрузкой", скорее, можно воспринимать это как две параллельные реальности, существующие друг в друге в шахматном порядке - после yield мы как правило ожидаем возврат к выполнению этой функции, т.е. можно представить, что она не остановилась, а только замерла на неопределённое время. Если же использовать многопоточность, то в идеале код будет выполняться физически разными устройствами (ядрами процессора) и, соответственно, вызов одной и той же функции будет в полностью параллельных и, в идеале, непрерывных вселенных (на практике операционная система делает ту же самую шахматную доску даже на многоядерном процессоре, потому что процессов у неё сотни, и их все нужно равномерно распределять, но с точки зрения прикладных программ всей этой работы вообще не видно). Кстати, yield можно использовать в _process и _physics_process, хотя пользы в этом мало, лучше выделять для этого отдельные функции. Т.е. после yield(сигнал) интерпретатор перейдёт к другим делам, потом снова запустит _process как обычно с самого начала, а потом в какой-то момент может выполнить тот участок _process, который после yield. В этом плане это самая обычная функция.
>эта функция не может быть перезагружена заново так как используется одним источником
Возможно, ты путаешь с термином "перегрузка функций"? В GDScript нет перегрузки функций. Или ты путаешь с "переопределение методов"? Хотя, судя по следующему тексту ты вообще путаешь с порядком выполнения/многопоточностью:
>может быть вызвана повторно даже не дойдя до конца
Не может такого случиться, если только не использовать yield в самой функции. Godot по умолчанию делает всё в одном потоке и GDScript тоже выполняется в одном потоке. Есть API для создания потоков, но одновременное обращение из разных потоков к одному объекту небезопасно, этого следует избегать, иначе потом будет сложно найти причину, по которой данные в памяти портятся или программа зависает или падает.
>то есть перезагружена
Нет такого термина, и никакой "перезагрузки" не происходит, во всяком случае в GDScript. Если с помощью yield приостановить выполнение функции и затем сразу запустить эту функцию снова, это не будет "перезагрузкой", скорее, можно воспринимать это как две параллельные реальности, существующие друг в друге в шахматном порядке - после yield мы как правило ожидаем возврат к выполнению этой функции, т.е. можно представить, что она не остановилась, а только замерла на неопределённое время. Если же использовать многопоточность, то в идеале код будет выполняться физически разными устройствами (ядрами процессора) и, соответственно, вызов одной и той же функции будет в полностью параллельных и, в идеале, непрерывных вселенных (на практике операционная система делает ту же самую шахматную доску даже на многоядерном процессоре, потому что процессов у неё сотни, и их все нужно равномерно распределять, но с точки зрения прикладных программ всей этой работы вообще не видно). Кстати, yield можно использовать в _process и _physics_process, хотя пользы в этом мало, лучше выделять для этого отдельные функции. Т.е. после yield(сигнал) интерпретатор перейдёт к другим делам, потом снова запустит _process как обычно с самого начала, а потом в какой-то момент может выполнить тот участок _process, который после yield. В этом плане это самая обычная функция.
Двачую. Я всем этим баловался в прошлые годы. Расписывал константами все магические числа. Ебашил горы кастомных сигналов. Тщательно инкапсулировал всё. Никакого выигрыша не получил. Только головняк при откапывании реально действующего кода в куче бойлерплейта.
В итоге я плюнул на это и юзаю глобальный синглтон. Удобно просто, быстро. Всё под рукой. Достаётся за полсекунды, в руке лежит как влитой. ООП-быдло оче боится.
>>794622
Я знаю про ту статью уже очень давно, она мне ничем не помогла (ну я её и не читал по сути). В любом случае я отложил генерацию на неопределённое будущее, т.к. толку от неё сейчас нет. Вообще не нужно было с неё начинать, нужна была только структура мира с какими-нибудь тестовыми данными.
>>795309
>глобальный синглтон. Удобно просто, быстро.
Проблема такого подхода в том, что сложно расширять и переносить решения в другой контекст, сложно вносить изменения в этот глобальный объект без исправления всего остального проекта. Короче, теряется гибкость. Низкая гибкость - это высокая сложность изменения кода, замедляющая разработку прототипа. Я вот уже много чего "с нуля" переделываю, копируя файлы, потому что малейшее изменение в одной глобальной структуре требует изменения сразу в нескольких других системах, и все эти изменения не так-то просты.
> этот глобальный объект
Я невнятно выразился, сорян. Разумеется до такого богокласса я не довожу. Сохранение например, в отдельном классе, независимое от игры и легко переносящееся. Персонажи, контроллеры, гуй, тоже отдельные классы. А синглтон всем этим управляет, как дирижёр оркестром.
У НЕСа были суровые ограничения на количество цветов, одновременно находящихся на экране, и на размер спрайта. Тут при сохранении общей палитры эти ограничения всё же не соблюдены, поэтому и графон кажется богаче.
>>793678
>>795128
>>795445
>суровые ограничения
Нашёл подробный туториал про ограничения, вдруг пригодится:
https://nesrocks.com/blog/nes-graphics/
Сенкс, бро, я это всё давно знаю (а туториал годный). Мне в этом плане близок подход "Лопатного рыцаря". Графические ограничения служат скорее стилистическими рамками, чем принципиальной границей. NES-палитра, ограниченное количество цветов внутри одного спрайта/тайлсета; ну и на этом всё. Просто (чисто моё имхо) это выглядит более стильно, чем современный полноцветный пикселярт.
Раньше о таких технических деталях вообще не задумывался...
Ну сохранишь ты эти туториалы, а дальше что? Смотреть будешь? Или сделаешь торрент-раздачу? Кому эти туториалы нужны вообще, кроме совсем глупых новичков.
Паниковать нужно будет если сам Ютуб забанит пользователей из России, а блокировки со стороны РКН как были дырявыми, так и останутся. Мне кажется, у РКН никогда не входило в планы блокировать что-то по-настоящему, чтобы никто не мог получить доступ; они только для тупых домохозяек блокируют, чтобы те возвращались к просмотру телевизора.
Алсо лайфхак: добавляете "pi" после youtube в адресной строке и попадаете на сервис скачивания видео, который работает довольно давно и практически без сбоев (алсо позволяет качать 18+ видео без авторизации в Ютубе). Даже если забанят Ютуб и даже если сам Ютуб заблокирует доступ с российских айпи, доступ к этому сервису скорее всего останется. Пример: https://youtubepi.com/watch?v=BhwMSfX-8iw
Двачую. Официальная документация ( https://docs.godotengine.org/en/stable/ ) необходима и достаточна для изучения движка. Для качественного написания игор нужна годот-независимая общая документация по теории конструирования видеоигор. Есть ли такая?
В любом случае, специалистами /ew/ много лет назад было обосновано, что на случай БП имеет смысл схоронять исключительно текстовые документы, в том числе чертежи и ноты. Видосы и музыка занимают много места, а ценность инфы на единицу ёмкости носителя значительно уступает тексту.
Тогда качай классику.
https://www.youtube.com/c/GameEndeavor
https://www.youtube.com/c/CodewithTom
https://www.youtube.com/c/BeIndieGameTutorials
https://www.youtube.com/channel/UCla6BhPwo5zGal6vR5le4YA
https://www.youtube.com/channel/UCrHQNOyU1q6BFEfkNq2CYMA
https://www.youtube.com/channel/UCoW5DE2TZxaK47qhtbN6g2g
https://www.youtube.com/c/Gdquest
https://www.youtube.com/channel/UCOTSosw_E-Cr88QkAb1Mdsg
https://www.youtube.com/channel/UCQeKBvYSJl4tqoEuLzBcfAg
https://www.youtube.com/watch?v=xKbZQHthbR8
Мне кажется не избежать постоянной смены состояния бота. Как вариант я бы сделал ограничения в несколько секунд, то бишь бот помимо расстояния, так же деспавнился через н-количество секунд, как только выходит из этого состояния. Ну и само собой, если это в отдельном потоке, то производительность не будет падать. Если ты в том же стулкере посмотришь на алайф, там что-то похожее реализовано. Автономная система ботов существует параллельно и нпс переключатся из состояния в состояние.
дополню насчет сталкера. в 2022 году люди для оптимизации смены состояния нпс в алайф просто выкручивают отрисовку на максимум, пушта эта постоянная смена в однопотоке только приносит лаги, проще сразу всех держать в памяти
> если игрок будет часто переходить из чанка в чанк, боты будут часто деспавниться и респавниться
Радиус подгрузки чанка меньше чем радиус выгрузки. Как тебе такое, Инол Макс?
Знач смари. Годот от прямой конкуренции с крупными движками останавливает сущая мелочь - отсутствие удобного способа компилировать и подключать к проекту либы на си++. Как бы ни был хорош и удобен гдскрипт для новичка, профессионалы не будут кодить на нём. Такова реальность.
В связи с чем нужен способ автоматизации процесса сборки, настройки и подключения на лету либ гднатив. Как я это вижу: Пишем расширение на вижуал студию, которое всем этим занимается. Пишем скрипты на плюсах. Одной кнопкой компилируем, собираем или обновляем конфиг (.gdns) и запускаем годот (или, если редактор уже открыт, выполняем в нём эфпяточку).
Как вам идея?
>Как бы ни был хорош и удобен гдскрипт для новичка, профессионалы не будут кодить на нём.
С чего вдруг такой вывод? Если ты реально оплачиваешь работу профессионала, он тебе на любом ЯП код напишет. Если какая-то студия решит использовать Годо как свой основной инструмент, то она будет использовать GDScript и будет иметь специально обученных скриптеров для этого языка. Потому что для большинства задач нет смысла трогать C++, производительности GDScript хватит для многого.
>способ автоматизации процесса сборки
Почему бы не использовать ту же систему сборки, что используется для сборки ядра движка? Зачем изобретать велосипед?
https://docs.godotengine.org/en/stable/development/compiling/introduction_to_the_buildsystem.html
>Godot uses SCons to build. We love it, we are not changing it for anything else. We are not even sure other build systems are up to the task of building Godot. We constantly get requests to move the build system to CMake, or Visual Studio, but this is not going to happen.
>>795827
>Радиус подгрузки чанка меньше чем радиус выгрузки.
Круто, спасибо, именно то, что у меня вертелось в голове, но я не мог это сформулировать. Сейчас у меня чанки встают в очередь на загрузку/выгрузку, но всё происходит так быстро, что можно "мигать" чанками, находясь на границе чанков. Разница в радиусах должна помочь с этой проблемой (и с ИИ тоже).
>>795816
>Попробуй представить чанки отдельно и ИИ отдельно. Тогда постоянно деспавниться не будет.
ИИ для физического существования в мире нужен физически существующий чанк, следовательно, радиус загрузки ИИ должен быть не больше радиуса загрузки физических чанков. Если физический чанк выгружается, все ИИ в нём должны немедленно быть выгружены, иначе они провалятся "под карту". Поэтому эти системы должны быть как-то связаны между собой.
>>795813
>если это в отдельном потоке
Я не уверен, что можно безопасно взаимодействовать с деревом сцены (KinematicBody, Area и т.д.) из параллельного потока. В любом случае хотел сделать сначала однопоточный вариант, а уже потом пытаться вынести в отдельный поток, если это будет возможно, потому что параллельные системы всегда сложнее.
>>795838
>Таким образом, если даже твой бот выгрузился и вгрузился через время t, ты абсолютно точно по школьной формуле определишь, какую часть отрезка A-B он преодолел.
Я думал об этом, но боюсь того, что моя формула не будет соответствовать реальному движению KinematicBody, потому что неизвестно, что там за формулы внутри move_and_slide и других функций. Получается, два бота, идущие в загруженном и выгруженном чанках, пройдут один участок за разное время... А что на счёт VehicleBody или каких-то кастомных машинок на RigidBody? Они же вообще сложную физику для движения используют. Впрочем, наверное, я зря об этом задумываюсь, т.к. вряд ли это будет легко заметить, если не пытаться специально обнаружить.
Реальная проблема у меня не с формулами движения. Сначала было бы неплохо загружать/выгружать неподвижных ботов. Проблема в том, как их объединить в одну систему с чанками и KinematicBody, чтобы не было десятка костылей-ссылок. Вроде как решений может быть несколько, но совершенно не ясно, какое из них будет лучше. Я уже задолбался переписывать одни и те же системы на новый лад, только чтобы обнаружить, что придётся переписывать снова. Заранее всё спланировать не удаётся...
Сейчас у меня такое дерево (описываю по памяти):
- WorldEnvironment и система времени (синглтон)
- HUD с мини-картой мира (синглтон)
- данные мира
- - генератор данных мира
- - отрисовщик блока (что-то устаревшее)
- - менеджер чанков (имеет ссылку на игрока)
- - - чанки (создаются менеджером в рантайме)
- - невидимая "безопасная" платформа (лол)
- - персонаж игрока
- - тестовые машинки
- - тестовые боты
Логично было бы создать менеджер ИИ жителей, а потом связать его ссылками и сигналами с менеджером чанков... А сам ИИ держать не в нодах, а в каких-то отдельных классах, я полагаю, наследниках Resource (чтобы можно было хранить образцы в файлах ресурсов, хотя, возможно, это не пригодится). Сложно...
Всем спасибо за ответы, не ожидал.
>>795827
>Радиус подгрузки чанка меньше чем радиус выгрузки.
Круто, спасибо, именно то, что у меня вертелось в голове, но я не мог это сформулировать. Сейчас у меня чанки встают в очередь на загрузку/выгрузку, но всё происходит так быстро, что можно "мигать" чанками, находясь на границе чанков. Разница в радиусах должна помочь с этой проблемой (и с ИИ тоже).
>>795816
>Попробуй представить чанки отдельно и ИИ отдельно. Тогда постоянно деспавниться не будет.
ИИ для физического существования в мире нужен физически существующий чанк, следовательно, радиус загрузки ИИ должен быть не больше радиуса загрузки физических чанков. Если физический чанк выгружается, все ИИ в нём должны немедленно быть выгружены, иначе они провалятся "под карту". Поэтому эти системы должны быть как-то связаны между собой.
>>795813
>если это в отдельном потоке
Я не уверен, что можно безопасно взаимодействовать с деревом сцены (KinematicBody, Area и т.д.) из параллельного потока. В любом случае хотел сделать сначала однопоточный вариант, а уже потом пытаться вынести в отдельный поток, если это будет возможно, потому что параллельные системы всегда сложнее.
>>795838
>Таким образом, если даже твой бот выгрузился и вгрузился через время t, ты абсолютно точно по школьной формуле определишь, какую часть отрезка A-B он преодолел.
Я думал об этом, но боюсь того, что моя формула не будет соответствовать реальному движению KinematicBody, потому что неизвестно, что там за формулы внутри move_and_slide и других функций. Получается, два бота, идущие в загруженном и выгруженном чанках, пройдут один участок за разное время... А что на счёт VehicleBody или каких-то кастомных машинок на RigidBody? Они же вообще сложную физику для движения используют. Впрочем, наверное, я зря об этом задумываюсь, т.к. вряд ли это будет легко заметить, если не пытаться специально обнаружить.
Реальная проблема у меня не с формулами движения. Сначала было бы неплохо загружать/выгружать неподвижных ботов. Проблема в том, как их объединить в одну систему с чанками и KinematicBody, чтобы не было десятка костылей-ссылок. Вроде как решений может быть несколько, но совершенно не ясно, какое из них будет лучше. Я уже задолбался переписывать одни и те же системы на новый лад, только чтобы обнаружить, что придётся переписывать снова. Заранее всё спланировать не удаётся...
Сейчас у меня такое дерево (описываю по памяти):
- WorldEnvironment и система времени (синглтон)
- HUD с мини-картой мира (синглтон)
- данные мира
- - генератор данных мира
- - отрисовщик блока (что-то устаревшее)
- - менеджер чанков (имеет ссылку на игрока)
- - - чанки (создаются менеджером в рантайме)
- - невидимая "безопасная" платформа (лол)
- - персонаж игрока
- - тестовые машинки
- - тестовые боты
Логично было бы создать менеджер ИИ жителей, а потом связать его ссылками и сигналами с менеджером чанков... А сам ИИ держать не в нодах, а в каких-то отдельных классах, я полагаю, наследниках Resource (чтобы можно было хранить образцы в файлах ресурсов, хотя, возможно, это не пригодится). Сложно...
Всем спасибо за ответы, не ожидал.
>>795961
Мимо другой анон
Хочется уточнить, что по идее в офф режиме вообще не нужна такая точность, по типу физики и т.д. Не знаю зачем вообще это нужно реализовывать. Проще создать параллельную упрощенную систему перемещения, чем упрощать текущую, с учетом реальной физике. Разделить карту на зоны и оперировать этими сущностями. Создать переменные, которые будут упрощенно вычислять пройдены путь в секундах. Из точки А в точку Б за 10 секунд и т.д. На н-ом участке допустим происходит бой, потому что по нему проходило 2 вражеских отряда и т.д, либо воспроизвести звук , с боем в далеке, в зависимости от геймплея.
С таким подходом на изи можно свой маунт анд блейд сделать, аля глобальная карта со своей жизнью.
впервые юзаю 3д, в туторах на ютабе челы просто накидывают контролы и всё норм рисуется сверху
нихуя не работает, но если снести worldenvironment, который отвечает за глоу интерфейса, начинает отрисовываться нормально
но как мне замутить интерфейс для 3д игоря с глоу эффектом?
>Это только если они у тебя ходят по физике.
А как ещё могут ходить жители города в ГТА-лайк игре?
>Но если они будут "в фоне" ходить по маршруту, то физика им не нужна, это просто translate.
Откуда возьмётся транслейт, если житель "в фоне" физически не существует? Не существует ноды, которую можно было бы транслейтить. Или ты предлагаешь оставлять Spatial ноду в сцене? Но я как бы пытаюсь избежать лишних нод, именно для этого и нужна чанковая система (удаляет из сцены лишние ноды).
>можно добавить Plane на всю карту на уровне моря,
Костыль уровня 90-х, где ты в ГТА-подобных играх видел такое?
>>795966
>не нужна такая точность, по типу физики и т.д. Не знаю зачем вообще это нужно реализовывать.
Всё так, физика нужна только пока житель вблизи игрока (пара сотен метров, к примеру). Когда житель удаляется от игрока, игрок удаляется от жителя, житель заходит в здание или игрок заходит в здание, KinematicBody жителя должен быть удалён из сцены или вообще уничтожен, в то время как мозги жителя перейдут в фоновый режим работы - меньше тиков и более абстрактное взаимодействие с данными мира. Проблема в том, как связать это с чанками.
>Разделить карту на зоны
Эти зоны называются чанками.
Вопщем последние несколько недель я играл в разные игры и чёт совсем приуныл. Наверное, отложу свою ЖТА в сторону снова на неопределённое число месяцев. Но заняться чем-то хочется и я думаю, а что если попробовать сделать 2Д космосим-песочницу по типу Space Impossible? Этот SI уже много лет в раннем доступе и разработка еле-еле шевелится, а последний апдейт радикально изменил геймплей в худшую, на мой взгляд, сторону. Выглядит стильно (шейдеры всякие), но возможностей слишком мало. Собственно, к чему я это пишу. Кто-нибудь знает, GodotPhysics в 2D нормально тянет процедурную генерацию произвольной формы из квадратиков? Вообще на Godot имеет смысл что-то в этом роде делать? Просто широко распространено мнение, что Terraria-подобные игрые нерационально делать на движках общего назначения, и ужасно глючный и тормозной Starbound на Unity в который раз подтверждает это мнение. В общем не хотелось бы начать делать очередной проект, который закончится ничем из-за принципиальной несовместимости движка уровня Godot (или Unity, UE, без разницы вообще, они все тяжёлые, Godot 4.0 тоже будет значительно тяжелее) с такого рода играми...
>Это только если они у тебя ходят по физике.
А как ещё могут ходить жители города в ГТА-лайк игре?
>Но если они будут "в фоне" ходить по маршруту, то физика им не нужна, это просто translate.
Откуда возьмётся транслейт, если житель "в фоне" физически не существует? Не существует ноды, которую можно было бы транслейтить. Или ты предлагаешь оставлять Spatial ноду в сцене? Но я как бы пытаюсь избежать лишних нод, именно для этого и нужна чанковая система (удаляет из сцены лишние ноды).
>можно добавить Plane на всю карту на уровне моря,
Костыль уровня 90-х, где ты в ГТА-подобных играх видел такое?
>>795966
>не нужна такая точность, по типу физики и т.д. Не знаю зачем вообще это нужно реализовывать.
Всё так, физика нужна только пока житель вблизи игрока (пара сотен метров, к примеру). Когда житель удаляется от игрока, игрок удаляется от жителя, житель заходит в здание или игрок заходит в здание, KinematicBody жителя должен быть удалён из сцены или вообще уничтожен, в то время как мозги жителя перейдут в фоновый режим работы - меньше тиков и более абстрактное взаимодействие с данными мира. Проблема в том, как связать это с чанками.
>Разделить карту на зоны
Эти зоны называются чанками.
Вопщем последние несколько недель я играл в разные игры и чёт совсем приуныл. Наверное, отложу свою ЖТА в сторону снова на неопределённое число месяцев. Но заняться чем-то хочется и я думаю, а что если попробовать сделать 2Д космосим-песочницу по типу Space Impossible? Этот SI уже много лет в раннем доступе и разработка еле-еле шевелится, а последний апдейт радикально изменил геймплей в худшую, на мой взгляд, сторону. Выглядит стильно (шейдеры всякие), но возможностей слишком мало. Собственно, к чему я это пишу. Кто-нибудь знает, GodotPhysics в 2D нормально тянет процедурную генерацию произвольной формы из квадратиков? Вообще на Godot имеет смысл что-то в этом роде делать? Просто широко распространено мнение, что Terraria-подобные игрые нерационально делать на движках общего назначения, и ужасно глючный и тормозной Starbound на Unity в который раз подтверждает это мнение. В общем не хотелось бы начать делать очередной проект, который закончится ничем из-за принципиальной несовместимости движка уровня Godot (или Unity, UE, без разницы вообще, они все тяжёлые, Godot 4.0 тоже будет значительно тяжелее) с такого рода играми...
>глоу интерфейса
По-моему ты пытаешься скрестить ежа с ужом, ты когда-нибудь вообще видел светящийся 2D интерфейс в играх? Я имею в виду процедурно светящийся, а не запечённый в текстуры. А если тебе нужны какие-то плавающие по экрану 3D штуки, которые будут светиться подобно AR штукам из научной фантастики, тогда делай это не через Control, а через Spatial, но на отдельном CanvasLayer, который будет накладываться поверх всего остального. Возможно, понадобится ещё отдельный Viewport и камера. Поищи как делают оружие в 3D шутерах, там точно такая же система - пушка на самом деле рисуется поверх всего остального, чтобы не проходить сквозь стены и другие препятствия.
А Control предназначены только для 2D, либо на экране (вьюпорт по умолчанию), либо для вывода в текстуру. Не вижу смысла кидать на контролы какие-либо 3D спецэффекты (глоу и т.п.).
Как делать ИИ на чанковой системе я подробно расписывал в давних тредах. Копаться в архивах лень, поэтому ебану с подливой по памяти, заодно что-то дополню. Итак.
Перво наперво, твоя игра должна содержать менеджеры, управляющие теми или иными аспектами игры. Некоторые менеджеры синглтонны и их есть смысл пихануть в автозагрузку. Некоторые менеджеры временны и/или многоинстансны, их логичнее создавать при надобности.
Менеджер ИИ - синглтон. Он загружается в память и сидит во время игры всегда. Он в реальном времени обсчитывает мысли, желания и стремления всех живых существ. Ууу, чот меня понесло. В общем, он в реальном времени обсчитывает GOAP-графики всех мобов. Всех, да не всех. Всех, да не одинаково. У менеджера ИИ тебе нужно сделать несколько "ЛОД"ов, уровней детализации мышления мобов. И они разумеется, привязаны к координатам игрока. Пусть нумерация ЛОДов начинается от игрока. Стало быть, нулевой уровень, это непосредственно взаимодействующие с игроком мобы. На уровне один - мобы, которых видно. На уровне два мобы, которые за спиной, за стенами, но в пределах существующих локаций. Всем этим мобам менеджер ИИ аттачит физические тела, которые берёт по запросу у менеджера существ. Мобы (которые есть чисто математическая сущность, душа, наследуемая от Node) управляют телами, водят их по навмешу, кусают или ебут игрока, катаются с ним на машинах, ходят на обед и в туалет, смотрят футбол (или 60 минут) по телевизору и занимаются своими мобскими делами.
Когда чанк, удаляющийся от игрока выгружается, он посылает сигнал "я выгружаюсь". Мобы, стоящие на чанке навмеша, принадлежащем выгружаемому чанку локации, подписаны на этот сигнал (вообще, нужно было сказать, что они переходя из чанка в чанк подписываются на сигналы нового и отписываются от сигналов старого). И с этого момента для мобов настаёт новая жизнь. Их тела выгружаются вместе с чанком, мобы получают null в переменной, отвечающей за их тело. У них жизненные процессы затормаживаются с дельта-тайма до скажем одного тика в минуту. В таком ленивом режиме мобы некоторое время существуют, чтобы завершить свои GOAP-графики, завершить те дела, которые важны для продвижения игрока по игре. Например, подождать некоторое время, как писал анон выше, достаточное, чтобы приблизительно дойти из Вайтрана в Лос-Сантос, сесть в казино и играть там в рулетку, чтобы проезжающий мимо игрок краем глаза именно этого моба увидел. Потому что, когда локация загрузится, она получит из менеджера мира данные о том, каких мобов грузить, загруженные мобы запросят у менеджера ИИ свой интеллект, и одним из таких будет вышеописанный лениво существующий в игровом астрале Node-моб.
Ну вот, как-то так. Кто осилил - молодец. Кто понял - ваще красаучег! Кто понял и нашёл ошибки - велком к дискассу.
Как делать ИИ на чанковой системе я подробно расписывал в давних тредах. Копаться в архивах лень, поэтому ебану с подливой по памяти, заодно что-то дополню. Итак.
Перво наперво, твоя игра должна содержать менеджеры, управляющие теми или иными аспектами игры. Некоторые менеджеры синглтонны и их есть смысл пихануть в автозагрузку. Некоторые менеджеры временны и/или многоинстансны, их логичнее создавать при надобности.
Менеджер ИИ - синглтон. Он загружается в память и сидит во время игры всегда. Он в реальном времени обсчитывает мысли, желания и стремления всех живых существ. Ууу, чот меня понесло. В общем, он в реальном времени обсчитывает GOAP-графики всех мобов. Всех, да не всех. Всех, да не одинаково. У менеджера ИИ тебе нужно сделать несколько "ЛОД"ов, уровней детализации мышления мобов. И они разумеется, привязаны к координатам игрока. Пусть нумерация ЛОДов начинается от игрока. Стало быть, нулевой уровень, это непосредственно взаимодействующие с игроком мобы. На уровне один - мобы, которых видно. На уровне два мобы, которые за спиной, за стенами, но в пределах существующих локаций. Всем этим мобам менеджер ИИ аттачит физические тела, которые берёт по запросу у менеджера существ. Мобы (которые есть чисто математическая сущность, душа, наследуемая от Node) управляют телами, водят их по навмешу, кусают или ебут игрока, катаются с ним на машинах, ходят на обед и в туалет, смотрят футбол (или 60 минут) по телевизору и занимаются своими мобскими делами.
Когда чанк, удаляющийся от игрока выгружается, он посылает сигнал "я выгружаюсь". Мобы, стоящие на чанке навмеша, принадлежащем выгружаемому чанку локации, подписаны на этот сигнал (вообще, нужно было сказать, что они переходя из чанка в чанк подписываются на сигналы нового и отписываются от сигналов старого). И с этого момента для мобов настаёт новая жизнь. Их тела выгружаются вместе с чанком, мобы получают null в переменной, отвечающей за их тело. У них жизненные процессы затормаживаются с дельта-тайма до скажем одного тика в минуту. В таком ленивом режиме мобы некоторое время существуют, чтобы завершить свои GOAP-графики, завершить те дела, которые важны для продвижения игрока по игре. Например, подождать некоторое время, как писал анон выше, достаточное, чтобы приблизительно дойти из Вайтрана в Лос-Сантос, сесть в казино и играть там в рулетку, чтобы проезжающий мимо игрок краем глаза именно этого моба увидел. Потому что, когда локация загрузится, она получит из менеджера мира данные о том, каких мобов грузить, загруженные мобы запросят у менеджера ИИ свой интеллект, и одним из таких будет вышеописанный лениво существующий в игровом астрале Node-моб.
Ну вот, как-то так. Кто осилил - молодец. Кто понял - ваще красаучег! Кто понял и нашёл ошибки - велком к дискассу.
>>Откуда возьмётся транслейт
>Будет высчитан математически.
В смысле? Я не понимаю, что ты называешь "транслейтом" - просто вектор смещения или поле Spatial.translation?
>Причем тут вообще ГТА?
Ты разве не видел мои прыдущие видео? Дороги, домики, мафынки, на мафынках можно кататься, а можно пешком ходить. ГТА? ГТА. Что тебе ещё нужно? Оружие? Оно не главное, ГТА - это "великий автоугонщик", в ГТА главное мафынки, жители и город.
>В ГТА когда ты отворачиваешься, жители и машины исчезают
Вот именно, вот это я и хотел бы исправить, т.е. превратить бездушные декорации в полноценную симуляцию жизни, социума и всего такого. В ГТА ты смотришь на жителя города и задаёшься вопросом, а куда он идёт, что он думает и вообще в каком состоянии сейчас находится; но в ГТА это просто тупой болванчик на рельсах замкнутого маршрута, не более чем пустая декорация. Было бы круто симулировать жизнь жителей и настроить их ИИ на эффективное выживание и размножение, а оружие максимально сократить, чтобы игрок не мог истребить весь город за пять минут. Но геймплейно и графически это та же самая ГТА, просто с более глубокой закулисной работой, чем в обычной экшн-игре.
>>796123
>есть смысл пихануть в автозагрузку
Кстати, пытаюсь от автозагрузки избавиться совсем. Имхо, это неудобно, когда делаешь прототип и нужно запускать разные сцены по отдельности. Сейчас у меня, например, мини-карта вообще отключена, потому что несовместима с остальными имеющимися системами... Что будет делать, например, менеджер ИИ, когда игра загрузила главное меню? Мир игры ещё не существует, агентов размещать негде, менеджер совершенно бесполезен. Значит, он не должен находиться в автозагрузке, даже если он нужен в единственном числе. Алсо синглтоны снижают гибкость кода, заставляя использовать в коде идентификаторы, зависящие от списка автозагрузки - я из-за этого пострадал, переписывая некоторые системы на новый лад.
>Он в реальном времени обсчитывает мысли, желания и стремления всех живых существ.
Вот это, я считаю, важная тема. Должен ли один общий менеджер обсчитывать всех агентов сразу, или у каждого агента должен быть свой логический аппарат, а менеджер должен вызывать process() каждого агента? Я считаю второе более гибким, потому что можно создать много разных агентов, и получить сложное эмерджентное поведение всей системы в целом. Особенно если ты объединяешь всех живых существ в одном менеджере.
>У менеджера ИИ тебе нужно сделать несколько "ЛОД"ов, уровней детализации мышления
Не проще ли сделать эти ЛОДы у самих агентов, и переключать их командами от менеджера ИИ/менеджера чанков?
>наследуемая от Node
Почему Node, почему не Resource/Reference? Количество Node в дереве сцены сильно ограничено (всего лишь несколько десятков тысяч) и они в таких количествах сильно нагружают одно ядро процессора, при этом у Node довольно много "лишнего" функционала. В мануале об этом даже отдельная статья есть... Именно по этой причине я постоянно вывожу на экран число активных и число скрытых из дерева нод, это важная инфа.
>Когда чанк, удаляющийся от игрока выгружается, он посылает сигнал "я выгружаюсь".
Вот этот момент не совсем ясен. Я думал о том, чтобы использовать сигналы, но не могу понять, кому их отправлять. Ведь чтобы использовать сигналы, нужно вешать обработчик сигналов. Если агенты ИИ независимо слушают сигналы от чанков, значит, кто-то должен связывать каждого агента с каждым чанком? Или лучше связывать менеджер чанков с менеджером ИИ? Сейчас у меня чанки вообще без скриптов и поэтому не могут генерировать сигналы, логично было бы генерировать сигналы с аргументами (x, y) в менеджере чанков...
Всё остальное и так очевидно. Непонятно как всё это сигналами связывать и вообще менеджить, чтобы не было лапши из ссылок. Моя тестовая версия бота оказалась совсем не подходящей из-за того, что его мозги вызываются из KinematicBody и обращаются к методам KinematicBody, а нужно что-то более абстрактное, отрезанное от KinematicBody, но при этом управляющее им, когда это возможно. Сложно это всё в голове представить (а схему чёт не додумался сделать, нужно будет попробовать начертить что-нибудь, в некоторых случаях в прошлом это мне помогало).
>>Откуда возьмётся транслейт
>Будет высчитан математически.
В смысле? Я не понимаю, что ты называешь "транслейтом" - просто вектор смещения или поле Spatial.translation?
>Причем тут вообще ГТА?
Ты разве не видел мои прыдущие видео? Дороги, домики, мафынки, на мафынках можно кататься, а можно пешком ходить. ГТА? ГТА. Что тебе ещё нужно? Оружие? Оно не главное, ГТА - это "великий автоугонщик", в ГТА главное мафынки, жители и город.
>В ГТА когда ты отворачиваешься, жители и машины исчезают
Вот именно, вот это я и хотел бы исправить, т.е. превратить бездушные декорации в полноценную симуляцию жизни, социума и всего такого. В ГТА ты смотришь на жителя города и задаёшься вопросом, а куда он идёт, что он думает и вообще в каком состоянии сейчас находится; но в ГТА это просто тупой болванчик на рельсах замкнутого маршрута, не более чем пустая декорация. Было бы круто симулировать жизнь жителей и настроить их ИИ на эффективное выживание и размножение, а оружие максимально сократить, чтобы игрок не мог истребить весь город за пять минут. Но геймплейно и графически это та же самая ГТА, просто с более глубокой закулисной работой, чем в обычной экшн-игре.
>>796123
>есть смысл пихануть в автозагрузку
Кстати, пытаюсь от автозагрузки избавиться совсем. Имхо, это неудобно, когда делаешь прототип и нужно запускать разные сцены по отдельности. Сейчас у меня, например, мини-карта вообще отключена, потому что несовместима с остальными имеющимися системами... Что будет делать, например, менеджер ИИ, когда игра загрузила главное меню? Мир игры ещё не существует, агентов размещать негде, менеджер совершенно бесполезен. Значит, он не должен находиться в автозагрузке, даже если он нужен в единственном числе. Алсо синглтоны снижают гибкость кода, заставляя использовать в коде идентификаторы, зависящие от списка автозагрузки - я из-за этого пострадал, переписывая некоторые системы на новый лад.
>Он в реальном времени обсчитывает мысли, желания и стремления всех живых существ.
Вот это, я считаю, важная тема. Должен ли один общий менеджер обсчитывать всех агентов сразу, или у каждого агента должен быть свой логический аппарат, а менеджер должен вызывать process() каждого агента? Я считаю второе более гибким, потому что можно создать много разных агентов, и получить сложное эмерджентное поведение всей системы в целом. Особенно если ты объединяешь всех живых существ в одном менеджере.
>У менеджера ИИ тебе нужно сделать несколько "ЛОД"ов, уровней детализации мышления
Не проще ли сделать эти ЛОДы у самих агентов, и переключать их командами от менеджера ИИ/менеджера чанков?
>наследуемая от Node
Почему Node, почему не Resource/Reference? Количество Node в дереве сцены сильно ограничено (всего лишь несколько десятков тысяч) и они в таких количествах сильно нагружают одно ядро процессора, при этом у Node довольно много "лишнего" функционала. В мануале об этом даже отдельная статья есть... Именно по этой причине я постоянно вывожу на экран число активных и число скрытых из дерева нод, это важная инфа.
>Когда чанк, удаляющийся от игрока выгружается, он посылает сигнал "я выгружаюсь".
Вот этот момент не совсем ясен. Я думал о том, чтобы использовать сигналы, но не могу понять, кому их отправлять. Ведь чтобы использовать сигналы, нужно вешать обработчик сигналов. Если агенты ИИ независимо слушают сигналы от чанков, значит, кто-то должен связывать каждого агента с каждым чанком? Или лучше связывать менеджер чанков с менеджером ИИ? Сейчас у меня чанки вообще без скриптов и поэтому не могут генерировать сигналы, логично было бы генерировать сигналы с аргументами (x, y) в менеджере чанков...
Всё остальное и так очевидно. Непонятно как всё это сигналами связывать и вообще менеджить, чтобы не было лапши из ссылок. Моя тестовая версия бота оказалась совсем не подходящей из-за того, что его мозги вызываются из KinematicBody и обращаются к методам KinematicBody, а нужно что-то более абстрактное, отрезанное от KinematicBody, но при этом управляющее им, когда это возможно. Сложно это всё в голове представить (а схему чёт не додумался сделать, нужно будет попробовать начертить что-нибудь, в некоторых случаях в прошлом это мне помогало).
> Что будет делать, например, менеджер ИИ, когда игра загрузила главное меню? Мир игры ещё не существует, агентов размещать негде, менеджер совершенно бесполезен.
var active : bool = false
И далее во всех критических участках кода оборачиваешь в
if active: ...
> каждого агента должен быть свой логический аппарат
А менеджер это менеджер, он управляет созданием и удалением агентов.
> Не проще ли сделать эти ЛОДы у самих агентов, и переключать их командами от менеджера ИИ/менеджера чанков?
Смотри сам по коду, как до реализации дойдёшь. Может и проще.
> Почему Node, почему не Resource/Reference?
Смотри сам, как удобнее.
> Вот этот момент не совсем ясен. Я думал о том, чтобы использовать сигналы, но не могу понять, кому их отправлять.
Сигналы это посты в треде. Вот у тебя допустим открыт годотред и ты видишь, как в нём появляются посты. Значит, ты подписан на эти сигналы. Приконнекчен. Если ты закроешь тред, мы, остальные аноны не исчезнем, мы будем всё так же постить посты, но ты их уже видеть не будешь. Вот так работают сигналы. Подробности в доках.
Единственный совет, который я хочу порекомендовать, в одном их прошлых тредов так же обсуждалось. В некоторых случаях может быть удобен синглтон для хранения своих кастомных сигналов. В его скрипте ты пишешь портянку из строк типа "signal hurr_durr", а потом в коде совершенно различных нод ты можешь и коннектить и излучать эти так сказать глобальные сигналы
> нужно что-то более абстрактное, отрезанное от KinematicBody
Ну вот попробуй на тестовом проекте, заведи четыре сцены, в одной напиши "signal hurr_durr", назови её signal_hub и запихни в автозапуск. Во второй, в ready напиши signal_hub.connect("hurr_durr", self, "foo") и сделай функцию foo конечно же, с каким нибудь принтом. И в третьей сцене в ready сделай signal_hub.emit("hurr_durr"). И сделай четвёртую сцену, которая стартует главной сценой, а в ней вторая и третья как чайдлы. Они могут быть разного типа, и не знают друг о друге, но когда третья дёргает сигнал, вторая, которая на сигнал подписана, выполнит свой метод, пристёгнутый к сигналу. Вот так можно абстрактной логикой связать совершенно разнотипные и инкапсулированные сущности. И не забудь, что сигналы ещё можно с аргументами объявлять. А коннекты можно с кастомными данными делать. Там такое широкое поле для манёвров - закачаешься!
> Что будет делать, например, менеджер ИИ, когда игра загрузила главное меню? Мир игры ещё не существует, агентов размещать негде, менеджер совершенно бесполезен.
var active : bool = false
И далее во всех критических участках кода оборачиваешь в
if active: ...
> каждого агента должен быть свой логический аппарат
А менеджер это менеджер, он управляет созданием и удалением агентов.
> Не проще ли сделать эти ЛОДы у самих агентов, и переключать их командами от менеджера ИИ/менеджера чанков?
Смотри сам по коду, как до реализации дойдёшь. Может и проще.
> Почему Node, почему не Resource/Reference?
Смотри сам, как удобнее.
> Вот этот момент не совсем ясен. Я думал о том, чтобы использовать сигналы, но не могу понять, кому их отправлять.
Сигналы это посты в треде. Вот у тебя допустим открыт годотред и ты видишь, как в нём появляются посты. Значит, ты подписан на эти сигналы. Приконнекчен. Если ты закроешь тред, мы, остальные аноны не исчезнем, мы будем всё так же постить посты, но ты их уже видеть не будешь. Вот так работают сигналы. Подробности в доках.
Единственный совет, который я хочу порекомендовать, в одном их прошлых тредов так же обсуждалось. В некоторых случаях может быть удобен синглтон для хранения своих кастомных сигналов. В его скрипте ты пишешь портянку из строк типа "signal hurr_durr", а потом в коде совершенно различных нод ты можешь и коннектить и излучать эти так сказать глобальные сигналы
> нужно что-то более абстрактное, отрезанное от KinematicBody
Ну вот попробуй на тестовом проекте, заведи четыре сцены, в одной напиши "signal hurr_durr", назови её signal_hub и запихни в автозапуск. Во второй, в ready напиши signal_hub.connect("hurr_durr", self, "foo") и сделай функцию foo конечно же, с каким нибудь принтом. И в третьей сцене в ready сделай signal_hub.emit("hurr_durr"). И сделай четвёртую сцену, которая стартует главной сценой, а в ней вторая и третья как чайдлы. Они могут быть разного типа, и не знают друг о друге, но когда третья дёргает сигнал, вторая, которая на сигнал подписана, выполнит свой метод, пристёгнутый к сигналу. Вот так можно абстрактной логикой связать совершенно разнотипные и инкапсулированные сущности. И не забудь, что сигналы ещё можно с аргументами объявлять. А коннекты можно с кастомными данными делать. Там такое широкое поле для манёвров - закачаешься!
>учесть, что есть три прохода
>сами боты до такого вряд ли додумаются.
Посмотрел на один проход - толпа ботов. Посмотрел на второй проход - тоже толпа ботов. Посмотрел на третий проход - почти никого. Пошёл в третий проход, потому что там свободнее движение. В самом упрощённом варианте можно "отталкивать" бота от его собратьев, тогда они просто не смогут создать плотную толпу где-либо, и будут вынуждены выбирать соседние проходы, чтобы избежать сближения, но при этом добраться до цели.
На пикриле 150 полностью независимых ботов, у каждого всего два шаблона поведения: приближаться к игроку по прямой и отдаляться от любого другого бота, который попал в Area-датчик (тоже по прямой). В результате боты не просто не создают скопления, но и обходят игрока с разных сторон, уступая друг другу место, в конечном итоге игрок должен оказаться в середине толпы (без шаблона избегания создавалась длинная очередь к игроку). Крупные препятствия эти боты будут обходить с разных сторон, разделяясь на две группы и затем объединяясь вновь (я сам это видел, круто выглядит). И всё это без какого-либо общего контроля, без планирования - это эмерджентность, когда простые элементы создают сложную систему. В этом суть любой симуляции, а не в том, чтобы заранее спланировать всё от и до. Зачем вообще "симуляция", если все будут ходить по рельсам, которые проложил один общий для всех менеджер всего?
>>796138
>раз ты делаешь совсем другое
У нас с тобой просто разное понимание жанра. Главное в жанре - базовый геймплей (то, что игрок делает бОльшую часть времени). В ГТА игрок полностью управляет одним персонажем как собственным телом, а над всеми остальными жителями прямой власти не имеет. В Симс игрок может управлять множеством персонажей, которые при этом живут сами по себе и могут обходиться без участия игрока, но напрямую подчиняются ему. Сеттинг у этих игр примерно похож - современный город, но из-за разного базового геймплея это совершенно разные игры. Однако, если перенести неигровых симсов из Симс в ГТА, оставив игрового героя ГТА без изменений, ГТА останется ГТА, она не превратится в Симс, потому что с точки зрения игрока геймплей игры останется от ГТА. Короче, я хочу прикрутить "симуляцию жизни" (элемент игрового мира) к геймплею ГТА, а не "шутер" и "гонки" (геймплейные возможности) к геймплею Симс, так понятнее?
Должен сказать спасибо, ты заставил меня серьёзно подумать на эту тему, три раза переписывал предыдущий абзац. Я и сам начал сомневаться в плане жанровой принадлежности того, что я хочу сделать, лол. Но нет, на базовом уровне это всё-таки ГТА (должна быть, во всяком случае, а там посмотрим, я уже думал над тем, чтобы реализовать опциональное непрямое управление кликами мыши - а что, у ботов в любом случае будет поиск пути и "автопилот", так почему у игрока его быть не должно?).
>>796137
>var active : bool = false
Ага, а потом игра грузит главное меню дольше запуска "новой игры". Если чего-то не должно быть в главном меню - оно не должно быть в списке автозагрузки, потому что так главное меню загрузится быстрее. Вообще, я считаю, в автозагрузке должны быть только максимально общие вещи, например, счётчик кадров, консоль/журнал (как на движке Source), какой-то обобщённый загрузчик ресурсов (но, как я понял из мануала, в Годо уже встроен загрузчик, умеющий в кэширование, так что изобретать велосипед не нужно). Всё остальное должно быть локальным в сцене, даже если эта сцена будет 99% времени игры и содержать всего один экземпляр чего-то.
>Сигналы это посты в треде.
Да это я понимаю, я не понимаю, как связать бота с чанком, чтобы потом не мучиться потерянными ссылками и т.п. И особенно - лишними вызовами/условиями ветвления и т.д. Когда последний раз тестировал, у меня была огромная просадка производительности, внезапно, на методе KinematicBody._physics_process(), и, несмотря на все оптимизации этого метода (закомментировал всё, что можно было), просадка осталась до сих пор, больше 150 тупых ботов = падение ФПС до неиграбельного состояния. Даже сократил им частоту тиков, всё равно почему-то дикая просадка именно на этом методе. Короче, если я хочу сохранить масштабируемость, нужны... преждевременные оптимизации, лол.
>учесть, что есть три прохода
>сами боты до такого вряд ли додумаются.
Посмотрел на один проход - толпа ботов. Посмотрел на второй проход - тоже толпа ботов. Посмотрел на третий проход - почти никого. Пошёл в третий проход, потому что там свободнее движение. В самом упрощённом варианте можно "отталкивать" бота от его собратьев, тогда они просто не смогут создать плотную толпу где-либо, и будут вынуждены выбирать соседние проходы, чтобы избежать сближения, но при этом добраться до цели.
На пикриле 150 полностью независимых ботов, у каждого всего два шаблона поведения: приближаться к игроку по прямой и отдаляться от любого другого бота, который попал в Area-датчик (тоже по прямой). В результате боты не просто не создают скопления, но и обходят игрока с разных сторон, уступая друг другу место, в конечном итоге игрок должен оказаться в середине толпы (без шаблона избегания создавалась длинная очередь к игроку). Крупные препятствия эти боты будут обходить с разных сторон, разделяясь на две группы и затем объединяясь вновь (я сам это видел, круто выглядит). И всё это без какого-либо общего контроля, без планирования - это эмерджентность, когда простые элементы создают сложную систему. В этом суть любой симуляции, а не в том, чтобы заранее спланировать всё от и до. Зачем вообще "симуляция", если все будут ходить по рельсам, которые проложил один общий для всех менеджер всего?
>>796138
>раз ты делаешь совсем другое
У нас с тобой просто разное понимание жанра. Главное в жанре - базовый геймплей (то, что игрок делает бОльшую часть времени). В ГТА игрок полностью управляет одним персонажем как собственным телом, а над всеми остальными жителями прямой власти не имеет. В Симс игрок может управлять множеством персонажей, которые при этом живут сами по себе и могут обходиться без участия игрока, но напрямую подчиняются ему. Сеттинг у этих игр примерно похож - современный город, но из-за разного базового геймплея это совершенно разные игры. Однако, если перенести неигровых симсов из Симс в ГТА, оставив игрового героя ГТА без изменений, ГТА останется ГТА, она не превратится в Симс, потому что с точки зрения игрока геймплей игры останется от ГТА. Короче, я хочу прикрутить "симуляцию жизни" (элемент игрового мира) к геймплею ГТА, а не "шутер" и "гонки" (геймплейные возможности) к геймплею Симс, так понятнее?
Должен сказать спасибо, ты заставил меня серьёзно подумать на эту тему, три раза переписывал предыдущий абзац. Я и сам начал сомневаться в плане жанровой принадлежности того, что я хочу сделать, лол. Но нет, на базовом уровне это всё-таки ГТА (должна быть, во всяком случае, а там посмотрим, я уже думал над тем, чтобы реализовать опциональное непрямое управление кликами мыши - а что, у ботов в любом случае будет поиск пути и "автопилот", так почему у игрока его быть не должно?).
>>796137
>var active : bool = false
Ага, а потом игра грузит главное меню дольше запуска "новой игры". Если чего-то не должно быть в главном меню - оно не должно быть в списке автозагрузки, потому что так главное меню загрузится быстрее. Вообще, я считаю, в автозагрузке должны быть только максимально общие вещи, например, счётчик кадров, консоль/журнал (как на движке Source), какой-то обобщённый загрузчик ресурсов (но, как я понял из мануала, в Годо уже встроен загрузчик, умеющий в кэширование, так что изобретать велосипед не нужно). Всё остальное должно быть локальным в сцене, даже если эта сцена будет 99% времени игры и содержать всего один экземпляр чего-то.
>Сигналы это посты в треде.
Да это я понимаю, я не понимаю, как связать бота с чанком, чтобы потом не мучиться потерянными ссылками и т.п. И особенно - лишними вызовами/условиями ветвления и т.д. Когда последний раз тестировал, у меня была огромная просадка производительности, внезапно, на методе KinematicBody._physics_process(), и, несмотря на все оптимизации этого метода (закомментировал всё, что можно было), просадка осталась до сих пор, больше 150 тупых ботов = падение ФПС до неиграбельного состояния. Даже сократил им частоту тиков, всё равно почему-то дикая просадка именно на этом методе. Короче, если я хочу сохранить масштабируемость, нужны... преждевременные оптимизации, лол.
>KinematicBody._physics_process()
А, не совсем так. Просадка была на методе Human._physics_process(), Human наследник KinematicBody и из тяжёлого кода там только обращение к move_and_slide(). При этом логика ИИ вызывается в Citizen._physics_process() (наследник Human), но не каждый тик, а с интервалом. Но профайлер показывал задержку в сотни миллисекунд именно в Human, а не в Citizen, и это очень странно. Особенно странно что самая большая просадка была, когда множество KinematicBody сталкивались. Не, я понимаю, move_and_slide() делает сразу несколько проверок на столкновения, но что же это получается, я не могу иметь больше 100-150 KinematicBody? Чё так мало-то...
А впрочем, пофиг, я полагаю, больше 100 KinematicBody мне не будет нужно, если правильно настроить чанковую систему. Просто не удастся симулировать толпу и дорожные заторы... Не понимаю, почему у меня даже 150 ботов на экране выглядят так мало, а в той же ГТА всего пара десятков человек - уже плотная толпа. В чём прикол? Я не умею считать на глаз?
> Если чего-то не должно быть в главном меню - оно не должно быть в списке автозагрузки, потому что так главное меню загрузится быстрее. Вообще, я считаю, в автозагрузке должны быть только максимально общие вещи
Окей, тогда вот тебе такая идея. Закидываешь в автозагрузку единственный синглтон, с названием, например Global или Game.
В его скрипте заводишь переменные под будущие менеджеры и системы. При запуске игры переменные пусты, ничего нет. При старте или загрузке, всё заполняется ссылками на актуальные объекты.
По оптимизации физики увы подсказать не могу, сам ещё не разобрался до конца.
>единственный синглтон, с названием, например Global
>заводишь переменные под будущие менеджеры
З А Ч Е М
А
Ч
Е
М
Что ты к этим "синглтонам" прицепился, из-за названия? Дерево сцены в .tscn так-то тоже из объектов состоит, и если какой-то объект является неизменным родителем других объектов - он, фактически, синглтон. Просто обращаешься к нему как к get_parent(). Хочешь понятное имя - заводишь локальную переменную. И даже не обязательно чтобы он был родителем, можно экспортировать ссылки на ноды и затем соединять ноды через инспектор. Преимущество в том, что не нужно лезть в меню автозагрузки и что-то менять. Если у тебя есть две разных сцены с разными конфигурациями из разных синглтонов, тебе не нужно ничего менять в автозагрузке, ты просто запускаешь две разные сцены. Автозагрузка - для самых-самых глобальных, вот прям наиглобальнейших вещей, которые нужны тебе с самого клика по ярылку игры на рабочем столе игрока, а не когда он решит начать новую игру или загрузить сохранённую. Да, это сложно понять, я считаю, надписи в окошках Годо путают, слово "синглтон" в особенности. Нужно понимать, что ООП синглтон не обязан называться синглтоном в каком-то средстве разработки, это просто договорённость с самим собой (и другими программистами) не создавать более одного экземпляра какого-то класса. Просто некоторые языки поддерживают синглтоны на уровне синтаксиса, чтобы тупые быдлокодеры реже стреляли себе в ногу, создавая несколько синглтонов, но мы-то не тупые быдлокодеры, правда?
Есть ещё трюк, который я как-то проворачивал. Можно вообще обойтись без добавления нод в автозагрузку. При запуске некоторой начальной сцены, она загружает специальный скрипт прямо в главный цикл, SceneTree.
> get_tree().set_deferred("script", preload("res://твой_скрипт_наследующийся_от_SceneTree.gd"))
Он прекрасно грузится и работает, правда там нет колбэков процесс, но там они и не нужны. Обращаешься к нему из любого участка кода при помощи get_tree().
При запуске через F6 соответственно этого не происходит и можно отлаживать определенную сцену не отвлекаясь на настройку игровой логики.
Есть ещё более мощный трюк, но тоже на любителя. Можно через хардлинки в файловой системе подключить папку со сценами к разным проектам. Один проект финишный, в котором грузится вся игра в том виде, в котором её увидят игроки, а второй проект девелоперский, в нём всё то же самое грузится в режиме моддинга, без менюшек, без автозапусков и т.п.
Встряну в вашу великосветскую беседу.
Синглтон в Годо - не более чем ещё одна нода, в дереве расположенная как дочерняя к SceneTree. В качестве таких синглтонов можно использовать целые сцены, кстати, а не только отдельные скрипты (если кто не знал).
Важные особенности:
1. Доступ одним словом, БЕЗ заведения дополнительных переменных.
2. Один экземпляр на весь проект.
3. Синглтон не меняется даже после смены сцены, так как находится с ней на одном уровне.
4. Синглтон-ноды всегда расположены выше, чем current_scene.
В остальном это точно такие же ноды, к которым просто удобно обращаться без лишних строчек кода.
И не надо тут разводить ООП-философии. Гдскрипт - скриптовый язык. Ему глубоко наплевать, синлтон у тебя или нет. Кодишь как тебе удобно, чтобы читалось хорошо. В памяти это всё одинаковые ноды.
>get_tree().set_deferred("script", preload("res://твой_скрипт_наследующийся_от_SceneTree.gd"))
Бесполезный грязный хак с непредсказуемыми последствиями в будущем, зачем это нужно? Я серьёзно. Тебе дали графический редактор - описывай свои сцены декларативно, нет, не хочу декларативно, хочу вкорячивать свои скриптики туда куда не надо императивным кодом. Что мешает сделать общую для всех ноду Game и назначить ей скрипт через редактор?
>через хардлинки в файловой системе подключить папку со сценами к разным проектам
К сожалению, жёсткие ссылки в Windows никак не обозначаются в Проводнике, да и создавать их можно только через консоль. Не знаю как в Linux, возможно, проще. В общем, сложно это использовать, последствия забывания "где что" непредсказуемы. Лучше бы Godot поддерживал подключение "библиотек с ассетами" из отдельных от папки проекта папок, но насколько я знаю (читал на гитхабе), в официальной ветке этого никогда не будет из-за каких-то теоретических проблем (типа это может повлечь какие-то ошибки в проектах).
>>796175
>это просто договорённость с самим собой
У любой договорённости есть причины, о которых я и спросил.
>>796182
>Синглтон в Годо - не более чем ещё одна нода, в дереве расположенная как дочерняя к SceneTree.
Да, это можно заметить, запустив проект и посмотрев удалённую сцену. Ну а что ещё можно было ожидать.
>удобно обращаться без лишних строчек кода
А потом искать баги...
>Важные особенности:
5. Невозможно настроить экспортируемые переменные. Т.е. если ты добавляешь в автозагрузку целую сцену, экспортированные переменные должны быть настроены в самой сцене. Другими словами, никакого тебе инспектора с кастомизацией полей. Если ты добавляешь в автозагрузку не сцену, а отдельный скрипт, то вообще забудь ключевое слово "export", лол.
6. Из-за предыдущего пункта невозможно связать автоматически загруженную сцену/скрипт ссылками с другими сценами. Придётся вручную обращаться к ней и передавать ссылки на объекты, которые ей нужны для работы. Короче, придётся забыть о декларативности. С другой стороны это логично, т.к. автозагружаемые сцены/скрипты могут загружаться с произвольным набором сцен и поэтому связывать их просто не с чем. Но если у тебя вся игра в одной "комнате" (опенворлд) и переключения сцен движком не нужно, стоит ли тогда вообще использовать автозагрузку? Наверное, автозагрузка полезна только для игр, разделённых на уровни...
>ООП-философии. Гдскрипт - скриптовый язык
ООП не зависит от реализации ЯП. ООП можно использовать на любом языке программирования, просто некоторые языки имеют специальный синтаксис для этого (GDScript имеет, но сильно ограниченный, к сожалению; мне бы очень хотелось ключевые слова как минимум для приватных и публичных членов класса, и соответствующий контроль доступа со стороны интерпретатора).
>Кодишь как тебе удобно, чтобы читалось хорошо.
Проблема в том, что многие проблемные способы кодить удобны на ближней дистанции, но создают серьёзные проблемы в будущем. Простой пример: удобно создавать однобуквенные переменные, и поэтому многие страдают этим, особенно новички, но общеизвестно, что так делать очень плохо в любом проекте больше "hello world", поскольку если большинство людей очень быстро забудет предназначение таких переменных, а посторонним будет ещё тяжелее разобраться. Так что "как тебе удобно" кодить нельзя, нужно кодить так, чтобы потом не тратить кучу времени на исправление проблем, которых можно было избежать. ООП, другие парадигмы и всё остальное с этой целью и разрабатывали, чтобы писали код как положено, а не как "удобно".
>get_tree().set_deferred("script", preload("res://твой_скрипт_наследующийся_от_SceneTree.gd"))
Бесполезный грязный хак с непредсказуемыми последствиями в будущем, зачем это нужно? Я серьёзно. Тебе дали графический редактор - описывай свои сцены декларативно, нет, не хочу декларативно, хочу вкорячивать свои скриптики туда куда не надо императивным кодом. Что мешает сделать общую для всех ноду Game и назначить ей скрипт через редактор?
>через хардлинки в файловой системе подключить папку со сценами к разным проектам
К сожалению, жёсткие ссылки в Windows никак не обозначаются в Проводнике, да и создавать их можно только через консоль. Не знаю как в Linux, возможно, проще. В общем, сложно это использовать, последствия забывания "где что" непредсказуемы. Лучше бы Godot поддерживал подключение "библиотек с ассетами" из отдельных от папки проекта папок, но насколько я знаю (читал на гитхабе), в официальной ветке этого никогда не будет из-за каких-то теоретических проблем (типа это может повлечь какие-то ошибки в проектах).
>>796175
>это просто договорённость с самим собой
У любой договорённости есть причины, о которых я и спросил.
>>796182
>Синглтон в Годо - не более чем ещё одна нода, в дереве расположенная как дочерняя к SceneTree.
Да, это можно заметить, запустив проект и посмотрев удалённую сцену. Ну а что ещё можно было ожидать.
>удобно обращаться без лишних строчек кода
А потом искать баги...
>Важные особенности:
5. Невозможно настроить экспортируемые переменные. Т.е. если ты добавляешь в автозагрузку целую сцену, экспортированные переменные должны быть настроены в самой сцене. Другими словами, никакого тебе инспектора с кастомизацией полей. Если ты добавляешь в автозагрузку не сцену, а отдельный скрипт, то вообще забудь ключевое слово "export", лол.
6. Из-за предыдущего пункта невозможно связать автоматически загруженную сцену/скрипт ссылками с другими сценами. Придётся вручную обращаться к ней и передавать ссылки на объекты, которые ей нужны для работы. Короче, придётся забыть о декларативности. С другой стороны это логично, т.к. автозагружаемые сцены/скрипты могут загружаться с произвольным набором сцен и поэтому связывать их просто не с чем. Но если у тебя вся игра в одной "комнате" (опенворлд) и переключения сцен движком не нужно, стоит ли тогда вообще использовать автозагрузку? Наверное, автозагрузка полезна только для игр, разделённых на уровни...
>ООП-философии. Гдскрипт - скриптовый язык
ООП не зависит от реализации ЯП. ООП можно использовать на любом языке программирования, просто некоторые языки имеют специальный синтаксис для этого (GDScript имеет, но сильно ограниченный, к сожалению; мне бы очень хотелось ключевые слова как минимум для приватных и публичных членов класса, и соответствующий контроль доступа со стороны интерпретатора).
>Кодишь как тебе удобно, чтобы читалось хорошо.
Проблема в том, что многие проблемные способы кодить удобны на ближней дистанции, но создают серьёзные проблемы в будущем. Простой пример: удобно создавать однобуквенные переменные, и поэтому многие страдают этим, особенно новички, но общеизвестно, что так делать очень плохо в любом проекте больше "hello world", поскольку если большинство людей очень быстро забудет предназначение таких переменных, а посторонним будет ещё тяжелее разобраться. Так что "как тебе удобно" кодить нельзя, нужно кодить так, чтобы потом не тратить кучу времени на исправление проблем, которых можно было избежать. ООП, другие парадигмы и всё остальное с этой целью и разрабатывали, чтобы писали код как положено, а не как "удобно".
> Бесполезный грязный хак с непредсказуемыми последствиями в будущем, зачем это нужно? Я серьёзно.
Чтобы все охуели, как я могу. Вот ты охуел. Уже радость.
> К сожалению, жёсткие ссылки в Windows никак не обозначаются в Проводнике, да и создавать их можно только через консоль.
HardLinkShell - рикаминдую.
> Не знаю как в Linux, возможно, проще.
Просто и естественно одной кнопкой, без мокрописечек типа HardLinkShell. Да.
>- WorldEnvironment и система времени (синглтон)
>- HUD с мини-картой мира (синглтон)
Сегодня выкинул это из автозагрузки (теперь там нет ничего), пришлось исправить код в куче мест и создать кучу ссылок, но теперь вроде логичнее выглядит. Пора попробовать сделать меню паузы и главное меню, начало новой игры и базовое сохранение/загрузку - а то что-то я тестирую разные отдельные фичи, а каркаса будущей игры у меня до сих пор нет. Ещё бы сенсорное управление прикрутить и на смартфоне протестировать (хотя бы чанковую систему, как по нагрузке будет), но как-то лень...
Алсо разделил HUD на части, думаю теперь разделить систему времени и WorldEnvironment, а то странно как-то выглядит. Изначально нужно было делать всё более независимым...
Вот ведь, уже забыл что собирался ботов делать. Просто проснулся с мыслью что нужно просто взять и начать что-нибудь делать. Хотел было меню паузы сделать, но начал с удаления автозагрузки, потом отвлёкся и вот уже день закончился... Как же хочется свою собственную игру, чтобы просто сидеть и играть в неё по 12 часов без перерыва, разве я многого хочу?
>Невозможно настроить экспортируемые переменные.
Но зачем это объекту, который всё равно будет представлен в единственном числе?
Вот у меня в игре сейчас есть:
1. Менеджер игровых сессий
2. Менеджер уровней
3. Менеджер игроков
4. Менеджер инвентаря
5. Менеждер музыки
6. Менеджер инпута
7. Фоновый загрузчик ресурсов
8. Интерфейс
9. Константы с предзагрузками
10. Всякая глобальная мелочь, не попавшая в предыдущие менеджеры.
И всё это синглтоны. Не синглтон - только уровень.
Почему так? Ну, сначала у меня не было синглтона, и я завёл некий корень всей сцены, к которому обращались все кому не лень. В какой-то момент стало бесить постоянное get_tree().current_scene, я создал один глобальный скрипт с коротким обращением g. А дальше начал заводить все эти менеджеры, и каждый из них начинался с
func _ready():
g.some_manager = self
Шапка глобального скрипта пухла, регулярно что-то отказывалось обращаться к чему-то в g, потому что оно там ещё не самоприсвоилось, постоянное реади с единственной строчкой тоже мозолило глаз. Но самое главное - к таким скриптам не было автодополнения. То есть, допустим, у меня есть в скрипте функция, я в каком-то другом скрипте пишу: g.some_manager.some_func() - я во-первых не узнаю, не опечатался ли я где в названии функции, а во-вторых рискую в рандомный момент получить ошибку, так как менеджер ещё не загрузился, а его уже вызывают.
Ну так вот. Нигде в этих менеджерах у меня нет экспортируемых данных. И я вообще не вижу смысла их экспортировать. И тем более хранить какие-то ссылки. Да, допустим, менеджер игрока создал игрока и хранит на него ссылку; кому надо ссылку на игрока, пусть обращается к менеджеру через функцию. Экспорт тут зачем? Чтобы что?
>А потом искать баги
Вообще не к месту тут это. Дебагать проще, когда есть автодополнение, и дебагер знает, что в этом скрипте есть только такие идентификаторы, никаких других нет.
Чтобы было автодополнение, в язык ввели регистрацию имён классов через class_name и типизацию переменных в общем-то.
Скрипт менеджера начинается с class_name MyAwesomeManager, а в глобальном скрипте создаётся переменная var my_awesome_manager : MyAwesomeManager и вуаля - у тебя работает автодополнение.
>В какой-то момент стало бесить постоянное get_tree().current_scene
А зачем получать дерево? Делаешь так:
>export var something_path: NodePath
>onready var _something: Something = get_node(something_path)
И вуаля, у тебя есть именованный доступ к какой-то части проекта, и ты при этом с самого заголовка скрипта знаешь о том, что этому скрипту требуется для работы. Даже более того, ты знаешь об этом ещё из инспектора нод, не открывая сам скрипт. А все эти обращения к синглтонам - скрытые зависимости, о которых ты узнаёшь лишь когда решаешь что-то изменить в синглтоне или удалить его. Плохо, очень плохо. В нормальных языках, например, на Паскале, ты обязан объявлять используемые модули:
>unit MyUnit;
>uses MyOtherUnit, SysUtils, Classes, MyAwesomeSingleton;
И ты сразу с первых строчек видишь, что конкретному модулю (ака скрипту) нужен для работы такой-то синглтон. А в GDScript нет такого, ты можешь написать несколько тысяч строк в одном скрипте, и попробуй потом разберись, что этому скрипту нужно.
>Экспорт тут зачем? Чтобы что?
Чтобы по-быстрому менять параметры проекта в процессе работы над прототипом или изменения баланса в уже оформившейся игре. Чтобы не бегать по коду и не менять константы в самом коде (рискуя что-нибудь сломать из-за невнимательности), а извне, через инспектор подвигать ползунки и получить новый результат. К примеру, синглтон "менеджер инвентаря" может экспортить размер инвентаря в ячейках или размер стандартной стопки предметов, чтобы можно было по-быстрому менять баланс между "ходишь с целой горой кирпичей в кармане" и "бегаешь за спичками, потому что не можешь унести больше одной за раз".
Вот только инвентарь не должен быть синглтоном. Что, если ты захочешь сделать мультиплеер на 2+ игрока? Что, если тебе понадобится сделать инвентарь у некоторых неигровых персонажей (такое есть во многих играх)? И почему вообще инвентарь отделён от игрового актёра, которому он принадлежит? Или ты подразумеваешь элемент графического интерфейса, отображающий квадратики ячеек и предметы в них? И т.д. Таким образом можно по любому "синглтону" пройтись и выявить его уязвимости.
Вообще, напоминаю, что синглтон - глобальный объект, а глобальных объектов принято избегать, поэтому синглтонов должно быть как можно меньше, как и других глобальных сущностей.
https://ru.wikipedia.org/wiki/Одиночка_(шаблон_проектирования)
>Плюсы:
>контролируемый доступ к единственному экземпляру.
>Минусы:
>глобальные объекты могут быть вредны для объектного программирования, в некоторых случаях приводят к созданию немасштабируемого проекта;
>усложняет написание модульных тестов и следование TDD;
>усложняется контроль за межпоточными гонками и задержками.
Ну тут без комментариев, лол.
>В какой-то момент стало бесить постоянное get_tree().current_scene
А зачем получать дерево? Делаешь так:
>export var something_path: NodePath
>onready var _something: Something = get_node(something_path)
И вуаля, у тебя есть именованный доступ к какой-то части проекта, и ты при этом с самого заголовка скрипта знаешь о том, что этому скрипту требуется для работы. Даже более того, ты знаешь об этом ещё из инспектора нод, не открывая сам скрипт. А все эти обращения к синглтонам - скрытые зависимости, о которых ты узнаёшь лишь когда решаешь что-то изменить в синглтоне или удалить его. Плохо, очень плохо. В нормальных языках, например, на Паскале, ты обязан объявлять используемые модули:
>unit MyUnit;
>uses MyOtherUnit, SysUtils, Classes, MyAwesomeSingleton;
И ты сразу с первых строчек видишь, что конкретному модулю (ака скрипту) нужен для работы такой-то синглтон. А в GDScript нет такого, ты можешь написать несколько тысяч строк в одном скрипте, и попробуй потом разберись, что этому скрипту нужно.
>Экспорт тут зачем? Чтобы что?
Чтобы по-быстрому менять параметры проекта в процессе работы над прототипом или изменения баланса в уже оформившейся игре. Чтобы не бегать по коду и не менять константы в самом коде (рискуя что-нибудь сломать из-за невнимательности), а извне, через инспектор подвигать ползунки и получить новый результат. К примеру, синглтон "менеджер инвентаря" может экспортить размер инвентаря в ячейках или размер стандартной стопки предметов, чтобы можно было по-быстрому менять баланс между "ходишь с целой горой кирпичей в кармане" и "бегаешь за спичками, потому что не можешь унести больше одной за раз".
Вот только инвентарь не должен быть синглтоном. Что, если ты захочешь сделать мультиплеер на 2+ игрока? Что, если тебе понадобится сделать инвентарь у некоторых неигровых персонажей (такое есть во многих играх)? И почему вообще инвентарь отделён от игрового актёра, которому он принадлежит? Или ты подразумеваешь элемент графического интерфейса, отображающий квадратики ячеек и предметы в них? И т.д. Таким образом можно по любому "синглтону" пройтись и выявить его уязвимости.
Вообще, напоминаю, что синглтон - глобальный объект, а глобальных объектов принято избегать, поэтому синглтонов должно быть как можно меньше, как и других глобальных сущностей.
https://ru.wikipedia.org/wiki/Одиночка_(шаблон_проектирования)
>Плюсы:
>контролируемый доступ к единственному экземпляру.
>Минусы:
>глобальные объекты могут быть вредны для объектного программирования, в некоторых случаях приводят к созданию немасштабируемого проекта;
>усложняет написание модульных тестов и следование TDD;
>усложняется контроль за межпоточными гонками и задержками.
Ну тут без комментариев, лол.
Слушайте этого анона. Он шарит.
>Чтобы было автодополнение, в язык ввели регистрацию имён классов через class_name
Да, но нет. Этот механизм удобно использовать, когда у тебя есть (или планируется) много экземпляров класса. В ином случае начинается нагромождение.
>>796337
>скрытые зависимости
А как насчёт - "все зависят от синглтона, синглтон не зависит ни от кого" - ? Он же один единственный.
>И ты сразу с первых строчек видишь, что конкретному модулю (ака скрипту) нужен для работы такой-то синглтон.
Вот кстати да. Если я где-то в скрипте написал var foo: MyClass, то скрипт начинает автоматически зависеть от MyClass, что бесит. Гораздо удобнее было бы прописывать все зависимости в заголовке. Но на маленьких проектах-прототипах такой подход ускоряет написание кода.
>И вуаля, у тебя есть именованный доступ к какой-то части проекта, и ты при этом с самого заголовка скрипта знаешь о том, что этому скрипту требуется для работы
Таким образом твой скрипт увеличился на две строчки, а с синглтоном их нет. И он будет криво работать а) в самом начале, пока не всё проинициализировалось, б) если запустить сцену отдельно.
>Вот только инвентарь не должен быть синглтоном
В моём случае это не инвентарь, а скорее менеджер способностей, сменного оружия и всяких прочих штук, которые принципиально могут быть только у игрока.
>Чтобы не бегать по коду и не менять константы в самом коде (рискуя что-нибудь сломать из-за невнимательности)
Ну чёрт знает, я обычно всё объявляю в самом верху, а не раскидываю по коду. Сначала константы одним блоком, потом переменные другим блоком, красивенько их разделяю комментариями, всё подписываю и обязательно типизирую.
Ну ладно, а в чём проблема создать сцену из одной ноды, прописать ей все экспорты, и эту сцену (не скрипт) использовать как синглтон? Я так не делаю (потому что все константы держу в отдельном файле, например), но должно же работать, не?
>Вообще, напоминаю, что синглтон - глобальный объект, а глобальных объектов принято избегать, поэтому синглтонов должно быть как можно меньше, как и других глобальных сущностей.
Мне кажется, ты не столько синглтоны ругаешь, сколько методы их использования. На мой взгляд, в Годо нет принципиальной разницы между синглтоном и любой другой нодой, кроме простого доступа и постоянного висения в дереве. Любая нода в Годо - глобальный объект, к которому можно обратиться без ограничений из любого места в проекте, что-нибудь с ним сделать (вплоть до того, чтобы подсунуть исполняемый код вместо скрипта), так что надо просто смириться с этим свойством и писать код так, будто все глобальные объекты не глобальны.
>Чтобы было автодополнение, в язык ввели регистрацию имён классов через class_name
Да, но нет. Этот механизм удобно использовать, когда у тебя есть (или планируется) много экземпляров класса. В ином случае начинается нагромождение.
>>796337
>скрытые зависимости
А как насчёт - "все зависят от синглтона, синглтон не зависит ни от кого" - ? Он же один единственный.
>И ты сразу с первых строчек видишь, что конкретному модулю (ака скрипту) нужен для работы такой-то синглтон.
Вот кстати да. Если я где-то в скрипте написал var foo: MyClass, то скрипт начинает автоматически зависеть от MyClass, что бесит. Гораздо удобнее было бы прописывать все зависимости в заголовке. Но на маленьких проектах-прототипах такой подход ускоряет написание кода.
>И вуаля, у тебя есть именованный доступ к какой-то части проекта, и ты при этом с самого заголовка скрипта знаешь о том, что этому скрипту требуется для работы
Таким образом твой скрипт увеличился на две строчки, а с синглтоном их нет. И он будет криво работать а) в самом начале, пока не всё проинициализировалось, б) если запустить сцену отдельно.
>Вот только инвентарь не должен быть синглтоном
В моём случае это не инвентарь, а скорее менеджер способностей, сменного оружия и всяких прочих штук, которые принципиально могут быть только у игрока.
>Чтобы не бегать по коду и не менять константы в самом коде (рискуя что-нибудь сломать из-за невнимательности)
Ну чёрт знает, я обычно всё объявляю в самом верху, а не раскидываю по коду. Сначала константы одним блоком, потом переменные другим блоком, красивенько их разделяю комментариями, всё подписываю и обязательно типизирую.
Ну ладно, а в чём проблема создать сцену из одной ноды, прописать ей все экспорты, и эту сцену (не скрипт) использовать как синглтон? Я так не делаю (потому что все константы держу в отдельном файле, например), но должно же работать, не?
>Вообще, напоминаю, что синглтон - глобальный объект, а глобальных объектов принято избегать, поэтому синглтонов должно быть как можно меньше, как и других глобальных сущностей.
Мне кажется, ты не столько синглтоны ругаешь, сколько методы их использования. На мой взгляд, в Годо нет принципиальной разницы между синглтоном и любой другой нодой, кроме простого доступа и постоянного висения в дереве. Любая нода в Годо - глобальный объект, к которому можно обратиться без ограничений из любого места в проекте, что-нибудь с ним сделать (вплоть до того, чтобы подсунуть исполняемый код вместо скрипта), так что надо просто смириться с этим свойством и писать код так, будто все глобальные объекты не глобальны.
> Мне кажется, ты не столько синглтоны ругаешь, сколько методы их использования. На мой взгляд, в Годо нет принципиальной разницы между синглтоном и любой другой нодой, кроме простого доступа и постоянного висения в дереве.
Вот кстати, недооценённый момент, который указывался ранее мимоходом и никто не обратил внимания. В выполняющемся проекте существует только один синглтон - дерево. Если разраб твёрдо знает, где у него в дереве что находится, он может просто получать один раз (или каждый раз по надобности) нужную ноду дерева по её пути get_node("/root/абсолютный/путь/до/ноды")
>get_node("/root/абсолютный/путь/до/ноды")
По-моему, даже в официальном руководстве было сказано, что использовать абсолютные пути - плохо. Даже get_parent() использовать не очень хорошо. Суть в том, что любая нода должна владеть только своими собственными потомками, знать она должна только о них, и обращаться напрямую ($Потомок) только к ним. Потому что расположение всех остальных нод в процессе работы над проектом может много раз меняться, да и в рантайме тоже могут потребоваться перемещения нод, и если нода пытается обращаться к предку или по абсолютному пути (не по ссылке, а через get_node()), она может обнаружить не то, что ожидает, и не факт, что проект остановится с ошибкой - ищи потом, почему у тебя игра работает, но как-то неправильно. Таким образом, все восходящие связи (потомок - родитель) должны быть через сигналы (кому надо - поймает, кому не надо - не будет реагировать), а вместо абсолютных путей в коде - настройка полей через инспектор:
>export var node_path: NodePath
>onready var node: Node = get_node(node_path)
Такая связь явно видна в инспекторе, в случае нарушения будет легко обнаружена дебаггером (если нода не найдена изначально или была освобождена раньше времени), и обращаемся мы здесь по ссылке, а не по пути в дереве, т.е. нода может свободно перемещаться в рантайме, даже совсем выходить из дерева (а в редакторе NodePath автоматически обновляется).
Почему GDScript разрешает делать то, что делать не рекомендуется? Потому что иногда это может очень сильно потребоваться, очевидно. Прямо как... костыли. Зачем ходить на костылях, если нет препятствий ходить как все здоровые люди? Нельзя привыкать ходить на костылях, а то потом проблемы будут.
>>796341
>В ином случае начинается нагромождение.
Тебе шашечки или ехать? Во всех нормальных языках у каждого класса должно быть имя, по которому к нему можно обращаться. GDScript разрешает не задавать имя класса, потому что это намного удобнее для новичков. Но без имени класса Godot не может знать, что именно ты пытаешься написать, и поэтому не может ничего подсказать. Сам подумай, ты объявил переменную типа Node, откуда Godot может узнать, что ты имеешь в виду безымянный класс из inventory_manager.gd? Без выполнения всего набора скриптов (на компьютере или мысленно) в данном случае нельзя узнать, что именно будет содержаться в этой переменной.
А нагромождение возникает из-за того, что в GDScript нет областей видимости, тех самых uses UnitName или чего-то похожего. Плохо, конечно. Но области видимости настраивать тоже сложно для новичков, видимо поэтому их и нет в GDScript. Зато порог входа очень низкий, сел и уже делаешь игру мечты.
>все зависят от синглтона
С какой это стати? Т.е. получается, что я должен ВСЕ скрипты проекта вручную просмотреть и по необходимости исправить, если захочу изменить один синглтон? А изменить синглтон когда-нибудь придётся, особенно если проект на ранних стадиях разработки.
>синглтон не зависит ни от кого
Опять странное утверждение, почему это синглтон не может от кого-то зависеть? Он что, сам всё делает? Как минимум он может зависеть от других синглтонов и создаваемых им/ими сущностей.
>скрипт увеличился на две строчки
Лол, считать строчки иди на ассемблер - ты проиграл, когда выбрал игровой движок общего назначения и скриптовый язык. Не вижу проблемы с тем, что скрипт будет больше на две строчки, которые несут в себе полезную функцию. Это даже не циклы какие-нибудь и не огромные массивы в памяти...
>в самом начале, пока не всё проинициализировалось
Слово onready гарантирует инициализацию переменной до того, как начнёт выполняться твой код в _ready(). А обработчик _init() в большинстве случаев не нужен. Что касается порядка готовности нод в дереве, то тут всё предсказуемо: сверху вниз, от самых дальних потомков к самым древним предкам. На автозагрузку это тоже влияет, если что, ты не можешь обращаться к нодам сцены из автозагруженного скрипта в его _ready(), потому что он выше по дереву и поэтому готов намного раньше основной сцены. Просто продумывай порядок действий заранее, это несложно.
>если запустить сцену отдельно
Если нода имеет зависимость от какой-то другой ноды, очевидно, нет смысла запускать её без этой ноды. Вот только если нода имеет зависимость от автозагружаемой ноды, ты не сможешь легко и просто запустить эту ноду, если в автозагрузке нет нужной ноды, или ноды нужной версии, или ноды с нужным именем и т.д. Т.е. если ты поработал над проектом и изменил что-то в автозагрузке, ты ВНЕЗАПНО обнаруживаешь, что несколько скриптов проекта превратились в тыкву и их теперь нужно переписывать или выкидывать и делать что-то другое с нуля. А если бы эти скрипты чётко прописывали свои зависимости через export, ты бы мог сохранить прежнюю версию требуемого им скрипта (или достать прежнюю версию из архива/системы контроля версий) и таким образом сохранить возможность запускать эти скрипты, даже после того, как внёс несовместимые изменения в зависимые скрипты.
Короче, автозагрузка сбивает с толку и добавляет кучу проблем на этапе прототипирования, когда системы проекта регулярно переписываются, заменяются и т.д. Да и в большом проекте скорее всего их невыгодно использовать, т.к. никогда не знаешь, когда может потребоваться полностью переделать какую-то систему, чтобы внедрить новую крутую фичу или исправить баг.
>менеджер способностей, сменного оружия и всяких прочих штук, которые принципиально могут быть только у игрока.
Ты лишаешь себя возможности сделать ботов с интересными способностями и всякими прочими штуками. Алсо не решён вопрос мультиплеера, какой-нибудь мультиплеер на двоих за одним экраном можно встроить, наверное, в любую игру. Будешь делать менеджер_способностей_игрок_2 или добавлять поддержку нескольких игроков в первый менеджер? А мог просто заспавнить второго игрока с идентичными способностями, осталось бы только изменить управление и разделить экран на два (или добавить синхронизацию через сеть и т.п.).
>всё объявляю в самом верху
Там в любом случае будет несколько экранов, особенно с комментариями и разделением пустыми строками.
>в чём проблема создать сцену из одной ноды, прописать ей все экспорты
Я до такого не додумался))
>смириться с этим свойством и писать код так, будто все глобальные объекты не глобальны.
Есть очень большая разница между аккуратной отправкой сигналов предкам (которые могут быть, а могут и не быть) и зарытым в километровые скрипты портянкам кода с чем-то вроде:
>MyBuggedSingleton.add_bugs(MyCountSingleton.Count.OVER_9000)
>if MyBuggedSingleton.is_single(): #== MyBooleanSingleton.Bool.TRUE:
>_ MyBuggedSingleton.find_bug_waifu(true, MyWaifuSingleton.Waifu.BUG)
>MyBuggedSingleton.waifu.hug(self, MyHuggingSingleton.Hug.TIGHT)
Я щас уже почти засыпаю, так что не ругайтесь, если где ошибся. Самое обидное что не знаю как найти ту статью в руководстве, где описывались проблемы, связанные с использованием абсолютных путей и т.п. Точно помню что было где-то, но читал не полностью и названия страницы не помню.
Кстати, куда делся туториал с забавной картинкой про повара? Там вроде говорилось, что разработчик игры как повар, а дерево сцены, мол, рецепт блюда, т.е. игры. Не могу найти в stable - удалили что ли? Странно, по-моему, нормальный туториал был.
>get_node("/root/абсолютный/путь/до/ноды")
По-моему, даже в официальном руководстве было сказано, что использовать абсолютные пути - плохо. Даже get_parent() использовать не очень хорошо. Суть в том, что любая нода должна владеть только своими собственными потомками, знать она должна только о них, и обращаться напрямую ($Потомок) только к ним. Потому что расположение всех остальных нод в процессе работы над проектом может много раз меняться, да и в рантайме тоже могут потребоваться перемещения нод, и если нода пытается обращаться к предку или по абсолютному пути (не по ссылке, а через get_node()), она может обнаружить не то, что ожидает, и не факт, что проект остановится с ошибкой - ищи потом, почему у тебя игра работает, но как-то неправильно. Таким образом, все восходящие связи (потомок - родитель) должны быть через сигналы (кому надо - поймает, кому не надо - не будет реагировать), а вместо абсолютных путей в коде - настройка полей через инспектор:
>export var node_path: NodePath
>onready var node: Node = get_node(node_path)
Такая связь явно видна в инспекторе, в случае нарушения будет легко обнаружена дебаггером (если нода не найдена изначально или была освобождена раньше времени), и обращаемся мы здесь по ссылке, а не по пути в дереве, т.е. нода может свободно перемещаться в рантайме, даже совсем выходить из дерева (а в редакторе NodePath автоматически обновляется).
Почему GDScript разрешает делать то, что делать не рекомендуется? Потому что иногда это может очень сильно потребоваться, очевидно. Прямо как... костыли. Зачем ходить на костылях, если нет препятствий ходить как все здоровые люди? Нельзя привыкать ходить на костылях, а то потом проблемы будут.
>>796341
>В ином случае начинается нагромождение.
Тебе шашечки или ехать? Во всех нормальных языках у каждого класса должно быть имя, по которому к нему можно обращаться. GDScript разрешает не задавать имя класса, потому что это намного удобнее для новичков. Но без имени класса Godot не может знать, что именно ты пытаешься написать, и поэтому не может ничего подсказать. Сам подумай, ты объявил переменную типа Node, откуда Godot может узнать, что ты имеешь в виду безымянный класс из inventory_manager.gd? Без выполнения всего набора скриптов (на компьютере или мысленно) в данном случае нельзя узнать, что именно будет содержаться в этой переменной.
А нагромождение возникает из-за того, что в GDScript нет областей видимости, тех самых uses UnitName или чего-то похожего. Плохо, конечно. Но области видимости настраивать тоже сложно для новичков, видимо поэтому их и нет в GDScript. Зато порог входа очень низкий, сел и уже делаешь игру мечты.
>все зависят от синглтона
С какой это стати? Т.е. получается, что я должен ВСЕ скрипты проекта вручную просмотреть и по необходимости исправить, если захочу изменить один синглтон? А изменить синглтон когда-нибудь придётся, особенно если проект на ранних стадиях разработки.
>синглтон не зависит ни от кого
Опять странное утверждение, почему это синглтон не может от кого-то зависеть? Он что, сам всё делает? Как минимум он может зависеть от других синглтонов и создаваемых им/ими сущностей.
>скрипт увеличился на две строчки
Лол, считать строчки иди на ассемблер - ты проиграл, когда выбрал игровой движок общего назначения и скриптовый язык. Не вижу проблемы с тем, что скрипт будет больше на две строчки, которые несут в себе полезную функцию. Это даже не циклы какие-нибудь и не огромные массивы в памяти...
>в самом начале, пока не всё проинициализировалось
Слово onready гарантирует инициализацию переменной до того, как начнёт выполняться твой код в _ready(). А обработчик _init() в большинстве случаев не нужен. Что касается порядка готовности нод в дереве, то тут всё предсказуемо: сверху вниз, от самых дальних потомков к самым древним предкам. На автозагрузку это тоже влияет, если что, ты не можешь обращаться к нодам сцены из автозагруженного скрипта в его _ready(), потому что он выше по дереву и поэтому готов намного раньше основной сцены. Просто продумывай порядок действий заранее, это несложно.
>если запустить сцену отдельно
Если нода имеет зависимость от какой-то другой ноды, очевидно, нет смысла запускать её без этой ноды. Вот только если нода имеет зависимость от автозагружаемой ноды, ты не сможешь легко и просто запустить эту ноду, если в автозагрузке нет нужной ноды, или ноды нужной версии, или ноды с нужным именем и т.д. Т.е. если ты поработал над проектом и изменил что-то в автозагрузке, ты ВНЕЗАПНО обнаруживаешь, что несколько скриптов проекта превратились в тыкву и их теперь нужно переписывать или выкидывать и делать что-то другое с нуля. А если бы эти скрипты чётко прописывали свои зависимости через export, ты бы мог сохранить прежнюю версию требуемого им скрипта (или достать прежнюю версию из архива/системы контроля версий) и таким образом сохранить возможность запускать эти скрипты, даже после того, как внёс несовместимые изменения в зависимые скрипты.
Короче, автозагрузка сбивает с толку и добавляет кучу проблем на этапе прототипирования, когда системы проекта регулярно переписываются, заменяются и т.д. Да и в большом проекте скорее всего их невыгодно использовать, т.к. никогда не знаешь, когда может потребоваться полностью переделать какую-то систему, чтобы внедрить новую крутую фичу или исправить баг.
>менеджер способностей, сменного оружия и всяких прочих штук, которые принципиально могут быть только у игрока.
Ты лишаешь себя возможности сделать ботов с интересными способностями и всякими прочими штуками. Алсо не решён вопрос мультиплеера, какой-нибудь мультиплеер на двоих за одним экраном можно встроить, наверное, в любую игру. Будешь делать менеджер_способностей_игрок_2 или добавлять поддержку нескольких игроков в первый менеджер? А мог просто заспавнить второго игрока с идентичными способностями, осталось бы только изменить управление и разделить экран на два (или добавить синхронизацию через сеть и т.п.).
>всё объявляю в самом верху
Там в любом случае будет несколько экранов, особенно с комментариями и разделением пустыми строками.
>в чём проблема создать сцену из одной ноды, прописать ей все экспорты
Я до такого не додумался))
>смириться с этим свойством и писать код так, будто все глобальные объекты не глобальны.
Есть очень большая разница между аккуратной отправкой сигналов предкам (которые могут быть, а могут и не быть) и зарытым в километровые скрипты портянкам кода с чем-то вроде:
>MyBuggedSingleton.add_bugs(MyCountSingleton.Count.OVER_9000)
>if MyBuggedSingleton.is_single(): #== MyBooleanSingleton.Bool.TRUE:
>_ MyBuggedSingleton.find_bug_waifu(true, MyWaifuSingleton.Waifu.BUG)
>MyBuggedSingleton.waifu.hug(self, MyHuggingSingleton.Hug.TIGHT)
Я щас уже почти засыпаю, так что не ругайтесь, если где ошибся. Самое обидное что не знаю как найти ту статью в руководстве, где описывались проблемы, связанные с использованием абсолютных путей и т.п. Точно помню что было где-то, но читал не полностью и названия страницы не помню.
Кстати, куда делся туториал с забавной картинкой про повара? Там вроде говорилось, что разработчик игры как повар, а дерево сцены, мол, рецепт блюда, т.е. игры. Не могу найти в stable - удалили что ли? Странно, по-моему, нормальный туториал был.
Спокойной ночи!
>нужную ноду дерева по её пути get_node
Фу так делать. Нет ничего более непостоянного, чем имена нод в рантайме. Один раз сделал отинстансил сцену, и вот уже она зовётся не my_scene, а my_scene@1, и хрен ты угадаешь, по какому адресу её искать в следующий раз.
>>796372
>Тебе шашечки или ехать?
Мне чтобы мой код приносил мне удовлетворение не только от результата, но и от процесса его написания, от того, как он логично внутри себя устроен.
>все зависят от синглтона, синглтон не зависит ни от кого
Разверну суть. К синглтонам обращаются самые разные ноды из самых разных частей проекта. Синглтоны - это своего рода АПИ для взаимодействия этих нод с игрой. Синглтон сам по себе не обращается к нодам и не зависит от них в гдскриптовом смысле: все типы максимально общие. Например, есть условный MyPlayerType, который наследует от KinematicBody2D, то в синглтоне будет только var player: KinematicBody2D, и во всех случаях, когда надо в нём вызвать что-то специфическое для MyPlayerType, то прибегаем к утиному вопросу has_method.
С другой стороны, если какая-то нода что-то хочет от синглтона, то никаких утят, сразу в лоб спрашиваем нужную функцию. Как она там внутри реализована, это уже другой разговор, там может быть просто pass вместо тело функции. Но она должна быть, потому что ноды пишутся под определённый игровой АПИ.
Ну и взаимодействие между синглтонами. В целом они почти не взаимодействуют. А если очень надо что-то сделать в связке, то есть синглтончик поменьше, который обращается к старшим братьям по их АПИ. Они изначально написаны так, чтобы каждый делал что-то одно.
>Если нода имеет зависимость от какой-то другой ноды, очевидно, нет смысла запускать её без этой ноды. Вот только если нода имеет зависимость от автозагружаемой ноды, ты не сможешь легко и просто запустить эту ноду, если в автозагрузке нет нужной ноды, или ноды нужной версии, или ноды с нужным именем и т.д
Ага, а если я обновил Годо, а там вдруг что-то переименовали? Ты раздуваешь проблему там, где её нет. Есть набор синглтонов, и я рассчитываю, что они в проекте есть под своими именами точно так же, как под своими именами в движке представлены функции.
>Я щас уже почти засыпаю
Пусть тебе приснится твоя готовая игра, как она хорошо продаётся на всех платформах и получает хвалебные отзывы.
А вообще, кмк, эту дискуссию пора заканчивать, ничего нового уже не скажем, и так уже начались повторы в аргументации. Свой проект переписывать, потому что анон с двача так сказал, я не буду, но определённые выводы сделаю, конечно же, зато сторонний читатель, может быть, найдёт в этом всём рациональное зерно и сделает свою игру чуточку лучше.
>нужную ноду дерева по её пути get_node
Фу так делать. Нет ничего более непостоянного, чем имена нод в рантайме. Один раз сделал отинстансил сцену, и вот уже она зовётся не my_scene, а my_scene@1, и хрен ты угадаешь, по какому адресу её искать в следующий раз.
>>796372
>Тебе шашечки или ехать?
Мне чтобы мой код приносил мне удовлетворение не только от результата, но и от процесса его написания, от того, как он логично внутри себя устроен.
>все зависят от синглтона, синглтон не зависит ни от кого
Разверну суть. К синглтонам обращаются самые разные ноды из самых разных частей проекта. Синглтоны - это своего рода АПИ для взаимодействия этих нод с игрой. Синглтон сам по себе не обращается к нодам и не зависит от них в гдскриптовом смысле: все типы максимально общие. Например, есть условный MyPlayerType, который наследует от KinematicBody2D, то в синглтоне будет только var player: KinematicBody2D, и во всех случаях, когда надо в нём вызвать что-то специфическое для MyPlayerType, то прибегаем к утиному вопросу has_method.
С другой стороны, если какая-то нода что-то хочет от синглтона, то никаких утят, сразу в лоб спрашиваем нужную функцию. Как она там внутри реализована, это уже другой разговор, там может быть просто pass вместо тело функции. Но она должна быть, потому что ноды пишутся под определённый игровой АПИ.
Ну и взаимодействие между синглтонами. В целом они почти не взаимодействуют. А если очень надо что-то сделать в связке, то есть синглтончик поменьше, который обращается к старшим братьям по их АПИ. Они изначально написаны так, чтобы каждый делал что-то одно.
>Если нода имеет зависимость от какой-то другой ноды, очевидно, нет смысла запускать её без этой ноды. Вот только если нода имеет зависимость от автозагружаемой ноды, ты не сможешь легко и просто запустить эту ноду, если в автозагрузке нет нужной ноды, или ноды нужной версии, или ноды с нужным именем и т.д
Ага, а если я обновил Годо, а там вдруг что-то переименовали? Ты раздуваешь проблему там, где её нет. Есть набор синглтонов, и я рассчитываю, что они в проекте есть под своими именами точно так же, как под своими именами в движке представлены функции.
>Я щас уже почти засыпаю
Пусть тебе приснится твоя готовая игра, как она хорошо продаётся на всех платформах и получает хвалебные отзывы.
А вообще, кмк, эту дискуссию пора заканчивать, ничего нового уже не скажем, и так уже начались повторы в аргументации. Свой проект переписывать, потому что анон с двача так сказал, я не буду, но определённые выводы сделаю, конечно же, зато сторонний читатель, может быть, найдёт в этом всём рациональное зерно и сделает свою игру чуточку лучше.
>>796372
>Лол, считать строчки иди на ассемблер
Тащемта речь не о строчках, а о красоте кода.
>Слово onready гарантирует инициализацию переменной до того, как начнёт выполняться твой код в _ready(). А обработчик _init() в большинстве случаев не нужен.
И тут _process такой: просто здравствуй, просто как дела. А за ним _input: мышиные движения готовности не ждут.
> И тут _process такой: просто здравствуй, просто как дела. А за ним _input: мышиные движения готовности не ждут.
Они не запускаются, если нода нот риди.
Ну дык всё обсуждение сводится к
>Если я вот тут так напишу, будет ошибка
>Не пиши так
>Азаза, но гдскрипт же ПОЗВОЛЯЕТ!!11
Позволяет. Как и все тьюринг-полные языки он позволяет стрелять себе в ногу. Проблемс?
Вот к какому выводу я пришёл. На все локации накинута сетка из точек. Камера плавно (интерполяцией) переходит от одной точки к другой, держась на некотором радиусе от персонажа, если персонаж уходит за поворот, скрываясь от камеры, она резко перескакивает к новой точке, где есть видимость. Плюс есть специальные точки на интерактивных объектах, чтобы рассматривать их подробно. Туда камера переводится только по клику игрока.
Стильно, но весь экран гуляет слишком, имхо. И когда бьются три кирпича, гуляет почти постоянно.
Имхо, нужна опция по силе тряски и трясти только если персонаж недалеко от места удара, на связанной стене
>Мне чтобы мой код приносил мне удовлетворение не только от результата, но и от процесса его написания, от того, как он логично внутри себя устроен.
Понимаю тебя, но эта дрочка на код не приносит проекту пользы, и даже может приносить вред. Ты отказываешься от строгой типизации из-за "нагромождения", тем самым провоцируешь проблемы в будущем, предотвратить которые могла бы строгая типизация. Что лучше: подрочить сегодня на код и получить проблемы в будущем, или сделать по уму и не иметь проблем в будущем? Ты же не просто самоудовлетворением занимаешься, а игру делаешь... так ведь?
>есть условный MyPlayerType, который наследует от KinematicBody2D, то в синглтоне будет только var player: KinematicBody2D, и во всех случаях, когда надо в нём вызвать что-то специфическое для MyPlayerType, то прибегаем к утиному вопросу has_method.
Ну вот опять ты вставляешь себе палки в колёса ради сиюминутного удовольствия. Сегодня ты сделал MyPlayerType с методом foo(), а завтра ты сделаешь MyBarType тоже с методом foo(), но метод этот будет немного другим... Сможет ли интерпретатор GDScript предупредить тебя, что ты творишь какую-то херню? Нет, потому что формально никаких нарушений нет, синглтон получил некий KinematicBody2D, нашёл в нём метод foo() и вызвал его, с точки зрения интерпретатора код абсолютно корректен, но ты получишь не тот результат, который ожидал, и будешь ломать голову. Зато сегодня ты подрочил на кажущееся красивым решение.
Алсо мне кажется, что метод has_method() должен вызывать лишнюю нагрузку. Сам подумай, интерпретатору заранее неизвестно, ссылка на какой объект окажется в переменной, следовательно, каждый раз нужно проверять наличие метода, и это никак не оптимизировать со стороны интерпретатора. Зато можно отказаться от этих проверок, если указать более точный тип. Если этот код выполняется часто, лишняя нагрузка будет существенной. И ради чего?
>если какая-то нода что-то хочет от синглтона, то никаких утят, сразу в лоб спрашиваем нужную функцию.
Ну а ежели синглтона БОЛЬШЕ НЕТ? Ну вот так, делал-делал и потом решил выкинуть нахрен, потому что оказалось НИНУЖНО, неправильно или вовсе контрпродуктивно.
>там может быть просто pass вместо тело функции
В ООП это чревато. Если объект O ожидает от синглтона S какой-то работы, а S ВНЕЗАПНО решил её больше не делать, весь дальнейший код в O окажется некорректным, но интерпретатор тебе никаких ошибок может не выдать. В лучшем случае O сломается на обращении к null, но может он работает только с простыми типами и получит допустимое значение, которое на деле ошибочно... Короче, ты не можешь просто оставить заглушку, не проанализировав весь код, который к ней в прошлом обращался.
>Есть набор синглтонов, и я рассчитываю, что они в проекте есть под своими именами точно так же, как под своими именами в движке представлены функции.
Функции из API движка ты изменить не можешь, если ты не лезешь в исходники движка и не собираешь свой форк движка. А свои синглтоны ты можешь свободно менять и будешь менять в процессе жизни проекта, особенно на начальных этапах, но и в будущем тоже. Глупо надеяться с первой попытки сделать всё правильно и потом никогда ничего не менять. Такое возможно только в самых мелких проектах, которые можно за недельку на коленке состряпать и потом больше не притрагиваться.
Вон, даже сам Годо существенно меняет API в 4.0, и до бета версии это самое API может ещё несколько раз измениться (поэтому не рекомендуют портировать большие проекты или делать что-то серьёзное на альфа версиях). Это нормально, просто осознали, что лучше сделать по-другому, и сделали по-другому. Но пользователям теперь весь код перебирать и исправлять кучу всего, особенно того, что касается 3D. Окей, возможно, что-то конвертируется автоматически, но это движок, со своими синглтонами ты такого провернуть не можешь (точнее можешь, но оно того не стоит - масштабы совсем не те, чтобы автоматизировать).
>как она хорошо продаётся на всех платформах и получает хвалебные отзывы
Ой, да пофиг на продажи и отзывы. Игроки будут нахваливать что угодно, не бывает играбельных игр с 0% рейтингом отзывов. А чтобы добиться продаж, нужны вложения в рекламу, качество игры в данном случае вторично, важен рекламный бюджет. В любом случае, я делаю хочу сделать игру для себя, и это даже скорее не игра, а эксперимент или площадка для экспериментов... Всё очень сложно, как ты понимаешь, у меня нет чёткого видения проекта. Забавно, но у меня есть множество других концепций игр, пусть полузабытых и плохо документированных, но они намного чётче (я даже мысленно играл в них, а этот проект мысленно не могу представить как целое), вот только мне совершенно не хочется над ними работать, интерес угас. Может, стоит сделать что-то простое, но завершённое, чтобы поднять мотивацию и силы для работы над этим проектом...
>>796378
>речь не о строчках, а о красоте кода
Сгруппируй строчки по категориям и будет красиво.
>И тут _process такой: просто здравствуй, просто как дела. А за ним _input: мышиные движения готовности не ждут.
Делаешь отдельное поле status и проверяешь:
>if status == Status.READY:
Тебя ведь не смущает перед каждым обращением к методу дёргать has_method()? Ну вот эта проверка очевидно быстрее has_method() и в целом полезнее, т.к. можно сделать разные статусы. А для совсем простой системы будет достаточно флага ready.
>>796385
>сетгеты стопудово запускаются
Вроде сетгет не запускается, если ты обращаешься к свойству класса из методов этого класса. Хрень какая-то, если честно, лишает сетгеты смысла, т.е. изнутри класса ты должен вручную делать set_foo(bar) вместо присвоения foo = bar. Хотя могу ошибаться, но меня это сильно смутило, т.к. на Паскале property позволяет запускать сеттеры и геттеры в том числе из методов класса, которому они принадлежат.
>>796403
>Ну дык всё обсуждение сводится к
>>Если я вот тут так напишу, будет ошибка
>>Не пиши так
>>Азаза, но гдскрипт же ПОЗВОЛЯЕТ!!11
Моя позиция в том, чтобы не использовать автозагрузочные синглтоны без крайней на то необходимости. То есть при любой возможности нужно создавать ноды в дереве сцены и связывать их между собой через экспортируемые переменные и сигналы. Это безопаснее и делает связи более очевидными. А если автозагрузку всё-таки придётся использовать, тогда да, ходишь как по минному полю, то не пиши, это не делай, вот это не работает, вон то работает, но не как обычно... СЛОЖНА и не очень-то полезно, т.к. ту же функциональность можно получить из обычных нод в сцене.
>Мне чтобы мой код приносил мне удовлетворение не только от результата, но и от процесса его написания, от того, как он логично внутри себя устроен.
Понимаю тебя, но эта дрочка на код не приносит проекту пользы, и даже может приносить вред. Ты отказываешься от строгой типизации из-за "нагромождения", тем самым провоцируешь проблемы в будущем, предотвратить которые могла бы строгая типизация. Что лучше: подрочить сегодня на код и получить проблемы в будущем, или сделать по уму и не иметь проблем в будущем? Ты же не просто самоудовлетворением занимаешься, а игру делаешь... так ведь?
>есть условный MyPlayerType, который наследует от KinematicBody2D, то в синглтоне будет только var player: KinematicBody2D, и во всех случаях, когда надо в нём вызвать что-то специфическое для MyPlayerType, то прибегаем к утиному вопросу has_method.
Ну вот опять ты вставляешь себе палки в колёса ради сиюминутного удовольствия. Сегодня ты сделал MyPlayerType с методом foo(), а завтра ты сделаешь MyBarType тоже с методом foo(), но метод этот будет немного другим... Сможет ли интерпретатор GDScript предупредить тебя, что ты творишь какую-то херню? Нет, потому что формально никаких нарушений нет, синглтон получил некий KinematicBody2D, нашёл в нём метод foo() и вызвал его, с точки зрения интерпретатора код абсолютно корректен, но ты получишь не тот результат, который ожидал, и будешь ломать голову. Зато сегодня ты подрочил на кажущееся красивым решение.
Алсо мне кажется, что метод has_method() должен вызывать лишнюю нагрузку. Сам подумай, интерпретатору заранее неизвестно, ссылка на какой объект окажется в переменной, следовательно, каждый раз нужно проверять наличие метода, и это никак не оптимизировать со стороны интерпретатора. Зато можно отказаться от этих проверок, если указать более точный тип. Если этот код выполняется часто, лишняя нагрузка будет существенной. И ради чего?
>если какая-то нода что-то хочет от синглтона, то никаких утят, сразу в лоб спрашиваем нужную функцию.
Ну а ежели синглтона БОЛЬШЕ НЕТ? Ну вот так, делал-делал и потом решил выкинуть нахрен, потому что оказалось НИНУЖНО, неправильно или вовсе контрпродуктивно.
>там может быть просто pass вместо тело функции
В ООП это чревато. Если объект O ожидает от синглтона S какой-то работы, а S ВНЕЗАПНО решил её больше не делать, весь дальнейший код в O окажется некорректным, но интерпретатор тебе никаких ошибок может не выдать. В лучшем случае O сломается на обращении к null, но может он работает только с простыми типами и получит допустимое значение, которое на деле ошибочно... Короче, ты не можешь просто оставить заглушку, не проанализировав весь код, который к ней в прошлом обращался.
>Есть набор синглтонов, и я рассчитываю, что они в проекте есть под своими именами точно так же, как под своими именами в движке представлены функции.
Функции из API движка ты изменить не можешь, если ты не лезешь в исходники движка и не собираешь свой форк движка. А свои синглтоны ты можешь свободно менять и будешь менять в процессе жизни проекта, особенно на начальных этапах, но и в будущем тоже. Глупо надеяться с первой попытки сделать всё правильно и потом никогда ничего не менять. Такое возможно только в самых мелких проектах, которые можно за недельку на коленке состряпать и потом больше не притрагиваться.
Вон, даже сам Годо существенно меняет API в 4.0, и до бета версии это самое API может ещё несколько раз измениться (поэтому не рекомендуют портировать большие проекты или делать что-то серьёзное на альфа версиях). Это нормально, просто осознали, что лучше сделать по-другому, и сделали по-другому. Но пользователям теперь весь код перебирать и исправлять кучу всего, особенно того, что касается 3D. Окей, возможно, что-то конвертируется автоматически, но это движок, со своими синглтонами ты такого провернуть не можешь (точнее можешь, но оно того не стоит - масштабы совсем не те, чтобы автоматизировать).
>как она хорошо продаётся на всех платформах и получает хвалебные отзывы
Ой, да пофиг на продажи и отзывы. Игроки будут нахваливать что угодно, не бывает играбельных игр с 0% рейтингом отзывов. А чтобы добиться продаж, нужны вложения в рекламу, качество игры в данном случае вторично, важен рекламный бюджет. В любом случае, я делаю хочу сделать игру для себя, и это даже скорее не игра, а эксперимент или площадка для экспериментов... Всё очень сложно, как ты понимаешь, у меня нет чёткого видения проекта. Забавно, но у меня есть множество других концепций игр, пусть полузабытых и плохо документированных, но они намного чётче (я даже мысленно играл в них, а этот проект мысленно не могу представить как целое), вот только мне совершенно не хочется над ними работать, интерес угас. Может, стоит сделать что-то простое, но завершённое, чтобы поднять мотивацию и силы для работы над этим проектом...
>>796378
>речь не о строчках, а о красоте кода
Сгруппируй строчки по категориям и будет красиво.
>И тут _process такой: просто здравствуй, просто как дела. А за ним _input: мышиные движения готовности не ждут.
Делаешь отдельное поле status и проверяешь:
>if status == Status.READY:
Тебя ведь не смущает перед каждым обращением к методу дёргать has_method()? Ну вот эта проверка очевидно быстрее has_method() и в целом полезнее, т.к. можно сделать разные статусы. А для совсем простой системы будет достаточно флага ready.
>>796385
>сетгеты стопудово запускаются
Вроде сетгет не запускается, если ты обращаешься к свойству класса из методов этого класса. Хрень какая-то, если честно, лишает сетгеты смысла, т.е. изнутри класса ты должен вручную делать set_foo(bar) вместо присвоения foo = bar. Хотя могу ошибаться, но меня это сильно смутило, т.к. на Паскале property позволяет запускать сеттеры и геттеры в том числе из методов класса, которому они принадлежат.
>>796403
>Ну дык всё обсуждение сводится к
>>Если я вот тут так напишу, будет ошибка
>>Не пиши так
>>Азаза, но гдскрипт же ПОЗВОЛЯЕТ!!11
Моя позиция в том, чтобы не использовать автозагрузочные синглтоны без крайней на то необходимости. То есть при любой возможности нужно создавать ноды в дереве сцены и связывать их между собой через экспортируемые переменные и сигналы. Это безопаснее и делает связи более очевидными. А если автозагрузку всё-таки придётся использовать, тогда да, ходишь как по минному полю, то не пиши, это не делай, вот это не работает, вон то работает, но не как обычно... СЛОЖНА и не очень-то полезно, т.к. ту же функциональность можно получить из обычных нод в сцене.
Мне это нужно для того, чтобы экспортировать проект с этим .pck на Андроид и там уже его использовать. Но его тупо нет в файловом менеджере. Его не считает допустимым файлом.
Если же это не вариант, то как мне заставить работать pck с андроидом? Неужели нет никакой возможности патчить игру, а всегда её придётся только полностью заменять?
>PCK файлы
>Андроид
PCK файлы как отдельные файлы существуют только на десктопных системах, лежат отдельно от исполняемого файла. На Android, насколько я понимаю, данные проекта пакуются в APK, который суть обычный ZIP с манифестом приложения, иконками, исполняемыми файлами, данными и т.д. Установленное на Android приложение копирует свои файлы в строго защищённую область памяти, куда без рута никак не попасть. Исключение - OBB файлы, они находятся в папке emulated/0/Android/obb и доступны для системного файлового менеджера, но это тоже какие-то архивы, а не просто файлы, и загружаются они самим Google Play (или пользователем-пиратом). Просто файлы данных находятся в emulated/0/Android/data, туда Google Play ничего не качает, туда пишут сами приложения, скорее всего это папка user:// в Godot (чисто предполагаю).
Вообще, я думаю, тебе нужно обратиться к документации Гугла, потому что именно он будет доставлять патчи твоего приложения, если ты опубликуешь его в Google Play. Из личного опыта, по ощущениям некоторые приложения целиком обновляют все файлы, а некоторые докачивают только мелкие патчи. Как это реализовано - нужно спрашивать у самого Гугла, т.к. он докачивает только APK и OBB. Могу предположить, что если ты упакуешь в APK/OBB дополнительный .PCK файл в дополнение к оригинальному, то Google Play автоматически скачает только этот дополнительный файл и самостоятельно запакует его куда следует у пользователя. А может быть и нет, лол. В любом случае я давно заметил, что крупные игры докачивают файлы обновлений с собственных серверов, в обход сервисов Гугла, и мы можем сделать что-то похожее с PCK файлами, если Godot позволяет динамически их подгружать из user://.
>Его не считает допустимым файлом.
Если проблема только в этом, упакуй PCK в ZIP без сжатия или вообще просто переименуй в ZIP, системный менеджер должен без проблем обрабатывать ZIP файлы. Ты же пытаешься из игры вызвать системное меню выбора файла, а оно тебе отказывает принимать PCK?
Спасибо за объяснение, почитаю то, как у гугла работают патчи.
А конкретно свою проблему решил очень легко: в экспорте на андроид нужно было просто указать, чтобы он экспортил все файлы с pck форматом. Тогда он их пакует в апк и они становятся доступны из андроид-приложения
Сейчас от APK уже отказываются, будет AAB, может быть схема с несколькими файлами ресурсов, надо проверить
Возможно можно такое и с pck провернуть. Как минимум со вторичными pck для патчей.
>Ты отказываешься от строгой типизации из-за "нагромождения"
Где? Да я даже функциям прописываю -> void и все переменные типизирую.
Нагромождение лишних строчек, когда можно то же самое сделать из редактора, да, не люблю. Засорять интерфейс редактора классами, которые существуют в единственном экземпляре, тоже не вижу смысла. Это вот да.
>>796504
>Сегодня ты сделал MyPlayerType с методом foo(), а завтра ты сделаешь MyBarType тоже с методом foo(), но метод этот будет немного другим
Опять ты сводишь разговор к "завтра ты будешь не ты, начнёшь рисовать одуванчики вместо кода, и всё посыпется". Этот оборот имеет смысл только в большой команде и только если никто не читает документацию к АПИ проекта.
>мне кажется, что метод has_method() должен вызывать лишнюю нагрузку.
Тебе кажется. У нас тут скриптовый язык,
>Ну а ежели синглтона БОЛЬШЕ НЕТ?
Из-за санкций?Использовать поиск по файлам при таком крупном изменении в проекте религия не позволяет?
>Короче, ты не можешь просто оставить заглушку, не проанализировав весь код, который к ней в прошлом обращался.
Да ты что! Если ты пишешь код, обращаясь к функции-заглушке, внезапно ты должен знать, что она пока не написана - вот ведь открытие! Внезапно ты должен отметить себе в тудулист, что там вот пока заглушка, надо в будущем написать. Внезапно надо отслеживать весь процесс и знать, где чего не хватает, не когда уже интерпретатор ругается, а на этапе написания кода. А мужики-то не знают!
>со своими синглтонами ты такого провернуть не можешь
Ctrl+Shift+F. Конечно, предполагается, что все синглтоны и их функции имеют достаточно уникальные имена, чтобы таким методом их можно было найти везде. Ну и при крупном изменении, конечно же, надо у себя где-то отмечать процесс его применения.
>Делаешь отдельное поле status и проверяешь
Терпеть не могу так делать.
>Тебя ведь не смущает перед каждым обращением к методу дёргать has_method()?
Совершенно не смущает, если это не в _process у тысячи нод, а в каком-нибудь разово вызываемом методе в синглтоне.
>Вроде сетгет не запускается, если ты обращаешься к свойству класса из методов этого класса
Сетгет обязательно запустится при инициализации экспортного поля, и это происходит до _реади.
>Хрень какая-то, если честно, лишает сетгеты смысла
Сделано всего лишь для того, чтобы присвоение внутри сеттера не вызывало рекурсивный вызов сеттера. А так вообще где угодно можно написать self.foo = bar и вызвать таким образом сеттер.
>Моя позиция в том, чтобы не использовать автозагрузочные синглтоны без крайней на то необходимости.
Да поняли уже. Ты молодец.
Моя позиция в том, чтобы использовать автозагрузочные синглтоны как АПИ игры.
>Ой, да пофиг на продажи и отзывы
Не душни, тебе лучи добра посылают.
>Может, стоит сделать что-то простое, но завершённое, чтобы поднять мотивацию и силы для работы над этим проектом
Ага, я именно с такой мыслью начал нынешний проект больше месяца назад. Правда, там действительно совсем чуть-чуть кодить осталось, и можно будет переходить к стадии наполнения контентом. Но не суть. Главное что в целом метод "сделать что-то простое, но завершённое" хоть и рабочий, но обманчивый.
>Ты отказываешься от строгой типизации из-за "нагромождения"
Где? Да я даже функциям прописываю -> void и все переменные типизирую.
Нагромождение лишних строчек, когда можно то же самое сделать из редактора, да, не люблю. Засорять интерфейс редактора классами, которые существуют в единственном экземпляре, тоже не вижу смысла. Это вот да.
>>796504
>Сегодня ты сделал MyPlayerType с методом foo(), а завтра ты сделаешь MyBarType тоже с методом foo(), но метод этот будет немного другим
Опять ты сводишь разговор к "завтра ты будешь не ты, начнёшь рисовать одуванчики вместо кода, и всё посыпется". Этот оборот имеет смысл только в большой команде и только если никто не читает документацию к АПИ проекта.
>мне кажется, что метод has_method() должен вызывать лишнюю нагрузку.
Тебе кажется. У нас тут скриптовый язык,
>Ну а ежели синглтона БОЛЬШЕ НЕТ?
Из-за санкций?Использовать поиск по файлам при таком крупном изменении в проекте религия не позволяет?
>Короче, ты не можешь просто оставить заглушку, не проанализировав весь код, который к ней в прошлом обращался.
Да ты что! Если ты пишешь код, обращаясь к функции-заглушке, внезапно ты должен знать, что она пока не написана - вот ведь открытие! Внезапно ты должен отметить себе в тудулист, что там вот пока заглушка, надо в будущем написать. Внезапно надо отслеживать весь процесс и знать, где чего не хватает, не когда уже интерпретатор ругается, а на этапе написания кода. А мужики-то не знают!
>со своими синглтонами ты такого провернуть не можешь
Ctrl+Shift+F. Конечно, предполагается, что все синглтоны и их функции имеют достаточно уникальные имена, чтобы таким методом их можно было найти везде. Ну и при крупном изменении, конечно же, надо у себя где-то отмечать процесс его применения.
>Делаешь отдельное поле status и проверяешь
Терпеть не могу так делать.
>Тебя ведь не смущает перед каждым обращением к методу дёргать has_method()?
Совершенно не смущает, если это не в _process у тысячи нод, а в каком-нибудь разово вызываемом методе в синглтоне.
>Вроде сетгет не запускается, если ты обращаешься к свойству класса из методов этого класса
Сетгет обязательно запустится при инициализации экспортного поля, и это происходит до _реади.
>Хрень какая-то, если честно, лишает сетгеты смысла
Сделано всего лишь для того, чтобы присвоение внутри сеттера не вызывало рекурсивный вызов сеттера. А так вообще где угодно можно написать self.foo = bar и вызвать таким образом сеттер.
>Моя позиция в том, чтобы не использовать автозагрузочные синглтоны без крайней на то необходимости.
Да поняли уже. Ты молодец.
Моя позиция в том, чтобы использовать автозагрузочные синглтоны как АПИ игры.
>Ой, да пофиг на продажи и отзывы
Не душни, тебе лучи добра посылают.
>Может, стоит сделать что-то простое, но завершённое, чтобы поднять мотивацию и силы для работы над этим проектом
Ага, я именно с такой мыслью начал нынешний проект больше месяца назад. Правда, там действительно совсем чуть-чуть кодить осталось, и можно будет переходить к стадии наполнения контентом. Но не суть. Главное что в целом метод "сделать что-то простое, но завершённое" хоть и рабочий, но обманчивый.
1. Стартовая сцена у нас аналог program.pas, её _ready() аналог main() точки входа.
2. В ready стартовой сцены добавляем в корень дерева нужные нам ноды, которые будут глобальными и статическими. Это будут аналоги модулей, которые будут юзаться динамическими сценами и объектами-субсценами. Например, мы напишем так: get_tree().root.call_deferred("add_child", preload("res://objects/ui/main_menu.tscn").instance())
3. В динамических скриптах мы теперь можем в самом начале организовать эдакую секцию uses: onready var main_menu := get_node("/root/main_menu")
Охуенно! Теперь скрипт, при перемещении в другой проект мгновенно просигнализирует (правда только в ран-тайме), что ему не хватает модуля main_menu.
Впрочем, при отсутствии дизайн-тайм-синглтона в автозагрузке, обычный без выебонов скрипт тоже заругается. Причем ещё в дизайн-тайме.
Хуан гений! Обошёлся без юзингов, импортов и прочей дремучей легаси-хуеты, и всё работает прекрасно!
>Засорять интерфейс редактора классами
Лол, это и есть типизация. Твой player по ООП не является "KinematicBody2D", он должен являться экземпляром Player, короче, отдельный класс. Годо позволяет тебе избежать индивидуального именования классов, но по-хорошему так делать нельзя. Отказываясь от class_name ты отказываешься от правильной типизации.
>завтра ты будешь не ты
>Этот оборот имеет смысл только в большой команде
"Завтра" - это гипербола. Пройти может неделя, месяц или год. И если ты не вундеркинд с фотографической памятью, который помнит абсолютно всё что видел со 100% точностью, то со временем ты обязательно, гарантированно забудешь, из чего состоит и как работает твой собственный код, который ты писал когда-то в прошлом. И в зависимости от твоей организованности, ты либо потратишь кучу времени на изучение своего кода, либо быстро что-то напишешь и потратишь ещё больше времени на поиск ошибок. Учитывая твоё отношение к коду, вероятнее всего второй вариант развития событий. Успехов в поиске ошибок, которых можно было бы избежать, но тебе лень.
>>has_method() должен вызывать лишнюю нагрузку.
>Тебе кажется. У нас тут скриптовый язык
Ну и? Этот метод должен сравнить строки-имена методов или связанные с ними числовые ключи. И чем больше методов в классе, тем больше сравнений в среднем. К чему этот костыль, если можно просто объявить конкретный тип класса?
Другое дело, если бы тебе реально было необходимо обрабатывать несколько совершенно разных классов с одной общей функцией. Я таким образом сделал функцию interact(), которую можно повесить на любой объект, сделав его интерактивным. Но думается мне, что это всё же неправильно и нужно будет переделать...
>Использовать поиск по файлам
И потом вручную исправлять все 100500 вхождений? А потом ловить ошибки из-за того, что нельзя было просто закомментировать строку, нужно было сделать что-то другое, но ты ведь не помнишь, что делает именно этот кусок кода, который ты писал в 2020.
>должен знать, что она пока не написана
Это противоречит принципу инкапсуляции, когда о состоянии какого-то элемента класса знает только сам класс. Если метод класса называется do_some_work(), то он действительно должен сделать какую-то работу, а не пукнуть в консольку и завершиться без выполнения заявленной работы.
>отслеживать весь процесс и знать, где чего не хватает
К счастью, я не обладаю фотографической памятью, а буфер оперативной памяти у меня такой же, как и большинства людей, соответственно я не могу удерживать в памяти десятки "туду" обо всём, чего не хватает моему коду. Пока пишешь одну функцию, ты фокусируешься только на ней, всё остальное вылетает из твоей оперативной памяти и это совершенно нормально для человека. Возможно, ты действительно гений с экстраординарными способностями...
>Ctrl+Shift+F
Мало просто найти, нужно знать, как изменить код в каждом конкретном случае, но скорее всего ты этого не знаешь.
>Терпеть не могу так делать.
Аргументы будут или это субъективное нежелание?
>Сделано всего лишь для того, чтобы присвоение внутри сеттера не вызывало рекурсивный вызов сеттера.
Что мешало сделать это ТОЛЬКО в теле непосредственно сеттера/геттера? Компилятор Паскаля (и, наверняка, компиляторы и интерпретаторы множества других ЯП) так может, почему тогда интерпретатор GDScript такую фигню творит? Вот же, написано программистом "setget", почему интерпретатор не принимает это слово во внимание?
>self.foo = bar
Костыль.
>АПИ игры
Исходя из https://semver.org/lang/ru/ стабильное АПИ может быть только с версии 1.0.0, в то время как версии 0.x предназначены для быстрой разработки, когда АПИ очень часто и сильно меняется. Т.е. окей, после релиза игры нельзя вносить случайные изменения в АПИ, иначе это будет уже 2.0 версия, но на этапе разработки 0.x изменения неизбежны. И чем сложнее их вносить, тем хуже для проекта. Автозагрузка усложняет внесение изменений.
>>796638
>_ready() аналог main() точки входа
Нифига подробного, выход из main = завершение программы.
>напишем так: get_tree().root.call_deferred("add_child",
Зачееееееем...
>get_node("/root/main_menu")
ЗАЧЕЕЕЕМ???
Тебе Хуан дал тебе export ...: NodePath, нет, не хочу экспортировать и тыкать мышкой в инспекторе, хочу костыли велосипедить и потом страдать из-за палок в колёсах своих велосипедов.
>просигнализирует (правда только в ран-тайме)
Ага, а с помощью export ты узнаешь о необходимости подключения какой-то специфичной ноды ещё до запуска проекта.
>Причем ещё в дизайн-тайме.
Вот это и плохо с "синглтонами", 100500 ошибок "скрипт не может быть проанализирован", приходится 100500 раз перезагружать редактор, чтобы исправить ошибки, которые мешают ему прочитать скрипты, в которых больше нет ошибок. Даже кнопка в меню есть "перезагрузить проект", знают прекрасно что редактор багнутый, но, видимо, ничего исправить пока не могут.
>Обошёлся без юзингов, импортов и прочей дремучей легаси
Повторяю, без этого можно только хэллоуворлды нубасам преподавать, для чего-то серьёзного это не подходит. В конце концов, делая сложный проект, ты дойдёшь до того, что будешь в комментариях к заголовку скрипта указывать, от чего этот скрипт зависит, вот только интерпретатор не сможет тебе подсказать, если ты ошибся в своём комментарии или он уже неактуален. А ключевое слово uses, import и т.п. тем и хорошо, что проверяется программой, то есть невозможно наломать дров и не заметить этого.
Да, кстати, главное достоинство слова uses в том, что оно ограничивает (вернее, расширяет) область видимости в рамках одного скрипта. Годо подразумевает, что из каждого скрипта видно вообще все остальные скрипты проекта и всё АПИ движка - это удобно в маленьких проектах, но становится сплошным неудобством и болью в сколь-либо больших проектах, где могут быть тысячи скриптов. Алсо именно из-за отсутствия uses невозможно использовать скрипты из других проектов, не копипастя их вручную, потому что Годо ограничивает видимость одной папкой проекта; на серьёзных ЯП ты можешь использовать юниты из любых папок на диске, расширяя видимость как тебе, лично тебе нужно, а не как задумал какой-то Хуан.
Надеюсь, со временем Хуан одумается и у нас будет какой-то аналог uses в GDScript. Для нубов это можно сделать опциональным: в настройках проекта сделать галочку "каждый скрипт видит все остальные скрипты", которая по умолчанию установлена, а если эту галочку снять, придётся добавлять в скрипты uses something.gd, иначе не запустится или упадёт с ошибкой доступа. В режиме по умолчанию эти ключевые слова игнорируются, т.к. расширяют и без того максимальную область видимости.
>Засорять интерфейс редактора классами
Лол, это и есть типизация. Твой player по ООП не является "KinematicBody2D", он должен являться экземпляром Player, короче, отдельный класс. Годо позволяет тебе избежать индивидуального именования классов, но по-хорошему так делать нельзя. Отказываясь от class_name ты отказываешься от правильной типизации.
>завтра ты будешь не ты
>Этот оборот имеет смысл только в большой команде
"Завтра" - это гипербола. Пройти может неделя, месяц или год. И если ты не вундеркинд с фотографической памятью, который помнит абсолютно всё что видел со 100% точностью, то со временем ты обязательно, гарантированно забудешь, из чего состоит и как работает твой собственный код, который ты писал когда-то в прошлом. И в зависимости от твоей организованности, ты либо потратишь кучу времени на изучение своего кода, либо быстро что-то напишешь и потратишь ещё больше времени на поиск ошибок. Учитывая твоё отношение к коду, вероятнее всего второй вариант развития событий. Успехов в поиске ошибок, которых можно было бы избежать, но тебе лень.
>>has_method() должен вызывать лишнюю нагрузку.
>Тебе кажется. У нас тут скриптовый язык
Ну и? Этот метод должен сравнить строки-имена методов или связанные с ними числовые ключи. И чем больше методов в классе, тем больше сравнений в среднем. К чему этот костыль, если можно просто объявить конкретный тип класса?
Другое дело, если бы тебе реально было необходимо обрабатывать несколько совершенно разных классов с одной общей функцией. Я таким образом сделал функцию interact(), которую можно повесить на любой объект, сделав его интерактивным. Но думается мне, что это всё же неправильно и нужно будет переделать...
>Использовать поиск по файлам
И потом вручную исправлять все 100500 вхождений? А потом ловить ошибки из-за того, что нельзя было просто закомментировать строку, нужно было сделать что-то другое, но ты ведь не помнишь, что делает именно этот кусок кода, который ты писал в 2020.
>должен знать, что она пока не написана
Это противоречит принципу инкапсуляции, когда о состоянии какого-то элемента класса знает только сам класс. Если метод класса называется do_some_work(), то он действительно должен сделать какую-то работу, а не пукнуть в консольку и завершиться без выполнения заявленной работы.
>отслеживать весь процесс и знать, где чего не хватает
К счастью, я не обладаю фотографической памятью, а буфер оперативной памяти у меня такой же, как и большинства людей, соответственно я не могу удерживать в памяти десятки "туду" обо всём, чего не хватает моему коду. Пока пишешь одну функцию, ты фокусируешься только на ней, всё остальное вылетает из твоей оперативной памяти и это совершенно нормально для человека. Возможно, ты действительно гений с экстраординарными способностями...
>Ctrl+Shift+F
Мало просто найти, нужно знать, как изменить код в каждом конкретном случае, но скорее всего ты этого не знаешь.
>Терпеть не могу так делать.
Аргументы будут или это субъективное нежелание?
>Сделано всего лишь для того, чтобы присвоение внутри сеттера не вызывало рекурсивный вызов сеттера.
Что мешало сделать это ТОЛЬКО в теле непосредственно сеттера/геттера? Компилятор Паскаля (и, наверняка, компиляторы и интерпретаторы множества других ЯП) так может, почему тогда интерпретатор GDScript такую фигню творит? Вот же, написано программистом "setget", почему интерпретатор не принимает это слово во внимание?
>self.foo = bar
Костыль.
>АПИ игры
Исходя из https://semver.org/lang/ru/ стабильное АПИ может быть только с версии 1.0.0, в то время как версии 0.x предназначены для быстрой разработки, когда АПИ очень часто и сильно меняется. Т.е. окей, после релиза игры нельзя вносить случайные изменения в АПИ, иначе это будет уже 2.0 версия, но на этапе разработки 0.x изменения неизбежны. И чем сложнее их вносить, тем хуже для проекта. Автозагрузка усложняет внесение изменений.
>>796638
>_ready() аналог main() точки входа
Нифига подробного, выход из main = завершение программы.
>напишем так: get_tree().root.call_deferred("add_child",
Зачееееееем...
>get_node("/root/main_menu")
ЗАЧЕЕЕЕМ???
Тебе Хуан дал тебе export ...: NodePath, нет, не хочу экспортировать и тыкать мышкой в инспекторе, хочу костыли велосипедить и потом страдать из-за палок в колёсах своих велосипедов.
>просигнализирует (правда только в ран-тайме)
Ага, а с помощью export ты узнаешь о необходимости подключения какой-то специфичной ноды ещё до запуска проекта.
>Причем ещё в дизайн-тайме.
Вот это и плохо с "синглтонами", 100500 ошибок "скрипт не может быть проанализирован", приходится 100500 раз перезагружать редактор, чтобы исправить ошибки, которые мешают ему прочитать скрипты, в которых больше нет ошибок. Даже кнопка в меню есть "перезагрузить проект", знают прекрасно что редактор багнутый, но, видимо, ничего исправить пока не могут.
>Обошёлся без юзингов, импортов и прочей дремучей легаси
Повторяю, без этого можно только хэллоуворлды нубасам преподавать, для чего-то серьёзного это не подходит. В конце концов, делая сложный проект, ты дойдёшь до того, что будешь в комментариях к заголовку скрипта указывать, от чего этот скрипт зависит, вот только интерпретатор не сможет тебе подсказать, если ты ошибся в своём комментарии или он уже неактуален. А ключевое слово uses, import и т.п. тем и хорошо, что проверяется программой, то есть невозможно наломать дров и не заметить этого.
Да, кстати, главное достоинство слова uses в том, что оно ограничивает (вернее, расширяет) область видимости в рамках одного скрипта. Годо подразумевает, что из каждого скрипта видно вообще все остальные скрипты проекта и всё АПИ движка - это удобно в маленьких проектах, но становится сплошным неудобством и болью в сколь-либо больших проектах, где могут быть тысячи скриптов. Алсо именно из-за отсутствия uses невозможно использовать скрипты из других проектов, не копипастя их вручную, потому что Годо ограничивает видимость одной папкой проекта; на серьёзных ЯП ты можешь использовать юниты из любых папок на диске, расширяя видимость как тебе, лично тебе нужно, а не как задумал какой-то Хуан.
Надеюсь, со временем Хуан одумается и у нас будет какой-то аналог uses в GDScript. Для нубов это можно сделать опциональным: в настройках проекта сделать галочку "каждый скрипт видит все остальные скрипты", которая по умолчанию установлена, а если эту галочку снять, придётся добавлять в скрипты uses something.gd, иначе не запустится или упадёт с ошибкой доступа. В режиме по умолчанию эти ключевые слова игнорируются, т.к. расширяют и без того максимальную область видимости.
>Лол, это и есть типизация. ... но по-хорошему так делать нельзя
Именно потому что так делать можно, я так делать буду. Я прописываю class_name либо если от скрипта кто-то будет наследоваться, либо если планирую это имя где-то употреблять. А от ООП в гдскрипте всё равно лишь огрызки, не вижу смысла гальванизировать труп.
>"Завтра" - это гипербола
Da_ladno.jpg
>гарантированно забудешь, из чего состоит и как работает твой собственный код, который ты писал когда-то в прошлом
Вот поэтому я комментирую почти каждую строчку и веду журнал разработки. С тех пор, как начал это делать, время вспоминания сократилось до "о, точняк, вот же как это было".
>Другое дело, если бы тебе реально было необходимо обрабатывать несколько совершенно разных классов с одной общей функцией.
Ну так да. Именно.
>И потом вручную исправлять все 100500 вхождений?
Погоди-ка, давай разберёмся, о какой ситуации мы говорим.
а) Ключевое слово изменилось, но суть осталась та же. Просто используем поиск и замену.
б) Ключевое слово пропало. Закомментировать все вхождения и посмотреть, что будет. Вряд ли это было что-то сильно важное, раз я его так без проблем выкинул.
в) Изменилось число аргументов или тип данных - в общем, что-то более сложное. А хорошо ли я подумал, прежде чем вообще делать такие изменения в проекте? Ну тогда ССЗБ.
Ещё раз. Изменения в АПИ - это ответственный шаг. Надо заранее подумать и написать всё с заделом на расширяемость и гибкость, чтобы потом не кусать локти, когда проект вырастет и вдруг надо будет что-то поменять.
>Это противоречит принципу инкапсуляции, когда о состоянии какого-то элемента класса знает только сам класс
Не подменяй понятия, речь шла о том, что я знаю о состоянии элемента, а не о том, что знает класс.
>К счастью, я не обладаю фотографической памятью, а буфер оперативной памяти у меня такой же, как и большинства людей, соответственно я не могу удерживать в памяти десятки "туду" обо всём, чего не хватает моему коду.
Так-то и у меня не фотографическая память. Спасает тетрадочка (обычная физическая на 96 листов), куда я записываю все свои туду. И баги туда же. И вообще любые замечания по проекту. Периодически пролистываю недавние записи и переношу на одну страницу все активные туду. Выполненные вычёркиваю. И ещё там же схемы зарисовываю, как что устроено в проекте.
>Мало просто найти, нужно знать, как изменить код в каждом конкретном случае, но скорее всего ты этого не знаешь.
Хммм... И как же мне изменить все обращения к одной и той же функции, которая везде работает одинаково? А, точно! Вот же в комментариях написано, что она тут иначе работает.
>Аргументы будут или это субъективное нежелание?
В данном случае чистая субъективщина. Просто всегда, когда я начинаю прибегать к подобным костылям, вокруг них начинает вырастать целая гора исключений, и в конечном итоге я прихожу к выводу, что изначально надо было выстроить цепочку действий иначе.
>Компилятор Паскаля...интерпретатор GDScript фигню творит
Наверное, потому что для паскалеподобного поведения ему нужно знать, что вызов идёт внутри сеттера-геттера. Компилятору проще с этим, он не ограничен по быстродействию. Предполагаю, что дело как раз в том, чтобы не проверять каждую строчку, а не сеттер ли у нас сейчас выполняется.
Или другое предположение: это лишнее исключение, которое только запутает логику написания кода.
>И чем сложнее их вносить, тем хуже для проекта. Автозагрузка усложняет внесение изменений.
Утверждение про автозагрузку тут не пришей кобыле хвост. Автозагрузка ничем не отличается от обыкновенного АПИ.
>Лол, это и есть типизация. ... но по-хорошему так делать нельзя
Именно потому что так делать можно, я так делать буду. Я прописываю class_name либо если от скрипта кто-то будет наследоваться, либо если планирую это имя где-то употреблять. А от ООП в гдскрипте всё равно лишь огрызки, не вижу смысла гальванизировать труп.
>"Завтра" - это гипербола
Da_ladno.jpg
>гарантированно забудешь, из чего состоит и как работает твой собственный код, который ты писал когда-то в прошлом
Вот поэтому я комментирую почти каждую строчку и веду журнал разработки. С тех пор, как начал это делать, время вспоминания сократилось до "о, точняк, вот же как это было".
>Другое дело, если бы тебе реально было необходимо обрабатывать несколько совершенно разных классов с одной общей функцией.
Ну так да. Именно.
>И потом вручную исправлять все 100500 вхождений?
Погоди-ка, давай разберёмся, о какой ситуации мы говорим.
а) Ключевое слово изменилось, но суть осталась та же. Просто используем поиск и замену.
б) Ключевое слово пропало. Закомментировать все вхождения и посмотреть, что будет. Вряд ли это было что-то сильно важное, раз я его так без проблем выкинул.
в) Изменилось число аргументов или тип данных - в общем, что-то более сложное. А хорошо ли я подумал, прежде чем вообще делать такие изменения в проекте? Ну тогда ССЗБ.
Ещё раз. Изменения в АПИ - это ответственный шаг. Надо заранее подумать и написать всё с заделом на расширяемость и гибкость, чтобы потом не кусать локти, когда проект вырастет и вдруг надо будет что-то поменять.
>Это противоречит принципу инкапсуляции, когда о состоянии какого-то элемента класса знает только сам класс
Не подменяй понятия, речь шла о том, что я знаю о состоянии элемента, а не о том, что знает класс.
>К счастью, я не обладаю фотографической памятью, а буфер оперативной памяти у меня такой же, как и большинства людей, соответственно я не могу удерживать в памяти десятки "туду" обо всём, чего не хватает моему коду.
Так-то и у меня не фотографическая память. Спасает тетрадочка (обычная физическая на 96 листов), куда я записываю все свои туду. И баги туда же. И вообще любые замечания по проекту. Периодически пролистываю недавние записи и переношу на одну страницу все активные туду. Выполненные вычёркиваю. И ещё там же схемы зарисовываю, как что устроено в проекте.
>Мало просто найти, нужно знать, как изменить код в каждом конкретном случае, но скорее всего ты этого не знаешь.
Хммм... И как же мне изменить все обращения к одной и той же функции, которая везде работает одинаково? А, точно! Вот же в комментариях написано, что она тут иначе работает.
>Аргументы будут или это субъективное нежелание?
В данном случае чистая субъективщина. Просто всегда, когда я начинаю прибегать к подобным костылям, вокруг них начинает вырастать целая гора исключений, и в конечном итоге я прихожу к выводу, что изначально надо было выстроить цепочку действий иначе.
>Компилятор Паскаля...интерпретатор GDScript фигню творит
Наверное, потому что для паскалеподобного поведения ему нужно знать, что вызов идёт внутри сеттера-геттера. Компилятору проще с этим, он не ограничен по быстродействию. Предполагаю, что дело как раз в том, чтобы не проверять каждую строчку, а не сеттер ли у нас сейчас выполняется.
Или другое предположение: это лишнее исключение, которое только запутает логику написания кода.
>И чем сложнее их вносить, тем хуже для проекта. Автозагрузка усложняет внесение изменений.
Утверждение про автозагрузку тут не пришей кобыле хвост. Автозагрузка ничем не отличается от обыкновенного АПИ.
Потыкался, вроде гскрипт лёгкий и дока читабельная, но с интерфейсом нихуя не понятно.
itemlist в ширину не хочет растягиваться по размеру, если добавлять "длинные" item`ы.
в panelcontainer + vboxcontainer + button1\2\3\4 вообще я понял хуй переключишь просто стрелками на следующую\соседнюю кнопку.
Анон, ты делаешь на дефолтном control?
Сложный вопрос. В айтемлисте можно настроить обрезку длинных названий, я точно помню. Можно сконструировать свой лист из лэбелов и вертикального бокса внутри скролла - это вообще WPF-стайл, сложный контрол составлять из простых.
В первом варианте это всё равно будет айтемлист и будет угадываться всегда.
Во втором случае кастомизация конечного составного контрола - аболютна, можно реализовать любой вид и поведение.
Делай, как тебе удобнее. Если предпочтёшь второй вариант, помни, что ничего не мешает каждый элемент оставного контрола делать отдельными сценами со своим скриптом.
> в panelcontainer + vboxcontainer + button1\2\3\4 вообще я понял хуй переключишь просто стрелками на следующую\соседнюю кнопку.
Создаёшь сцену item.tscn ей оставляешь включенным выбираемость по стрелкам и табу.
Накидываешь в неё кнопок, пикч, лебелов. Им всем отключаешь выбираемость.
Настраиваешь так, чтобы если элемент получил фокус, все события инпута перенаправляются куда следует: ввод на нажатие кнопки, текст в текстбокс и тд. Таб передаёт фокус следующему элементу.
Вместо просто кнопок добавляешь в бокс инстансы этой сцены-айтема.
> >itemlist
> Этим, походу, никто не пользуется.
Это контрол не для игровых меню, а для всяческих приложений, конфигураторов и утилит. Стандартный список стандартных оконных приложений.
Ну некоторые предпочитают работать в фирмах, а не на себя
> он слишком выбивается по концепции из архитектуры
Это да. Сам заметил. Он выглядит так, будто листбокс из Дельфи эпохи Ильхама перетащили в годот, забыв по пути всё удобное, оставив только дидовский подход к работе со списочными контролами.
> как получить item #1
Из айтема сразу через геттеры вида get_item_...(index) получаешь данные напрямую. Тупо, не ООПно, ну как есть. Потому я тоже предпочитаю конструировать самодельные листы на бокс-контейнерах. Все так делают.
Кстати, если откроешь не ИП, а именно ООО, то доход с него сможешь получать только методом получения от него зарплаты. Лайфхак!
Это когда доход будет. А его не бу дет. Дивиденды с дохода же. А пока нет дохода - зарплата.
Вижу в тебе собрата-гендиректора.
>>796739
Ну я сделал как в прикрепленном, потыкался и понял что к чему.
Не привычно, даже кажется не удобно, вообще пока постараюсь отложить работу с интерфейсом.
>>796763
Можно попробовать собрать, только до пукарни надо добраться.
Может вообще буду отписывать что за хуйню обнаружил-прочитал и что сделал, когда будет хоть что-то кроме нихуя.
> Не привычно, даже кажется не удобно
Когда майкрософт выкатила свой WPF все тоже охуели от того, что за ебанутая хрень, неудобно, непривычно. Спустя годы все тулкиты оконных приложений являются WPF-клонами. Так, чисто, к размышлению инфа.
> отложить работу с интерфейсом
Надолго не советую откладывать. Интерфейс одна из сложных задач. Лучше бы держать интерфейс актуальным игре, чтобы не получилось так, что игра в общем-то готова, но ни менюшек, ни диалогов нет, и делать не хочется. И игра улетает на свалку истории.
Однако!
Есть и такие игры, в которых инвентарь надо закрывать только повторным отжатием I, а при нажатии ESC всё ставится на паузу, в том числе открытые внутриигровые интерфейсные окна.
А теперь внимание вопрос.
Какие подходы вы считаете правильнее? Опишите в терминологии годо ваш подход (Какие ноды? Какие сигналы? Нужно ли помещать что-либо в автозагрузку?) со скринами иерархий нод приветствуется.
>от ООП в гдскрипте всё равно лишь огрызки
Што? Тебе объектов недостаточно? Или объекты - не ООП? Это другие ЯП слишком расширяют ООП ненужным мусором, а так достаточно собрать данные и функции для обработки этих данных в одном месте. Даже специальных ключевых слов языка не нужно.
>Вот поэтому я комментирую почти каждую строчку и веду журнал разработки.
1. Мне это не помогает, например.
2. Комментировать слишком много - тоже антипаттерн, говорящий о том, что код сложно понять без комментариев; следовательно, нужно переписать код так, чтобы он стал понятнее и без комментариев. К примеру, ввести или конкретизировать типы там, где приходится в комментариях описывать, с чем работает кусок кода, потому что типы несут именно эту роль.
Вместо:
>var obj: Spatial // движимые коробки из movable_box.gd
Что-нибудь вроде:
>var obj: MovableBox
И сразу понятно, что это взаимодействие с movable_box.gd.
>тетрадочка обычная физическая
Что мешает использовать программы? Я последний раз к тетрадям в школе прикасался, такая гадость, кожа болит от бумаги, а если не болит кожа - страницы впитывают пот и портятся))
>знать, что вызов идёт внутри сеттера-геттера
>не проверять каждую строчку
Какие строчки? GDScript же компилируется в байт-код, не? В любом случае, сделать одну отметку "это сеттер/геттер" в памяти не проблема, учитывая что код выполняется не построчно, а после полного чтения. Построчное выполнение исходников действительно имело бы массу проблем, но Годо не вчера начали делать и таких наивных реализаций в нём быть не должно. Компилятор Паскаля просто в один проход делает машинный код, а Годо сначала делает байт-код, потом из него, грубо говоря, машинный код (ну, переходы к каким-то участкам ядра Годо, которое в машинном коде). Если бы Годо выполнял наш код построчно, тормоза были бы в разы сильнее, потому что работа со строками сложнее работы с числами.
Так что это просто какое-то неудачное дизайнерское решение, мол, вызывайте явно set_foo(), get_foo() или self.foo, непонятно только зачем тогда объявлять setget для полей, используемых самим классом или преимущественно самим классом.
>Автозагрузка ничем не отличается от обыкновенного АПИ.
Я уже объяснял, что "обыкновенный АПИ" разрабатывается отдельными людьми и меняется редко, а над игрой ты ведёшь активную работу, особенно в самом начале, особенно если новичок. Автозагрузка мешает свободно экспериментировать, а именно свободу таких экспериментов считают преимуществом Годо.
Был бы ты доволен, если бы в твой набор деталек Лего вмешивался строгий дядя и говорил, что вот эти детальки можно размещать только в таком порядке, потому что две недели назад ты с ними поиграл именно в таком порядке, и теперь должен расхлёбывать последствия нечаянно принятых важных решений, о которых тебя никто даже не пытался предупредить? Да, Годо сам по себе игрушка, достаточно простая для освоения, просто так получилось, что в нём можно делать игры. Они сами хвастаются, что Годо сделан на Годо, значит (редактор) Годо - это такая игра с глубоким многосторонним геймплеем)))
>от ООП в гдскрипте всё равно лишь огрызки
Што? Тебе объектов недостаточно? Или объекты - не ООП? Это другие ЯП слишком расширяют ООП ненужным мусором, а так достаточно собрать данные и функции для обработки этих данных в одном месте. Даже специальных ключевых слов языка не нужно.
>Вот поэтому я комментирую почти каждую строчку и веду журнал разработки.
1. Мне это не помогает, например.
2. Комментировать слишком много - тоже антипаттерн, говорящий о том, что код сложно понять без комментариев; следовательно, нужно переписать код так, чтобы он стал понятнее и без комментариев. К примеру, ввести или конкретизировать типы там, где приходится в комментариях описывать, с чем работает кусок кода, потому что типы несут именно эту роль.
Вместо:
>var obj: Spatial // движимые коробки из movable_box.gd
Что-нибудь вроде:
>var obj: MovableBox
И сразу понятно, что это взаимодействие с movable_box.gd.
>тетрадочка обычная физическая
Что мешает использовать программы? Я последний раз к тетрадям в школе прикасался, такая гадость, кожа болит от бумаги, а если не болит кожа - страницы впитывают пот и портятся))
>знать, что вызов идёт внутри сеттера-геттера
>не проверять каждую строчку
Какие строчки? GDScript же компилируется в байт-код, не? В любом случае, сделать одну отметку "это сеттер/геттер" в памяти не проблема, учитывая что код выполняется не построчно, а после полного чтения. Построчное выполнение исходников действительно имело бы массу проблем, но Годо не вчера начали делать и таких наивных реализаций в нём быть не должно. Компилятор Паскаля просто в один проход делает машинный код, а Годо сначала делает байт-код, потом из него, грубо говоря, машинный код (ну, переходы к каким-то участкам ядра Годо, которое в машинном коде). Если бы Годо выполнял наш код построчно, тормоза были бы в разы сильнее, потому что работа со строками сложнее работы с числами.
Так что это просто какое-то неудачное дизайнерское решение, мол, вызывайте явно set_foo(), get_foo() или self.foo, непонятно только зачем тогда объявлять setget для полей, используемых самим классом или преимущественно самим классом.
>Автозагрузка ничем не отличается от обыкновенного АПИ.
Я уже объяснял, что "обыкновенный АПИ" разрабатывается отдельными людьми и меняется редко, а над игрой ты ведёшь активную работу, особенно в самом начале, особенно если новичок. Автозагрузка мешает свободно экспериментировать, а именно свободу таких экспериментов считают преимуществом Годо.
Был бы ты доволен, если бы в твой набор деталек Лего вмешивался строгий дядя и говорил, что вот эти детальки можно размещать только в таком порядке, потому что две недели назад ты с ними поиграл именно в таком порядке, и теперь должен расхлёбывать последствия нечаянно принятых важных решений, о которых тебя никто даже не пытался предупредить? Да, Годо сам по себе игрушка, достаточно простая для освоения, просто так получилось, что в нём можно делать игры. Они сами хвастаются, что Годо сделан на Годо, значит (редактор) Годо - это такая игра с глубоким многосторонним геймплеем)))
>геттеры вида get_item_...(index) получаешь данные напрямую. Тупо, не ООПно, ну как есть.
Лол, а как ещё предлагаешь?
>item_list.item_aaaaa = ...
>item_list.item_bbbbb = ...
Так что ли? Хрень какая-то, зачем элементам списка имена?
Список элементов предназначен для однородных текстовых данных, которым не нужно ничего кроме вывода текста и которые никак не нужно идентифицировать кроме номера строки. При этом этих элементов может быть неизвестное заранее количество. Это очень полезный компонент, например, в меню сохранения и загрузки чего-либо, особенно если слотов для сохранения неограниченное количество. Ты просто выводишь список имён файлов в компонент, а потом получаешь ID строки, которую выбрал пользователь - ВСЁ! Никакой головной боли с созданием уникальных объектов, их настройкой и т.д. Просто загоняешь набор строк и получаешь в ответ номер выбранной строки.
>>796886
>меню паузы: Продолжить, Сохранить, Загрузить, Настройки, Выход
Слишком располагает к сейвскаму. Лучше так:
>Продолжить
>Настройки
>Сохранить & выйти
А загрузку только из главного меню.
В Террарии и Майнкрафте, например, именно так.
>нажимаете клавишу I
>повторным отжатием I
>окно инвентаря
УГ мамонта, которое должно было умереть в 80-х. Чем я от WASD и мыши должен тянуться к I? Биндят самые часто используемые функции в середину клавиатуры, не давая ребиндить, и удивляются потом, что на их игру негативные отзывы. Что мешает использовать таб, или, на крайний случай, близкие к WASD буквенные клавиши? А все остальные меню могут быть вкладками окна инвентаря, потому что нечего создавать кучу отдельных окон.
>игра может встать на паузу или не встать,
>нажмёте ESC, то меню пазы не появится, сначала закроется инвентарь,
>при нажатии ESC всё ставится на паузу,
Я бы попробовал совместить всё в одно меню, открывающееся по Esc, в котором на разных вкладках можно найти и инвентарь, и карту мира, и справку, и настройки, и выход из игры. А пауза может включаться или не включаться в зависимости от выбора игрока в настройках игры, и переключаться отдельной кнопкой в этом меню, если автопауза отключена. Всё просто, ничего лишнего.
>геттеры вида get_item_...(index) получаешь данные напрямую. Тупо, не ООПно, ну как есть.
Лол, а как ещё предлагаешь?
>item_list.item_aaaaa = ...
>item_list.item_bbbbb = ...
Так что ли? Хрень какая-то, зачем элементам списка имена?
Список элементов предназначен для однородных текстовых данных, которым не нужно ничего кроме вывода текста и которые никак не нужно идентифицировать кроме номера строки. При этом этих элементов может быть неизвестное заранее количество. Это очень полезный компонент, например, в меню сохранения и загрузки чего-либо, особенно если слотов для сохранения неограниченное количество. Ты просто выводишь список имён файлов в компонент, а потом получаешь ID строки, которую выбрал пользователь - ВСЁ! Никакой головной боли с созданием уникальных объектов, их настройкой и т.д. Просто загоняешь набор строк и получаешь в ответ номер выбранной строки.
>>796886
>меню паузы: Продолжить, Сохранить, Загрузить, Настройки, Выход
Слишком располагает к сейвскаму. Лучше так:
>Продолжить
>Настройки
>Сохранить & выйти
А загрузку только из главного меню.
В Террарии и Майнкрафте, например, именно так.
>нажимаете клавишу I
>повторным отжатием I
>окно инвентаря
УГ мамонта, которое должно было умереть в 80-х. Чем я от WASD и мыши должен тянуться к I? Биндят самые часто используемые функции в середину клавиатуры, не давая ребиндить, и удивляются потом, что на их игру негативные отзывы. Что мешает использовать таб, или, на крайний случай, близкие к WASD буквенные клавиши? А все остальные меню могут быть вкладками окна инвентаря, потому что нечего создавать кучу отдельных окон.
>игра может встать на паузу или не встать,
>нажмёте ESC, то меню пазы не появится, сначала закроется инвентарь,
>при нажатии ESC всё ставится на паузу,
Я бы попробовал совместить всё в одно меню, открывающееся по Esc, в котором на разных вкладках можно найти и инвентарь, и карту мира, и справку, и настройки, и выход из игры. А пауза может включаться или не включаться в зависимости от выбора игрока в настройках игры, и переключаться отдельной кнопкой в этом меню, если автопауза отключена. Всё просто, ничего лишнего.
> а как ещё предлагаешь?
Нет, не так. Я хочу, чтобы по индексу возвращался цельный элемент, чтобы я делал с ним всё, что захочу.
> for item in list: item.text = "foo"
Так как сейчас тоже можно перечислить, но менее элегантно:
> for i in list.get_item_count(): list.set_item_text(i, "foo")
> Слишком располагает к сейвскаму.
Натоящие сейвскамеры, если им запретишь сейвиться, будут сейвфайлами на диске манипулировать, через самодельные утилиты. А простые игроки будут жаловаться, что до босса далеко идти.
> Я бы попробовал совместить всё в одно меню
Слишком располагает к сейвскаму))
Слишком расточительно сохранять игровой мир целиком в сейв-файл. Нужна какая-то методика, как разделить игровой мир на мир-эталон и мир-корректировку. Мир-эталон это массив данных, вшитый в игру и представляющий собой мир в его изначальном состоянии. Мир-корректировка это данные для сейв-файла, в них будут содержаться исключительно позиции, стейты, инвентари.
Как вам идея? Есть ли что почитать на данную тему?
А как бы ещё организовать откат транзакции применения корректировки на мир, чтобы организовать быстрый возврат персонажа перед битвой с боссом? Ну, как в СУБД. Но на базе словарей.
А впрочем, зачем какие-то транзакции? Я ведь могу просто включить в запрос параметра мира и эталон и корректировку. Эталон ридонли. Корректировка нет. Любой геттер сначала пытается найти переменную в корректировке, если не находит, ищет в эталоне. Любой сеттер записывает данные исключительно в корректировку. Да. Так никакая субд с хтоническими транзакциями не нужна будет. Надо сохранить чек-поинт перед боссом? Копируем корректировку во временную переменную. Если бокк отпиздил игрока, возвращаем корректировку из переменной. Перезагружаем локацию.
Белиссимо!
И еще вопрос вдогонку. Что если в нарушение принципов разделения кода и данных ебашить данные игрового мира в скриптах. Удобно же, ёпт! Разделение кода и данных производить разделяя скрипты, например, в одном скрипте описывается код, в другом данные:
> class_name MyData
> extends Reference
> var data = {}
а потом где-то в игре:
> class_name MyManager
> extends Node # Он будет в дереве
> var my_data := MyData(new).data.duplicate(true) # Поскольку MyData наследуется от Reference, он отдаст данные и уйдёт в ГЦ.
> Удобно же, ёпт!
Удобство в том, что в редакторе скриптов удобно создавать древовидные словари прямо ручками, прямо с вычислением переменных на ходу. Сторонние редакторы, не имея доступа к коду, не позволят такое. Внутри редактора я могу юзать константы и энумы, а в стороннем, будь добр хуярь только текст или числа.
>Годо сделан на Годо
Полнота по Тьюрингу, лол. (вообще, я заметил, ИДЕ часто так делают)
>Что мешает использовать программы?
Тетрадочка ламповее. Так-то ничто не мешает, даже отсутствие второго монитора (а переключаться между окнами - значит мысленно выходить из контекста). Но записывая в тетрадку я перевожу информацию как бы в иное состояние, что позволяет и в голове её иначе представить.
Кароч. Лично мне так нравится и удобно.
А спорить с тобой я уже не хочу, потому что устал, да и аргументы уже по третьему кругу повторяются. Ты молодец и всё правильно говоришь, вот.
Неудобно. Для андроида лучше бы просто интерактивный обработчик скриптов бы запилили, чтобы чисто код в дороге набрасывать. Полноценный там редактор нахуй не нужон.
>сейвфайлами на диске манипулировать
Ну это нужно совсем упороться. Тот же Майнкрафт... Там есть режим хардкор. Да, можно делать бекап мира, и тогда даже когда игра удалит твой мир, ты можешь его восстановить. Но в чём тогда смысл играть в этот режим, если ты ломаешь его суть? Просто играй в обычном режиме, с бесконечным числом жизней. Аналогично с хардкорными персонажами Террарии, которые удаляются игрой после первой смерти (мир остаётся существовать): зачем создавать такого персонажа, если ты планируешь восстанавливать его из бекапа? Просто создай персонажа лёгкой или средней сложности.
>простые игроки будут жаловаться, что до босса далеко идти.
Хех, мда, ну что ж, делай чекпойнты ближе друг к другу, в чём проблема? Я же говорю, запрещать квиклоады, а сохраниться можно в любом месте по нажатию кнопки "выход". Т.е. простой игрок, без манипуляции файлами, может только закрыть игру с автоматическим сохранением мира, и затем загрузиться в том же месте, где вышел. Чтобы не было такого "ой, я проиграл в лотерею, загружу квиксейв, который сделал 30 секунд назад и попробую сыграть снова".
>>совместить всё в одно меню
>Слишком располагает к сейвскаму))
С чего вдруг? Вот в GTA 5 карта мира, меню с информацией, меню настроек и прочее на одной карусели расположены. Ещё где-то подобное видел, не помню уже. Просто не добавляй в это меню квиксейвы и квиклоады, и не будет соблазна сейвскамить.
Вообще, касательно сейвскама, лично я ближе к простым игрокам, т.е. не буду манипулировать файлами в большинстве случаев. Умер и умер, проиграл так проиграл. Но если в игре есть грёбанные ХОТКЕИ специально для сейвскама (F5/F6), то рано или поздно я начну ими пользоваться и это будет меня дико БЕСИТЬ, потому что соблазн загрузиться и поменять ход истории слишком велик - достаточно нажать всего одну кнопку. В то же время манипуляции файлами намного сложнее нажатия хоткея, поэтому заниматься ими я, скорее всего, не буду, а если игра слишком сложная - скорее брошу игру, чем буду пытаться её переиграть тем или иным способом. Вот я о чём, чтобы не было лишнего соблазна там, где можно обойтись без этого, а не чтобы помешать всем любителям сейвскамить.
>сейвфайлами на диске манипулировать
Ну это нужно совсем упороться. Тот же Майнкрафт... Там есть режим хардкор. Да, можно делать бекап мира, и тогда даже когда игра удалит твой мир, ты можешь его восстановить. Но в чём тогда смысл играть в этот режим, если ты ломаешь его суть? Просто играй в обычном режиме, с бесконечным числом жизней. Аналогично с хардкорными персонажами Террарии, которые удаляются игрой после первой смерти (мир остаётся существовать): зачем создавать такого персонажа, если ты планируешь восстанавливать его из бекапа? Просто создай персонажа лёгкой или средней сложности.
>простые игроки будут жаловаться, что до босса далеко идти.
Хех, мда, ну что ж, делай чекпойнты ближе друг к другу, в чём проблема? Я же говорю, запрещать квиклоады, а сохраниться можно в любом месте по нажатию кнопки "выход". Т.е. простой игрок, без манипуляции файлами, может только закрыть игру с автоматическим сохранением мира, и затем загрузиться в том же месте, где вышел. Чтобы не было такого "ой, я проиграл в лотерею, загружу квиксейв, который сделал 30 секунд назад и попробую сыграть снова".
>>совместить всё в одно меню
>Слишком располагает к сейвскаму))
С чего вдруг? Вот в GTA 5 карта мира, меню с информацией, меню настроек и прочее на одной карусели расположены. Ещё где-то подобное видел, не помню уже. Просто не добавляй в это меню квиксейвы и квиклоады, и не будет соблазна сейвскамить.
Вообще, касательно сейвскама, лично я ближе к простым игрокам, т.е. не буду манипулировать файлами в большинстве случаев. Умер и умер, проиграл так проиграл. Но если в игре есть грёбанные ХОТКЕИ специально для сейвскама (F5/F6), то рано или поздно я начну ими пользоваться и это будет меня дико БЕСИТЬ, потому что соблазн загрузиться и поменять ход истории слишком велик - достаточно нажать всего одну кнопку. В то же время манипуляции файлами намного сложнее нажатия хоткея, поэтому заниматься ими я, скорее всего, не буду, а если игра слишком сложная - скорее брошу игру, чем буду пытаться её переиграть тем или иным способом. Вот я о чём, чтобы не было лишнего соблазна там, где можно обойтись без этого, а не чтобы помешать всем любителям сейвскамить.
>Слишком расточительно сохранять игровой мир целиком в сейв-файл.
Нипонел. Ты прям .tscn в сейв-файл пишешь? В сейве должны быть только абстрктные данные, которые загрузчик накатывает на какие-то сущности в сцене, загруженной из res://. Я так считаю. Тогда никакой расточительности, если у тебя обычный шутан, а не какой-нибудь майнкрафт с миллиардами кубиков. Майнкрафт же использует специальные техники сжатия данных, без них никак.
>Мир-корректировка
Рано или поздно ты допустишь ошибку. Забудешь что-то сохранить или загрузить. В результате у игроков сломаются сейвы и игровой процесс, игра станет непроходимой. Алсо нужно учитывать важный момент, что если ты патчишь релизнутую игру, твой патч не должен ломать игрокам сейвы, в идеале, конечно. Вот что будет, если твой патч затрагивает "эталон", делая "корректировку" некорректной?
Ну а так, если сделать какой-то универсальный алгоритм, который не будет подвержен ошибкам и будет обходить проблему патчей, тогда всё норм, такой укороченный сейв должен быть полезен, по идее.
>>796998
>class_name MyData
>extends Reference
Если вместо Reference использовать Resource, то можно будет:
1. Создавать и заполнять объект этого класса прямо через инспектор нод, в тех нодах, которые экспортируют поле Resource.
2. Сохранять заполненный объект в файл и загружать из файла через код или мышкой в инспекторе.
Т.е. Resource в каком-то смысле урезанный Node, единственное что он не умеет - находиться в дереве сцены самостоятельно.
>var my_data := MyData.new().data.duplicate(true) # Поскольку MyData наследуется от Reference, он отдаст данные и уйдёт в ГЦ.
А зачем ты делаешь .new() и сразу освобождаешь его? Это создаёт лишнюю нагрузку на кучу и сборщик мусора в куче. Либо храни этот объект где-то и получай ссылку на него, либо создавай новую копию и храни её как объект. Вместо Data := {} ты можешь создать набор конкретных переменных, чтобы не было лишнего слова. Dictionary по сути тот же ООП объект, создающийся в куче, и я не вижу смысла использовать его вместо Reference, не вижу смысла использовать Reference как одноразовый контейнер для Dictionary.
>Слишком расточительно сохранять игровой мир целиком в сейв-файл.
Нипонел. Ты прям .tscn в сейв-файл пишешь? В сейве должны быть только абстрктные данные, которые загрузчик накатывает на какие-то сущности в сцене, загруженной из res://. Я так считаю. Тогда никакой расточительности, если у тебя обычный шутан, а не какой-нибудь майнкрафт с миллиардами кубиков. Майнкрафт же использует специальные техники сжатия данных, без них никак.
>Мир-корректировка
Рано или поздно ты допустишь ошибку. Забудешь что-то сохранить или загрузить. В результате у игроков сломаются сейвы и игровой процесс, игра станет непроходимой. Алсо нужно учитывать важный момент, что если ты патчишь релизнутую игру, твой патч не должен ломать игрокам сейвы, в идеале, конечно. Вот что будет, если твой патч затрагивает "эталон", делая "корректировку" некорректной?
Ну а так, если сделать какой-то универсальный алгоритм, который не будет подвержен ошибкам и будет обходить проблему патчей, тогда всё норм, такой укороченный сейв должен быть полезен, по идее.
>>796998
>class_name MyData
>extends Reference
Если вместо Reference использовать Resource, то можно будет:
1. Создавать и заполнять объект этого класса прямо через инспектор нод, в тех нодах, которые экспортируют поле Resource.
2. Сохранять заполненный объект в файл и загружать из файла через код или мышкой в инспекторе.
Т.е. Resource в каком-то смысле урезанный Node, единственное что он не умеет - находиться в дереве сцены самостоятельно.
>var my_data := MyData.new().data.duplicate(true) # Поскольку MyData наследуется от Reference, он отдаст данные и уйдёт в ГЦ.
А зачем ты делаешь .new() и сразу освобождаешь его? Это создаёт лишнюю нагрузку на кучу и сборщик мусора в куче. Либо храни этот объект где-то и получай ссылку на него, либо создавай новую копию и храни её как объект. Вместо Data := {} ты можешь создать набор конкретных переменных, чтобы не было лишнего слова. Dictionary по сути тот же ООП объект, создающийся в куче, и я не вижу смысла использовать его вместо Reference, не вижу смысла использовать Reference как одноразовый контейнер для Dictionary.
> В сейве должны быть только абстрктные данные
Разумеется.
Описатель мира - это словарь словарей древовидный, при экспорте в ЖСОН получается около 40 Мб. Не так уж и много по нынешним временам, но это просто непрактично копировать в сейв всё это.
Наигранные игроком корректировки занимают пару сотен КИЛОбайт. Разница налицо.
>сервер
>сейв портился, чанки исчезали
Это уже проблема сервера. Сервер в идеале сам должен делать периодические бекапы. Но эти бекапы - на случай технических проблем, как когда чанки пропадают. Сейчас речь идёт о компульсивной загрузке после "неудачных" игровых событий, которые полностью честные и правильные, но не нравятся игроку.
>>797173
>Получается, что с квиклоадом бы ты прошел игру, а без него - дропнул...
Не факт. Я нормально играю в ту же Террарию, помню, на одной из старых версий убивал всех боссов, т.е. фактически проходил игру. И это без "квиклоадов", потому что в Террарии их нет. В теории можно резко крашнуть игру через диспетчер задач или параметры приложения андроида, чтобы она не успела сохранить неудачный исход, но мне лично никогда не хотелось с этим возиться. Наоборот, в большинстве случаев настолько негативных исходов в игре нет, и ты больше потеряешь из-за квиклоада, чем приобретёшь.
Другой пример, в Half-Life вроде есть квиксейвы и квиклоады по хоткеям, те самые F6/F7. Но я её так и не прошёл. Просто когда обнаружил, что я могу сохраняться буквально каждую секунду, я начал экономить КАЖДЫЙ патрон и КАЖДЫЙ хитпойнт, загружаясь после малейшей ошибки, и это меня настолько выбесило, что я забросил игру и больше не пытался в неё играть.
И ещё пример: в GTA SA я обнаружил способ "легально" заработать миллионы долларов, ставя все деньги на скачки в Лос Сантосе, предварительно купив ближайший дом и сохранившись в нём. Если проиграл - загрузился, вышел из дома, добежал, поставил ещё раз все деньги на самую слабую лошадь (лучший множитель). В результате нескольких попыток у тебя огромная сумма денег, а игра считает это легальным, потому что тебе "просто повезло". Сюжетку-то я как минимум один раз прошёл, но что толку? Мне было скучно иметь все деньги и покупать всё, что вижу. Было бы намного лучше, если бы я не нашёл этого способа накрутки денег и играл "как задумано", т.е. сводя концы с концами до конца игры. Сам себе испортил игру...
> Другой пример, в Half-Life вроде есть квиксейвы и квиклоады по хоткеям, те самые F6/F7. Но я её так и не прошёл. Просто когда обнаружил, что я могу сохраняться буквально каждую секунду, я начал экономить КАЖДЫЙ патрон и КАЖДЫЙ хитпойнт, загружаясь после малейшей ошибки, и это меня настолько выбесило, что я забросил игру и больше не пытался в неё играть.
Ты же поехавший. Таких меньшинство. Я молчал-молчал, но больше не могу терпеть. Нахуй твои советы. Аноны, следуя его советам вы сделаете не игру а говно, в которое никто не будет играть, только этот.
>Хочу сделать программу-опросник, выложить на готм или на итч и опрашивать анончиков.
Чем тебе гугл формы не нравятся? Там всё есть. Твой велосипед максимум свистоперделки графические добавит, зачем?
>Но как мне собирать статистику?
Я не знаю, как устроен итч.ио и его аналоги, скорее всего там нет возможности сохранять данные. В таком случае тебе нужен сервер, на котором у тебя есть доступ на запись данных в файлы или базу данных. Тебе нужно будет разместить свою программу на Годо на этом сервере и/или создать на сервере программу, которая через какой-то интерфейс принимает запросы от твоей программы на Годо. Но это всё небезопасно, недоброжелатели могут изучить, какие запросы ты делаешь и испортить тебе статистику/данные. Короче, лучше рассмотри вариант гугл форм поближе.
>>797108
>переменную SEED, TRANSFORM и т.д,
А к ним нет прямого доступа на запись из кода GDScript?
>Ты же поехавший. Таких меньшинство.
Тогда почему квиксейв/лоады так редко делают в играх?
>Аноны, следуя его советам вы сделаете не игру а говно, в которое никто не будет играть, только этот.
По сути я предлагаю сделать как в майнкрафте и террарии. Игра в фоне регулярно сохраняется, плюс дополнительно сохраняется после нажатия кнопки "выход" или нажатия alt+f4. Загрузиться можно только из главного меню.
Похожее сделано в GTA Online, там тоже постоянное сохранение и сохранение по выходу, загрузка всегда одна на входе. В сингле можно сохраняться в любой момент и сейвскамить, это плохо, но кто сейчас в сингл играет? А в онлайне хорошо сделали, жаль только это всё на серверах держится и без серверов уже не поиграешь.
> Тогда почему квиксейв/лоады так редко делают в играх?
Потому что индустрия пошла на поводу плоечных подпивасников.
>то, что они "задумали", может не подходить всем
В сюжетных играх? Ну тогда не играй, раз не подходит.
Я привёл конкретный пример, в ГТА СА мы играем за натурального нигера, выходца нищих слоёв американского населения. Очень глупо выглядят все эти начальные миссии на велосипедах, за которые тебе дают только "респект", если ты с помощью сейвскама и ставок на электронные скачки "заработал" миллиарды долларов. Ты бы мог выкупить всех этих балласов с потрохами и смоуком, но вынужден проходить тупые миссии, будучи, возможно, самым богатым человеком в мире. Очевидно, разработчики задумывали, что игрок не будет иметь столько денег, по крайней мере в самом начале, а про сейвскам не догадались.
Ну ладно, ГТА в каком-то смысле песочница и ты можешь делать что угодно, но для правильного восприятия сюжетки всё же лучше идти по маркерам, особо не отвлекаясь на посторонние вещи, да?
>Иногда сложный - черезчур сложный, иногда простой - слишком простой.
Не понял, в чём проблема? Сложный - сложный, простой - простой. Или ты имел в виду, что "сложный" слишком простой, а "простой" слишком сложный? Тогда ещё можно понять.
>гта онлайн
>у разрабов может быть свой умысел делать зарабатывание валюты сложным. Чтобы ты покупал ее за реал.
Играю иногда в ГТА Онлайн, не вижу ни единой причины покупать валюту за реал, тем более после ДЛЦ Кайо-Перико. Тем более не вижу причины пытаться накрутить деньги с помощью читов и читеров: деньги очень легко добываются внутриигровыми способами и их буквально не на что тратить, кроме дурацких одинаковых машин, которые лично мне не интересны. Алсо вся Суть™ ГТА Онлайн заключается в заработке денег, и после того, как ты заработаешь, купишь за реал или накрутишь определённую сумму, игра теряет всякий смысл и её можно удалять или ждать следующего ДЛЦ. Так что по сравнению с классическими ММОРПГ, где без доната ты ничего сделать не можешь, ГТА Онлайн очень даже дружелюбна к игрокам. Просто игроки - тупая школота и быдло, предпочитающие читы и пвп нормальной спокойной игре, но это уже совсем другая история.
Чёт мы уже скатываемся в обсуждение игр...
>то, что они "задумали", может не подходить всем
В сюжетных играх? Ну тогда не играй, раз не подходит.
Я привёл конкретный пример, в ГТА СА мы играем за натурального нигера, выходца нищих слоёв американского населения. Очень глупо выглядят все эти начальные миссии на велосипедах, за которые тебе дают только "респект", если ты с помощью сейвскама и ставок на электронные скачки "заработал" миллиарды долларов. Ты бы мог выкупить всех этих балласов с потрохами и смоуком, но вынужден проходить тупые миссии, будучи, возможно, самым богатым человеком в мире. Очевидно, разработчики задумывали, что игрок не будет иметь столько денег, по крайней мере в самом начале, а про сейвскам не догадались.
Ну ладно, ГТА в каком-то смысле песочница и ты можешь делать что угодно, но для правильного восприятия сюжетки всё же лучше идти по маркерам, особо не отвлекаясь на посторонние вещи, да?
>Иногда сложный - черезчур сложный, иногда простой - слишком простой.
Не понял, в чём проблема? Сложный - сложный, простой - простой. Или ты имел в виду, что "сложный" слишком простой, а "простой" слишком сложный? Тогда ещё можно понять.
>гта онлайн
>у разрабов может быть свой умысел делать зарабатывание валюты сложным. Чтобы ты покупал ее за реал.
Играю иногда в ГТА Онлайн, не вижу ни единой причины покупать валюту за реал, тем более после ДЛЦ Кайо-Перико. Тем более не вижу причины пытаться накрутить деньги с помощью читов и читеров: деньги очень легко добываются внутриигровыми способами и их буквально не на что тратить, кроме дурацких одинаковых машин, которые лично мне не интересны. Алсо вся Суть™ ГТА Онлайн заключается в заработке денег, и после того, как ты заработаешь, купишь за реал или накрутишь определённую сумму, игра теряет всякий смысл и её можно удалять или ждать следующего ДЛЦ. Так что по сравнению с классическими ММОРПГ, где без доната ты ничего сделать не можешь, ГТА Онлайн очень даже дружелюбна к игрокам. Просто игроки - тупая школота и быдло, предпочитающие читы и пвп нормальной спокойной игре, но это уже совсем другая история.
Чёт мы уже скатываемся в обсуждение игр...
>А к ним нет прямого доступа на запись из кода GDScript?
Я как полагаю, там вообще у шейдеров вообще нет способа сохранения переменных и получение их. Видимо только построение карт с кодированием значения в цвет пикселя
Я бы не сказал. Сейвскам механика ущербна тем, что вы по кд сейвишься, её обычно приходится резать, по типу сохранением только вне комбата или у аля костров. Иначе игрок ф5 ф5 ф5 ф5 юзать, а если забыл и не сейвился, приходится играть тоже самое. В общем сама концепция геймдизайна плохая.
мимодругой анон
>Там есть режим хардкор
Очень неудачный пример. Ты же говоришь о том, чтобы запретить сейвскамить. Не дать игроку выбор - сейвскамить или нет - а просто запретить. А режим как раз именно что выбирает игрок.
>"ой, я проиграл в лотерею, загружу квиксейв, который сделал 30 секунд назад и попробую сыграть снова"
Ненавижу, блять, рандомные события в играх. Лишают меня чувства, что игровой мир зависит от меня.
>>797177
>должны
Ты опять начал рассказывать другим, как они должны проектировать свои игры.
>в Half-Life вроде есть квиксейвы и квиклоады по хоткеям, те самые F6/F7. Но я её так и не прошёл.
А я дропаю шутан, если в нём нет квиксейвов. Потому что экономлю каждый патрон и стараюсь поддерживать максимальное ХП, насколько это возможно.
А в первой Халве есть бесячие снайперы, которых надо убивать точным броском гранаты в окно, и хуй знает, как это вообще без квиксейвов можно пройти, с тамошней кривой физикой гранат.
Чекпоинты нужны. Квиксейвы, если жанрово это принято, нужны. Для любителей - отдельный режим сложности с запретом квиксейвов.
Ну смотри, если ты знаешь шарп и пришёл в ГД из ентерпрайз-галеры, где поднимал сервисы на бэке, то тогда лично тебе перспективнее писать на шарпе. Ты просто напишешь ещё один бэк, фронтом для которого будет годот.
Ну а если ты пришёл из бэ, то перспективнее выучить гд скрипт, он простой, учится за неделю, и уже сможешь сделать свою первую игру.
Ну впрочем ожидаемо
>Фиксанули производительность в 4.0?
Что ты имеешь в виду? Всё норм с производительностью.
>Есть ли полноценная не костыльная поддержка нормальных языков
Всегда была, но в 4.x C# не будет до релиза 4.1.
>а не уебанского и богомерзкого gdscript'а?
Это троллинг тупостью? Нормальный СЯП, лучше JS.
>Можно ли уже трогать и пилить что-то в продакшн?
На 3.x всегда можно было, а на 4.0 - жди как минимум Beta.
>сохранения состояния шейдера партиклов? Если конкретно переменную SEED, TRANSFORM и т.д, которые при запуске партикла генерируются
>>797200
>у шейдеров вообще нет способа сохранения переменных и получение их
А это ты читал?
https://docs.godotengine.org/en/stable/tutorials/shaders/shader_reference/particle_shader.html
>...transform feedback shaders can build on themselves each run, unlike other shaders that discard the data they have calculated once they draw to the frame buffer.
>Render mode
>keep_data - Do not clear previous data on restart.
Дык есть минимальная реализация подобного?
> Что ты имеешь в виду? Всё норм с производительностью.
2д свет и пост процессинг убивали нахуй производительность буквально в разы, особенно с тайлмапами. А треды на гихабе с этими проблемами висели не решенным 2 года назад, сейчас хз как. И я даже не затрагиваю недоделанный 3д рендер.
> Всегда была, но в 4.x C# не будет до релиза 4.1.
Шарпы работали очень костыльно и неудобно, и я не говорю о сетапе, а именно о работе.
> Это троллинг тупостью? Нормальный СЯП, лучше JS.
Js отлично подходит под свои задачи, сам язык тоже очень приятный, лучше ебанного питона на котором ничего кроме несвязанных микроскриптов я бы писать не стал. В gdscript как только уходишь от микроскриптов и начинаешь писать какую-то систему, сразу сталкиваешься с ограничениями языка. Или какими-то уебанскими реализациями, как например ивенты. Это конечно вкусовщина, но все равно хочу норм язык заточенный под игры, а не то что имеем.
> На 3.x всегда можно было, а на 4.0 - жди как минимум Beta.
Ну раньше возможности были очень ограничены, особенно у меня вопросы именно к работе рендринга. Тип игры без постпроцессинга конечно можно делать, но с ними многие игры выглядят лучше, а некоторые напрямую на них опираются.
Не подумайте, что я какой-то хуй с треда движкосрачей. Годот вполне интересный движок, и я бы рад начать на нем что-то пилить, если когда-нибудь фиксанут проблемы, которые мне в нем не нравятся. И я на него смотрю не из-за того, что хочу обосрать, а из-за того, что в других движках тоже говна хватает, а хочется конфетку.
В чем преимущества по сравнению с ue/unity?
Мда, толстота и репорт за движкосрач, канешн, но вот это любопытно
> уебанскими реализациями, как например ивенты
Что именно уебанского ты нашёл в местных ивентах?
Легковесность (50 мегов бинарник достаётся за полмикросекунды, в руке лежит как влитой), опенсорц лицензия (никому ничего не должен, не обязан).
>начинаешь писать какую-то систему, сразу сталкиваешься с ограничениями языка
Примеры, нам нужны примеры. Я вот пробовал писать системы и ограничений языка пока не ощутил. Разве что напрягает отсутствие статически типизированных массивов и словарей, и необычная, нелогичная работа свойств класса (setget). Наверное, ты просто избалован излишествами всяких C++, где каждую задачу можно решить сотнями разных свистелок и перделок.
>ивенты
А что ты предлагаешь вместо них? Это же классика, это знать надо. Событийно-ориентированное программирование и всё такое. Как ты без ивентов собрался игру делать? Или тебе не нравится функция connect(), которую вызвать надо?
>норм язык заточенный под игры
Выбирай: https://github.com/Vivraan/godot-lang-support/
Вот Lua: https://github.com/gilzoide/godot-lua-pluginscript
>игры без постпроцессинга конечно можно делать, но с ними многие игры выглядят лучше
Постпроцессинг - последний этап в разработке игры, как нанесение глазури и посыпки на торт. А пока ты будешь основу игры делать, 4.0 выйдет в релиз, да и 4.1 тоже, игры же годами делаются. А постпроцессинг, это так, мелочь на полгодика, совсем не стоит о ней задумываться в начале столь долгого пути (10+ лет минимум).
>Годот - опенсорс движок с открытой лицензией МИТ
Это нельзя назвать киллер-фичей, потому что существует множество других опенсорс движков. Да, некоторые под GPL, но позволяют делать закрытые игры, GPL действует только на модификации ядра движка. В остальном движков полно, живых и не очень.
>>797366
>Киллер-фичи есть какие-нибудь?
Организация сцен/нодовая система лучше, чем в юнити, но по этой же причине непривычна перекатывающимся с юнити (был тут кто-то, кто активно ругал ноды/сцены в Годо, сравнивая с юнити). В Годо нет концепции "префаб", здесь роль префаба выполняет упакованная сцена, а сценой может быть любая нода с потомками. Ну, на словах сложно объяснить, как это работает и почему это круто, лучше самому попробовать. Просто это очень удобно и открывает массу возможностей... Хотя лично я сталкивался с ограничениями или багами, дико снижающими производительность редактора, но, по-моему, это уже исправили, т.к. с тех пор прошло много версий и я открывал более сложные сцены, чем тогда. Просто не нужно спамить десятками тысяч нод, в таких ситуациях ядро процессора давится из-за однопоточности нодовой системы, т.к. каждый тик происходит обход всего дерева. Как оно в 4.0 - не знаю, не тестил.
Короче, есть преимущества, есть недостатки, всё как у всех.
>Зачем он вообще нужен?
Для новичков и мелкоигр на джемы и итч.ио хорошо заходит.
Спасибо за разъяснение, но если многопотока нет - в топку.
Хотя если опенсорс, то можно поебаться и прикрутить его самостоятельно, но это такое
> но если многопотока нет
Многопоток есть, но дефолтный искаробочный майнлуп (дерево сцены) работает в одном потоке. Движок не запрещает реализовать свой майнлуп, но этого пока никто не делает, потому что подавляющему большинству разрабов достаточно дефолта.
>>797388
Два билда нужно будет делать тебе только в том случае, если у тебя появятся игроки на 32-хбитной винде.
> многопоток
В настройках проекта можно рендеринг в мультипоточность переключить. По умолчанию однопоток.
И все свои вычисления в скриптах можно через потоки делать, весь инструментарий для этого имеется, треды, мьютексы, семафоры.
>А где преломление длинных волн?
Что ты от меня хочешь, я пытался из базовых компонентов Годо и текстуры, нарисованной в пейнте, сделать что-то похожее на небо, шейдеры пока боюсь трогать. Пытался сделать так, чтобы текстура из голубой в полдень становилась жёлтой к вечеру и чёрной к полночи, но не получилось сделать это красиво, только сплошная заливка. Как сделать градиенты вокруг солнца - без понятия.
>>796979
>Там андроиде релиз намутили
1 апреля потестил, пикрил. У меня заработал только с GLES 2, попытка открыть проект с GLES 3 выдаёт чёрный экран, хотя видеочип поддерживает "OpenGL ES 3.2 build". Интересно, что вращение камеры пальцем работает прекрасно без изменений в коде, хотя в редакторе Годо вращать сцену (или перемещать что-либо на ней) пальцем невозможно - вместо этого идёт выделение рамкой. FPS 19, GPU была загружена на 100%, а CPU отдыхал, ну оно и понятно, слишком много отдельных мелких объектов вдалеке. Кстати, чёт я так и не понял, как сделать так, чтобы объекты на фоне выглядели в дымке и не выделялись на фоне неба. Рисовать дымку спрайтами?
А вообще, знаете, я думаю опять попробовать 2D. Последнее время играл в разные 2D игры и вижу, что они тоже бывают очень интересными и богатыми на геймплей. А в 3D я всё равно не смогу нарисовать ничего стоящего, вот это детское лоуполи со сплошной заливкой никому не нужно, включая даже меня. Тем более что я хотел, всё же, фокусироваться на ИИ, а не на декорациях, просто меня прокрастинация замучила... Прошлый раз забил на 2D только из-за того, что не смог адаптировать генерацию карты на мелкие тайлы (размером с персонажа), психанул и забил на игры вообще.
В детстве летними курортными вечерами долго пытался поймать неуловимый зелёный луч. Так и не поймал.
Ну вот смотри, пикрелейтед искаробочное процедурное небо. У него есть градиент неба из двух цветов, от зенита до горизонта, и цвет Солнца. Ещё есть позиция Солнца. Увязываем эти параметры в контроллер (менеджер) времени суток, который двигает позицию Солнца, корректирует цвета согласно времени. Всё просто же. Попробуй.
>Всё просто же. Попробуй.
Ты троллишь так или правда дураком меня считаешь? Алсо, ты сам-то пробовал это использовать? Пробовал гуглить, как оно устроено? Я попробовал это первым же делом, до изобретения велосипеда со сферой и текстурой. Эта встроенная хрень рендерится на процессоре после каждого изменения. В результате, если ты хочешь обновлять небо достаточно плавно, игра будет натурально пропукиваться прямо как в движкосраче описывают, только по-настоящему. Да даже если обновлять редко, пропук на каждое такое обновление, а скачкообразное изменение неба выглядит максимально некрасиво. Также, если снизить качество неба, само по себе небо выглядит норм, но в зените образуется чёрная дырень, которую никак не убрать, только закрывать чем-нибудь вроде облаков. А ещё там проблемы с излучением от солнца, неба и земли, и какими-то параметрами, не помню уже, но это мелочи по сравнению с пропуками и чёрной дырой над головой.
Godot 4.0 обещают какой-то новый шейдер, который можно будет писать специально для неба, вместо этой старой фигни.
Вообще, лучше бы по 2D чё посоветовали. Меня лично не вдохновляет видеть всю карту плоской в виде квадратиков крыш и круглых человечков, но делать псевдо 3D как в GTA 2 я не знаю как, типа, использовать 3D рендерер? Но это значит опять совокупляться с созданием мешей из ничего, натягиванием текстур, ручным группированием... Хочется вот прям максимально всё упростить, чтобы было как конструктор Лего... Но не GridMap, он какой-то недоделанный, это я уже проходил.
> Вообще, лучше бы по 2D чё посоветовали.
Это всё строго индивидуально. Я делал двадэ джва года, но разочаровался в самом принципе двадэ. Я сейчас рассматриваю вариант двадэ игор в тридэ сценах, ну, как старые стратежки, знаешь? Там не нужны детализированные модельки. На всё смотришь издалека.
> Ты троллишь так или правда дураком меня считаешь?
С дивана спизднул. Сорян. Я тут погуглил. Есть варианты самодельного неба, прям с облаками и годреями. Но нагрузочка на систему тоже будь здоров.
>нагрузочка на систему тоже будь здоров
Тогда не надо. Меня вообще удивило, что на моём старом ПК 100-200+ фпс, а на достаточно свежем телефоне <20 фпс. Из сильно грузящих игр, для сравнения, Майнкрафт играбелен (30-40+ фпс) и выглядит прям как на ПК, даже дальность прорисовки не пришлось снижать в ноль, а тут прям беда какая-то...
>вариант двадэ игор в тридэ сценах
Ну вот ГТА 1/2 как я понимаю и есть оно. Эх... Типа, сделать 2D геймплей с прибитой к потолку камерой? А часть мелких моделек можно будет заменить спрайтами. И поскольку персонажи сами прицеливаются по высоте (игрок только вращает персонажа по вертикальной оси), многое упрощается (вроде бы). Но тогда придётся делать фичу с просвечиванием персонажа и объектов через более крупные объекты типа мостов, деревьев, крыш домов (в ГТА 2, как я помню, отсутствие просвечивания сильно мешало, а лестницы сбивали с толку). Всё же чисто 2Д проще из-за отсутствия перекрытия объектов объектами.
>разочаровался в самом принципе двадэ
Что именно разочаровало? Я лично 2Д не хотел трогать из-за того, что оно сильно ограничивает возможности, не даёт действовать в трёхмерном пространстве, и приходится выбирать между "всё в одной плоскости сверху" и "всё в одной плоскости сбоку", либо изобретать велосипеды с комбинацией видов и переходами (я много об этом думал в своё время, пытаясь продумать что-то вроде Диггера в двумерной проекции, но с трёхмерным миром, в итоге забил из-за очень высокой сложности восприятия такого мира).
> Меня вообще удивило, что на моём старом ПК 100-200+ фпс, а на достаточно свежем телефоне <20 фпс.
Потому что мобильная архитектура - не архитектура. Гигагерцы там есть, а гигафлопсов нет.
> 2Д проще из-за отсутствия перекрытия объектов объектами
> Что именно разочаровало?
А там обратная задача. Если надо организовать симуляцию частичного перекрытия - наебёшься.
>пропукиваться прямо как в движкосраче описывают, только по-настоящему
А что, пропуки в годотьке не настоящие что-ли?
>Потому что мобильная архитектура
Дело не в архитектуре, а в ограничениях, в которых приходится разрабатывать хардварные алгоритмы. Десктопная видеокарта может потреблять очень много электричества и не беспокоиться о температуре. Мобильный чип мало того что должен максимально экономить энергию, он ещё и не имеет активного охлаждения. Поэтому там, где десктопная видеокарта брутфорсит, мобильный чип должен быть умнее. Но к умным алгоритмам нужен умный подход, а Годо тупо спамит дроуколлами... да и я сам модельки никак не оптимизировал, но в теории это мог бы делать сам движок (перестройка геометрии в зависимости от расстояния).
>надо организовать симуляцию частичного перекрытия
ПРОСТО рисуешь все деревья на отдельном слое выше персонажей, машин и других низких объектов, а коллизии деревьев делаешь в разы меньше их спрайтов, создавая иллюзию наличия ствола. Здания вообще тупо из слоёв, отключил слой крыши и увидел планировку самого верхнего этажа. Или ты про изометрию? Изометрия да, но её лучше на специализированных движках делать, РПГ мейкер там и т.д.
В тридэ точно так же как ты описал для двадэ. Разбиваешь модели по слоям. Если рейкаст от камеры до перса не проходит, то он возвращает АйДи меша, мешу посылаем сигнал отключиться. До тех пор, пока рейкаст не достигнет перса.
А в двадэ не спроста отказались от изометрии, в ней приходится не просто послойно рубить спрайты а ещё и резать на куски спрайт в одном слое, и каждый кусок на своём дополнительном слое, чтоб, когда перекрыты ноги - торчал торс и наоборот.
Короче говоря - это всё вкусовщина. Кому-то нравится ебаться с виртуозной нарезкой спрайтов, а кому-то ебаться с четырёхмерными квартернионами.
>>797625
Вас, ебанатов в отдельный загон и выгнали из-за вот этого: там где в юнити у вас "недостаточная оптимизация" и "разраб школьник", в годоте для аналогичных вещей у вас "годот говно" и "Хуан лох". А когда вам показываешь решение в юнити, у вас "ммм, заебись решение, движок позволяет даже такооое?", а когда вам показываешь аналогичное решение в годоте у вас "костыли! Хуан не шмог! ты накостылил!"
Это примитивнейший щитпостинг готтентотской логикой. До создания движкосрач-треда я сидел в обоих движкотредах и учил оба движка и задавал примерно те же нубские вопросы.
Поэтому - вон из треда в свой загон, быдло!
>отказались от изометрии
Кто отказался? Когда? Хотя, конечно, чисто плоских игр выходит больше (платформеры, квадратные рогалики, космосимы)...
>резать на куски спрайт в одном слое
Нууу... я бы так не сказал. Разве не достаточно просто рисовать персонажа между слоями, которые находятся выше и ниже от него по экрану? Если дерево на клетку выше, оно в слое ниже, рисуется раньше персонажа. Если дерево на клетку ниже, оно в слое выше, рисуется позже игрока и перекрывает его. Просто в изометрии, в отличие от топ-дауна, нужно смотреть на диагонали, а не на строки, в остальном алгоритм по идее одинаков. Правда, не знаю, как это сделать на Godot, т.к. тут придётся ноды персонажей перемещать по дереву сцены между тайлмапами, меняя порядок отрисовки.
Если что, изометрию я пробовал делать, квадратную в Inkscape и гексагональную на самодельном движке. Но сортировку так и не сделал, было лень и архитектура движка не позволяла свободно менять порядок отрисовки (зато абстрактненько!).
>у вас
Ходят слухи, что движкосрачер-годоненавистник всего один, просто он упёртый и всё никак не сдаётся. Остальным скучно этим заниматься, слишком однообразный срач, неоткуда взять свежие аргументы и боевые картинки. Думаю, он же и юнити обсирает, когда не находит оппонентов для холивара.
Ну ты же триггернулся, остальным поебать. Значит за этим что-то есть
Движкосрачера не надо кормить. Его надо молча репортить.
>Разве не достаточно просто рисовать персонажа между слоями, которые находятся выше и ниже от него по экрану? Если дерево на клетку выше, оно в слое ниже, рисуется раньше персонажа.
После этой некомпетентной бредятины неудивительно, что ты начинаешь выискивать каких-то движкосрачеров. Когда просто есть люди, которые хлебнули говна с годотом и отговаривают им пользоваться.
Художественный вкус, конечно, нужен, но в 3D ещё и чисто технические сложности. Я много лет пытался сделать няшную тяночку, но всё время спотыкаюсь об торчащие углы полигонов и прочие артефакты, из-за чего идеально гладкое округлое тело просто не получается, приходится начинать с нуля. А лицо вообще ад, там столько плотно расположенных треугольников должно быть, что я даже не знаю как лупы правильно соединить, все эти инструкции и скриншоты сеток не помогают. С анимацией ещё сложнее, полигоны будет колбасить только так...
Так что если выбирать, лучше уж изометрия, отрендеренная с 3Д моделек, как в старых играх типа Fallout, чем труъ 3Д. В таком маленьком разрешении все эти косяки геометрии не видно, а поскольку это статичные спрайты, видеокарте не приходится давиться твоими косячными полигонами с артефактами.
Алсо вектор, растр и пикселяч намного проще технически, чем 3Д, там сложно накосячить из-за инструментов. Да, не получится отрендерить домик с разных углов или анимировать персонажа как тряпичную куклу. Но зато порог входа значительно ниже.
Тест производительности.
https://4pda.to/devdb/oppo_reno2_z
Штош, буду делать 2D игру про 1 прыгающий спрайт.
Да шучу я, шучу, для 2D норм производительность.
>>797760
>отговаривают им пользоваться
Не нравится - не пользуйся. Зачем кого-то отговаривать?
Как дети малые обижаетесь на прикладные программы.
Очень странно, но сбросив масштаб спрайта в (1, 1) мне удалось сохранить ФПС около 60 примерно на 3500-4000 движущихся спрайтов, интересно. Падение до 30 ФПС примерно на 6000-7000, точно не помню. В целом, мне кажется, производительность упирается в мощность одного ядра ЦПУ, т.к. дальше нагрузка на ГПУ не достигает 100% несмотря на падение ФПС, а нагрузка на ЦПУ никогда не превышала 25%. Также странно, что нагрузка получается как на четырёхядерном процессоре, хотя у меня
>6x ARM Cortex-A55 @ 2000 МГц
>2x ARM Cortex-A75 @ 2200 МГц
Т.е. при максимальной нагрузке на ядро он должен работать как двухъядерный... Ладно, это зависит от системных настроек, которые без рута вроде никак не поменять. К тому же телефон и так нагрелся как от тяжёлой 3D игры, лол, в 2D играх такого не замечал (кроме некоторых игр на юнити, там прям сковородка + фпс ниже играбельного, помню одно время много в такое играл страдал).
Впрочем, 30 ФПС для мобильных 2D игр в самый раз, а три тысячи спрайтов (всё ещё 60 ФПС) я даже не знаю как достичь в реальной игре, разве что в жанре буллет хелл такое возможно. Тем более что в большинстве игр основная часть "спрайтов" будет статично в тайлмапе, а там какие-то свои оптимизации. Просто видел такие тесты с движущимися спрайтами на других движках...
Ах, да, там не только спрайты, там ещё одна Node2D с каждым спрайтом, так что это не совсем чистый тест - дерево сцены было нагружено в два раза больше необходимого. А как мы помним, дерево сцены работает на единственном ядре...
Ещё бы управление было адекватным на Андроиде, а то замучаешься тыкаться, а некоторые функции (выпадающее меню по правой кнопке, сдвиг сцены, вращение 3Д сцены) вообще недоступны. Я могу подключить клавомышь, но в чём смысл? Это получится ПК с неудобно маленьким дисплеем. Они заявили этот релиз как "сфокусированный на планшетах", но разве планшеты на Андроиде ещё не вымерли как класс устройств?
Не буду оверквотить гринтекстом. Просто бери мэйкхуман для тяночек и бесплатные паки анимаций из интернетов. Вопрос с человеческими персами закроешь. Конечно, придётся где-то дополнительно искать модельки животных, растительности. Где-то бесплатно, где-то за копеечку. Ну уж домики-то деревянные кубами самостоятельно намоделить сможешь?
Ты главное пойми. Если ты хочешь делать игру - делай игру и таскай арт отовсюду. Если ты хочешь делать арт - делай арт.
А то развелось, блять, нытиков:
> я хочу делать игру, но у меня не получааается!
> что именно не получается?
> модель тяночки не получаааетсяяя!11
А игры тут причём?
И ещё добавлю. Игру нужно делать такую, чтобы в её прототип на кубах и квадратах было интересно играть.
А уж графониум чтобы шёл приятным бонусом.
Вообще, с одной стороны, это правильная идея. А с другой - существование контрпримеров говорит нам, что это не абсолютная истина. Полно игр, где играешь в графон; убери приятный визуал, и сразу весь интерес пропадёт. Многие игры делаются ради атмосферы, которая создаётся в первую очередь визуальными средствами.
Кстати есть ещё причина, почему двадэ проще тридэ для одинокого разработчика. Для двумерного уровня нужно заполнить объектами площадь, а для трёхмерного - объём. В объёме помещается больше контента, а значит больше труда нужно затратить на его создание. Это при том, что позиционирование в трёх измерениях на плоской проекции экрана выполняется медленнее, чем двумерное позиционирование там же.
Такие дела. Никаких художеств, простая математика.
зашёл тредик почитать (давно не заглядывал), решил высказаться.
> Я вот пробовал писать системы и ограничений языка пока не ощутил.
Я честно не вспомню сейчас все претензии, которые у меня были два года назад, но все же. Никакая реализация ООП, нам дали классы, возможность их наследования, но человеческого полиморфизма тут нет. Можно конечно попробовать использовать их просто как структуры данных и пытаться кодить процедурно, но система нодов совсем к этом не располагает. Из-за этого ощущение, что язык просто не доделан или хуёво спроектирован. А пытался я сделать аля диаблойдную систему лута.
> Наверное, ты просто избалован излишествами всяких C++, где каждую задачу можно решить сотнями разных свистелок и перделок.
Я бы понял, если бы ты привёл в пример шарпы, джаву или тот же питон, но избалован плюсами? Язык должен быть гибким, это любому кодеру понятно.
> А что ты предлагаешь вместо них? Это же классика, это знать надо. Событийно-ориентированное программирование и всё такое. Как ты без ивентов собрался игру делать? Или тебе не нравится функция connect(), которую вызвать надо?
Нет, ивенты это заебись, я против них ничего плохого не имею, кроме злоупотребления ими. Мне не нравится конкретно как они реализованы в гдскрипте, где ты ко всему соединяешься и обращаешься через строки.
> Вот Lua: https://github.com/gilzoide/godot-lua-pluginscript
Спасибо, как-нибудь потрогаю.
> Постпроцессинг - последний этап в разработке игры, как нанесение глазури и посыпки на торт.
Не согласен, постпроцессинг может напрямую определять визуальный стиль игры и быть его фишкой. Например Return of the Obra Dinn или Inmost, где отсутствие постпроцессинга значительно бы поменяло восприятие игры.
> А пока ты будешь основу игры делать, 4.0 выйдет в релиз, да и 4.1 тоже, игры же годами делаются. А постпроцессинг, это так, мелочь на полгодика, совсем не стоит о ней задумываться в начале столь долгого пути (10+ лет минимум).
Даже занимаясь проектом пару часов в неделю можно выпустить пару мелкоигр за год. Хотя если ты делаешь в соло ГТА 6, то твои слова имеют смысл.
И я опять же говорю, что я за годот. Уже сейчас это отличный движок для небольших игр. А если его доведут до ума, то мы получим прекрасный движок с открытой лицензией. хотя дроч автора годота на питон я не разделяю
> Я вот пробовал писать системы и ограничений языка пока не ощутил.
Я честно не вспомню сейчас все претензии, которые у меня были два года назад, но все же. Никакая реализация ООП, нам дали классы, возможность их наследования, но человеческого полиморфизма тут нет. Можно конечно попробовать использовать их просто как структуры данных и пытаться кодить процедурно, но система нодов совсем к этом не располагает. Из-за этого ощущение, что язык просто не доделан или хуёво спроектирован. А пытался я сделать аля диаблойдную систему лута.
> Наверное, ты просто избалован излишествами всяких C++, где каждую задачу можно решить сотнями разных свистелок и перделок.
Я бы понял, если бы ты привёл в пример шарпы, джаву или тот же питон, но избалован плюсами? Язык должен быть гибким, это любому кодеру понятно.
> А что ты предлагаешь вместо них? Это же классика, это знать надо. Событийно-ориентированное программирование и всё такое. Как ты без ивентов собрался игру делать? Или тебе не нравится функция connect(), которую вызвать надо?
Нет, ивенты это заебись, я против них ничего плохого не имею, кроме злоупотребления ими. Мне не нравится конкретно как они реализованы в гдскрипте, где ты ко всему соединяешься и обращаешься через строки.
> Вот Lua: https://github.com/gilzoide/godot-lua-pluginscript
Спасибо, как-нибудь потрогаю.
> Постпроцессинг - последний этап в разработке игры, как нанесение глазури и посыпки на торт.
Не согласен, постпроцессинг может напрямую определять визуальный стиль игры и быть его фишкой. Например Return of the Obra Dinn или Inmost, где отсутствие постпроцессинга значительно бы поменяло восприятие игры.
> А пока ты будешь основу игры делать, 4.0 выйдет в релиз, да и 4.1 тоже, игры же годами делаются. А постпроцессинг, это так, мелочь на полгодика, совсем не стоит о ней задумываться в начале столь долгого пути (10+ лет минимум).
Даже занимаясь проектом пару часов в неделю можно выпустить пару мелкоигр за год. Хотя если ты делаешь в соло ГТА 6, то твои слова имеют смысл.
И я опять же говорю, что я за годот. Уже сейчас это отличный движок для небольших игр. А если его доведут до ума, то мы получим прекрасный движок с открытой лицензией. хотя дроч автора годота на питон я не разделяю
>Если ты хочешь делать игру - делай игру и таскай арт отовсюду. Если ты хочешь делать арт - делай арт.
Однако игра - это и есть произведение искусства, в общем и целом, а не одни только голые механики. Существует масса похожих друг на друга игр в плане механик, но у них разная аудитория из-за разного аудиовизуального наполнения.
>>798024
>Игру нужно делать такую, чтобы в её прототип на кубах и квадратах было интересно играть.
У меня за множество лет попыток нет ничего, во что можно было бы играть, не говоря о том, чтобы это было интересно. А когда ты несколько лет двигаешь по экрану кубы да квадраты, при том что остальные игры сегодня уже на уровне реальности, рано или поздно впадаешь в депрессивное состояние "а зачем я вообще это делаю, зачем мне это нужно, не хочу больше это делать".
В общем, я согласен, что в прототип игры должно быть интересно играть без графики и всего остального, но несколько лет таскать кубы по голой сцене и так и не получить ничего играбельного - слишком сильно демотивирует. А если ты ещё и графику с интернетов воруешь, то что ты вообще сделал? Ничего, только время зря потратил.
Искал в документации, но в упор не вижу. Хелп!
Опишу задачу толковее. Есть массив, скажем
[
Foo
Foo 1
Bar
Bar 1
Bar 2
Bar 3
]
и есть функция, которая добавляет в массив данные из аргумента. У функции есть параметр перезаписи, можно переписывать имена при совпадении, а можно добавлять следующее.
Если я пишу add("Foo", "replace") то массив не изменится, если же я напишу add("Foo", "rename"), то я ожидаю, что в массиве появится Foo 2.
Похоже, без обхода массива тут не обойтись, но как мне извлечь цифру из элемента массива?
Ты допускаешь типичную ошибку новичка, задающего вопросы в интернете. У тебя есть некая проблема X, для решения которой ты попытался применить Y, но у тебя не получилось, и теперь ты спрашиваешь решение Z для работы Y, хотя на самом деле тебя интересует X, а не Y. Значит, спрашивать ты должен об X.
>функция, которая выдаёт номер, если он содержится в имени
У String такой функциональности нет.
https://docs.godotengine.org/en/stable/classes/class_string.html
>>798097
>add("Foo", "replace")
>add("Foo", "rename")
К теме не относится, но лучше сделать
>replace("Foo")
>rename("Foo")
Либо, если тебе очень нужен универсальный метод add(), использовать enum:
>enum AddMode {REPLACE, RENAME}
>func add(text: String, mode: int = AddMode.REPLACE) -> ...
Сравнение строк в любом ЯП занимает значительное время и делает код менее предсказуемым по времени (разные строки сравниваются разное время), поэтому лучше избегать использования строк в своём коде всегда, когда это возможно. В то же время enum - это просто целое число, которому присвоен идентификатор для удобства чтения исходного кода программы.
>Похоже, без обхода массива тут не обойтись
Можно, если использовать отдельный массив счётчиков.
>>798101
Твой код не даёт использовать пробелы в строках, кроме пробела перед числом; использует сравнение строк, которого будет тем больше, чем больше строк в массиве; использует сортировку массива чисел, которая тоже займёт существенное время, если будет много строк с одним и тем же "именем".
Возвращаясь к первому абзацу, какую задачу ты пытаешься решить? От характера задачи зависит то, какое решение будет более эффективным в плане времени/памяти/сложности реализации. Твоё решение подойдёт только если массивы небольшие и обращения к ним происходят редко, иначе всё будет тормозить.
Я бы на твоём месте создал отдельный словарь счётчиков, в котором каждой уникальной строке соответствует число-счётчик. Тогда при добавлении любой строки мы проверяем, какое следующее по порядку число мы должны добавить, и увеличиваем счётчик или создаём новый, если это первое вхождение строки. Но такое решение не подойдёт, если тебе нужно удалять строки с промежуточными номерами и затем заполнять "пробелы" в последовательности чисел, потому что счётчик всегда указывает на последнее использованное число, не учитывая "пробелы" в последовательности.
Чисто по скорости, Dictionary в GDScript вроде достаточно быстро работает благодаря хэшированию строк, т.е. тебе не нужно вручную перебирать все строки, достаточно обратиться по названию:
>var lines: Array
>var counters: Dictionary
>func add(line: String) -> void:
>_ if not counters.has(line):
>_ _ counters[line] = 0 # новый счётчик
>_ lines.append(line + str(counters[line]))
>_ counters[line] += 1
Если тебе нужно это всё проделать единожды и потом словарь со счётчиками больше не нужен, можешь сбросить ссылку на него, и сборщик мусора должен освободить занятую им память:
>counters = null
Совсем другое дело, если тебе нужно динамически добавлять и удалять строки, постоянно поддерживая целостность последовательности номеров, присвоенных этим строкам. В таком случае, я считаю, лучше вообще отказаться от хранения строк, соединённых с номерами, хранить номера отдельно от самих строк и объединять их только когда нужно получить строку с номером. Если у тебя будет много повторяющихся длинных строк, можно пойти ещё дальше и избежать повторений самих строк, создав три отдельных массива: массив с уникальными строками, массив с номерами строк, и массив, в котором уникальная строка соединяется с соответствующим ей номером... Эээ, правда, есть один нюанс: из-за того, что массивы в GDScript хранят ссылки, такая конструкция может оказаться не столь эффективной или даже вредной, так что нужно проверять на практике, что будет лучше. В любом случае, т.к. строка хранит длинный набор Unicode символов, пачка указателей на одну строку должна быть лучше множества копий этой строки.
В общем, всё зависит от твоей исходной задачи.
Ты допускаешь типичную ошибку новичка, задающего вопросы в интернете. У тебя есть некая проблема X, для решения которой ты попытался применить Y, но у тебя не получилось, и теперь ты спрашиваешь решение Z для работы Y, хотя на самом деле тебя интересует X, а не Y. Значит, спрашивать ты должен об X.
>функция, которая выдаёт номер, если он содержится в имени
У String такой функциональности нет.
https://docs.godotengine.org/en/stable/classes/class_string.html
>>798097
>add("Foo", "replace")
>add("Foo", "rename")
К теме не относится, но лучше сделать
>replace("Foo")
>rename("Foo")
Либо, если тебе очень нужен универсальный метод add(), использовать enum:
>enum AddMode {REPLACE, RENAME}
>func add(text: String, mode: int = AddMode.REPLACE) -> ...
Сравнение строк в любом ЯП занимает значительное время и делает код менее предсказуемым по времени (разные строки сравниваются разное время), поэтому лучше избегать использования строк в своём коде всегда, когда это возможно. В то же время enum - это просто целое число, которому присвоен идентификатор для удобства чтения исходного кода программы.
>Похоже, без обхода массива тут не обойтись
Можно, если использовать отдельный массив счётчиков.
>>798101
Твой код не даёт использовать пробелы в строках, кроме пробела перед числом; использует сравнение строк, которого будет тем больше, чем больше строк в массиве; использует сортировку массива чисел, которая тоже займёт существенное время, если будет много строк с одним и тем же "именем".
Возвращаясь к первому абзацу, какую задачу ты пытаешься решить? От характера задачи зависит то, какое решение будет более эффективным в плане времени/памяти/сложности реализации. Твоё решение подойдёт только если массивы небольшие и обращения к ним происходят редко, иначе всё будет тормозить.
Я бы на твоём месте создал отдельный словарь счётчиков, в котором каждой уникальной строке соответствует число-счётчик. Тогда при добавлении любой строки мы проверяем, какое следующее по порядку число мы должны добавить, и увеличиваем счётчик или создаём новый, если это первое вхождение строки. Но такое решение не подойдёт, если тебе нужно удалять строки с промежуточными номерами и затем заполнять "пробелы" в последовательности чисел, потому что счётчик всегда указывает на последнее использованное число, не учитывая "пробелы" в последовательности.
Чисто по скорости, Dictionary в GDScript вроде достаточно быстро работает благодаря хэшированию строк, т.е. тебе не нужно вручную перебирать все строки, достаточно обратиться по названию:
>var lines: Array
>var counters: Dictionary
>func add(line: String) -> void:
>_ if not counters.has(line):
>_ _ counters[line] = 0 # новый счётчик
>_ lines.append(line + str(counters[line]))
>_ counters[line] += 1
Если тебе нужно это всё проделать единожды и потом словарь со счётчиками больше не нужен, можешь сбросить ссылку на него, и сборщик мусора должен освободить занятую им память:
>counters = null
Совсем другое дело, если тебе нужно динамически добавлять и удалять строки, постоянно поддерживая целостность последовательности номеров, присвоенных этим строкам. В таком случае, я считаю, лучше вообще отказаться от хранения строк, соединённых с номерами, хранить номера отдельно от самих строк и объединять их только когда нужно получить строку с номером. Если у тебя будет много повторяющихся длинных строк, можно пойти ещё дальше и избежать повторений самих строк, создав три отдельных массива: массив с уникальными строками, массив с номерами строк, и массив, в котором уникальная строка соединяется с соответствующим ей номером... Эээ, правда, есть один нюанс: из-за того, что массивы в GDScript хранят ссылки, такая конструкция может оказаться не столь эффективной или даже вредной, так что нужно проверять на практике, что будет лучше. В любом случае, т.к. строка хранит длинный набор Unicode символов, пачка указателей на одну строку должна быть лучше множества копий этой строки.
В общем, всё зависит от твоей исходной задачи.
>У тебя есть некая проблема X
Тут подробнее об этом, не сразу вспомнил название:
https://ru.wikipedia.org/wiki/Проблема_XY
>Проблема XY — это проблема возникающая при обращении в службу поддержки и в других похожих ситуациях, когда обратившийся за помощью человек ставит не проблему X напрямую, а спрашивает решение проблемы Y, которая по его мнению позволит решить проблему X. Тем не менее решение проблемы Y часто не решает проблему X или является не самым удачным для неё решением, при этом пытающийся помочь человек может испытывать проблемы коммуникации и/или предлагать не самые оптимальные решения.
Реально ли в годоте реализовать такое поведение: основной геймплей в 2д, но периодически камера сдвигается с оси (например, наезжает на объект и меняет перспективу), в связи с чем он отображается в виде 3д модели. Есть возможность бесшовного перехода между такими двумя режимами?
Насколько мне известно, на юнити такое сделать достаточно просто, а как тута пока не имею понятия.
> какую задачу ты пытаешься решить?
Файлы-данные будут динамически добавляться в общий пул, общим пулом будет словарь. Массив имён с которым надо работать - это как раз таки массив его ключей. Часть файлов-данных будут перезаписывать предыдущие (установленные моды или ДЛЦ), часть будут задваиваться. В зависимости от потребностей. Нужен элегантный и предсказуемый механизм такого задваивания. Или не нужен. Может всё тупо заменять и не париться?
Словарь датафайлов будет в виде {"filename" : "file/path"}, далее с этим словарём будет работать мой патентованный существующий пока что в голове модульный менеджер доступа к данным. Суть его проста: все файлы-данные рид-онли, при попытке игры записать данные формируется файл-сейв, при попытке чтения данных менеджер следует приоритетам: сначала ищет ключ в файле-сейве, затем в дата-файлах, загруженных на данный момент игрой, хранящихся в вышеописанном словаре. Если данных нигде нет, используется дефолтное значение, которое передаётся функцией чтения, по классике: get_data(section, name, default)
Сорян за tl;dr
>Godot умеет работать в вечном оффлайне
Да
>экспортировать пректы чуть не на любую платформу
Да и нет, нужно докачивать экспортер для каждой платформы. потом можно в офлайне компилировать.
>не требует регистрации/лицензии
Да, не требует
Я реализовал так как в документации, что создается override.cfg с помощью функции ProjectSettings.save_custom("res://override.cfg").
То бишь в момент игры я меняю ProjectSettings и сохраняю впоследствии. Вот только столкнулся с проблемой, что при изменении в редакторе файла project.godot по пути >Project>ProjectSettings, я не знаю как получить сигнал о том, что этот файл изменился, дабы впоследствии написать сохранении в override. Реализовал довольно костыльно, создал аддон, который конектит сигнал "resource_saved", то бишь как-то так : connect("resource_saved", self, "save_project_settings"). В итоге при сохранении любого из файлов, сохраняется и ProjectSettings, но это довольно костыльно, потому что каждый раз это происходит, при сохранении любого из файлов. Проц не грузит, но все же, вдруг кто-то реализовал подобное лучше меня.
Ебался с этой системой несколько раз, но так и не смог добиться понятного и удобного лично мне поведения этой системы. Карочи, я принял стратегическое решение - хранить свои настройки в своём велосипедном конфигураторе.
>>798179
Override.cfg это для настроек проекта а не твоей игры. Типа версия там, ещё что-то, что ты сам меняешь. Настройки игры и делаются самим, сохраняешь просто json какой-нибудь в user:// - там им самое место, права на запись точно есть. Не могу представить ситуации, чтобы в момент игры пришлось менять project settings.
>бесшовного перехода
Теоретически возможно, но намного проще будет делать всё изначально в 3Д и не переключаться. Вот только с чисто эстетической точки зрения 3Д модели выглядят хуже стилизованного 2Д, поэтому я бы на твоём месте рассмотрел возможность сделать всё в чистом 2Д, а переключение в 3Д делать только для катсцен. В древних играх так часто делали, игра 2Д, а катсцены - видео с 3Д модельками. Алсо производительность 2Д выше, что особенно актуально для каких-нибудь стратегий реального времени и на ветке 3.x движка, у которой до сих пор нет 3Д батчинга.
>>798172
>Godot умеет работать в вечном оффлайне и экспортировать пректы чуть не на любую платформу, и при всём при этом не требует регистрации/лицензии?
>>798174
>движок мечты
Не считая 3.5 платных движков типа юнити, все остальные десятки, если не сотни игровых движков работают точно так же. Просто Годо последнее время набирает популярность, а остальные подобные движки никогда популярными не были или только теряют популярность.
>override.cfg
Я так и не понял, что и зачем ты пытаешься сделать с этим файлом, но с ним связано несколько багов, что-то пофиксят в 3.5:
https://github.com/godotengine/godot/issues/30912
Тебе по какой-то причине неудобен встроенный редактор настроек и ты вместо него хочешь менять настройки проекта из запущенной игры? Но зачем такие извращения?
>Часть файлов-данных будут перезаписывать предыдущие (установленные моды или ДЛЦ), часть будут задваиваться.
Насколько я знаю, моды/ДЛЦ сами перезаписывают файлы с одинаковыми именами. Т.е. если у тебя в двух пакетах два одинаковых файла, актуальным будет тот, что в последнем загруженном пакете. А чтобы было два файла, они должны иметь разное имя или путь. К тому же я не вижу простого способа "задваивать" файлы добавлением порядкового номера: ведь другие файлы (скрипты) ссылаются на эти файлы по пути в файловой системе, и понятия не имеют, какой там у них порядковый номер. Если твой менеджер переименует foo.bar в foo2.bar, тогда твой скрипт foo.gd не сможет найти этот файл. А даже если как-то сможет, зачем тебе две копии одного и того же файла и/или два разных файла с одинаковым названием? У тебя уже есть ситуация, в которой такая функциональность обязательно нужна?
Если ты изобретаешь инструмент для некой абстрактной задачи, и пока не нашёл никакой прикладной задачи для него - не стоит тратить на это время. Вот когда встанет некая реальная проблема, тогда и будешь искать/делать под неё инструмент.
>>798189
Вы видимо не до конца поняли задумку, тогда объясняю.
Во время игры я меняю узел ProjectSettings и сохраняю изменения в файлы override.cfg и project.godot. Но в самом редакторе, при попытке изменения файла project.godot с помощью окна Project>ProjectSettings, файл override.cfg не меняется, то бишь эти изменения не будут отображены в игре при следующем её запуске. В итоге я эту реализовал фичу, выше описав как, могу в самом редакторе как обычно менять настройки, разрешение, не нужно лезть в сам файл override.cfg для этого, просто меняю как обычно что-то в редакторе, сохраняется это в override.cfg, в самой игре я могу изменить что-то, опять все сохранить уже в 2 файла override.cfg и project.godot, это в итоге и в редакторе изменится все и в файле override.cfg. Сохраняю эти файлы с помощью двух функций в самой игре
var _error_save_custom := ProjectSettings.save_custom("res://override.cfg")
и
var _error_save := ProjectSettings.save()
А в редакторе мне нужно сохранить только override.cfg
Проблема была только в том, что нужно как-то отслеживать именно момент сохранения файла project.godot, но я это решил костыльно, выше описав. Сохраняю по сигналу "resource_saved" у узла EditorPlugin
Алсо анон, изменять узел ProjectSettings помому в сто раз лучше, чем городить джейсоны для этого
Я просто беру и через эту функцию что-то изменяю
ProjectSettings.set_setting("display/window/size/fullscreen", value)
Вот тебе и фулскрин
При желании можно добавить свои проперти их менять, получать при желании из любого участка проекта
ProjectSettings.set_setting("player/fov", value)
А так же нет багов с задержкой изменного разрешения экрана, когда запускается окно исходя из данных project.godot или override.cfg, допустим 1280x720, а где-то в джейсоне потом подхватывается и оказывается, что разрешение должно было 1980x1080, дык еще и изменять в редакторе невозможно джейсон.
Зачем тебе писать в override.cfg, если ты можешь писать напрямую в project.godot? Просто удали override.cfg и не создавай его без крайней на то необходимости (вообще не знаю зачем он).
>>798193
Вот тут согласен, такие глобальные параметры, как разрешение экрана, имеет смысл хранить в настройках движка. Но может быть что-то, что касается только одного сейва игры, вот для такой информации нужен кастомный джсон.
>Зачем тебе писать в override.cfg
В смысле зачем override.cfg? Он нужен когда уже игра будет скомпилирована и играться, любой желающий мог поправить этот конфиг и настройки изменятся при запуске. Любая игра подобное имеет. Вон, туча конфигов для игр, с разными настройками, бывает так, что параметры в конфиге не выведены в настройках самой игре, в итоге люди благодаря конфигам правят что-то.
Он может хоть где находится. Для андройд сделан user://, для винды и линкс похуй где. Я для удобства сделал так.
> Не могу представить ситуации, чтобы в момент игры пришлось менять project settings.
Настройки графики требующие перезапуска? Как тебе такой пример?
> для винды и линкс похуй где
Не похуй. В линуксе без прав админа изначально хуй куда сунешься кроме home/username (далее просто home), а в винде ввели аналог sudo начиная с висты, тот самый UAC, позволяющий повышать права когда надо, а в остальное время сидеть под юзером, но зассали вводить полноценный запрос повышения прав с вводом пароля, ограничились диалогом да/нет, и не прогадали, потому что виндузятники 10 лет хуесосили UAC и отключали всегда и везде, и до сих пор некоторые виндоадмины этой хуйнёй маются, вместо того, чтобы один раз изучить вопрос с правами и не испытывать проблем с лишними запросами на повышение прав.
Ну а андроид, поскольку основан на линуксе, реализует линуксовый подход к безопасности. Тот самый user:// годота везде символизирует выделенную папочку в home, просто home для разных систем по разному зовётся.
>зассали вводить полноценный запрос повышения прав с вводом пароля, ограничились диалогом да/нет
Профиль администратора в Windows - это тот самый sudo, который может делать с системой всякое, и сам вход в систему с профилем администратора равносилен входу в Linux с правами sudo. В Linux из-под sudo ты сможешь выполнять любые команды без лишнего ввода пароля sudo, а в Windows, начиная с Vista, опционально нажимаешь "да" в окне UAC, тоже без пароля. Если же ты заходишь в Windows точно так же, как в Linux, т.е. не через sudo (профиль администратора), то будешь вводить пароль админа точно так же как пароль sudo в Linux, и эта фича была в Windows задолго до Vista с её UAC. Просто большинство пользователей не парится созданием отдельного профиля админа (sudo) и отдельного профиля пользователя, поэтому для защиты таких чайников ввели UAC для профиля администратора. Так понятно?
Ты путаешь su и sudo.
Вот точно - не поняли. Зачем из игры менять ProjectSettings? Сделай обычный объект с названием Settings для настроек пользователя и меняй его как хочешь. Храни в user:// То что ты в res:// делаешь - это, по-моему, полная херня. Где оно по-товоему должно этот файл переписывать у юзера на компе? Внутри твоих ресурсов, которые ты приложил? В папке Program Files на Винде? В чем смысл?
>>Зачем из игры менять ProjectSettings? Сделай обычный объект с названием Settings для настроек пользователя и меняй его как хочешь
Выше писал, что из редактора возможно одним кликом галочки изменить этот конфиг, без шизокостылей.
>рани в user:// То что ты в res:// делаешь - это, по-моему, полная херня.
Я же написал, сделал для удобства, потом изменю, мне удобней пока разрабатывают проект, хранить конфиг в самой папке проекта. Странно что доебались до этого, это и так должно понятно быть.
>Где оно по-твоему должно этот файл переписывать у юзера на компе? Внутри твоих ресурсов, которые ты приложил? В папке Program Files на Винде? В чем смысл?
Сделал для удобства, при компиляции путь user
Понятно теперь
Я так и не понял, в чём проблема. Метод save_custom() сохраняет все параметры проекта, все параметры, отличающиеся от значений по умолчанию, или только параметры, отличающиеся от исходной версии настроек? Если я правильно понял, у тебя проблема в том, что save_custom() сохраняет то, что не следует, и ты потом никак не можешь изменить эти настройки из редактора, не удаляя этот кастомный файл, так? Ну так и не создавай этот кастомный файл, зачем тебе, ты же игру разрабатываешь, а не играешь в неё...
Как устранить проблему? Возможно дефолтно ставится Immediate playmode, но в документации как его сменить - я найти не могу.
Кто сталкивался с таким - помогите.
Нет. Проблема в отслеживании файла project.godot, чекать когда он изменился.
>как его сменить
Там все параметры дерева анимации изменяются через универсальный метод set(), первым аргументом которого должна быть строка с именем параметра. Сложно, короче.
https://docs.godotengine.org/en/stable/tutorials/animation/animation_tree.html
https://docs.godotengine.org/en/stable/classes/class_object.html#id4
>void set ( String property, Variant value )
>Assigns a new value to the given property. If the property does not exist or the given value's type doesn't match, nothing will happen.
Не понимаю, почему не сделают интерфейс через точку, но, возможно, другого способа нет или он слишком сложный.
а в чем вы делаете 2Д графику?
ну допустим это аркадка с четко прорисоваными элементами,хоть примитивные?
я правильно понимаю,что скорее всего придеться раскошелиться на планшет со стилусом?Как мощно мышью рисовать эстетические изображения?
а ты что используешь?
>больше профитов
Если не знаешь C#, сделай сначала прототип игры на GDScript. Если почувствуешь необходимость в C#, тогда переписывай на C#. В ином случае связываться с ним - только время тратить. Алсо 4.0 обещает дополнительные оптимизации GDScript по производительности, там много чего переработали. Вообще, главное преимущество Godot - скорость прототипирования, а C# её замедляет.
>>798373
>придеться раскошелиться на планшет со стилусом?
Нет, не обязательно. Любую картинку можно нарисовать любым электронным устройством ввода. Проблема только в скорости - неподходящими инструментами рисовать сложнее и поэтому требуется больше времени. Однако, не ожидай от графического планшета чудес - даже профессиональным художникам приходится долгое время привыкать к графическому планшету, что уж говорить о полных новичках. Также, если совсем не умеешь рисовать, учиться лучше карандашом на бумаге, потом сканировать или фотографировать рисунок и дорабатывать на компьютере.
Всё это справедливо и для графического редактора: Krita хороша, но для новичка в цифровом рисунке любой профессиональный редактор будет сложен, а разнообразие функций может сбить с толку. Так что если не умеешь рисовать, лучше сначала рисовать научиться, а потом погружаться в цифровой рисунок.
>Как можно мышью рисовать эстетические изображения?
Если ты хочешь быстрее и при этом тебя устраивает векторная графика с её преимуществами и недостатками, то скачивай https://inkscape.org/ - очень быстро освоишься и сможешь мышкой творить то, на что у растровых художников даже с графическим планшетом уходят годы тренировок (ровные прямые, ровные кривые и прочая геометрия, ровные сплошные заливки и ровные градиенты, всё эстетически ровное и математически красивое, максимально концентрированный кайф для перфекциониста). Но в любом случае тебе нужно иметь художественную базу, без которой твои рисунки будут уровня "палка, палка, огуречик" в любом редакторе и с любым набором вспомогательных инструментов.
>потом сканировать или фотографировать рисунок и дорабатывать на компьютере.
есть ссыль на гайд?
>есть ссыль на гайд?
Гайд на что?
1. Как рисовать? В /pa/йнтаче подскажут.
2. Как сканировать? Берёшь сканер, кладёшь лист рисунком на стекло, закрываешь, в компьютере запускаешь сканирование.
3. Как фотографировать? Ищешь или создаёшь максимально равномерное освещение, фотографируешь рисунок максимально ровно, чтобы не было перспективного искажения.
4. Как обрабатывать? Зависит от того, что у тебя за рисунок и какой результат ты хочешь получить на его основе:
4.1. Если хочешь глянцево-конфетную картинку, делаешь скетч на бумаге и потом обводишь мышкой в Inkscape, делаешь всякие там глянцевые градиенты, блики и всё такое, скетч удаляешь.
4.2. Если хочешь раскрасить а-ля масло, обмазываешь свой скетч различными кисточками в растровом редакторе типа Krita.
4.3. Если хочешь олдскул "игра из бумаги", рисуешь на листочках в клеточку, на компе обрезаешь рисунки, по необходимости удаляешь лишний мусор (дефекты бумаги, освещения и т.д.).
4.4. Если хочешь пиксель-арт, то всё это вообще не нужно, нужен пиксель-арт редактор, мышь, уйма времени и терпения.
Можно вообще ничего не рисовать, а лепить из пластилина и фотографировать с равномерным освещением, такие игры всегда выделяются из толпы безликих пиксельных платформеров и векторных гиперказуалок своим неповторимым стилем.
>>798427
>вообще c++ использую
Для чего? У тебя есть острая необходимость в максимальной производительности? Или просто из принципа?
>в целом
В целом - рисуешь, сканируешь, доделываешь в цифре. Всё. Если у тебя дома есть сканер, то всё остальное ты сам знаешь. Если сканера нет, то ты наверняка обрабатывал фотки с телефона, так вот тут практически то же самое.
Ты рисовать-то умеешь? Никаких магических инструментов нет, если рисуешь как ребёнок, то инструменты профессиональных художников ничем не помогут. А учиться рисованию долго и трудно, не жди результатов после нескольких туториалов (в отличие от кодинга, в рисовании недостаточно знать формальные правила, которых вообще мало и они не так уж обязательны).
И если ты планируешь всё же рисовать в векторе, то рисовать от руки и сканировать не обязательно. Можно просто открыть векторный редактор, набросать эскиз из простых геометрических форм или даже от руки кривые линии, а потом править до желаемого результата. Карандашный рисунок только ускоряет первый этап работы для тех, кто уже умеет хорошо и быстро рисовать карандашом.
Зачем?
Никак. Геймдев в России переходит из бизнеса в хобби и искусство.
Наконец-то. ради искусства я сюда и пришёл уже как 4 года назад, и дико фрустрировал с засилья кабанчиков в разделе.
> Не могу представить ситуации, чтобы в момент игры пришлось менять project settings.
Давайте возобновим дискасс. Привязки клавиш хранятся там, и если мы даём игроку возможность переназначать клавиши, перед нами возникает палка о двух стульях.
Вот тут.
Если ты могёшь в кресты - ты сразу Бог и Царь, но дискасс.
> Клиент UI GDScript, логика c++
Да, с логикой на крестах, ты просто без задней мысли накидываешь свои ноды в перекомпилированном движке, типа как-то так, и оно просто работает.
Оооо, братишка, помню, сам мучился с этой проблемой. Её пиздец как неочевидно сделали. Когда экспортируешь проект и выходит окно сохранения файла, там есть незаметная переключалка "в режиме отладки", вот её выключи.
А теперь у меня вопрос всем. Эт нормально, если у моего перса 8 рейкастов постоянно шмаляют во все стороны? Не накладно физону?
Я вообще без рейкастов сделал. Вообще не понимаю, нахуя их добавляют к персонажам, если и так всё работает.
Сделай 10к рейкастов погляди лагает нет
Итак вопрос. Как синхронизировать скорость с движущейся платформой?
>Как синхронизировать скорость с движущейся платформой?
Неправильный вопрос. Вор правильный: Как синхронизировать платформу с физикой?
Ответ:
1. Платформа должна быть кинематиком, не статиком.
2. У всех нод, участвующих в движении платформы (ну та патх, патхфоллов, твин, анимейшонплеер, смотря как ты её двигаешь), и у самой платформы должна стоять галка синхронизации с физикой.
> Платформа - ригидбоди и движется путём передачи импульса в сторону точки своего следующего местонахождения apply_central_impulse((target.global_position - global_position) delta speed)
Ну чтобы без пердолинга и всякой подобной хуиты.
Просто я на работе уже десять лет ебашу в си/с++ под всякий эмбедед... У меня уже развился синдром утенка, я не могу и не хочу никакой другой язык и инструменты. Я просто привык.
Не могу я на шарпе - у меня психическая проблема при виде шарповых полотен кода без возможности уютненько их раскидать по файлам на объявления и определения.
Питон я в глаза не видел, да и динамическая типизация вызывает попоболь при одном только упоминании.. А уж блоки кода пробелами - просто феерия.
Ясен пень я не движкодел... Пытался, но обосрался. Так что годот как либу я не осилю сам.
Ну и мне нравится все писать в коде. Без мышкотаскания ассетов. Много раз проверял - мне реально проще написать текстовый json с координами столиков/стульев. Чем сидеть и таскать их мышкой.
И вот я в постоянном поиске движка под себя.
Дополню этого анона:
Есть два стула:
1. Модули движка, которые компилируются с движком.
2. Модули гднатив, которые компилируются в либы целевой платформы и через текстовый конфигурационный гдн-файл подключаются к существующему движку без его перекомпиляции.
На оба стула я бы посадил врага (как не могущий в кресты).
Можешь глянуть этот движок >>795483 (OP)
Там плюсы сразу из коробки без пердолинга. Сам движок по уровню сложности как годот, если не проще.
>можно писать на c++ кастомные ноды
Но ведь это именно что кастомные ноды, то есть в любом случае их придется звать из питон-скрипта, то есть в любом случае это не С++ кодинг, разве нет?
(другими словами в юнити тоже можно написать dll расширения на С++, но это же не значит что в юнити можно писать всю логику на с++, также и с кастомными нодами и модулями - в любом случае основной код будет на питоне или шарпе)
>>798901
>1. Модули движка, которые компилируются с движком.
проблема что движок компилируется по несколько часов на SSD (scons говно тормозное, даже UE4 при своих объемах кода быстрее компилируется)
>>798905
В флаксе много наворовали кода из UE4, что юридически незаконно со всеми вытекающими последствиями. Я проверял.
>юридически незаконно со всеми вытекающими последствиями
Так это проблемы разрабов движка, а не игроделов. Да и странно, что эпики до сих пор не подали в суд за столько то лет.
Ох, ебать! Я нашёл идеальное сочетание областей захвата (при котором риджидбади удобно, но достаточно "челленджово" ползает как муха по всей локации, включая стены и потолки) и вы поглядите, как оно похоже на фрактал Мандельброта! Воистину всё взаимосвязано в матане!
Мелкие кружки справа-слева отвечают за захват стен, большие - пол-потолок, а центральный кружок - само тело.
Нужно вычитывать несколько строк с json из файла, вычитываю только 1.
Я же правильно понимаю, что get_line() должна выполниться по количеству строк в файле, при этом eof_reached() всё это время не будет true? У меня получается, что я один раз пробегаюсь и упираюсь eof_reached(), который достигает true.
Погуглил - на форумах плюс-минус та же логика, но она не работает:
https://godotforums.org/discussion/17372/how-can-you-make-godot-read-from-a-file-take-a-random-line-and-assign-it-to-a-variable
https://godotengine.org/qa/46343/display-line-text-from-game-bestly-which-best-known-techniques
У меня что-то не так с пониманием eof_reached()?
Вот набросал тебе правильное чтение из файла. Пикрелейтед у меня выводит построчно в консольку указанный ТЕКСТОВЫЙ файл.
Вот я подзапарился и набросал тебе эдакий юнит-тест, у меня он выводит в консольку набранные тут же данные.
>>798937
>>798941
Спасибо.
Не, файлы нормальные, многострочники, с переносами строк, пикрил.
А теперь вишенка на торте. Абсолютно глупая.
У меня таки код оказался абсолютно правильный в этой части. Вдоль и поперек. Прикол заключался в том, что экраном ниже у меня return() съехал с позиции, и попал под цикл
while not gameSaveFile.eof_reached():
Естественно, после прохода по первой строке оно и выходило.
Слава богу! воистину воскрес!
Но я не перемину покритиковать твой подход.
1) Почему в файле сохранения не абстрактные данные ("бизнес"-логика) а пути к файлам в res:// ? Рекомендую отказаться от этого. В файле хранятся зарегистрированные игрой имена сущностей, а игра при чтении файлов, по этим зарегистрированным уникальным именам достаёт из своей res:// конкретные модели/сцены/итд.
2) Если у тебя файл, в котором построчно выложены логические сущности, то предполагается, что ты будешь их читать выборочно. Однако у тебя я не наблюдаю заголовочной части в котором описано "оглавление" по сути, индекс номеров строк и сущностей по этим строкам, следовательно файл ты будешь читать в цикле до первого найденного искомого объекта, что в общем-то делает бессмысленным всё это построчное чтение. Функция загрузки будет долго и нудно проходиться сотни раз по массиву, чтобы достать нужное. Предлагаю тебе два стула:
2.1. Для огромных сейв-файлов: Создавать индекс в начала каждого сейва, ассоциативный массив, он же словарь, с записями о том, по какому номеру строк сохранены локации, по каким номерам засели сущности, и т.д.. После чего ты пролетаешь в нужную часть файла и считываешь нужные данные. При этом текстовый файл здесь будет только мешаться. Лучше сразу разобраться с бинарным доступом к данным и в индекс класть не номера строк, а номера байтов в бинарном файле и бинарным доступом путём смещения курсора читать-писать.
2.2. Для мелких сейв-файлов: без задней мысли сохранять в файл одну строку-словарь с данными, а при чтении одной командой его считывать, парсить и класть в переменную.
1) Пути - заглушка.
Фактически, у меня формируется отдельны набор универсальных скриптов, которые отвечают за словари, переменные пути и т.п. Туда же скрипты по работе с интерфейсом - фатически, то же сохранение/загрузка игры или карты в редакторе в часте функционала, привязанного к кнопкам интерфейса - одно и то же.
У меня 9 штук объектов с разными человекочитаемыми путями, чтобы было видно, что словарь с данными раскладывается по файлу норально, что дорога приходит к городам и шахтам, а не идёт где-то в поле в никуда, и не думать, что абстрактные tile1, tile2, tile3 и т.д значат в данном конкретном сохранённом примере. Прямо здесь и сейчас я делаю то, что описал - смотрю, как данные ходят, ложатся на диск, загружаются, раскладываются обратно в словари. В первой итерации я начал накидывать именно игровые механики, объекты, а потом понял, что начинаются проблемы с тем, как я потом буду с этим всем работать. Зашёл с другой стороны. Как я это буду структурировать. Сразу пошло лучше. Без заморачиваания, что же там используется в виде конкретных значений. А это уже легко менять.
2) Не, читаются они целиком и полностью. В моём видении без разницы, где и на какой позиции и как это всё хранится. Одна строка - один json, читаю все строки. К концу прочитки файла должен вычитать гарантированный список json'ов. В противном случае просто считаю файл невалидным/повреждённым.
Мне необязательно знать, что где лежит. У меня к каждому словарю цепляется ещё одно ключ-значение, которое является сервисной меткой, определяющей назначение вот этого конкретного json - пикрил.
На загрузке я просто убираю метку и отправляю дальше данные в обработку.
>Функция загрузки будет долго и нудно проходиться сотни раз по массиву, чтобы достать нужное. Предлагаю тебе два стула:
Не думаю, что это проблема. Файл-то может быть большой, однако количество json'ов будет всё равно небольшим, поэтому тут я проблем не ожидаю. Вычитал, сверил хэши, что не повреждено, дальше отдал на обработку.
Вот будет у тебя в школе информатика - там тебе преподадут основы. Потом с этими основами придёшь обратно и охуеешь, как всё просто.
> читаются они целиком и полностью
Вот теперь я понял, и пожалуй возьму на вооружение. Файл читается один раз, но читается не одной блокирующей функцией целиком, а построчно в цикле с возможностью приостанавливать чтение при нагрузке. Как я сразу этого не понял. Классика же.
>а построчно в цикле с возможностью приостанавливать чтение при нагрузке
Хотя даже это неправильно с точки зрения нагрузки и скорости работы. Самый быстрый вариант, который я потом и планирую - читать файл линейно без каких-либо остановок и обработок, построчно, занося строку в словарь. В итоге у тебя на выходе максимально быстрое чтение файла с диска и словарь в памяти, с которым, теоретически, работать будет быстрее, ибо оно в RAM, т.к. ты не останавливаешь циклы на работу обработчиков, возвращаясь к чтению с диска позже, нарушая последовательное чтение большого файла. Чтение с диска - всегда дорогая операция. Но, подозреваю, в подовляющем большинстве инди этим можно пренебрегать, т.к. это микрооптимизации и преждевлеменные оптимизации. Это следует делать отдельными функциями/скриптами, чтобы потом вернуться, если необходимость действительно возникнет, и при этом не пришлось бы менять условия контрактов, используемых при взаимодействии.
Хей, анон, а давай обсудим мою идею о сейвах? Вот я вкратце накидал образец того, как я это вижу, включая полученную от тебя сегодня инфу. На пикче 1 я формирую эдакие атомарные словарики-проперти, соответствующие одному полю одного логического объекта в наборе сохраняемых данных. У каждого словарика вместо сервисных меток сохраняется путь в метаданных (бизнес-логике) будущего большого ворлд-словаря, которым будет оперировать игра всеми своими подсистемами.
На пикче 2 сам этот ворлд-словарь, который будет разумеется намного больше этого образца, там будет всё, и локации, и неписи, и диалоги, и динамические предметы. Каждый объект будет формировать данные, которые у него подлежат сохранению, и будет самостоятельно отсылать в ворлд-объект актуальные сейв-данные о себе через специальный менеджер, который может отвергать подобные запросы, если он, скажем, в состоянии работы с файлом сейва. О менеджере я писал ранее, там дополнительно будет модульность, часть данных рид-онли, например, данные о диалогах - рид-онли, а вот данные о прочитанных ветвях, уже нет, и подлежат записи в сейв. И у менеджера будет несколько ворлд-датасетов, один мастер и один слейв, так сказать, а при наличии модов, таких слейвов будет несколько в порядке загрузки модов, и все рид-онли, и только самый последний в этой последовательности датасет - это сейв-файл, который рид-райт.
Гениальность подобной атомизации в том, что можно весь процесс обрабатывать не единым циклом, блокирующим поток, а раскидать по фреймам, как это делают большинство игор, которые выводят иконку бэкграунд-сохранения и просят "не выключать ваше устройство пока горит/мигает/вращается иконка".
Сложно. НУ для моей структуры, по крайней мере. Описывать все эти структуры в коде, в случае чего все их править, править ещё исходные данные... У меня механика позволяет послупать иначе.
>На пикче 1 я формирую эдакие атомарные словарики-проперти
Если взять тайлы со скрина выше, то получается так:
у меня каждый отдельный объект знает своё состояние. Это вот и есть аналог твоих атомарных словарей. В момент загрузки в сцену, либо по факту изменения свойств тайла, каждый тайл передаёт своё состояние в один глобальный словарь. Никогда не забудешь что-то где-то обновить. Просто у тебя сам объект на карте делает за тебя. При сохранении сохраняется этот один глобальный словарь. При загрузке - обратная колбаса. Ты загружаешь словарь, потом при загрузке каждый тайл бежит узнать своё состояние из глобального словаря. Работается с этом всем как я описал до этого.
В итоге, у тебя всегда актуальный глобальный словарь, который просто возьми да положи на диск, без лишних манипуляций.
В коде у меня вообще нет нигде структур, только обращение к определённым ключам (типа "key"). А единственное место, где это приходится править - поведение для новых типов ключей, а сами ключи и структура - в отдельном файле. Отсюда, кстати, у меня и пути в заглушках.
А описывать всё каждый раз в коде и оттуда же менять - не самая удобная штука. Я слишком ленив для этого.
> описывать всё каждый раз в коде и оттуда же менять - не самая удобная штука
Ты наверное как-то неправильно понял.
Описывать ничего не надо. Не более, чем описывается в других вариантах. Обычно как пишут:
> var speed = 150
...
> func _process(dt):
> ____move_and_slide(bla bla speed)
Так?
Так.
Так вот. В моём (продумываемом) случае изменится только одна строка, первая:
> var speed = data_base.read("/player/speed", 150)
Выглядит странно, хотя где-то вполне и удобно. Годот сам раздербанил csv, всё красиво, запятые окавыченные нормально воспринимает, т.е. текст можно красиво загонять.
Но есть один нюанс.
Можно ли задать дефолтный шрифт для текстов, используемых на всяких лейблах, кнопках и т.п.?
Пока только кастомно для каждого отдельного элемента или через интерфейс, или описывать подгрузку кодом. Вот это прямо очень неудобно смотртся. Особенно с учётом того, что кириллицы. Ну у меня, по крайней мере. Возможно из-за того, что всё под en_US настроено.
Пикрил - OPTIONS, MAP_EDITOR, EXIT - плейсхолдеры, которые показывают состояние шрифта для конкретного лейбла у кнопки. У MAP_EDITOR кастом шрифта нет - нет и кириллицы в запущенном варианте.
Пока из мыслей для костылей - делать отдельный инициализатор, где будет по всем текстовым элементам пробежка, устанавливающая ключ локализации и кастомный шрифт. Но это костыль.
> Выглядит странно
Не страннее остальных вариантов локализации. А этот вариант сделан по всем стандартам.
> где-то вполне и удобно
Везде удобно.
> раздербанил csv, всё красиво, запятые окавыченные нормально воспринимает, т.е. текст можно красиво загонять
Отмечу, что для цсв можно установить свой разделитель, например | и вообще не париться с окавычиванием.
> Но есть один нюанс.
> Можно ли задать дефолтный шрифт для текстов
Это не вопрос локализации. Это вопрос тем. Можешь не запариваться с темами, а выставить дефолтный шрифт в настройках проекта, но тему тебе всё равно придётся делать или готовую загружать. Так что проще всего сразу изучить вопрос. И да. Этот анон прав:
>>799323
> Тема, которая задается для корневого контрола, распространяется на все контролы в дереве нод.
И это тоже такая классика, что просто охуеть, почему её не знают.
> Пока из мыслей для костылей - делать отдельный инициализатор, где будет по всем текстовым элементам пробежка, устанавливающая ключ локализации и кастомный шрифт. Но это костыль.
Костылить костыль придётся только в том случае, если ты хочешь дать игроку самостоятельно переключать язык игры. Если же такого функционала не требуется, то все ресурсы сразу со старта будут грузиться в системной локали.
Если же надо переключать, то вот общий алгоритм:
1. Игрок выбирает нужный язык из списка.
2. Игра сообщает серверу переводов: TranslationServer.set_locale ( String locale )
3. Игра рассылает всем задействованным нодам (интерфейсным) сообщение NOTIFICATION_TRANSLATION_CHANGED
4. ПРОФИТ! Игра сразу вся на другом языке, без перезагрузки. В том числе локализованные текстуры, не только текст.
А ещё есть нюанс, из-за того, что все внутридвижковые ноды опираются на трансляшон сервер, то по дефолту, если ты юзаешь в игре диалоговые окна, например, диалог открытия файла, то там всё по английски. И минимальный шрифт с одними английскими буквами. И если ты пытаешься туда написать в заголовок "пжлст выбери фаел", то там будет пустота. Но если ты задашь диалогу тему с русским шрифтом (или поместишь диалог в потомки Control c русским шрифтом), и если ты в CSV файл добавишь строки, как на пикче 2.
То тебя ждут открытия. Получишь русифицированный и стилизованный диалог открытия файла. И вот так легко и непринуждённо локализуется всё везде.
И да.
>>799389
> свой разделитель, например |
Вот тут я конечно многого захотел, это из другой оперы. В годо только (, ; Tab)
Спасибо.
>>799389
>И это тоже такая классика, что просто охуеть, почему её не знают.
Не очевидная штука. На самом деле такое часто бывает. Вроде бы простые штуки - а нигде и не описано.>>799395
>Если же надо переключать, то вот общий алгоритм:
>1. Игрок выбирает нужный язык из списка.
>2. Игра сообщает серверу переводов: TranslationServer.set_locale ( String locale )
Уже. Именно по-человечески нормальный выбор локализации планирую.
>пилю сетевую игру с сервером
>усложнение декомпиляции
>процентов 90% мамкиных хакеров тут срежется
Ходишь по очень тонкому льду с самого начала.
https://ru.wikipedia.org/wiki/Безопасность_через_неясность
В контексте сетевых игр с сервером: все критически важные вычисления должны происходить строго на сервере. Игрок нажал кнопку W - клиент передал эту информацию серверу - сервер придал импульс персонажу - клиент отрисовал этот импульс на экране. А чтобы это всё не лагало, клиент должен предсказывать будущие сообщения сервера, но последнее слово всегда за сервером. В такой системе просто нечего взламывать, ты не можешь отправить серверу запрос "телепортируй меня на 10 километров вверх", потому что в API сервера такой команды нет, а телепортация модельки на клиенте будет видна только этому клиенту и только до следующей корректировки по информации с сервера.
Аналогично с деньгами, лутом и т.д. Клиент не может запросить "добавь мне 999999 монет" или "я взял ульта супер меч", он только отображает результат, который посчитал сервер, и если монеткам и супер мечу взяться неоткуда, они ниоткуда и не возьмутся. И даже если у игрока есть исходники сервера, единственное, что он может с ними сделать - это запустить свой собственный сервер.
Другое дело P2P игры с минимальным сервером авторизации, вот там читеры отрываются как могут, отследить их автоматически практически невозможно из-за отсутствия полноценного сервера. В таких играх читеры ловятся только по неадекватной статистике аккаунта, например, когда накручивают неадекватно большое количество денег или получают недоступный предмет (лол).
>...платформа из под них уезжает. Не я понимаю, если тело только попало на платформу, но если она постоянно движется, скорости должны синхронизироваться же.
>Итак вопрос. Как синхронизировать скорость с движущейся платформой?
>>798849
>Платформа - ригидбоди и движется путём передачи импульса в сторону точки своего следующего местонахождения apply_central_impulse((target.global_position - global_position) delta speed)
Тут дело в том, что игровые физические движки по умолчанию не симулируют силу трения покоя. Пример: ИРЛ стопка досок на гладкой поверхности при относительно лёгком воздействии на нижнюю доску будет двигаться вся целиком из-за трения покоя между досками, которое выше трения покоя между нижней доской и поверхностью, по которой она скользит. Но игровой физический движок для упрощения вычислений игнорирует эту силу/взаимодействие тел (как если бы все тела были бесконечно гладкие/скользкие), поэтому стопка "досок" в игровом движке легко рассыпается при любом движении нижней доски.
Прикол в том, что такие ситуации, как "стопка досок" в играх случаются крайне редко. Если тебе нужно разместить персонажа на каком-то транспорте, ты скорее всего соединишь их в один физический объект после короткой анимации, верно? То-то и оно. Поэтому симулировать эту силу по умолчанию невыгодно для игровых физических движков. Но если тебе она вот прям очень нужна - делай сам, кто мешает.
Если не ошибаюсь, достаточно просто регистрировать контакты между объектом-персонажем и объектом-транспортом, и если ускорение транспорта не превышает определённого порогового значения, все скорости персонажа суммируются со скоростями транспорта, что создаёт иллюзию, будто бы персонаж покоится на поверхности транспорта (ну... это уже философский вопрос, покоится ли он на самом деле или нам так только кажется).
>В первой итерации я начал накидывать именно игровые механики, объекты, а потом понял, что начинаются проблемы с тем, как я потом буду с этим всем работать. Зашёл с другой стороны. Как я это буду структурировать.
Ты слишком рано начал париться сохранением и загрузкой, имхо. Работать со структурой игрового мира можно чисто в оперативной памяти. Сохранение и загрузка - отдельная система, от которой структура мира никак не зависит. Сначала делаешь игру, потом делаешь сохранение и загрузку.
>Одна строка - один json, читаю все строки. К концу прочитки файла должен вычитать гарантированный список json'ов.
Что тебе мешает сделать JSON массив записей?
[
{"строка 1": "бла бла бла", "параметр": 1},
{"строка 2": "больше бла", "параметр": 2},
{"строка 3": "меньше бла", "параметр": 3}
]
Читаешь весь файл как JSON и у тебя будет в памяти массив словарей, дальше делай с ними что хочешь. Учитывая, что так будет меньше переходов между GDScript и ядром движка, оно должно получиться быстрее твоего велосипеда. Тем более если у тебя сейвы не больше пары мегабайт, сегодня это пустяк.
А вот если у тебя могут быть сейвы по сотне и больше мегабайт (как мир Майнкрафта, который может и терабайты занимать) - лучше сделать что-то бинарное, очень сильно сэкономишь на скорости и объёме. И строки не пиши, забудь про строки, только числа. Кстати, тема оптимизации больших сейвов интересная, там внутри может потребоваться своя собственная файловая система, позволяющая сохранить валидность сейва даже в случае частичной записи - когда, например, у юзера батарейка сдохла во время записи очередного чанка огромного мира. Ну или разделять большой файл на множество по чанкам, как это делает Майнкрафт, и доверить защиту файлов NTFS (с линуксом непонятно, а на андроид вообще защиты нет).
Самое главное, как мне кажется, сохранить валидность сейва любой ценой, даже если часть чанков придётся генерировать с нуля. Лучше потерять пару чанков, чем вообще весь мир. Лучше багнутая побочная миссия, чем прохождение всей сюжетки с нуля. И т.д. Впрочем, бекапы никто не отменял и это ответственность игрока...
>В первой итерации я начал накидывать именно игровые механики, объекты, а потом понял, что начинаются проблемы с тем, как я потом буду с этим всем работать. Зашёл с другой стороны. Как я это буду структурировать.
Ты слишком рано начал париться сохранением и загрузкой, имхо. Работать со структурой игрового мира можно чисто в оперативной памяти. Сохранение и загрузка - отдельная система, от которой структура мира никак не зависит. Сначала делаешь игру, потом делаешь сохранение и загрузку.
>Одна строка - один json, читаю все строки. К концу прочитки файла должен вычитать гарантированный список json'ов.
Что тебе мешает сделать JSON массив записей?
[
{"строка 1": "бла бла бла", "параметр": 1},
{"строка 2": "больше бла", "параметр": 2},
{"строка 3": "меньше бла", "параметр": 3}
]
Читаешь весь файл как JSON и у тебя будет в памяти массив словарей, дальше делай с ними что хочешь. Учитывая, что так будет меньше переходов между GDScript и ядром движка, оно должно получиться быстрее твоего велосипеда. Тем более если у тебя сейвы не больше пары мегабайт, сегодня это пустяк.
А вот если у тебя могут быть сейвы по сотне и больше мегабайт (как мир Майнкрафта, который может и терабайты занимать) - лучше сделать что-то бинарное, очень сильно сэкономишь на скорости и объёме. И строки не пиши, забудь про строки, только числа. Кстати, тема оптимизации больших сейвов интересная, там внутри может потребоваться своя собственная файловая система, позволяющая сохранить валидность сейва даже в случае частичной записи - когда, например, у юзера батарейка сдохла во время записи очередного чанка огромного мира. Ну или разделять большой файл на множество по чанкам, как это делает Майнкрафт, и доверить защиту файлов NTFS (с линуксом непонятно, а на андроид вообще защиты нет).
Самое главное, как мне кажется, сохранить валидность сейва любой ценой, даже если часть чанков придётся генерировать с нуля. Лучше потерять пару чанков, чем вообще весь мир. Лучше багнутая побочная миссия, чем прохождение всей сюжетки с нуля. И т.д. Впрочем, бекапы никто не отменял и это ответственность игрока...
>Не очевидная штука. На самом деле такое часто бывает. Вроде бы простые штуки - а нигде и не описано.
Чукча не читатель, однако?
https://docs.godotengine.org/en/stable/tutorials/ui/gui_skinning.html
Да и чего там неочевидного. Это же как CSS в HTML - наследуется всем вложенным элементам и может быть локально перезаписано кастомными свойствами. Вас там в школах вёрстке сайтов с помощью тетрадки в клеточку перестали учить?
> все скорости персонажа суммируются со скоростями транспорта, что создаёт иллюзию, будто бы персонаж покоится на поверхности транспорта
Я с этого начал, но матан лишь посмеялся надо мной. Такие глитчи ловил - охуеть просто! Более менее рабочий вариант обладает совсем уж нереалистичным свойством: если упираешься в стену подвижной платформы, стоя на ней, она начинает двигаться. Эффект Мюнхаузена, епт!
Склоняюсь к мысли сделать как тут
> Если тебе нужно разместить персонажа на каком-то транспорте, ты скорее всего соединишь их в один физический объект после короткой анимации, верно?
Набросать на все интерактивные объекты джойнты-слоты и коннектить к ним игрока (и друг друга).
Ты доебался к файлу анона, разбитому по факту на чанки (каждая строка-словарь и есть этот чанк), затем ты начал ему советовать разбивать файл внутри на чанки.
Кроме того, когда файл читается не одной функцией весь, а в цикле построчно, то внутри цикла можно сделать (в псевдокоде) yield(main_loop(), is_busyness_less_than(0.75)), что сделает загрузку ненапрягающей основной поток игры, если у игрока в данный момент что-то тяжёлое считается (абстрактная "занятость" больше 75%), и в этот момент запущено схоронение, оно может и подождать, чтоб у игрока не пролагивало.
> код общий, именно он позволяет предсказывать
Таким образом тебе нужно критически важную логику запихнуть в нативную библиотеку и подключить её через гд-натив. Только так ты можешь себе гарантировать, что читаки с манчкинами ломанут код не в первый день релиза, в во второй, например.
Из гд-скрипта это будет выглядеть так, игрок нажимает клавишу Ц, скрипт передаёт инфу на сервер и в натив либу, в них обоих код одинаков и они обе возвращают передвижение на сколько-то единиц вперёд, но инфа от либы - предикция, а инфа от сервера - стандарт.
https://www.youtube.com/watch?v=pGbQ_z0IvMk
https://godotengine.org/asset-library/asset/1171
Свобода слова же. Хочу и пишу. И что ты мне сделоеш?
>Представь себе свою входную дверь...
Ясно, ты не читал статью по ссылке:
>Например, если кто-то хранит запасной ключ под ковриком, в случае, если двери заперты снаружи, то он полагается на безопасность через неясность. Теоретическая уязвимость в системе безопасности в том, что кто-то может ворваться в дом, открыв дверь с помощью этого запасного ключа. Кроме того, поскольку грабители часто знают предполагаемые места тайников, владелец дома будет подвергаться большому риску кражи со взломом, скрывая ключ, так как усилие, требуемое для того, чтобы найти ключ, вероятно, будет меньше усилий, необходимых для проникновения (например путём взлома) другим способом, например, через стекло. Хозяин добавил уязвимость — тот факт, что входной ключ хранится под ковриком — в систему, и такую, которую очень легко угадать и эксплуатировать.
Вот у тебя есть какой-то код. У него есть известная тебе уязвимость (ключ под ковриком), но ты надеешься, что "90% хакеров" не смогут этой уязвимостью воспользоваться, потому что они не знают о существовании этой уязвимости (не видели, как ты клал ключ под коврик). Но на практике тебе, во-первых, будет достаточно всего одного ограбления квартиры, а, во-вторых, твой ключ под ковриком хакеры видели у сотен закрытых дверей, владельцы которых так же как и ты полагались на то, что об этой уязвимости никто не узнает.
>Поэтому, код сервера и клиента общий. Поэтому то и важно усложнить декомпиляцию кода устройства игры.
Не понял. Ты чего боишься? Читеров на твоём сервере или создания независимых серверов третьими лицами? На счёт серверов не беспокойся, если твоя игра когда-нибудь станет достаточно популярной, обязательно создадут пиратский сервер путём обратной разработки протокола, по которому клиент общается с сервером, так делали для многих ММО. К тому же для инди-игр выгодно предоставлять игрокам свободу создания собственных серверов, это делает их более популярными и надёжными.
Что касается читеров, повторюсь, читерам бесполезно знать код твоего сервера, потому что читерам важно лишь изменить данные на реальном сервере, а сделать им это не позволит разумно построенное АПИ сервера (как минимум без встроенных бекдоров "для своих"). Если ты боишься читов вроде "рентгена", когда игрок видит то, чего видеть не должен - то тут всё ещё проще, сервер просто не должен сообщать клиенту то, чего клиенту знать не обязательно. Клиенту не нужно знать, что противник находится за стеной, даже если стену возможно прострелить или взорвать. Если нужно воспроизвести звук шагов за стеной, то очевидно, что этот звук услышат все игроки, а не только читеры. Какие ещё читы могут быть?
Разве что с аим-ботами таким способом не справиться. Но аим-боту вообще не нужно копаться в каком-то коде, ему достаточно видеть картинку, которую видит игрок, и эмулировать движения мыши, что ты никак не сможешь отследить со стороны клиента/сервера. Тут поможет только обучение нейронок на собранных с читеров данных, либо модерация вручную (суть одно и то же).
Короче, не понимаю твоей проблемы. Обычно исходный код скрывают либо от стыда за говнокод, либо насмотревшись на большие корпорации... А большим корпорациям скрывать код нужно лишь чтобы их конкуренты не сделали копипасту, переманив всех платёжеспособных пользователей. Почему Майкрософт не волнует существование линукса? Потому что линукс - не винда, он не способен заменить винду. Почему Майкрософт не волнует Колибри? Потому что Колибри - не копия, а обратная разработка, не успевающая за оригиналом, и поэтому тоже не способна заменить винду. Вот если Майкрософт откроет исходники винды бесплатно для всех, то быстро возникнут 100% совместимые и взаимозаменяемые с оригиналом форки-конкуренты, которые переманят большинство пользователей от сервисов Майкрософт, и она разорится. А ты - не Майкрософт, ты ноунейм индюк, который сам должен платить игроку (все эти обзорщики, бесплатные раздачи, скидки на и без того смешную цену в 30 рублей, когда с продажи карточек игрок получает больше, чем потратил на игру), чтобы он захотел скачать твоё поделие себе на компьютер, не говоря уж о том, чтобы регулярно запускать. Ты только выиграешь от опенсурса и форков, если твоя игра стоит хоть что-то, в противном случае ничего не проиграешь (так и останешься никому не нужным ноунеймом с никому не нужным быдлокодом на гитхабе).
>Представь себе свою входную дверь...
Ясно, ты не читал статью по ссылке:
>Например, если кто-то хранит запасной ключ под ковриком, в случае, если двери заперты снаружи, то он полагается на безопасность через неясность. Теоретическая уязвимость в системе безопасности в том, что кто-то может ворваться в дом, открыв дверь с помощью этого запасного ключа. Кроме того, поскольку грабители часто знают предполагаемые места тайников, владелец дома будет подвергаться большому риску кражи со взломом, скрывая ключ, так как усилие, требуемое для того, чтобы найти ключ, вероятно, будет меньше усилий, необходимых для проникновения (например путём взлома) другим способом, например, через стекло. Хозяин добавил уязвимость — тот факт, что входной ключ хранится под ковриком — в систему, и такую, которую очень легко угадать и эксплуатировать.
Вот у тебя есть какой-то код. У него есть известная тебе уязвимость (ключ под ковриком), но ты надеешься, что "90% хакеров" не смогут этой уязвимостью воспользоваться, потому что они не знают о существовании этой уязвимости (не видели, как ты клал ключ под коврик). Но на практике тебе, во-первых, будет достаточно всего одного ограбления квартиры, а, во-вторых, твой ключ под ковриком хакеры видели у сотен закрытых дверей, владельцы которых так же как и ты полагались на то, что об этой уязвимости никто не узнает.
>Поэтому, код сервера и клиента общий. Поэтому то и важно усложнить декомпиляцию кода устройства игры.
Не понял. Ты чего боишься? Читеров на твоём сервере или создания независимых серверов третьими лицами? На счёт серверов не беспокойся, если твоя игра когда-нибудь станет достаточно популярной, обязательно создадут пиратский сервер путём обратной разработки протокола, по которому клиент общается с сервером, так делали для многих ММО. К тому же для инди-игр выгодно предоставлять игрокам свободу создания собственных серверов, это делает их более популярными и надёжными.
Что касается читеров, повторюсь, читерам бесполезно знать код твоего сервера, потому что читерам важно лишь изменить данные на реальном сервере, а сделать им это не позволит разумно построенное АПИ сервера (как минимум без встроенных бекдоров "для своих"). Если ты боишься читов вроде "рентгена", когда игрок видит то, чего видеть не должен - то тут всё ещё проще, сервер просто не должен сообщать клиенту то, чего клиенту знать не обязательно. Клиенту не нужно знать, что противник находится за стеной, даже если стену возможно прострелить или взорвать. Если нужно воспроизвести звук шагов за стеной, то очевидно, что этот звук услышат все игроки, а не только читеры. Какие ещё читы могут быть?
Разве что с аим-ботами таким способом не справиться. Но аим-боту вообще не нужно копаться в каком-то коде, ему достаточно видеть картинку, которую видит игрок, и эмулировать движения мыши, что ты никак не сможешь отследить со стороны клиента/сервера. Тут поможет только обучение нейронок на собранных с читеров данных, либо модерация вручную (суть одно и то же).
Короче, не понимаю твоей проблемы. Обычно исходный код скрывают либо от стыда за говнокод, либо насмотревшись на большие корпорации... А большим корпорациям скрывать код нужно лишь чтобы их конкуренты не сделали копипасту, переманив всех платёжеспособных пользователей. Почему Майкрософт не волнует существование линукса? Потому что линукс - не винда, он не способен заменить винду. Почему Майкрософт не волнует Колибри? Потому что Колибри - не копия, а обратная разработка, не успевающая за оригиналом, и поэтому тоже не способна заменить винду. Вот если Майкрософт откроет исходники винды бесплатно для всех, то быстро возникнут 100% совместимые и взаимозаменяемые с оригиналом форки-конкуренты, которые переманят большинство пользователей от сервисов Майкрософт, и она разорится. А ты - не Майкрософт, ты ноунейм индюк, который сам должен платить игроку (все эти обзорщики, бесплатные раздачи, скидки на и без того смешную цену в 30 рублей, когда с продажи карточек игрок получает больше, чем потратил на игру), чтобы он захотел скачать твоё поделие себе на компьютер, не говоря уж о том, чтобы регулярно запускать. Ты только выиграешь от опенсурса и форков, если твоя игра стоит хоть что-то, в противном случае ничего не проиграешь (так и останешься никому не нужным ноунеймом с никому не нужным быдлокодом на гитхабе).
Годнота-то годнотой, но нащёт быстро накидать мешей и спрототипировать уровень, эт я конешно поторопился. Да... Прошло 4 часа. Дверь для дома готова.
Ещё одна панелька. Ещё чуть-чуть и панельная ди вити иташка будет готова.
>Более менее рабочий вариант обладает совсем уж нереалистичным свойством: если упираешься в стену подвижной платформы, стоя на ней, она начинает двигаться. Эффект Мюнхаузена, епт!
У меня такое вообще без каких-либо велосипедов было. Если ты прикладываешь "силу" к RigidBody, он будет толкать все остальные RigidBody, даже если якобы "стоит" на их же поверхности. Дело в том, что функция для применения силы работает примерно как ракетный двигатель, тогда как мы ожидаем от персонажа отталкивание от поверхности, на которой он стоит. Если уходить в реалистичную физику, персонаж должен прикладывать к объекту, по которому идёт, соответствующие силы, отталкивающие опору в противоположном движению персонажа направлении, тогда толкать стену не получится - силы, направленные в противоположные направления, в сумме будут равны нулю. Правда, я думаю, на практике достичь стабильной симуляции не получится, обязательно будет хотя бы небольшой дрейф в каком-либо направлении из-за ошибок округления float.
Но мне кажется, что выход всё же есть, нужно просто раздельно регистрировать контакты "ступней" персонажа и всего остального его тела. Если ступни касаются движущейся платформы, ускорение которой меньше силы трения покоя (или как оно там, я не разбираюсь в физике) - персонаж суммирует свою скорость со скоростью платформы. Но если он пытается двигаться и упирается телом в препятствие, которое является одним целым с платформой, то он должен принудительно остановиться относительно платформы, не ожидая ответа физического движка. Думаю, для этого потребуется две отдельных Area, превышающих по размеру CollisionShape игрока, и для Area тела нужно точно знать вектор контакта, чтобы отличать касание спиной от касания грудью.
Честно говоря, я пытался сделать что-то подобное примерно полгода назад, но так ни к чему хорошему не пришёл, а в моём случае скреплять персонажа с другими объектами - не выход, мне хотелось иметь возможность двигаться по рандомно раскиданным RigidBody, которые могут иметь собственные двигатели разного вида. Психанул и забил на проект, но иногда хочется продолжить...
>Более менее рабочий вариант обладает совсем уж нереалистичным свойством: если упираешься в стену подвижной платформы, стоя на ней, она начинает двигаться. Эффект Мюнхаузена, епт!
У меня такое вообще без каких-либо велосипедов было. Если ты прикладываешь "силу" к RigidBody, он будет толкать все остальные RigidBody, даже если якобы "стоит" на их же поверхности. Дело в том, что функция для применения силы работает примерно как ракетный двигатель, тогда как мы ожидаем от персонажа отталкивание от поверхности, на которой он стоит. Если уходить в реалистичную физику, персонаж должен прикладывать к объекту, по которому идёт, соответствующие силы, отталкивающие опору в противоположном движению персонажа направлении, тогда толкать стену не получится - силы, направленные в противоположные направления, в сумме будут равны нулю. Правда, я думаю, на практике достичь стабильной симуляции не получится, обязательно будет хотя бы небольшой дрейф в каком-либо направлении из-за ошибок округления float.
Но мне кажется, что выход всё же есть, нужно просто раздельно регистрировать контакты "ступней" персонажа и всего остального его тела. Если ступни касаются движущейся платформы, ускорение которой меньше силы трения покоя (или как оно там, я не разбираюсь в физике) - персонаж суммирует свою скорость со скоростью платформы. Но если он пытается двигаться и упирается телом в препятствие, которое является одним целым с платформой, то он должен принудительно остановиться относительно платформы, не ожидая ответа физического движка. Думаю, для этого потребуется две отдельных Area, превышающих по размеру CollisionShape игрока, и для Area тела нужно точно знать вектор контакта, чтобы отличать касание спиной от касания грудью.
Честно говоря, я пытался сделать что-то подобное примерно полгода назад, но так ни к чему хорошему не пришёл, а в моём случае скреплять персонажа с другими объектами - не выход, мне хотелось иметь возможность двигаться по рандомно раскиданным RigidBody, которые могут иметь собственные двигатели разного вида. Психанул и забил на проект, но иногда хочется продолжить...
>внутри движка мини-тридэ-редактор
Зачем это нужно, если для прототипов в Годо есть CSG шейпы, которые намного проще в использовании и тоже прекрасно экспортируются в OBJ (правда, сетка там то ещё говно, но в блендере фиксится), а для любой более-менее серьёзной 3D графики (включая текстурирование отдельных полигонов) есть полноценный Блендер, из которого можно экспортировать сцены в формате Годо?
Я один раз целую квартиру с предметами интерьера в Годо из одних только CSG форм собрал, особенно понравилось лепить технику вроде холодильника, плиты, стиралки... Тасканием вершин и полигонов я бы замучился это делать, тем более в Годо с его кривыми/отсутствующими хоткеями по сравнению с Блендером.
>>799757
>>799765
Ну и в чём преимущество по сравнению с CSG?
> Ну и в чём преимущество по сравнению с CSG?
CSG вроде как тормозной, по заверениям на форумах, а от этого плагина получаются обычные меши. Плагин предоставляет гизмы для редактирования простых мешей.
И да, автор заявляет поддержку плагином CSG мешей, то есть, часть прототипирования можно сделать юнионами, а часть редактированием вершин/граней.
> персонаж должен прикладывать к объекту, по которому идёт, соответствующие силы, отталкивающие опору в противоположном движению персонажа направлении, тогда толкать стену не получится
Передвижение при помощи невидимого колеса, которому скрипт придаёт torque_impulse но там есть свои траблы. В общем, с физикой на данном этапе развития пекарен бида-бида. Даже в платных физических движках, типа havok всё организовано так же, как в буллете.
>CSG вроде как тормозной
Только если ты в рантайме шейпы двигать пытаешься. Результат генерируется только один раз на каждый сдвиг одного из шейпов, дальше там обычный меш отрисовывается.
>получаются обычные меши
Экспорт в GLTF есть. Что тебе ещё для прототипа нужно?
>>799775
>extrude
За таким в Blender, очевидно же.
>двигать точки
А за такое олдфаги-тридешники бьют по рукам.
>Передвижение при помощи невидимого колеса, которому скрипт придаёт torque_impulse но там есть свои траблы.
Зачем такие костыли, если можно самостоятельно все нужные законы физики реализовать. Просто математика там... и скорость вычислений на GDScript будет не очень.
>Даже в платных физических движках, типа havok всё организовано так же, как в буллете.
Я читал, что PhysX впереди планеты всей благодаря хардварной поддержке NVIDIA. В своё время компания, создавшая физикс, пыталась производить собственные "ускорители физики", которые предполагалось вставлять в материнскую плату подобно видеокартам. Но нвидиа быстренько купила эту компанию и встроила их чипы в свои видеокарты... Короче, эти чипы - не CUDA, и использовать их разрешено только PhysX, поэтому все остальные физические движки (даже платные) автоматически проигрывают.
> Зачем такие костыли
> если можно самостоятельно все нужные
> костыли
> Зачем
> и скорость вычислений на GDScript будет не очень
А torque_impulse отправляет запрос на физические вычисления прямо в сишные потроха физического сервера.
>torque_impulse отправляет запрос на физические вычисления прямо в сишные потроха физического сервера
Это очевидно. Но как ты будешь сцену с колесом собирать? Колесо - это отдельный физический объект, соединённый с помощью джойнтов с основным физическим объектом персонажа? Я к тому, что на практике может оказаться эффективнее посчитать простую формулу на GDScript, чем конструировать что-то из нескольких базовых физических объектов, хотя, разумеется, тот же код на C работал бы в несколько раз быстрее. Даже если ты откажешься от дерева сцены и будешь напрямую манипулировать объектами физического сервера, что, между прочим, лишает тебя удобств графического редактора.
>>799734
Годится для того, чтобы быстро заглушки на прототипе набросать в виде таблеток, кубов, цилиндров и сфер. Потом всё равно на нормальные модели менять надо. Сделай гигантскую сферу - увидишь угловатости дикие, как не сглаживай.
> Но как ты будешь сцену с колесом собирать? Колесо - это отдельный физический объект, соединённый с помощью джойнтов с основным физическим объектом персонажа?
Не так.
Объект и есть колесо.
А чтобы спрайт прикреплённый не вращался, ему в _process задаётся -rotation физического объекта. Но тут возникает ограничение, невозможно задать никакую другую форму коллизий, кроме круга.
Сам же и нашёл. Может кому полезно тоже будет.
В простом виде без условий и проверок это выглядит как
func _on_ExitGame_pressed():
$ConfirmationWindow.show()
yield($ConfirmationWindow, "visibility_changed")
InGameMenuUIiFunctions._on_ExitGame_pressed()
Без yield() пролетит что с паузой, что без неё. А если как у меня, с проверками того, что было нажато в окне подтверждения, то флаг подтверждения сработает только при повторном нажатии кнопки ExitGame.
Извини, не заметил твой пост. Да, конечно же yield().
Если нужно красиво, то на каждый возможный стык тебе нужно нарисовать отдельные клетки и подставлять их динамически, при обнаружении стыков.
>спрайт
>круг
Ааа, так с этого и нужно было начинать, что у тебя 2D колобок, а не нормальный 3D гуманоид. Это всё меняет.
>как лучше организовать стыки рядом стоящих клеток с разными типами покрытия, например земля и песок, или земля и трава?
Для каждого типа блока (земля, трава, песок, камень и т.д.) заполняется специальный текстурный атлас на несколько десятков вариаций этого типа блока, с прозрачными пикселями там, где должен быть блок другого типа. Шаблоны ищи в интернете сам. Если тайл окружён 4/8 тайлами того же типа, что и он, это будет полный тайл, без прозрачных пикселей. Если есть соседи другого типа - поверх соседа рисуется один из вариантов с прозрачными пикселями, создавая плавный переход между блоками.
Помню, где-то была старая хорошая статья на эту тему сразу с примером шаблона, но не помню где. Для наглядного примера загугли тайлсеты блоков Террарии, там этот способ используется.
>>799945
>Земля - земля трава - трава
Этот вариант потребует создавать огромную кучу атласов на каждую комбинацию типов тайлов, и при добавлении нового типа число атласов будет расти экспоненциально. Поэтому так делали лишь в самых примитивных играх, а не "всегда", для чего-то более сложного приходится делать методом с прозрачными пикселями.
>>799961
>стыка рёбер клетки
Подгоняй тайлы в своей рисовальной программе, чтобы не было видно стыков, лол. В некоторых есть специальные инструменты для тестирования бесшовности текстур.
>>799971
>подставлять их динамически
Это только если он генерирует карту сам или использует какой-то другой велосипед. Встроенный редактор тайлмап поддерживает автоматический тайлинг. Правда, чтобы прозрачные тайлы работали как я описываю (частичный тайл поверх полного тайла), придётся делать несколько тайлмап, если не ошибаюсь.
Наверное, во внешних редакторах типа Tiled тоже должен быть реализован автотайлинг с прозрачными пикселями. Во всяком случае карты там многослойные и редактор куда удобнее, чем у Годо.
И ещё в плагинах в целом не нравится то, что подавляющее их количество требует самих себя в релизном паке игры, это вообще хуита, ладно там если 3,5 скрипта, но есть же плагины с кучей графики, иконки кнопок например, которые в релизном продукте воще не нужны. Почему плагиноделы не думают об этом? Надо чтобы каждый плагин генерировал файлы с данными и оставлял один легковесный скрипт-парсер, который используется игрой и всё, весь остальной плагин отключается и исключается из экспорта. Нахуй он там не нужон. Но это к делу не относится, так, чисто боль свою выложил, держу в курсе.
Подумываю пилить свой велосипед диалогового конструктора, но думаю, вдруг я упускаю годноту? Кто юзает сторонние редакторы/парсеры диалогов? Прорекламируйте ваши выбранные решения, плиз. Может есть вообще не на годоте редакторы, но генерирующие готовые файлы, например ЖСОН? Парсер уж я сам сваяю, не проблема.
А есть еще годные текстовые туториалы? (ненавижу видео)
Могу тебя прямо ИТТ в онлайн-режиме обучить. Только сообщи время когда ты будешь точно на дваче.
Ну а пока ученики собираются, я начну. Текст ведь никуда не пропадёт.
Типовые туториалы обычно начинаются с того, как двигать кинематик-боди, и как читать клавиши инпута. Ящитаю, это контрпродуктивно. Начинать следует с сущности которая будет в твоём контроллере энивей, так зачем же переписывать код по сто раз? Начнём со стейт-машины.
Определим, какие состояния будет иметь наш будущий персонаж:
1. IDLE. Состояние покоя. Персонаж деактивирован вообще. Это состояние потребуется для катсцен или предзагрузок.
2. GROUNDED. Состояние покоя но уже активированное. Персонаж жив, готов действовать и стоит на твёрдой поверхности. В этом состоянии игра ожидает ввод от игрока.
3. WALK. Идти. Персонаж медленно движется.
4. RUN. Бежать. Персонаж шифтует. Если мы захотим подключать к игре геймпад, то персонаж всегда будет переходить в это состояние, минуя предыдущее. Потому что на геймпаде мы сможем задавать силу движения аналоговым стиком, а на клавиатуре нет. Поэтому на клавиатуре традиционно этот режим будем включать с шифтом.
5. JUMP. Короткое состояние, при котором перс подпрыгивает и сразу переходит в следующее.
6. FALL. Падение. В этом состоянии персонаж падает вниз. пока не обнаружится коллизия.
7. TOUCHDOWN. При обнаружении коллизии мы считаем урон и переходим в одно из возможных состояний.
8. DIE. Персонаж умирает и переходит в IDLE. За тип смерти будут отвечать другие компоненты, потому что смерть может наступить по разным причинам, очевидно.
Итак. Создадим новый скрипт, унаследуемся от KinematicBody и напишем в него:
> enum states { idle, grounded, walk, run, jump, fall, touchdown, die }
> var state : int = states.idle
Заметь, мы пока ещё даже не создавали ни сцену, ни тела, ни коллизии. Только скрипт. Всё остальное будет позже. Возможно даже у тебя уже есть наработки, их можно задействовать, подключив новосозданный скрипт.
Теперь опишем утилитарные функции стейтмашины, в которых будет происходить вся магия. Это несложно и когда ты прочувствуешь принцип стейтмашин, ты сам охуеешь от того, как ты жил без них раньше.
1. Функция обновления, которая будет вызываться из _process. В ней мы будем обновлять состояние.
2. Функция транзита, котораю будет выключать предыдущее состояние и включать следующее.
3. Функция включения (входа).
4. Функция отключения (выхода).
Если ты посмотришь существующие аддоны стейтмашин, то сможешь заметить, что подавляющее большинство их построено по данной схеме, но с различными усложнениями и абстракциями. Например, стейты - это отдельные объекты, а вся машина унаследована от Node и её можно запихнуть в дерево сцен. Нам это не нужно на данном этапе, а если в дальнейшем нам потребуется, мы с лёгкостью усложним наш код минимальными усилиями, потому что он будет соответствовать принципам SOLID.
Итак, запишем:
> func fsm_process(delta: float): pass
> func fsm_transition(state_from: int, state_to: int): pass
> func fsm_state_enter(state_id: int): pass
> func fsm_state_exit(state_id: int): pass
Еще раз обращу внимание, пока что мы вообще не касались темы кинематики, физики и всего прочего, с чего начинаются типовые туториалы.
Ну а пока ученики собираются, я начну. Текст ведь никуда не пропадёт.
Типовые туториалы обычно начинаются с того, как двигать кинематик-боди, и как читать клавиши инпута. Ящитаю, это контрпродуктивно. Начинать следует с сущности которая будет в твоём контроллере энивей, так зачем же переписывать код по сто раз? Начнём со стейт-машины.
Определим, какие состояния будет иметь наш будущий персонаж:
1. IDLE. Состояние покоя. Персонаж деактивирован вообще. Это состояние потребуется для катсцен или предзагрузок.
2. GROUNDED. Состояние покоя но уже активированное. Персонаж жив, готов действовать и стоит на твёрдой поверхности. В этом состоянии игра ожидает ввод от игрока.
3. WALK. Идти. Персонаж медленно движется.
4. RUN. Бежать. Персонаж шифтует. Если мы захотим подключать к игре геймпад, то персонаж всегда будет переходить в это состояние, минуя предыдущее. Потому что на геймпаде мы сможем задавать силу движения аналоговым стиком, а на клавиатуре нет. Поэтому на клавиатуре традиционно этот режим будем включать с шифтом.
5. JUMP. Короткое состояние, при котором перс подпрыгивает и сразу переходит в следующее.
6. FALL. Падение. В этом состоянии персонаж падает вниз. пока не обнаружится коллизия.
7. TOUCHDOWN. При обнаружении коллизии мы считаем урон и переходим в одно из возможных состояний.
8. DIE. Персонаж умирает и переходит в IDLE. За тип смерти будут отвечать другие компоненты, потому что смерть может наступить по разным причинам, очевидно.
Итак. Создадим новый скрипт, унаследуемся от KinematicBody и напишем в него:
> enum states { idle, grounded, walk, run, jump, fall, touchdown, die }
> var state : int = states.idle
Заметь, мы пока ещё даже не создавали ни сцену, ни тела, ни коллизии. Только скрипт. Всё остальное будет позже. Возможно даже у тебя уже есть наработки, их можно задействовать, подключив новосозданный скрипт.
Теперь опишем утилитарные функции стейтмашины, в которых будет происходить вся магия. Это несложно и когда ты прочувствуешь принцип стейтмашин, ты сам охуеешь от того, как ты жил без них раньше.
1. Функция обновления, которая будет вызываться из _process. В ней мы будем обновлять состояние.
2. Функция транзита, котораю будет выключать предыдущее состояние и включать следующее.
3. Функция включения (входа).
4. Функция отключения (выхода).
Если ты посмотришь существующие аддоны стейтмашин, то сможешь заметить, что подавляющее большинство их построено по данной схеме, но с различными усложнениями и абстракциями. Например, стейты - это отдельные объекты, а вся машина унаследована от Node и её можно запихнуть в дерево сцен. Нам это не нужно на данном этапе, а если в дальнейшем нам потребуется, мы с лёгкостью усложним наш код минимальными усилиями, потому что он будет соответствовать принципам SOLID.
Итак, запишем:
> func fsm_process(delta: float): pass
> func fsm_transition(state_from: int, state_to: int): pass
> func fsm_state_enter(state_id: int): pass
> func fsm_state_exit(state_id: int): pass
Еще раз обращу внимание, пока что мы вообще не касались темы кинематики, физики и всего прочего, с чего начинаются типовые туториалы.
И тут у нас обнаруживается мааленькая проблемка. Когда мы идём или бежим, мы ведь можем двигаться наклонившись, или лёжа ползти, или ещё каким способом в зависимости от потребностей игры. Нам что, дописывать стейты? Нет. Нам поможет принцип иерархических стейтмашин. Допишем в наш код следующее:
> enum stance_states { standing, climbing, crouching, lying}
и
> func stance_fsm_process(delta: float): pass
> func stance_fsm_transition(state_from: int, state_to: int): pass
> func stance_fsm_state_enter(state_id: int): pass
> func stance_fsm_state_exit(state_id: int): pass
ииии...
Тут у нас обнаруживается вторая проблема, уже покрупнее. Наш код стал нарушать DRY-принцип (донт рипит ёселф), мы ударились в копипасту. Что делать?
Нам следует организовать систему подключаемых невизуальных компонентов. Прямо сейчас, сразу, не написав FPS-related кода ни строки. Это и есть проектирование, чуваки. Мы можем делать с нашим кодом всё что угодно, потому что код наш это пока что одни шаблоны, каркас, кости. Без мяса.
Итак, создадим новый скрипт, унаследуемся от Reference и напишем там
> extends Reference
> class_name Component
И мы создадим ещё один скрипт, и напишем в нём:
> extends Component
> class_name FSMComponent
> var state : int
И наконец мы можем создать ещё два скрипта, в одном мы напишем:
> extends FSMComponent
> class_name MovingFSM
И мы перенесем в него предыдущий код:
> enum states { idle, grounded, walk, run, jump, fall, touchdown, die }
> func process(delta: float): pass
> func transition(state_from: int, state_to: int): pass
> func state_enter(state_id: int): pass
> func state_exit(state_id: int): pass
Во втором мы напишем, перенеся и удалив лишнее:
> extends FSMComponent
> class_name StanceFSM
> enum states { standing, climbing, crouching, lying}
> func process(delta: float): pass
> func transition(state_from: int, state_to: int): pass
> func state_enter(state_id: int): pass
> func state_exit(state_id: int): pass
И наконец, в опустевшем первоначальном скрипте мы напишем:
> extends KinematicBody
> var moving_state := MovingFSM.new()
> var stance_state := StanceFSM.new()
> func _physic_process(delta):
>____moving_state.process(delta)
>____stance_state.process(delta)
Примечание: Если бы гдскрипт поддерживал на должном уровне наследование и интерфейсы, мы бы в абстрактные классы вынесли бы все функции, а так нам нет смысла этим заниматься, проще реализовать интерфейс вручную, держа в уме, что каждый потомок класса FSMComponent должен иметь вышеописанные 4 метода-функции. Если делать это же самое в шарпе, то там всё шоколадно будет, мы бы описали интерфейсы вместо двух пустых классов, и затем реализовали бы их.
Вот теперь можно приступать к уроку 2.
И тут у нас обнаруживается мааленькая проблемка. Когда мы идём или бежим, мы ведь можем двигаться наклонившись, или лёжа ползти, или ещё каким способом в зависимости от потребностей игры. Нам что, дописывать стейты? Нет. Нам поможет принцип иерархических стейтмашин. Допишем в наш код следующее:
> enum stance_states { standing, climbing, crouching, lying}
и
> func stance_fsm_process(delta: float): pass
> func stance_fsm_transition(state_from: int, state_to: int): pass
> func stance_fsm_state_enter(state_id: int): pass
> func stance_fsm_state_exit(state_id: int): pass
ииии...
Тут у нас обнаруживается вторая проблема, уже покрупнее. Наш код стал нарушать DRY-принцип (донт рипит ёселф), мы ударились в копипасту. Что делать?
Нам следует организовать систему подключаемых невизуальных компонентов. Прямо сейчас, сразу, не написав FPS-related кода ни строки. Это и есть проектирование, чуваки. Мы можем делать с нашим кодом всё что угодно, потому что код наш это пока что одни шаблоны, каркас, кости. Без мяса.
Итак, создадим новый скрипт, унаследуемся от Reference и напишем там
> extends Reference
> class_name Component
И мы создадим ещё один скрипт, и напишем в нём:
> extends Component
> class_name FSMComponent
> var state : int
И наконец мы можем создать ещё два скрипта, в одном мы напишем:
> extends FSMComponent
> class_name MovingFSM
И мы перенесем в него предыдущий код:
> enum states { idle, grounded, walk, run, jump, fall, touchdown, die }
> func process(delta: float): pass
> func transition(state_from: int, state_to: int): pass
> func state_enter(state_id: int): pass
> func state_exit(state_id: int): pass
Во втором мы напишем, перенеся и удалив лишнее:
> extends FSMComponent
> class_name StanceFSM
> enum states { standing, climbing, crouching, lying}
> func process(delta: float): pass
> func transition(state_from: int, state_to: int): pass
> func state_enter(state_id: int): pass
> func state_exit(state_id: int): pass
И наконец, в опустевшем первоначальном скрипте мы напишем:
> extends KinematicBody
> var moving_state := MovingFSM.new()
> var stance_state := StanceFSM.new()
> func _physic_process(delta):
>____moving_state.process(delta)
>____stance_state.process(delta)
Примечание: Если бы гдскрипт поддерживал на должном уровне наследование и интерфейсы, мы бы в абстрактные классы вынесли бы все функции, а так нам нет смысла этим заниматься, проще реализовать интерфейс вручную, держа в уме, что каждый потомок класса FSMComponent должен иметь вышеописанные 4 метода-функции. Если делать это же самое в шарпе, то там всё шоколадно будет, мы бы описали интерфейсы вместо двух пустых классов, и затем реализовали бы их.
Вот теперь можно приступать к уроку 2.
Во-первых, по уроку: сначала стоило схематически или словами описать архитектуру, которую ты предлагаешь реализовать, прежде чем вдаваться в подробности устройства конечных автоматов. А то сейчас твои уроки можно назвать "изучаем конечные автоматы на примере игрового персонажа", а не "FPS-контроллер".
Во-вторых, по архитектуре: я правильно понял, что весь код персонажа будет разбросан по обработчикам событий нескольких разных конечных автоматов? В смысле, ты упомянул, что у тебя код дважды дублируется, после чего разделил дубли на два отдельных файла, но кода-то меньше не стало! Как было 8 обработчиков событий, так и осталось, и говоришь, что на каждый конечный автомат их нужно копипастить. Зачем тогда было это всё начинать, если, как ты говоришь, GDScript не поддерживает то, что ты пытаешься реализовать? Так много вопросов, так мало ответов...
Я сначала хотел предложить перенести обработчики конечных автоматов в их общего предка (FSMComponent), но потом понял, что ты планируешь каждому конечному автомату какое-то своё поведение делать (зачем?), и поэтому так коротко написал.
Сам я пока только базовый контроллер персонажа делал, движение, ускорение, прыжок, всё в одном коротеньком скрипте без конечного автомата. Упёрся в то, что невозможно сделать нормальную физику движения, постоянно какие-то баги, глюки, рывки и т.п. Так что забил и не развиваю эту тему, смысл реализовывать сложную систему, если движок багнутый и эти баги никак не обойти, а разрабы движка их много лет не исправляют? Недавно даже порезал контроллер, сократив всё до одного вызова move_and_slide(), потому что Godot безбожно тормозит даже на одном этом вызове, приходится экономить...
> ты планируешь каждому конечному автомату какое-то своё поведение делать (зачем?)
Один будет переключать состояние движения, второй состояние позы/стойки...
> постоянно какие-то баги, глюки, рывки и т.п. Так что забил и не развиваю эту тему, смысл реализовывать сложную систему, если движок багнутый и
> эти баги никак не обойти, а разрабы движка их много лет не исправляют
Ясн.
>Ясн.
Чего тебе ясно? Уже несколько тредов подряд обсуждаем это. На стыках проблемы, в углах проблемы, на ступеньках проблемы, на наклонных поверхностях проблемы, как фиксить - никто не знает, иссуи весят по 4 года и все только разводят руками. При этом на буллете одни баги, на встроенном движке другие, но оба варианта неюзабельные. Я не знаю, может, во всяких хавоках и физиксах точно такие же баги, может, так принято во всех игровых физических движках? Ну, типа, из-за оптимизаций... Но строить на этом стабильную физическую песочницу невозможно. Вот и остаётся только делать персонажа как в играх 90-х и смириться с рывками на стыках идеально состыкованных поверхностей. Но когда ты пытаешься накинуть на сцену побольше персонажей, ВНЕЗАПНО оказывается, что move_and_slide съедает всё время кадра начиная с примерно 100-150 персонажей, вот как это фиксить? А хрен знает, лезть в исходники движка и пытаться разобраться не хочу. В общем, всё очень печально, а альтернатив нет...
> На стыках проблемы
> в углах проблемы
Твои низкокачественные модели. Проектируй уровень лучше. Всё просчитывай.
> на ступеньках проблемы
> на наклонных поверхностях проблемы
Твой низкокачественный код движения, не учитывающий, ни ступеньки, ни наклоны.
> как фиксить - никто не знает
Отучаемся говорить за всех.
> иссуи весят по 4 года и все только разводят руками
Кто эти все, о которых речь? Они сейчас с нами в одной комнате?
> move_and_slide съедает всё время кадра начиная с примерно 100-150 персонажей, вот как это фиксить?
Учить физику и юзать RigidBody.
Я с давних пор для себя понял одну вещь, чем проще инструмент, чем более доступным он кажется, тем менее он функционален. И наоборот, когда инструмент сложен, и его создатель говорит, что с наскоку инструментом не воспользуешься, надо учиться с ним работать, то такой инструмент гораздо более функционален. Приведу примеры.
Blender и SketchUp - первый сложнее второго, его надо осваивать, второй проще, можно без какого бы то ни было опыта моделировать модельки. Но! В блендере ты сможешь смоделировать буквально всё, а в скетчапе только примитивные модельки и упрёшься в невозможность нормально их выгрузить.
И вторым примером является как раз таки KinematicBody, который в документации же заявлен как простой инструмент для тех, кому неохота связываться и разбираться с физикой. Догадываешься уже, в чём попадалово? Овладев интеграцией сил в RigidBody ты сможешь буквально всё, а с KinematicBody будешь бороться с багами move_and_slide, ловя себя на мысли, что тебе приходится велосипедить всю физику заново. Обычно типовое создание персонажа на KinematicBody включает в себя добавление таких переменных, как гравитация и скорость. Я тут недавно тоже лепил с нуля, и поймал себя на мысли, что добавляю ещё и переменную массы, и и инерции и тогда я спросил себя, нахуй я это делаю? Ведь рядом лежит готовое решение - RigidBody со всей физикой из коробки.
Давно меня тут не было, так и не смог сделать физику меча и добавить персонажу dash для его быстрого перемещения по полю. Ну и похуй! Забыли и забили!
Есть вопрос к знатокам движка, будет трудно готовый код из unity в godot переписать? Вот хоть убейте, но я не программист! Создать страничку на html для меня уже достижение.
Спасибо, сейчас это пока только крик души.
Почему нельзя нормально написать, что-то типа node not found?
Это копия, сохраненная 4 марта в 07:45.
Скачать тред: только с превью, с превью и прикрепленными файлами.
Второй вариант может долго скачиваться. Файлы будут только в живых или недавно утонувших тредах. Подробнее
Если вам полезен архив М.Двача, пожертвуйте на оплату сервера.