gpt4 book ai didi

c# - 将系统与事件连接起来

转载 作者:太空狗 更新时间:2023-10-29 20:29:48 25 4
gpt4 key购买 nike

使用实体-组件-系统模式,我想将一些系统与事件连接起来。所以有些系统不应该循环运行,它们应该按需运行。

健康系统为例,死亡系统应该仅在组件低于 1 健康时运行。

我考虑过拥有两种类型的系统。第一类是周期系统。这每帧运行一次,例如 RenderMovement 系统。另一种类型是基于事件的系统。如前所述,健康死亡之间存在联系。

首先,我创建了一个可供两种系统类型使用的基本接口(interface)。

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
}

我进一步创建了接口(interface)

internal interface IReactiveSystem : ISystem
{
// event based
}

internal interface IPeriodicSystem : ISystem
{
// runs in a loop
}

但我不确定它们是否有必要。使用没有问题

foreach (ISystem system in entityManager.Systems)
{
system.UpdateCacheEntities();
}

但如果不需要,我不想运行系统。

有两种类型的事件,ChangeEventExecuteEvent。当组件的值发生变化时,第一个被触发。当应该对特定实体执行某些操作时会触发第二个。

如果你需要或想要你可以看看 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
}
}

如何为不同的系统创建 ChangeEventsExecuteEvents


编辑

有没有一种方法可以将事件委托(delegate)添加到组件中,以便在更改事件正在监听时或在执行事件正在监听时按需运行此实体的特定系统?

提到 ChangeEventExecuteEvent 我只是指事件委托(delegate)。

目前我可以做这样的事情

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);
}
}
}

但我希望通过使用事件委托(delegate)使系统相互通信和共享数据来实现更好的架构。

最佳答案

我不是这个设计模式的专家,但我读了一些关于它的文章,我的建议是:尽量不要忘记这个模式的真正目的。这次我找到了 article on Wikipedia非常有意思。它基本上是在说(至少我是这么理解的)这个模式被“设计”为避免产生太多的依赖关系,失去解耦。这是我从文章中摘录的一个例子:

Suppose there is a drawing function. This would be a "System" that iterates through all entities that have both a physical and a visible component, and draws them. The visible component could typically have some information about how an entity should look (e.g. human, monster, sparks flying around, flying arrow), and use the physical component to know where to draw it. Another system could be collision detection. It would iterate through all entities that have a physical component, as it would not care how the entity is drawn. This system would then, for instance, detect arrows that collide with monsters, and generate an event when that happens. It should not need to understand what an arrow is, and what it means when another object is hit by an arrow. Yet another component could be health data, and a system that manages health. Health components would be attached to the human and monster entities, but not to arrow entities. The health management system would subscribe to the event generated from collisions and update health accordingly. This system could also now and then iterate through all entities with the health component, and regenerate health.

我认为您使架构过于复杂,失去了这种模式可以给您带来的优势。

首先:为什么需要 EntityManager?我再次引用:

The ECS architecture handles dependencies in a very safe and simple way. Since components are simple data buckets, they have no dependencies.

相反,您的组件是使用注入(inject)的 EntityManager 依赖项构建的:

entityManager.AddSystem(new Movement(entityManager));

结果是一个相对复杂的内部结构来存储实体和相关组件。

解决这个问题后,问题是:如何与 ISystem 进行“通信”?同样,答案在文章中:观察者模式。本质上,每个组件都有一组附加系统,每次发生特定操作时都会通知这些系统。

关于c# - 将系统与事件连接起来,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54389211/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com