diff --git a/README-RU.md b/README-RU.md index 0eeb088..1131b04 100644 --- a/README-RU.md +++ b/README-RU.md @@ -48,10 +48,10 @@ # Оглавление - [Установка](#установка) - [Debug](#debug) - - [Debug Модуль](#debug-модуль) - [Debug Сервис](#debug-сервис) + - [Debug Модуль](#debug-модуль) - [Визуальная отладка](#визуальная-отладка) -- [Шаблон Сущности](#шаблон-сущности) +- [Шаблоны](#шаблоны) - [Связь с GameObject](#связь-с-gameobject) - [World Provider](#world-provider) - [Шаблон Пайплайна](#шаблон-пайплайна) @@ -85,21 +85,8 @@ https://github.com/DCFApixels/DragonECS-Unity.git
# Debug -## Debug Модуль -Подключение модуля отладки в Unity. -```c# -EcsDefaultWorld _world = new EcsDefaultWorld(); -EcsEventWorld _eventWorld = new EcsDefaultWorld(); - -_pipeline = EcsPipeline.New() - //... - // Подключение и инициализация отладки для миров _world и _eventWorld - .AddUnityDebug(_world, _eventWorld) - //... - .BuildAndInit(); -``` ## Debug Сервис -`UnityDebugService`- реализация [Debug-сервиса для `EcsDebug`](https://github.com/DCFApixels/DragonECS/blob/main/README-RU.md#ecsdebug). В редакторе по умолчанию автоматически инициализируется и связывает `EcsDebug.Print` с консолью Unity, `EcsProfilerMarker` c профайлером и т.д. +`UnityDebugService` - реализация [Debug-сервиса для `EcsDebug`](https://github.com/DCFApixels/DragonECS/blob/main/README-RU.md#ecsdebug). В редакторе он инициализируется автоматически и обеспечивает интеграцию: например, вызовы `EcsDebug.Print` направляются в консоль Unity, а `EcsProfilerMarker` подключается к встроенному профайлеру и т.д. ```c# //Ручная активация. UnityDebugService.Activate(); @@ -115,8 +102,19 @@ someMarker.End(); //Остановка игрового режима. EcsDebug.Break(); ``` + ## Визуальная отладка -Выполнена в виде специальных объектов-мониторов в которых отображается состояние разных аспектов фреймворка. Найти эти мониторы можно в Play Mode в разделе `DontDestroyOnLoad`. + +Выполнена в виде специальных объектов-мониторов в которых отображается состояние разных частей фреймворка. Найти эти мониторы можно в `Play Mode` в разделе `DontDestroyOnLoad`. + +```c# +_pipeline = EcsPipeline.New() + //... + // Инициализация отладки для пайплайна и миров + .AddUnityDebug(_world, _eventWorld) + //... + .BuildAndInit(); +```

@@ -143,7 +141,7 @@ EcsDebug.Break(); ----- * ### `WorldMonitor` -Показывает состояние `EcsWorld`. на каждый казанный мир создается отдельный монитор. +Показывает состояние `EcsWorld`. на каждый мир, переданный в `AddUnityDebug(...)`, создается отдельный монитор.

@@ -162,26 +160,11 @@ EcsDebug.Break();
-# Шаблон Сущности -Настраиваемый набор компонентов которые можно применить к сущностям. Шаблоны должны реализовывать интерфейс `ITemplateNode`. -```c# -ITemplateNode someTemplate = /*...*/; -//... -foreach (var e in _world.Where(out Aspect a)) -{ - // Применение шаблона сущности. - someTemplate.Apply(e, _world.id); -} -``` -```c# -// Применение шаблона сразу при создании сущности. -int e = _world.NewEntity(someTemplate); -``` -По умолчанию расширение содержит 2 вида шаблонов: `ScriptableEntityTemplate`, `MonoEntityTemplate`. +# Шаблоны +Интеграция содержит шаблоны расширяющие `ITemplateNode`, предназначенные для настройки сущностей из редактора. ## ScriptableEntityTemplate Хранится как отдельный ассет. Наследуется от `ScriptableObject`. -Действия чтобы создать `ScriptableEntityTemplate` ассет:

Создать ассет: Asset > Create > DragonECS > ScriptableEntityTemplate. @@ -222,8 +205,9 @@ int e = _world.NewEntity(someTemplate); ## Шаблон компонента +Чтобы компонент попал в меню `Add Component` требуется шаблон. Шаблоны компонента это типы реализующие `IComponentTemplate`. + ### Реализация -Чтобы компонент попал в меню `Add Component` нужно реализовать шаблон компонента. Шаблоны компонента это типы реализующие `IComponentTemplate`. * Упрощенная реализация: ```c# @@ -243,6 +227,8 @@ class SomeTagComponentTemplate : TagComponentTemplate { }
* Полная реализация: +Если не подходят `ComponentTemplate` или `TagComponentTemplate`, можно напрямую реализовать интерфейс `IComponentTemplate`. Например это может пригодиться для работы в связке с кастомной реализацией пула. В большинстве случаев достаточно упрощенной. + ```c# [Serializable] struct SomeComponent : IEcsComponent { /* ... */ } @@ -251,6 +237,7 @@ class SomeComponentTemplate : IComponentTemplate [SerializeField] protected SomeComponent component; public Type Type { get { return typeof(SomeComponent); } } + public bool IsUnique { get { return true; } } public void Apply(int worldID, int entityID) { EcsWorld.GetPoolInstance>(worldID).TryAddOrGet(entityID) = component; @@ -268,28 +255,37 @@ class SomeComponentTemplate : IComponentTemplate ### Кастомизация отображения типов В раскрывающемся при нажатии `Add Component` меню выбора компонента поддерживается иерархическое группирование. Производится группирование на основе мета-атрибута `[MetaGroup]`. -Компоненты в инспекторе по умолчанию отображаются окрашенными в случайный цвет сгенерированный на основе имени компонента, выбрать другой режим окраски можно в [окне настроек](#окно-настроек) фреймворка. Задать конкретный цвет можно при помощи мета-атрибута `[MetaColor]`. +Компоненты в инспекторе по умолчанию отображаются со случайным цветом, зависящим от его имени, выбрать другой режим окраски можно в [окне настроек](#окно-настроек) фреймворка. Задать конкретный цвет можно при помощи мета-атрибута `[MetaColor]`. -Если редактор смог автоматически определить связанный с компонентом скрипт, то слева от крестика удаления компонента будет иконка файла. Клик по иконке выделит файл скрипта в папке проекта, двойной клик откроет скрип для редактирования. Связанный файл ищется по сопоставлению имени типа и имени файла скрипта. +Если интеграции удается найти соответствующий скрипт (по совпадению имени типа и файла, либо при наличии `[MetaID]`), рядом с крестиком удаления появляется иконка файла — клик выделяет скрипт в проекте, двойной клик открывает его. -Если у компонента есть мета-атрибут `[MetaDescription]`, то слева от крестика удаления компонента будет иконка подсказки, при наведении курсора покажется информация из `[MetaDescription]`. +При наличии атрибута `[MetaDescription]` показывается иконка подсказки с текстом из него.
### Применение шаблонов компонентов вне стандартных шаблонов сущностей -При необходимости создания пользовательского шаблона, шаблоны компонентов поддерживают отображение вне стандартных `MonoEntityTemplate` и `ScriptableEntityTemplate`. +Шаблоны компонентов можно использовать не только внутри стандартных `MonoEntityTemplate` и `ScriptableEntityTemplate`, но и в любых пользовательских классах. Для этого предусмотрены два способа: + +Атрибут `[ComponentTemplateReference]`: ```c# -// ComponentTemplateReference добавляет кнопку выбора доступной реализации IComponentTemplate +// Добавляет кнопку выбора доступной реализации IComponentTemplate // и отображает шаблон компонента аналогично компонентам в MonoEntityTemplate или ScriptableEntityTemplate. [SerializeReference, ComponentTemplateReference] -private IComponentTempalte _someComponent1; +private IComponentTemplate _someComponent1; +``` -// Обертка над IComponentTempalte, которая работает аналогично примеру с атрибутом ComponentTemplateReference. +Обертка `ComponentTemplateProperty`: +```c# +// Обертка над IComponentTemplate, аналогично примеру с атрибутом ComponentTemplateReference. private ComponentTemplateProperty _someComponent2; +``` -// Все это работает и для массивов. +Оба подхода работают и для массивов: +```c# [SerializeReference, ComponentTemplateReference] -private IComponentTempalte[] _components; +private IComponentTemplate[] _components; +// или +private ComponentTemplateProperty[] _components; ```
diff --git a/src/Connectors/EcsEntityConnect.cs b/src/Connectors/EcsEntityConnect.cs index cb9e103..8a53fb6 100644 --- a/src/Connectors/EcsEntityConnect.cs +++ b/src/Connectors/EcsEntityConnect.cs @@ -113,9 +113,9 @@ namespace DCFApixels.DragonECS { get { return _monoTemplates; } } - public IEnumerable AllTemplates + public IEnumerable AllTemplates { - get { return ((IEnumerable)_scriptableTemplates).Concat(_monoTemplates); } + get { return ((IEnumerable)_scriptableTemplates).Concat(_monoTemplates); } } #endregion diff --git a/src/Connectors/GameObjectConnect.cs b/src/Connectors/GameObjectConnect.cs index b5ebdde..dd30270 100644 --- a/src/Connectors/GameObjectConnect.cs +++ b/src/Connectors/GameObjectConnect.cs @@ -84,6 +84,12 @@ namespace DCFApixels.DragonECS public static class GameObjectRefExt { + public static entlong NewEntityWithGameObject(this EcsWorld world, ITemplateNode template, string name = "Entity", GameObjectIcon icon = GameObjectIcon.NONE) + { + entlong e = world.NewEntityWithGameObject(name, icon); + template.Apply(world.ID, e.ID); + return e; + } public static entlong NewEntityWithGameObject(this EcsWorld self, string name = "Entity", GameObjectIcon icon = GameObjectIcon.NONE) { entlong result = self.NewEntityLong(); diff --git a/src/Templates/EntityTemplate/Editor/ComponentTemplatePropertyDrawer.cs b/src/Templates/EntityTemplate/Editor/ComponentTemplatePropertyDrawer.cs index f87d874..8591dd0 100644 --- a/src/Templates/EntityTemplate/Editor/ComponentTemplatePropertyDrawer.cs +++ b/src/Templates/EntityTemplate/Editor/ComponentTemplatePropertyDrawer.cs @@ -33,7 +33,6 @@ namespace DCFApixels.DragonECS.Unity.Editors private static ComponentTemplatesDropDown _componentDropDown; #region Properties - private float SingleLineWithPadding => OneLineHeight + Padding * 4f; private float Padding => Spacing; protected override bool IsStaticInit => _componentDropDown != null; #endregion diff --git a/src/Templates/EntityTemplate/Editor/EntityTemplateEditor.cs b/src/Templates/EntityTemplate/Editor/EntityTemplateEditor.cs index 5585279..4c74f71 100644 --- a/src/Templates/EntityTemplate/Editor/EntityTemplateEditor.cs +++ b/src/Templates/EntityTemplate/Editor/EntityTemplateEditor.cs @@ -7,7 +7,7 @@ using UnityEngine; namespace DCFApixels.DragonECS.Unity.Editors { - internal abstract class EntityTemplateEditorBase : ExtendedEditor + internal abstract class EntityTemplateEditorBase : ExtendedEditor { private ComponentTemplatesDropDown _componentDropDown; @@ -17,15 +17,13 @@ namespace DCFApixels.DragonECS.Unity.Editors protected abstract bool IsSO { get; } - //public virtual bool IsStaticData { get { return false; } } - #region Init protected override bool IsInit { get { return _componentDropDown != null; } } protected override void OnInit() { _componentDropDown = new ComponentTemplatesDropDown(); - _componentsProp = serializedObject.FindProperty(Target.ComponentsPropertyName); + _componentsProp = serializedObject.FindProperty("_componentTemplates"); _reorderableComponentsList = new ReorderableList(serializedObject, _componentsProp, true, false, false, false); _reorderableComponentsList.onAddCallback += OnReorderableComponentsListAdd; @@ -142,19 +140,6 @@ namespace DCFApixels.DragonECS.Unity.Editors #endregion - #region Add/Remove - private void OnRemoveComponentAt(int index) - { - if (this.target is IEntityTemplateInternal target) - { - SerializedProperty componentsProp = serializedObject.FindProperty(target.ComponentsPropertyName); - componentsProp.DeleteArrayElementAtIndex(index); - serializedObject.ApplyModifiedProperties(); - EditorUtility.SetDirty(this.target); - } - } - #endregion - protected override void DrawCustom() { Init(); @@ -204,7 +189,7 @@ namespace DCFApixels.DragonECS.Unity.Editors { using (EcsGUI.Layout.BeginVertical(UnityEditorUtility.GetTransperentBlackBackgrounStyle())) { - DrawTop(Target, _componentsProp); + DrawTop(_componentsProp); _reorderableComponentsList.DoLayoutList(); } } @@ -214,7 +199,7 @@ namespace DCFApixels.DragonECS.Unity.Editors } } } - private void DrawTop(IEntityTemplateInternal target, SerializedProperty componentsProp) + private void DrawTop(SerializedProperty componentsProp) { GUILayout.Space(2f); diff --git a/src/Templates/EntityTemplate/IEntityTemplate.cs b/src/Templates/EntityTemplate/IEntityTemplate.cs deleted file mode 100644 index 552de85..0000000 --- a/src/Templates/EntityTemplate/IEntityTemplate.cs +++ /dev/null @@ -1,26 +0,0 @@ -#if DISABLE_DEBUG -#undef DEBUG -#endif - -namespace DCFApixels.DragonECS -{ - public interface IEntityTemplate : ITemplateNode { } - - public static class ITemplateNodeExtensions - { - public static entlong NewEntityWithGameObject(this EcsWorld world, ITemplateNode template, string name = "Entity", GameObjectIcon icon = GameObjectIcon.NONE) - { - entlong e = world.NewEntityWithGameObject(name, icon); - template.Apply(world.ID, e.ID); - return e; - } - } -} - -namespace DCFApixels.DragonECS.Unity.Internal -{ - internal interface IEntityTemplateInternal : IEntityTemplate - { - string ComponentsPropertyName { get; } - } -} \ No newline at end of file diff --git a/src/Templates/EntityTemplate/IEntityTemplate.cs.meta b/src/Templates/EntityTemplate/IEntityTemplate.cs.meta deleted file mode 100644 index c3e7e3c..0000000 --- a/src/Templates/EntityTemplate/IEntityTemplate.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 33a7d50d86178eb43a36d5e8bdd70982 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/src/Templates/EntityTemplate/Templates/MonoEntityTemplate.cs b/src/Templates/EntityTemplate/Templates/MonoEntityTemplate.cs index 21d8915..08cb1d7 100644 --- a/src/Templates/EntityTemplate/Templates/MonoEntityTemplate.cs +++ b/src/Templates/EntityTemplate/Templates/MonoEntityTemplate.cs @@ -11,7 +11,7 @@ using UnityEngine.Serialization; namespace DCFApixels.DragonECS { - public abstract class MonoEntityTemplateBase : MonoBehaviour, IEntityTemplate + public abstract class MonoEntityTemplateBase : MonoBehaviour, ITemplateNode { public abstract void Apply(short worldID, int entityID); } @@ -22,20 +22,13 @@ namespace DCFApixels.DragonECS [MetaGroup(EcsUnityConsts.PACK_GROUP, EcsUnityConsts.ENTITY_BUILDING_GROUP)] [MetaDescription(EcsConsts.AUTHOR, nameof(MonoBehaviour) + " implementation of an entity template. Templates are a set of components that are applied to entities.")] [MetaID("DragonECS_C734BA8092014833C14F21E05D7B1551")] - public class MonoEntityTemplate : MonoEntityTemplateBase, IEntityTemplateInternal + public class MonoEntityTemplate : MonoEntityTemplateBase, ITemplateNode { [SerializeReference] [ReferenceButton(true, typeof(IComponentTemplate))] [FormerlySerializedAs("_components")] private IComponentTemplate[] _componentTemplates; - #region Properties - string IEntityTemplateInternal.ComponentsPropertyName - { - get { return nameof(_componentTemplates); } - } - #endregion - #region Methods public ReadOnlySpan GetComponentTemplates() { diff --git a/src/Templates/EntityTemplate/Templates/ScriptableEntityTemplate.cs b/src/Templates/EntityTemplate/Templates/ScriptableEntityTemplate.cs index 07e92ae..675acd1 100644 --- a/src/Templates/EntityTemplate/Templates/ScriptableEntityTemplate.cs +++ b/src/Templates/EntityTemplate/Templates/ScriptableEntityTemplate.cs @@ -11,7 +11,7 @@ using UnityEngine.Serialization; namespace DCFApixels.DragonECS { - public abstract class ScriptableEntityTemplateBase : ScriptableObject, IEntityTemplate + public abstract class ScriptableEntityTemplateBase : ScriptableObject, ITemplateNode { public abstract void Apply(short worldID, int entityID); } @@ -21,7 +21,7 @@ namespace DCFApixels.DragonECS [MetaDescription(EcsConsts.AUTHOR, nameof(ScriptableObject) + " implementation of an entity template. Templates are a set of components that are applied to entities.")] [CreateAssetMenu(fileName = nameof(ScriptableEntityTemplate), menuName = EcsConsts.FRAMEWORK_NAME + "/" + nameof(ScriptableEntityTemplate), order = 1)] [MetaID("DragonECS_7C4DBA809201D959401A5BDFB6363EC0")] - public class ScriptableEntityTemplate : ScriptableEntityTemplateBase, IEntityTemplateInternal + public class ScriptableEntityTemplate : ScriptableEntityTemplateBase, ITemplateNode { [SerializeField] private ScriptableEntityTemplateBase[] _templates; @@ -30,13 +30,6 @@ namespace DCFApixels.DragonECS [FormerlySerializedAs("_components")] private IComponentTemplate[] _componentTemplates; - #region Properties - string IEntityTemplateInternal.ComponentsPropertyName - { - get { return nameof(_componentTemplates); } - } - #endregion - #region Methods public ReadOnlySpan GetTemplates() {