|
Unity Мультиплатформенный инструмент для разработки игр |
25.10.2020, 16:35
|
#1
|
Гигант индустрии
Регистрация: 13.09.2008
Сообщений: 2,893
Написано 1,185 полезных сообщений (для 3,298 пользователей)
|
LeoECS
Привет всем. Случайно вспомнил про булку, зашел и оказывается тут еще есть активность.
Вступление:
В некоторых темах увидел тред где Crystal с "процедурными" знаниями Блитза в очередной раз пытается сделать свой фаллаут, но только уже на Юнити и как ему сложно. Увидел как Кирпи4 спрашивает, как новичку влиться в геймдев. И вспомнилось былое время, когда у меня тоже не было знаний, но было много вопросов и как сложно было раскуривать ооп.
Но спасение есть. Когда-то давно на конференции Юнити представили Entitas фреймворк с ECS для Юнити и после этого эта тема всё больше и больше форсится, а многие мелкие студии уже давно перешли на ECS так как по уровню сложности это примерно как визуальное программирование и любой новичок крайне быстро может во всем разобраться и влиться в геймдевчик.
Самих ECS множество со своими плюсами, минусами и интеграцией в Юнити ( DOTS/uECS). Но я напишу тут пример кода на LeoECS так как он максимально простой, позволяет делать "как хочешь" в отличии от DOTS/uECS, но при этом достаточно быстрый, изначально не привязан к Юнити и без кодогенерации как тот же Entitas.
Что к чему:
Краткая суть почему ECS это хорошо заключается в том, что практически не нужно уметь кодить, не нужно знать тонну паттернов и прочих сложностей. Все просто, как и в визуальном программировании, но только там соединяем ноды, а тут печатаем кусочки кода.
Так же использование ECS идеально подходит для небольших игр на мобилки типа Match3, но и большие тоже можно писать.
Сам ECS из себя представляет:
World - "мир" в котором всё крутится
System - системы, которые обрабатывают данные
Entity - фактически контейнер, который содержит в себе компоненты
Component - сам компонент представляющий собой структуру в которой храниться несколько значений.
*собственно Entity и Component это тоже самое, что и в Юнити GameObject и Component. Но только в Юнити свернули не туда
Ещё ECS можно представить просто как конвейер ( World) по которому движутся коробки ( Entity) в которых что-то лежит ( Component), а рядом стоящие работники ( System) берут эти коробки ( Entity), что-то делают с ними или c их содержимым ( Component), а затем или возвращают коробку ( Entity) обратно на конвейер ( World) или вовсе "выбрасывают в мусорку".
Особенность всего этого в том, что System, Entity и Component ничего не знают друг о друге и вся магия происходит благодаря System.EcsFilter<T, ..>, который берет все Entity в текущем "мире", сортирует их по наличию запрашиваемых компонентов на них и возвращает пользователю грубо говоря массив с Entity.
Ресурсы:
Для начала нам нужно скачать ECS и два модуля к нему для связи с Юнити (это кстати единственная сложность в использовании стороннего ECS).
LeoECS: https://github.com/Leopotam/ecs
(тут так же есть краткая документация, ссылки на другие модули, ссылки на примеры кода и на некоторые игры сделанные на этом ECS)
Unity integration: https://github.com/Leopotam/ecs-unityintegration
(это нужно просто для дебага ECS в редакторе Юнити)
Service Locator: https://github.com/Leopotam/globals
(это фактически синглтон для вызова ECS из классов MonoBehaviour)
Простой пример:
После добавления ресурсов с гитхаба в Юнити нужно нажать правой кнопной мышки например на папку Assets и выбрать " Create > LeoECS > Create Startup template". Это создаст MonoBehaviour класс с инициализацией ECS.
Данный юнити-компонент нужно добавить на игровой объект в сцене.
using Leopotam.Ecs; using LeopotamGroup.Globals; using UnityEngine; namespace Example { internal class EcsStartup : MonoBehaviour { private EcsWorld world = default; private EcsSystems systems = default; // Это нужно для интеграции с Юнити так как сам ECS изначально // никак не связан с ним. // В небольшом комьюнити по LeoECS принято использовать этот шаблон где: // GameData используется для реалтайм-данных так как System, Entity и Component // ничего не знают друг о друге. // [System.Serializable] // public class GameData { // public int shootCount = 0; // public int collisionsCount = 0; // } [SerializeField] private GameData gameData = new GameData(); // SceneData наследуется от MonoBehaviour и содержит в себе ссылки // на объекты сцены. Например это камера и какие-то // заранее созданные объекты. Я в этом примере заранее создал // игрока и сделал ссылку на его игровой объект. // public class SceneData : MonoBehaviour { // ссылка на объект игрока, который уже находится на сцене // public PlayerView PlayerView; // //public Camera mainCamera; // //... // } [SerializeField] private SceneData sceneData = default; // Config наследуется от ScriptableObject и служит для хранения // всяких настроек, ссылок на префабы, которые в какой-то момент // нужно будет создать. Так же в нем можно хранить ссылки на // другие ScriptableObject с конфигами. // Именно этот класс сугубо только для удобства. Данные можно // так же классическим способом хранить и на MonoBehaviour игрока, врага. //[CreateAssetMenu] // public class Config : ScriptableObject { // Данные игрока, которые можно изменять в реальном времени // и которые сохраняться после выхода из игрового режима в редакторе // public float PlayerMoveSpeed = 1f; // public float PlayerRotateSpeed = 50f; // [Space] // public ProjectileView ProjectilePrefab = default; // public float ProjectileStartSpeed; // } [SerializeField] private Config config = default; private void Start() { world = new EcsWorld(); systems = new EcsSystems(world); // Это пак Service Locator, который является аналогом синглтона. // Для примера сохраним ссылку на реалтайм-данные Service<GameData>.Set(gameData); // Это пак Unity integration, который нужнен для дебага ECS в сцене. // Так же именно это создаёт некоторое количество аллокаций так как // для наглядности при добавлении Entity или компонентов изменяет // имя скрытых игровых объектов, которые отображаются в дебаге. // Скрин в аттаче #if UNITY_EDITOR Leopotam.Ecs.UnityIntegration.EcsWorldObserver.Create(world); Leopotam.Ecs.UnityIntegration.EcsSystemsObserver.Create(systems); #endif // Это хендл для систем. Тут в список добавляются системы. systems // Сам процесс добавления систем. Если не добавлять систему или если // что-то закомментить, то у нас просто пропадёт часть функционала // без каких либо ошибок. Один из серьезных плюсов. .Add(new PlayerInitSystem()) .Add(new PlayerInputSystem()) .Add(new PlayerMoveSystem()) .Add(new PlayerRotateSystem()) // Удаляет все экземпляры указанного компонента со всех Entity и со // всех тут указанных систем. // Этот метод специфичен и иногда при неправильном добавлении // систем создаёт проблемы. Так как если сначала в список // добавить систему с обработкой компонента, а ниже добавить // систему с генерацией компонента, то естественно на следующем // цикле этот компонент уже будет удален и система с обработкой // компонента уже не будет работать. .OneFrame<PlayerInputEvent>() // Это Dependency injection данных во все системы в текущем EcsSystems .Inject(gameData) .Inject(sceneData) .Inject(config) // Инициализация EcsSystems .Init(); } // Тут вызывается цикл EcsSystems. Если нужно использовать FixedUpdate, // то нужно создать еще одну систему и по аналогии вызвать. // Важно помнить, что Entity с компонентами хранятся в EcsWorld и добавление // новых или удаление EcsSystems повлияет только на функционал. private void Update() { systems?.Run(); } // Очистка системы и "мира". // При добавлении новых EcsSystems в мир нужно будет не много переделать // код дабы сначала удалить все EcsSystems, а потом и сам "мир". private void OnDestroy() { if (systems != null) { systems.Destroy(); systems = null; world.Destroy(); world = null; } } } }
В идеале система должна выполнять минимально количество кода. Из-за этого количество систем может быть и 10 и 100 и соответственно лучше сразу называть их понятным для себя образом.
Первая система называется у нас PlayerInitSystem. В ней мы создаем Entity и связываем с игроком на сцене.
using Leopotam.Ecs; using UnityEngine; internal class PlayerInitSystem : IEcsInitSystem { // Тот самый Dependency injection. // Для EcsWorld выполняется автоматически, а все остальное нужно добавлять // руками через .Inject(..) private readonly EcsWorld ecsWorld = default; private readonly SceneData sceneData = default; // IEcsInitSystem.Init для вызова на старте игры или при вызове EcsSystem.Init() public void Init() { // Получаем ссылку на PlayerView var view = sceneData.PlayerView; // Создаем новый Entity. Все Entity находятся в пуле. Если свободный Entity // уже есть, то тогда берется из пула var entity = ecsWorld.NewEntity(); // Добавляем в Entity компонент PlayerRef и сохраняем ссылку на PlayerView // из которого можно будет получить ссылку на transform и другие компоненты entity.Get<PlayerRef>().View = view; // В сам PlayerView тоже сохраняем ссылку на Entity view.Entity = entity; } } public class PlayerView : MonoBehaviour { public EcsEntity Entity; // Фактически PlayerView не нужен, достаточно только в ECS-компоненте // сохранить ссылку на transform игрока. // Но при таком подходе потом при вызове любого MonoBehaviour события // допустим OnCollisionEnter можно будет сразу добавить нужный компонент // на Entity игрока // private void OnCollisionEnter(Collision other) { // Entity.Get<PlayerCollideEvent>(); // } } internal struct PlayerRef { public PlayerView View; }
Далее у нас система PlayerInputSystem в которой обрабатываем Input. Вообще нужно делать по другому, но для примера будет достаточно.
using Leopotam.Ecs; using UnityEngine; internal class PlayerInputSystem : IEcsRunSystem { // Тут в EcsFilter<T> мы указываем с каким компонентом нам нужны Entity. // Компонентов можно задать больше // Так же можно использовать EcsFilter<T, ..>.Exclude<T, ..> для исключения // определенных компонентов из результата private readonly EcsFilter<PlayerRef> filter = default; // IEcsRunSystem.Run этот метод вызывается в каждом цикле public void Run() { // В данном случае это нужно только для того, что бы не вызывался // лишний раз Input и создание Vector2 если вдруг у нас пустой фильтр if(filter.IsEmpty()) return; var h = Input.GetAxisRaw("Horizontal"); var v = Input.GetAxisRaw("Vertical"); var direction = new Vector2(h, v).normalized; // Проходим по всем элементам. Тут за foreach можно не переживать // Код с Input'ом можно перенести и сюда, но это будут лишние // вычисления если у нас например в фильтре будет не 1, а 1000 Entity if (direction.sqrMagnitude > 0f) { foreach (var i in filter) { // Получаем ссылку на Entity данной итерации и добавляем // компонент, который заканчивается на Event. Таким образом // мы только для себя обозначаем, что этот компонент должен // быть удален после использования всеми системами. // В данном случае он будет удален в конце главного цикла // через метод .OneFrame<PlayerInputEvent>() filter.GetEntity(i).Get<PlayerInputEvent>().Value = direction; } } } } internal struct PlayerInputEvent { public Vector2 Value; }
Система PlayerMoveSystem будет двигать все Entity с определенным количеством компонентов
internal class PlayerMoveSystem : IEcsRunSystem { // Как видим тут мы фильтруем по наличию компонентов PlayerRef // и PlayerInputEvent, которые в данном примере должны быть только // у Entity игрока. private readonly EcsFilter<PlayerRef, PlayerInputEvent> filter = default; // DI конфига private readonly Config config = default; public void Run() { // Тут уже не нужны никакие доп. вычисления типа Input как в прошлой системе foreach (var i in filter) { // Обратите внимание на "ref". Так как у нас компоненты // являются "struct", мы должны получать ссылку на них // именно через ref иначе мы получим копию, которая // ничего не изменит и удалится сразу же после выхода // из этого метода. // Через Get1, Get2, GetN мы получаем компонент из Entity. // Нумерация компонентов такая же как в EcsFilter ref var playerRef = ref filter.Get1(i); ref var inputEvent = ref filter.Get2(i); // Получаем ссылку на transform игрока через PlayerView, // который до этого сохранили в компоненте PlayerRef // Так же получаем из конфига скорость игрока, // которую можно менять в реальном времени. // Если у нас будет 1000 игроков в фильтре, // то скорость изменится для всех. var tr = playerRef.View.transform; tr.position += tr.forward * inputEvent.Value.y * config.PlayerMoveSpeed * Time.deltaTime; } } }
Следующая система фактически копи-паст предыдущей и может возникнуть вопрос нафига этот лишний код? А ответ тот же, что и был выше - если отключить систему или если закоментить её подключение в коде, то в игре просто пропадёт функционал, который содержится в системе и никаких ошибок не будет.
internal class PlayerRotateSystem : IEcsRunSystem { private readonly EcsFilter<PlayerRef, PlayerInputEvent> filter = default; private readonly Config config = default; public void Run() { foreach (var i in filter) { ref var playerRef = ref filter.Get1(i); ref var inputEvent = ref filter.Get2(i); // Все тоже самое, но только мы тут разворачиваем игрока // Конечно можно объединить в одну, но тогда мы теряем // ту самую гибкость ECS var tr = playerRef.View.transform; tr.Rotate(Vector3.up, inputEvent.Value.x * config.PlayerRotateSpeed * Time.deltaTime); } } }
|
(Offline)
|
|
Эти 3 пользователя(ей) сказали Спасибо Nex за это полезное сообщение:
|
|
25.10.2020, 16:36
|
#2
|
Гигант индустрии
Регистрация: 13.09.2008
Сообщений: 2,893
Написано 1,185 полезных сообщений (для 3,298 пользователей)
|
Ответ: LeoECS
А сейчас добавим возможность пострелять. Для этого создайте на сцене некоторое количество объектов с коллайдерами, которые будут являться препятствием для пули.
Так же нужно создать системы и добавить их в список в EcsStartup классе.
.Add(new PlayerInputShootSystem()) .Add(new ProjectileCreateSystem()) .Add(new ProjectileMoveSystem()) .Add(new ProjectileDestroyEventSystem())
Система PlayerInputShootSystem будет создавать Entity с компонентом PlayerShootEvent и некоторым данными для создания пули.
Код очень похож на предыдущую систему где создавался компонент с событие движения игрока.
Конечно системы можно унифицировать дабы они двигали сразу все Entity допустим с компонентом Move, но в этом случае мы потеряем гибкость и при отключении этой системы перестанут двигаться и игрок и пули.
internal class PlayerInputShootSystem : IEcsRunSystem { // Тут для пример вместе с EcsFilter<T> есть еще и .Exclude<T> специально // что бы пули не могли создаваться если игрок движется или // вращается (если на Entity игрока есть компонент PlayerInputEvent) private readonly EcsFilter<PlayerRef>.Exclude<PlayerInputEvent> filter = default; private readonly EcsWorld ecsWorld = default; private readonly Config config = default; private readonly GameData gameData = default; public void Run() { if (filter.IsEmpty()) return; if (!Input.GetKeyDown(KeyCode.Space)) return; foreach (var i in filter) { ref var playerRef = ref filter.Get1(i); var tr = playerRef.View.transform; ecsWorld.NewEntity().Get<PlayerShootEvent>() = new PlayerShootEvent() { Position = tr.position, Angle = tr.rotation.eulerAngles.y, Speed = config.ProjectileStartSpeed }; // Как помним GameData класс был у нас для временных реалтайм-данных. // В данном случае при выстреле увеличиваем переменную и // для примера можно где-то её отрисовать в UI или можно // посмотреть её значение в редакторе так как у нас // этот класс сериализован gameData.shootCount++; } } } // Данный компонент хоть и заканчивает на "Event", но добавлять // его в .OneFrame<T> не будем потому-что он создается вместе // с отдельным Entity. В этом случае лучше удалить руками // сам Entity, а вместе с ним удалится и этот компонент internal struct PlayerShootEvent { public Vector3 Position; public float Angle; public float Speed; }
В системе ProjectileCreateSystem создаем префаб и Entity пули. Так же обязательно удаляем Entity с событием PlayerShootEvent, которое сигнализирует о необходимости создания пули. Иначе пули будут создаваться в каждом цикле * на количество Entity в фильтре.
internal class ProjectileCreateSystem : IEcsRunSystem { // Получаем все Entity с PlayerShootEvent private readonly EcsFilter<PlayerShootEvent> filter = default; private readonly EcsWorld ecsWorld = default; private readonly Config config = default; public void Run() { foreach (var i in filter) { ref var eventData = ref filter.Get1(i); var position = eventData.Position; position.y = 0.5f; var rotation = Quaternion.Euler(0, eventData.Angle, 0); // Так же создаем и связываем игровой объект и Entity. var entity = ecsWorld.NewEntity(); ref var projectileRef = ref entity.Get<ProjectileRef>(); // На Entity пули добавляем постоянный компонент, // который будет хранить постоянную скорость пули entity.Get<ProjectileMove>().Value = eventData.Speed; var view = UnityEngine.Object.Instantiate(config.ProjectilePrefab, position, rotation); view.Entity = entity; projectileRef.View = view; // И обязательно удаляем текущий Entity, который содержит // компонент-событие для создания пули filter.GetEntity(i).Destroy(); } } } // ref - компонент для Entity пуль internal struct ProjectileRef { public ProjectileView View; } // View - компонент для пули. Так же тут показан пример как из MonoBehaviour // взаимодействовать с Entity игрового объекта public class ProjectileView : MonoBehaviour { public EcsEntity Entity; // Если пуля столкнулась с чем-то кроме игрока (PlayerView), // то добавляем на Entity пули компонент-событие ProjectileDestroyEvent // благодаря которому эта пуля будет удалена в последующей системе private void OnTriggerEnter(Collider other) { if (other.GetComponent<PlayerView>()) return; // Просто пример как использовать это. // В данном случае мы получаем ссылку на реалтайм-данные и увеличиваем // значение переменной, которая будет показывать количество // столкновений пуль за игру // Можно так же получать ссылку на мир EcsWorld и создавать Entity Service<GameData>.Get().collisionsCount++; // Для примера добавлен параметр в который записывается // игровой объект с которым произошло столкновение Entity.Get<ProjectileDestroyEvent>() = new ProjectileDestroyEvent() { Value = other.gameObject }; } }
В данной небольшой системе мы просто двигаем все пули с постоянной скоростью, которая сохранена в компоненте ProjectileMove. Опять же это сохранение скорости пули только как пример. Данные скорости пули можно так же брать из Config, как и в системе с движением игрока.
internal class ProjectileMoveSystem : IEcsRunSystem { private readonly EcsFilter<ProjectileRef, ProjectileMove> filter = default; public void Run() { foreach (var i in filter) { // Помним что "ref" нужен обязательно при получении компонентов, // которые являются "struct" ref var projectileRef = ref filter.Get1(i); ref var projectileMove = ref filter.Get2(i); // Непосредственно двигаем игровой объект на сцене var step = projectileMove.Value * Time.deltaTime; var transform = projectileRef.View.transform; transform.position += transform.forward * step; } } } internal struct ProjectileMove { public float Value; }
А в этой последней системе ProjectileDestroyEventSystem просто удаляем и игровой объект и Entity. Сам Entity не удалится с "мира", а только пометится как удаленный и в любой момент будет использован заново.
internal class ProjectileDestroyEventSystem : IEcsRunSystem { private readonly EcsFilter<ProjectileRef, ProjectileDestroyEvent> filter = default; public void Run() { foreach (var i in filter) { ref var projectileRef = ref filter.Get1(i); ref var destroyData = ref filter.Get2(i); // Тут просто для примера выводим к консоль название // игрового объекта с которым столкнулась пуля Debug.Log(destroyData.Value); // Удаление gameObject пули на сцене и Entity из "мира" Object.Destroy(projectileRef.View.gameObject); filter.GetEntity(i).Destroy(); } } } internal struct ProjectileDestroyEvent { public GameObject Value; }
Всё. Выглядит это конечно более сложнее, чем классический код и синхронизация с игровыми объектами на сцене тоже такое себе. Но за то мы получаем максимально разграниченный функционал, который не зависит друг от друга. Так же это всё легко тестится и расширяется хоть до уровня ММО-игры.
|
(Offline)
|
|
Эти 3 пользователя(ей) сказали Спасибо Nex за это полезное сообщение:
|
|
25.10.2020, 16:49
|
#3
|
Быдлокодер
Регистрация: 05.07.2009
Адрес: Проспит
Сообщений: 5,024
Написано 2,312 полезных сообщений (для 5,349 пользователей)
|
Ответ: LeoECS
Сообщение от Nex
Краткая суть почему ECS это хорошо заключается в том, что практически не нужно уметь кодить, не нужно знать тонну паттернов и прочих сложностей. Все просто, как и в визуальном программировании, но только там соединяем ноды, а тут печатаем кусочки кода.
|
Сообщение от Nex
Выглядит это конечно более сложнее, чем классический код и синхронизация с игровыми объектами на сцене тоже такое себе. Но за то мы получаем максимально разграниченный функционал, который не зависит друг от друга. Так же это всё легко тестится и расширяется хоть до уровня ММО-игры.
|
Так ECS легко или сложно?
Сообщение от Nex
Crystal с "процедурными" знаниями Блитза в очередной раз пытается сделать свой фаллаут
|
Это «покемоны».
|
(Offline)
|
|
25.10.2020, 17:20
|
#4
|
[object Object]
Регистрация: 01.08.2008
Адрес: В России
Сообщений: 4,361
Написано 2,473 полезных сообщений (для 6,856 пользователей)
|
Ответ: LeoECS
Сообщение от Arton
Так ECS легко или сложно?
|
Блиц был про "легко начать, но тяжело закончить".
Тут наоборот.
Это сложно или легко? [риторический вопрос]
__________________
Retry, Abort, Ignore? █
Intel Core i7-9700 4.70 Ghz; 64Gb; Nvidia RTX 4090 3070
AMD Ryzen 7 3800X 4.3Ghz; 64Gb; Nvidia 1070Ti
AMD Ryzen 7 1700X 3.4Ghz; 8Gb; AMD RX 570
AMD Athlon II 2.6Ghz; 8Gb; Nvidia GTX 750 Ti
|
(Offline)
|
|
Сообщение было полезно следующим пользователям:
|
|
26.10.2020, 01:29
|
#5
|
Терабайт исходников
Регистрация: 05.07.2007
Сообщений: 5,196
Написано 1,721 полезных сообщений (для 5,374 пользователей)
|
Ответ: LeoECS
Когда мне надоест программировать фоллауты, я возьму UE с его нодами.
Смысла перехода на LeoECS не вижу имхо. Так же можно было предложить
на огре по кодить, по тому что "это другое", а смысл? ХЗ.
Нужны более лёгкие варианты? - UE.
Сообщение от Arton
Так ECS легко или сложно?
Это «покемоны».
|
Не совсем. Этот проект делается под впечатлением
от покемонов и фоллаутов с частицей героев меча и магии.
Так что да всё же это очередной фоллаут.
Прошлый мой фоллаут кстати 10 лет назад успешно создавался,
был уже набор механик собрав которые в одну кучу можно
было бы вывалить демо уровень игры. Там и управление персонажем,
и поиск пути, и инвентарь, и редактор уровня, и загрузка с сохранением.
Проект был закрыт по двум причинам:
1. Незаинтересованность аудитории.
2. Смена сферы интересов (мотоцикл, бабы, бухло, рокнролл).
Щас я откатил интересы на 10 лет назад, и проект успешно
производится потихонечку, не смотря на отсутствие заинтересованности
в нём кем либо кроме меня. Я бы даже сказал, что это тот самый фоллаут,
который я делал 10 лет назад, но пересмотренный под другим углом.
Будет всё то, что планировалось и плюсом покемоны,
но сюжет выкинут в мусорку, и придуман новый.
Хотя можно что-то из старого проекта впендюрить в этот по сюжету,
у меня как раз несколько фракций будет, вот Бимелов из "Выжженной Земли"
можно и добавить. Главный плюс нового фоллаута в том, что он совмещает
в себе реалтайм игру с пошаговыми боями, а вариант 10 лет назад
должен был быть чисто реалтаймом, без пошаговости, как фоллаут тактикс.
Короче новый вариант ближе к первым двум фоллаутам, но с боями как
в четвёртых героях.
|
(Offline)
|
|
Эти 2 пользователя(ей) сказали Спасибо Crystal за это полезное сообщение:
|
|
26.10.2020, 04:07
|
#6
|
Разработчик
Регистрация: 12.01.2011
Адрес: Moscow
Сообщений: 422
Написано 68 полезных сообщений (для 100 пользователей)
|
Ответ: LeoECS
ECS конечно тема модная, но пока не изучал.
https://habr.com/ru/post/358108/
|
(Offline)
|
|
26.10.2020, 08:30
|
#7
|
Гигант индустрии
Регистрация: 13.09.2008
Сообщений: 2,893
Написано 1,185 полезных сообщений (для 3,298 пользователей)
|
Ответ: LeoECS
Сообщение от Crystal
Этот проект делается под впечатлением
от покемонов и фоллаутов
|
Я почему и написал про фаллаут. Помню даже какие-то видосы где у избы крыша пропадала при наведении на неё камеры.
Сообщение от Crystal
Щас я откатил интересы на 10 лет назад, и проект успешно
производится потихонечку, не смотря на отсутствие заинтересованности
в нём кем либо кроме меня.
|
Поэтому уже с 2013 года все делают на мобилки, добавляя не много бесполезного визуального доната и редкой рекламы.
На мобилках даже бессмысленное нечто под названием "гиперказуалки" с модельками а-ля 2002 год хавают за обе щеки.
То есть будет и респект от игроков и может даже какой-то бабос.
Сообщение от Crystal
Когда мне надоест программировать фоллауты, я возьму UE с его нодами.
|
Кстати есть тоже самое на Unity и называется оно Bolt. Летом его выкупили и сделали бесплатным.
Но я всё же рекомендую попробовать LeoECS так как с этим очень просто кодить и фактически без ООП. По простоте получается тот же Блитз.
|
(Offline)
|
|
26.10.2020, 11:58
|
#8
|
Терабайт исходников
Регистрация: 05.07.2007
Сообщений: 5,196
Написано 1,721 полезных сообщений (для 5,374 пользователей)
|
Ответ: LeoECS
Сообщение от Nex
Я почему и написал про фаллаут. Помню даже какие-то видосы где у избы крыша пропадала при наведении на неё камеры.
Поэтому уже с 2013 года все делают на мобилки, добавляя не много бесполезного визуального доната и редкой рекламы.
На мобилках даже бессмысленное нечто под названием "гиперказуалки" с модельками а-ля 2002 год хавают за обе щеки.
То есть будет и респект от игроков и может даже какой-то бабос.
Кстати есть тоже самое на Unity и называется оно Bolt. Летом его выкупили и сделали бесплатным.
Но я всё же рекомендую попробовать LeoECS так как с этим очень просто кодить и фактически без ООП. По простоте получается тот же Блитз.
|
По видосу, это 2009 год, там был прототип редактора карты,
а так же сохранение, и загрузка.
Дальше это всё переехало на хорс:
А после я наработки по фоллауту использовал для прототипа RTS на хорсе с физиксом:
Про игры на мобилки. Если мне удастся дотащить игру до релиза,
если появится фанбаза, если я стану отечественным Кодзимой,
то выпущу версию для мобилок. Если первый вариант не сработает,
выпущу ремейк своего Unreal Racinga на мобилки с рекламой:
|
(Offline)
|
|
Эти 2 пользователя(ей) сказали Спасибо Crystal за это полезное сообщение:
|
|
26.10.2020, 16:08
|
#9
|
[object Object]
Регистрация: 01.08.2008
Адрес: В России
Сообщений: 4,361
Написано 2,473 полезных сообщений (для 6,856 пользователей)
|
Ответ: LeoECS
Сообщение от Crystal
Смысла перехода на LeoECS не вижу имхо. Так же можно было предложить
на огре по кодить, по тому что "это другое", а смысл? ХЗ.
|
Ты часто апеллируешь к тому, что у тебя нет тех или иных проблем (отсылка к теме, где тебе советовали как кодить более эффективно).
Но всё вот это "излишнее" и непонятное это профилактика тех проблем, которые возникнут, когда твой проект уже будет содержать огроменное количество связанных сущностей и изменение чего-то одного повлечёт за собой целый каскад правок.
Не сочти за призыв к действию, просто пытаюсь рассказать что, почему и зачем.
__________________
Retry, Abort, Ignore? █
Intel Core i7-9700 4.70 Ghz; 64Gb; Nvidia RTX 4090 3070
AMD Ryzen 7 3800X 4.3Ghz; 64Gb; Nvidia 1070Ti
AMD Ryzen 7 1700X 3.4Ghz; 8Gb; AMD RX 570
AMD Athlon II 2.6Ghz; 8Gb; Nvidia GTX 750 Ti
|
(Offline)
|
|
26.10.2020, 17:53
|
#10
|
Терабайт исходников
Регистрация: 05.07.2007
Сообщений: 5,196
Написано 1,721 полезных сообщений (для 5,374 пользователей)
|
Ответ: LeoECS
Сообщение от Randomize
Ты часто апеллируешь к тому, что у тебя нет тех или иных проблем (отсылка к теме, где тебе советовали как кодить более эффективно).
Но всё вот это "излишнее" и непонятное это профилактика тех проблем, которые возникнут, когда твой проект уже будет содержать огроменное количество связанных сущностей и изменение чего-то одного повлечёт за собой целый каскад правок.
Не сочти за призыв к действию, просто пытаюсь рассказать что, почему и зачем.
|
Процитирую сам себя: Код существует для того, чтобы его переписывать.
Имхо любой программист смотря на свой старый код, видит что можно было по другому, и лучше.
Но а мои спотыкания, это неопытность. Мой первый проект на юнити,
первый на сишарпе, да ещё и чуть ли не триплэй уровня девяностых,
и после 9-10 лет паузы в геймдеве. Сам понимаешь, не так то просто
с разбегу влететь в это дело. В любом случае уже почти 10к строк кода,
переноситься на другую платформу разработки (или недоплатформу) я уже не буду.
Ну и собственно сложности существуют для того, чтобы их преодолевать.
Я не просто разрабатываю, я обучаюсь.
|
(Offline)
|
|
26.10.2020, 23:56
|
#11
|
[object Object]
Регистрация: 01.08.2008
Адрес: В России
Сообщений: 4,361
Написано 2,473 полезных сообщений (для 6,856 пользователей)
|
Ответ: LeoECS
Сообщение от Crystal
Процитирую сам себя: Код существует для того, чтобы его переписывать.
Имхо любой программист смотря на свой старый код, видит что можно было по другому, и лучше.
|
В первых 2х постах описывается вариант на тему того, как избежать подобного.
Методика "Всё круто, но переделывай" хорошо катит для детей и бессмертных.
__________________
Retry, Abort, Ignore? █
Intel Core i7-9700 4.70 Ghz; 64Gb; Nvidia RTX 4090 3070
AMD Ryzen 7 3800X 4.3Ghz; 64Gb; Nvidia 1070Ti
AMD Ryzen 7 1700X 3.4Ghz; 8Gb; AMD RX 570
AMD Athlon II 2.6Ghz; 8Gb; Nvidia GTX 750 Ti
|
(Offline)
|
|
Эти 2 пользователя(ей) сказали Спасибо Randomize за это полезное сообщение:
|
|
28.10.2020, 16:21
|
#12
|
Ференька
Регистрация: 26.01.2007
Адрес: улица Пушкина дом Колотушкина
Сообщений: 10,742
Написано 5,461 полезных сообщений (для 15,675 пользователей)
|
Ответ: LeoECS
Сообщение от Crystal
Процитирую сам себя: Код существует для того, чтобы его переписывать.
Имхо любой программист смотря на свой старый код, видит что можно было по другому, и лучше.
|
Всё так, но бизнес с этим не очень согласен.
Да и программист, который хочет кушац за счёт своих писулек тоже.
__________________
Мои проекты:
Анальное Рабство
Зелёный Слоник
Дмитрий Маслов*
Различие**
Клюква**
* — в стадии разработки
** — в стадии проектирования
Для проектов в стадии проектирования приведены кодовые имена
|
(Offline)
|
|
Сообщение было полезно следующим пользователям:
|
|
Ваши права в разделе
|
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения
HTML код Выкл.
|
|
|
Часовой пояс GMT +4, время: 10:01.
|