Используя шаблон Entity-Component-System, я хочу связать некоторые системы с событиями.Поэтому некоторые системы не должны работать в цикле, они должны просто запускаться по требованию.
Учитывая пример системы Health , система Death должна запускаться только тогда, когдакомпонент получает менее 1 здоровья.
Я думал о наличии двух типов систем.Первый тип - это периодическая система.Это выполняется один раз за кадр, например Render или Movement System.Другой тип - это система, основанная на событиях.Как упоминалось ранее, связь между Health и Death .
Сначала я создал базовый интерфейс, используемый обоими типами систем.
internal interface ISystem
{
List<Guid> EntityCache { get; } // Only relevant entities get stored in there
ComponentRequirements ComponentRequirements { get; } // the required components for this system
void InitComponentRequirements();
void InitComponentPools(EntityManager entityManager);
void UpdateCacheEntities(); // update all entities from the cache
void UpdateCacheEntity(Guid cacheEntityId); // update a single entity from the cache
}
ДалееЯ создал интерфейсы
internal interface IReactiveSystem : ISystem
{
// event based
}
и
internal interface IPeriodicSystem : ISystem
{
// runs in a loop
}
, но я не уверен, понадобятся ли они.Нет проблем с использованием
foreach (ISystem system in entityManager.Systems)
{
system.UpdateCacheEntities();
}
, но я не хочу запускать систему, если она не нужна.
Существует два типа событий: ChangeEvent
и ExecuteEvent
.,Первый срабатывает при изменении значения компонента.Второй срабатывает, когда что-то должно быть сделано с определенной сущностью.
Если вам нужно или хотите, вы можете взглянуть на EntityManager
https://pastebin.com/NnfBc0N9
ComponentRequirements
https://pastebin.com/xt3YGVSv
и использование ECS
https://pastebin.com/Yuze72xf
Пример системы будет примерно таким
internal class HealthSystem : IReactiveSystem
{
public HealthSystem(EntityManager entityManager)
{
InitComponentRequirements();
InitComponentPools(entityManager);
}
private Dictionary<Guid, HealthComponent> healthComponentPool;
public List<Guid> EntityCache { get; } = new List<Guid>();
public ComponentRequirements ComponentRequirements { get; } = new ComponentRequirements();
public void InitComponentRequirements()
{
ComponentRequirements.AddRequiredType<HealthComponent>();
}
public void InitComponentPools(EntityManager entityManager)
{
healthComponentPool = entityManager.GetComponentPoolByType<HealthComponent>();
}
public void UpdateCacheEntities()
{
for (int i = 0; i < EntityCache.Count; i++)
{
UpdateCacheEntity(EntityCache[i]);
}
}
public void UpdateCacheEntity(Guid cacheEntityId)
{
Health healthComponent = healthComponentPool[cacheEntityId];
healthComponent.Value += 10; // just some tests
// update UI
}
}
Как создать ChangeEvents
и ExecuteEvents
для разных систем?
РЕДАКТИРОВАТЬ
Есть лиспособ добавления делегатов событий в компоненты для запуска конкретной системы для этой сущности при изменении, если событие изменения прослушивается, или по запросу, если прослушивается событие выполнения?
Упомянув ChangeEvent
и ExecuteEvent
Iпросто имею в виду делегатов событий.
В настоящее время я мог бы сделать что-то вроде этого
internal class HealthSystem : IReactiveSystem
{
//… other stuff
IReactiveSystem deathSystem = entityManager.GetSystem<Death>(); // Get a system by its type
public void UpdateCacheEntity(Guid cacheEntityId)
{
// Change Health component
// Update UI
if(currentHealth < 1) // call the death system if the entity will be dead
{
deathSystem.UpdateCacheEntity(cacheEntityId);
}
}
}
Но я надеялся добиться лучшей архитектуры, используя делегатов событий, чтобы системы взаимодействовали и обменивались данными между собой.