Извините, ничего не найдено.

Не расстраивайся! Лучше выпей чайку!
Регистрация
Справка
Календарь

Вернуться   forum.boolean.name > Программирование игр для компьютеров > Unity

Unity Мультиплатформенный инструмент для разработки игр

Ответ
 
Опции темы
Старый 25.10.2020, 16:35   #1
Nex
Гигант индустрии
 
Аватар для Nex
 
Регистрация: 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<PlayerReffilter = default;

    
// IEcsRunSystem.Run этот метод вызывается в каждом цикле
    
public void Run() {
        
// В данном случае это нужно только для того, что бы не вызывался
        // лишний раз Input и создание Vector2 если вдруг у нас пустой фильтр
        
if(filter.IsEmpty())
            return;
        
        var 
Input.GetAxisRaw("Horizontal");
        var 
Input.GetAxisRaw("Vertical");
        var 
direction = new Vector2(hv).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<PlayerRefPlayerInputEventfilter = 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.config.PlayerMoveSpeed Time.deltaTime;
        }
    }

Следующая система фактически копи-паст предыдущей и может возникнуть вопрос нафига этот лишний код? А ответ тот же, что и был выше - если отключить систему или если закоментить её подключение в коде, то в игре просто пропадёт функционал, который содержится в системе и никаких ошибок не будет.
internal class PlayerRotateSystem IEcsRunSystem {
    private 
readonly EcsFilter<PlayerRefPlayerInputEventfilter = 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.upinputEvent.Value.config.PlayerRotateSpeed Time.deltaTime);
        }
    }

Изображения
Тип файла: png ECS Debug.PNG (9.0 Кб, 2619 просмотров)
Тип файла: png Игрок.PNG (77.2 Кб, 2576 просмотров)
(Offline)
 
Ответить с цитированием
Эти 3 пользователя(ей) сказали Спасибо Nex за это полезное сообщение:
Evgen (26.10.2020), pax (26.10.2020), Randomize (25.10.2020)
Старый 25.10.2020, 16:36   #2
Nex
Гигант индустрии
 
Аватар для Nex
 
Регистрация: 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<PlayerInputEventfilter = 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<PlayerShootEventfilter = 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.0.5f;
                var 
rotation Quaternion.Euler(0eventData.Angle0);

                
// Так же создаем и связываем игровой объект и 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.ProjectilePrefabpositionrotation);

                
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<ProjectileRefProjectileMovefilter = 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<ProjectileRefProjectileDestroyEventfilter = 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;
    } 

Всё. Выглядит это конечно более сложнее, чем классический код и синхронизация с игровыми объектами на сцене тоже такое себе. Но за то мы получаем максимально разграниченный функционал, который не зависит друг от друга. Так же это всё легко тестится и расширяется хоть до уровня ММО-игры.
Изображения
Тип файла: png Пуля.PNG (108.8 Кб, 2619 просмотров)
(Offline)
 
Ответить с цитированием
Эти 3 пользователя(ей) сказали Спасибо Nex за это полезное сообщение:
Evgen (26.10.2020), pax (26.10.2020), Randomize (25.10.2020)
Старый 25.10.2020, 16:49   #3
Arton
Быдлокодер
 
Аватар для Arton
 
Регистрация: 05.07.2009
Адрес: Проспит
Сообщений: 5,024
Написано 2,313 полезных сообщений
(для 5,350 пользователей)
Ответ: LeoECS

Сообщение от Nex Посмотреть сообщение
Краткая суть почему ECS это хорошо заключается в том, что практически не нужно уметь кодить, не нужно знать тонну паттернов и прочих сложностей. Все просто, как и в визуальном программировании, но только там соединяем ноды, а тут печатаем кусочки кода.
Сообщение от Nex Посмотреть сообщение
Выглядит это конечно более сложнее, чем классический код и синхронизация с игровыми объектами на сцене тоже такое себе. Но за то мы получаем максимально разграниченный функционал, который не зависит друг от друга. Так же это всё легко тестится и расширяется хоть до уровня ММО-игры.
Так ECS легко или сложно?

Сообщение от Nex Посмотреть сообщение
Crystal с "процедурными" знаниями Блитза в очередной раз пытается сделать свой фаллаут
Это «покемоны».
(Offline)
 
Ответить с цитированием
Старый 25.10.2020, 17:20   #4
Randomize
[object Object]
 
Аватар для Randomize
 
Регистрация: 01.08.2008
Адрес: В России
Сообщений: 4,361
Написано 2,473 полезных сообщений
(для 6,857 пользователей)
Ответ: 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)
 
Ответить с цитированием
Сообщение было полезно следующим пользователям:
Arton (26.10.2020)
Старый 26.10.2020, 01:29   #5
Crystal
Терабайт исходников
 
Аватар для Crystal
 
Регистрация: 05.07.2007
Сообщений: 5,196
Написано 1,721 полезных сообщений
(для 5,374 пользователей)
Ответ: LeoECS

Когда мне надоест программировать фоллауты, я возьму UE с его нодами.
Смысла перехода на LeoECS не вижу имхо. Так же можно было предложить
на огре по кодить, по тому что "это другое", а смысл? ХЗ.
Нужны более лёгкие варианты? - UE.



Сообщение от Arton Посмотреть сообщение
Так ECS легко или сложно?
Это «покемоны».
Не совсем. Этот проект делается под впечатлением
от покемонов и фоллаутов с частицей героев меча и магии.
Так что да всё же это очередной фоллаут.

Прошлый мой фоллаут кстати 10 лет назад успешно создавался,
был уже набор механик собрав которые в одну кучу можно
было бы вывалить демо уровень игры. Там и управление персонажем,
и поиск пути, и инвентарь, и редактор уровня, и загрузка с сохранением.
Проект был закрыт по двум причинам:
1. Незаинтересованность аудитории.
2. Смена сферы интересов (мотоцикл, бабы, бухло, рокнролл).

Щас я откатил интересы на 10 лет назад, и проект успешно
производится потихонечку, не смотря на отсутствие заинтересованности
в нём кем либо кроме меня. Я бы даже сказал, что это тот самый фоллаут,
который я делал 10 лет назад, но пересмотренный под другим углом.
Будет всё то, что планировалось и плюсом покемоны,
но сюжет выкинут в мусорку, и придуман новый.
Хотя можно что-то из старого проекта впендюрить в этот по сюжету,
у меня как раз несколько фракций будет, вот Бимелов из "Выжженной Земли"
можно и добавить. Главный плюс нового фоллаута в том, что он совмещает
в себе реалтайм игру с пошаговыми боями, а вариант 10 лет назад
должен был быть чисто реалтаймом, без пошаговости, как фоллаут тактикс.
Короче новый вариант ближе к первым двум фоллаутам, но с боями как
в четвёртых героях.

__________________
Проект "Deathbring World - Rangers" и его финансовая поддержка:
https://boosty.to/deathbringrangers

Я на - TWITCH
Канал на YouTube
(Offline)
 
Ответить с цитированием
Эти 2 пользователя(ей) сказали Спасибо Crystal за это полезное сообщение:
Arton (26.10.2020), Randomize (26.10.2020)
Старый 26.10.2020, 04:07   #6
Evgen
Разработчик
 
Аватар для Evgen
 
Регистрация: 12.01.2011
Адрес: Moscow
Сообщений: 424
Написано 70 полезных сообщений
(для 103 пользователей)
Ответ: LeoECS

ECS конечно тема модная, но пока не изучал.

https://habr.com/ru/post/358108/
(Offline)
 
Ответить с цитированием
Старый 26.10.2020, 08:30   #7
Nex
Гигант индустрии
 
Аватар для Nex
 
Регистрация: 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
Crystal
Терабайт исходников
 
Аватар для Crystal
 
Регистрация: 05.07.2007
Сообщений: 5,196
Написано 1,721 полезных сообщений
(для 5,374 пользователей)
Ответ: LeoECS

Сообщение от Nex Посмотреть сообщение
Я почему и написал про фаллаут. Помню даже какие-то видосы где у избы крыша пропадала при наведении на неё камеры.

Поэтому уже с 2013 года все делают на мобилки, добавляя не много бесполезного визуального доната и редкой рекламы.
На мобилках даже бессмысленное нечто под названием "гиперказуалки" с модельками а-ля 2002 год хавают за обе щеки.
То есть будет и респект от игроков и может даже какой-то бабос.

Кстати есть тоже самое на Unity и называется оно Bolt. Летом его выкупили и сделали бесплатным.
Но я всё же рекомендую попробовать LeoECS так как с этим очень просто кодить и фактически без ООП. По простоте получается тот же Блитз.
По видосу, это 2009 год, там был прототип редактора карты,
а так же сохранение, и загрузка.



Дальше это всё переехало на хорс:



А после я наработки по фоллауту использовал для прототипа RTS на хорсе с физиксом:



Про игры на мобилки. Если мне удастся дотащить игру до релиза,
если появится фанбаза, если я стану отечественным Кодзимой,
то выпущу версию для мобилок. Если первый вариант не сработает,
выпущу ремейк своего Unreal Racinga на мобилки с рекламой:

__________________
Проект "Deathbring World - Rangers" и его финансовая поддержка:
https://boosty.to/deathbringrangers

Я на - TWITCH
Канал на YouTube
(Offline)
 
Ответить с цитированием
Эти 2 пользователя(ей) сказали Спасибо Crystal за это полезное сообщение:
Arton (27.10.2020), Randomize (26.10.2020)
Старый 26.10.2020, 16:08   #9
Randomize
[object Object]
 
Аватар для Randomize
 
Регистрация: 01.08.2008
Адрес: В России
Сообщений: 4,361
Написано 2,473 полезных сообщений
(для 6,857 пользователей)
Ответ: 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
Crystal
Терабайт исходников
 
Аватар для Crystal
 
Регистрация: 05.07.2007
Сообщений: 5,196
Написано 1,721 полезных сообщений
(для 5,374 пользователей)
Ответ: LeoECS

Сообщение от Randomize Посмотреть сообщение
Ты часто апеллируешь к тому, что у тебя нет тех или иных проблем (отсылка к теме, где тебе советовали как кодить более эффективно).
Но всё вот это "излишнее" и непонятное это профилактика тех проблем, которые возникнут, когда твой проект уже будет содержать огроменное количество связанных сущностей и изменение чего-то одного повлечёт за собой целый каскад правок.
Не сочти за призыв к действию, просто пытаюсь рассказать что, почему и зачем.
Процитирую сам себя: Код существует для того, чтобы его переписывать.
Имхо любой программист смотря на свой старый код, видит что можно было по другому, и лучше.
Но а мои спотыкания, это неопытность. Мой первый проект на юнити,
первый на сишарпе, да ещё и чуть ли не триплэй уровня девяностых,
и после 9-10 лет паузы в геймдеве. Сам понимаешь, не так то просто
с разбегу влететь в это дело. В любом случае уже почти 10к строк кода,
переноситься на другую платформу разработки (или недоплатформу) я уже не буду.
Ну и собственно сложности существуют для того, чтобы их преодолевать.
Я не просто разрабатываю, я обучаюсь.
__________________
Проект "Deathbring World - Rangers" и его финансовая поддержка:
https://boosty.to/deathbringrangers

Я на - TWITCH
Канал на YouTube
(Offline)
 
Ответить с цитированием
Старый 26.10.2020, 23:56   #11
Randomize
[object Object]
 
Аватар для Randomize
 
Регистрация: 01.08.2008
Адрес: В России
Сообщений: 4,361
Написано 2,473 полезных сообщений
(для 6,857 пользователей)
Ответ: 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 за это полезное сообщение:
ABTOMAT (28.10.2020), St_AnGer (28.10.2020)
Старый 28.10.2020, 16:21   #12
ABTOMAT
Ференька
 
Аватар для ABTOMAT
 
Регистрация: 26.01.2007
Адрес: улица Пушкина дом Колотушкина
Сообщений: 10,742
Написано 5,461 полезных сообщений
(для 15,675 пользователей)
Ответ: LeoECS

Сообщение от Crystal Посмотреть сообщение
Процитирую сам себя: Код существует для того, чтобы его переписывать.
Имхо любой программист смотря на свой старый код, видит что можно было по другому, и лучше.
Всё так, но бизнес с этим не очень согласен.
Да и программист, который хочет кушац за счёт своих писулек тоже.
__________________
Мои проекты:
Анальное Рабство
Зелёный Слоник
Дмитрий Маслов*
Различие**
Клюква**

* — в стадии разработки
** — в стадии проектирования
Для проектов в стадии проектирования приведены кодовые имена

(Offline)
 
Ответить с цитированием
Сообщение было полезно следующим пользователям:
Randomize (28.10.2020)
Ответ


Опции темы

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.


Часовой пояс GMT +4, время: 23:53.


vBulletin® Version 3.6.5.
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Перевод: zCarot
Style crйe par Allan - vBulletin-Ressources.com