Продолжай мужик, очень круто. Таких людей не хватало на русскоязычном сегменте. Очень грамотный подход видео, все эти презентации, объяснение своих действий и того что происходит в коде.
Очень хороший пример того что нужно выстраивать архитектуру под свои нужды. Многие думают Опа есть MVC/MVVM пишу весь проект на нём и должно быть удобно и расширяемо, или весь проект на ECS. Более опытные уже понимают что можно инфраструктурные штучки просто на ООП писать, геймплей на ECS, UI на MVC. Но тут же в самом геймплее гибрид ECS с идеями из ООП. И можно негодовать, ведь вроде как системы предназначены как раз для работы со всем пулом энтити, а тут какие-то кастомные штуки для конкретной энтити. Но цель не сделать всё как на википедии написано, а сделать чтобы было удобно и расширяемо🙂
Тут сразу вопрос есть: вот у тебя есть патрулирование. Сразу же вспоминаем, что на патруль люди юнитов ставят не для того, чтобы они просто так бегали. В плане, они должны при нахождении врага рядом начать его атаковать. То есть, в целом стейт-машина должна сама совершить переход в другое состояние. Может это я что-то не заметил, но как именно в коде такой переход осуществляется - пока не увидел: выглядит так, что все команды задаются исключительно вручную. Опять же - а как это будет работать с туманом войны? Есть теория, что так же, как и в суприм командере: если ты затаргетил врага, то твои танки до него буду ехать хоть через всю карту, даже если он вообще к себе на базу убежал. В плане, что нет компонента, который бы сбрасывал таргет, если цель в тумане войны. В общем, есть теория, что все равно придется делать еще какую-то вторую стейт машину, которая будет следить за такими моментами.
Все так, состояние патруля должно детектить врагов и переключать в стейт атаки, этого пока что у меня еще нет в проекте, НО, засчет переиспользования компонентов и систем, это сделать не сложно, вопрос времени :)
Проблема Дублирование кода в состояниях - мне кажется эта проблема решается разбиением на две машины состояний. Одна отвечает за то, что юнит делает в данный момент, а вторая за его долгосрочную стратегию. Что по сути у вас и сделано высокоуровневые системы управляют низкоуровневыми
У меня FSM на монобехах, но вся логика в системах. Сами стейты в зависимости от инпута перемещают по другим состояниям, к примеру HeroIdleState, просто чекает есть ли инпут на бег, если есть то го в HeroMoveState, она в методе Enter на сущность прикрепляет PerformMovementComponet, система MovementSystem подхватыает и двигает, направление рассчитывается системой CalculateDirectionSystem, также есть компонент movementdirection в котором конечная точка. Если мы выходим с HeroMoveState, то в Exit подчищаем компоненты. Ну примерно вот так у меня работает Ecs + FSM
Думаю тут можно улучшить стейт машину, если добавить некие Decision и Transitions. Тогда в Decision мы чекаем есть ли инпут на бег, и если есть, то проходит условие и транзишин сам перейдет в HeroMoveState. По идее, стейты тогда станут полностью обособленными и не будут знать друг о друге. И еще полностью вынесли логику проверок переходов вне стейтов, которую легче найти. (Обычно такие стейт машины инициализируются сразу со всеми переходами и условиями в одном месте, удобнее читать). Минусы конечно тоже есть. Такую фсм банально сложнее написать, классов может быть еще больше, и не всегда это нужно.
@@TheGoBenderстейты и не знают друг о друге, их переход происходит через state switcher, логику проверок можно вынести куда-нибудь просто чтобы код не дублировать это да. Ну про кол-во классов тут париться не стоит, каждый стейт для каждого типа врага уникальный, так как разные переходы могут быть.
На самом деле, каждый стейт можно представить в виде локальной ecs системы, апдейт которой работает, когда ты вошел в это состояние. По поводу переходов, думаю, что лучше сделать так, чтобы стейт-машина сама занималась переходами между стейтами, такой подход позволит уменьшить зависимость на state switcher, уберет дублирование кода при проверках на переход, и сделает класс более читаемым и поддерживаем с точки зрения SOLID
Это конечно с моего ООП склада ума) И такой вопрос: Получается если внутри юнита создается какая то своя ECS система, то у каждого юнита будет Свой Update который будет обрабатываться вне Глобального Update? Если так то красота ECS рушится на этом моменте
Не совсем, локальные системы, которые крепятся к конкретному юниту подчиняются глобальному апдейту. Просто это следующий шаг в построении архитектуры игры. Ключевая идея ECS сохраняется, поскольку логика отделяется от данных, но сущности можно делать уникальными не только засчет наполнения данных, но и наполнения локальных систем, которые с ними работают.
Для Команд - почему нельзя отклонять команды при получении состояния из пула команд? Просто помечая команду как выполненная? Если я сейчас нахожусь в стейт Окопанный, то при получении приказа Мув - у юнита спрашивается - ты можешь ходить? - из пула доступных Стейтов [Могу Атаковать, Могу Выкопаться], и раз в пуле нет Могу Мув - то состояние скипается (помечается выполненным) MoveNext в команде
Не очень понял про пул команд. У меня это работает немного по-другому. Приходит приказ на перемещение, есть обработчик, который висит на юните, и если обработчик видит, что юнит закопан, то такая команда просто скипается
@@CodeCraftUnityEdition Ну просто по коду ты говорил что для каждого юнита надо какой то свой скрипт для обработки команд писать, я утверждаю что это излишне) Но может это сложнее, хотя просто будет опять таки какая то система прокидываться, которая будет хранить в себе список доступных Стейтов для юнита в данный момент.
Смотри, поскольку юниты разные, то у каждого из них будут свои команды, так? Поэтому для каждого типа юнита нужна своя система, которая и будет обрабатывать команды. Есть два варика. Первый варик, написать одну глобальную CommandSystem, которая будет брать всех юнитов и обрабатывать их команды в зависимости от набора их команд. А второй - это вместо глобальной системы сделать несколько локальных систем CommandStateMachine, которые будут обрабатывать команды для каждого из юнитов
Не совсем, я делал стейт-машину исходя из команд, которые может выполнять юнит. Получается, что персонаж не может выполнять два приказа одновременно, поэтому сюда хорошо ложится концепция FSM. Но да, для IDLE нужна отдельная система, которая работает, когда нет активной команды
@@CodeCraftUnityEdition Почти во всех играх есть "Перемещение с атакой" это как раз двумя машинами решается, во второй я забыл добавить IDLE (NONE) как угодно) Ну да ладно)
Да, есть, такая механика "Перемещение с атакой", у меня в проекте есть две локальные системы: одна система работает "или беги или бей", вторая - просто атакует, если цель в радиусе :)
Продолжай мужик, очень круто. Таких людей не хватало на русскоязычном сегменте. Очень грамотный подход видео, все эти презентации, объяснение своих действий и того что происходит в коде.
Довольно уникальный и качественный контент! Лайк
Очень хороший пример того что нужно выстраивать архитектуру под свои нужды. Многие думают Опа есть MVC/MVVM пишу весь проект на нём и должно быть удобно и расширяемо, или весь проект на ECS. Более опытные уже понимают что можно инфраструктурные штучки просто на ООП писать, геймплей на ECS, UI на MVC. Но тут же в самом геймплее гибрид ECS с идеями из ООП. И можно негодовать, ведь вроде как системы предназначены как раз для работы со всем пулом энтити, а тут какие-то кастомные штуки для конкретной энтити. Но цель не сделать всё как на википедии написано, а сделать чтобы было удобно и расширяемо🙂
Комент для продвижение канала
Хорошечно!
Супер
Безумно круто, обязательно продолжайте)
Очень интересно.
Брат когда новое видео заждался уже!
Спасибо! Очень интересный и полезный контент. 😊
Стар крафт легендарная игра, надеюсь у тебя будет такая же стратегия на равные с этой легендарной игрой!😊
хорош братишка продолжай.
пожалуйста сделай продолжение
Норм
Спасибо!
Тут сразу вопрос есть: вот у тебя есть патрулирование. Сразу же вспоминаем, что на патруль люди юнитов ставят не для того, чтобы они просто так бегали. В плане, они должны при нахождении врага рядом начать его атаковать. То есть, в целом стейт-машина должна сама совершить переход в другое состояние. Может это я что-то не заметил, но как именно в коде такой переход осуществляется - пока не увидел: выглядит так, что все команды задаются исключительно вручную.
Опять же - а как это будет работать с туманом войны? Есть теория, что так же, как и в суприм командере: если ты затаргетил врага, то твои танки до него буду ехать хоть через всю карту, даже если он вообще к себе на базу убежал. В плане, что нет компонента, который бы сбрасывал таргет, если цель в тумане войны.
В общем, есть теория, что все равно придется делать еще какую-то вторую стейт машину, которая будет следить за такими моментами.
Все так, состояние патруля должно детектить врагов и переключать в стейт атаки, этого пока что у меня еще нет в проекте, НО, засчет переиспользования компонентов и систем, это сделать не сложно, вопрос времени :)
Да, про туман войны хорошее замечание, в коде стоит TODO-шка, что в будущем нужно чекать, что цель в тумане войны
Проблема Дублирование кода в состояниях - мне кажется эта проблема решается разбиением на две машины состояний. Одна отвечает за то, что юнит делает в данный момент, а вторая за его долгосрочную стратегию. Что по сути у вас и сделано высокоуровневые системы управляют низкоуровневыми
У меня FSM на монобехах, но вся логика в системах. Сами стейты в зависимости от инпута перемещают по другим состояниям, к примеру HeroIdleState, просто чекает есть ли инпут на бег, если есть то го в HeroMoveState, она в методе Enter на сущность прикрепляет PerformMovementComponet, система MovementSystem подхватыает и двигает, направление рассчитывается системой CalculateDirectionSystem, также есть компонент movementdirection в котором конечная точка. Если мы выходим с HeroMoveState, то в Exit подчищаем компоненты. Ну примерно вот так у меня работает Ecs + FSM
Думаю тут можно улучшить стейт машину, если добавить некие Decision и Transitions. Тогда в Decision мы чекаем есть ли инпут на бег, и если есть, то проходит условие и транзишин сам перейдет в HeroMoveState.
По идее, стейты тогда станут полностью обособленными и не будут знать друг о друге.
И еще полностью вынесли логику проверок переходов вне стейтов, которую легче найти. (Обычно такие стейт машины инициализируются сразу со всеми переходами и условиями в одном месте, удобнее читать).
Минусы конечно тоже есть. Такую фсм банально сложнее написать, классов может быть еще больше, и не всегда это нужно.
@@TheGoBenderстейты и не знают друг о друге, их переход происходит через state switcher, логику проверок можно вынести куда-нибудь просто чтобы код не дублировать это да. Ну про кол-во классов тут париться не стоит, каждый стейт для каждого типа врага уникальный, так как разные переходы могут быть.
На самом деле, каждый стейт можно представить в виде локальной ecs системы, апдейт которой работает, когда ты вошел в это состояние. По поводу переходов, думаю, что лучше сделать так, чтобы стейт-машина сама занималась переходами между стейтами, такой подход позволит уменьшить зависимость на state switcher, уберет дублирование кода при проверках на переход, и сделает класс более читаемым и поддерживаем с точки зрения SOLID
хз, в ооп не обязательно страдать внутренними стейт-машинами. Потом что как вариант сама комманда может являть собой стейт.
Зависит от тз
Это конечно с моего ООП склада ума) И такой вопрос: Получается если внутри юнита создается какая то своя ECS система, то у каждого юнита будет Свой Update который будет обрабатываться вне Глобального Update? Если так то красота ECS рушится на этом моменте
@@igorgulkin6251 Понял, шикарно!
Не совсем, локальные системы, которые крепятся к конкретному юниту подчиняются глобальному апдейту. Просто это следующий шаг в построении архитектуры игры. Ключевая идея ECS сохраняется, поскольку логика отделяется от данных, но сущности можно делать уникальными не только засчет наполнения данных, но и наполнения локальных систем, которые с ними работают.
12:00 ля, напиши мувер для юнита и пусть состояния его используют. Используешь композицию и избавишься от дублирования логики
Для Команд - почему нельзя отклонять команды при получении состояния из пула команд? Просто помечая команду как выполненная? Если я сейчас нахожусь в стейт Окопанный, то при получении приказа Мув - у юнита спрашивается - ты можешь ходить? - из пула доступных Стейтов [Могу Атаковать, Могу Выкопаться], и раз в пуле нет Могу Мув - то состояние скипается (помечается выполненным) MoveNext в команде
Это всё стейт машина с условными переходами делает Транзишн(СтейтФром, СтейтТо, Бул)
Не очень понял про пул команд. У меня это работает немного по-другому. Приходит приказ на перемещение, есть обработчик, который висит на юните, и если обработчик видит, что юнит закопан, то такая команда просто скипается
@@CodeCraftUnityEdition Ну просто по коду ты говорил что для каждого юнита надо какой то свой скрипт для обработки команд писать, я утверждаю что это излишне) Но может это сложнее, хотя просто будет опять таки какая то система прокидываться, которая будет хранить в себе список доступных Стейтов для юнита в данный момент.
Смотри, поскольку юниты разные, то у каждого из них будут свои команды, так? Поэтому для каждого типа юнита нужна своя система, которая и будет обрабатывать команды. Есть два варика. Первый варик, написать одну глобальную CommandSystem, которая будет брать всех юнитов и обрабатывать их команды в зависимости от набора их команд. А второй - это вместо глобальной системы сделать несколько локальных систем CommandStateMachine, которые будут обрабатывать команды для каждого из юнитов
Как будто в ООП должно было быть 2 стейт машины - Стейт IDLE и MOVE в первой, во второй ATTACK, GATHER, PATROL... Поправь если так не работает)
Не совсем, я делал стейт-машину исходя из команд, которые может выполнять юнит. Получается, что персонаж не может выполнять два приказа одновременно, поэтому сюда хорошо ложится концепция FSM. Но да, для IDLE нужна отдельная система, которая работает, когда нет активной команды
@@CodeCraftUnityEdition Почти во всех играх есть "Перемещение с атакой" это как раз двумя машинами решается, во второй я забыл добавить IDLE (NONE) как угодно)
Ну да ладно)
Да, есть, такая механика "Перемещение с атакой", у меня в проекте есть две локальные системы: одна система работает "или беги или бей", вторая - просто атакует, если цель в радиусе :)
Ну я тут пока попишу что-нибудь. Чем больше комментарием, тем ютуб лучше прогвигает этот канал, вроде.
Спасибо!