return class 而不是集合持有接口中的接口
return class instead of interface from collection holding interfaces
我想创建一个小的实体-组件-系统示例并创建了一些组件,例如
internal struct Position : IComponent
{
public int X { get; set; }
public int Y { get; set; }
}
和
internal struct MovementSpeed : IComponent
{
public int Value { get; set; }
}
每个组件都实现了一个当前为空的接口 IComponent
。当系统循环遍历实体时,我想快速找到相关组件。
我想创建一个字典,将组件类型作为键,将当前实体的组件作为值。
我从 public Dictionary<Type, IComponent> Components { get; }
开始
我可以使用 myEntity.Components.Add(typeof(Movement), new Movement() as IComponent);
添加组件
但是我怎样才能 return 一个组件呢?我创建了一个运动系统示例
internal class Movement : ISystem
{
public void Update()
{
foreach (Entity entity in EntityPool.activeEntities.Values) // Loop through all entities
{
Dictionary<Type, IComponent> components = entity.Components;
if (components.TryGetValue(typeof(Position), out Position positionComponent))
{
if (components.TryGetValue(typeof(MovementSpeed), out MovementSpeed movementSpeedComponent))
{
// TEST: move (1 * movementspeed) units
positionComponent.X += movementSpeedComponent.Value;
positionComponent.Y += movementSpeedComponent.Value;
}
}
}
}
}
if (components.TryGetValue(typeof(Position), out Position positionComponent))
崩溃是因为字典的值 return 不是所需类型本身的组件,它 return 是接口。
我怎样才能让它发挥作用?
(是的,我知道我可以使用 ECS 框架,但出于学习目的我想自己做)
简短的回答:你不能。如果字典是 Dictionary<Type, IComponent>
类型,那么它只会 return IComponent
.
但是您可以为此创建一个扩展方法:
public static class DictionaryExtensions
{
public static TComponent GetValueOrNull<TComponent>(this Dictionary<Type, IComponent> dict) where TComponent : IComponent
{
dict.TryGetValue(typeof(TComponent), out IComponent component);
return component as TComponent;
}
}
并使用它:
internal class Movement : ISystem
{
public void Update()
{
foreach (Entity entity in EntityPool.activeEntities.Values) // Loop through all entities
{
var posComponent = entity.Components.GetValueOrNull<Position>();
if (posComponent != null)
{
// some code
}
}
}
}
如果插入 IComponent 类型的项目,则只能将项目检索为 IComponent。
如果您向字典查询特定类型,您可以直接转换为该类型。
foreach (Entity entity in EntityPool) // Loop through all entities
{
Dictionary<Type, IComponent> components = entity.Components;
if (components.TryGetValue(typeof(Position), out IComponent positionComponent))
{
Position position = (Position)positionComponent;
if (components.TryGetValue(typeof(MovementSpeed), out IComponent movementSpeedComponent))
{
MovementSpeed speed = (MovementSpeed)movementSpeedComponent;
// TEST: move (1 * movementspeed) units
position.X += speed.Value;
position.Y += speed.Value;
}
}
}
使用 linq,您可以非常有效地对列表进行操作。也许这对您来说是更好的方法。这是一个例子:
public void Update2()
{
List<IComponent> list = new List<IComponent>();
list.OfType<Position>().ToList().ForEach(p =>
{
var speed = list.OfType<MovementSpeed?>().FirstOrDefault();
if (speed.HasValue)
{
p.X = speed.Value.Value;
p.Y = speed.Value.Value;
}
});
}
我想创建一个小的实体-组件-系统示例并创建了一些组件,例如
internal struct Position : IComponent
{
public int X { get; set; }
public int Y { get; set; }
}
和
internal struct MovementSpeed : IComponent
{
public int Value { get; set; }
}
每个组件都实现了一个当前为空的接口 IComponent
。当系统循环遍历实体时,我想快速找到相关组件。
我想创建一个字典,将组件类型作为键,将当前实体的组件作为值。
我从 public Dictionary<Type, IComponent> Components { get; }
我可以使用 myEntity.Components.Add(typeof(Movement), new Movement() as IComponent);
但是我怎样才能 return 一个组件呢?我创建了一个运动系统示例
internal class Movement : ISystem
{
public void Update()
{
foreach (Entity entity in EntityPool.activeEntities.Values) // Loop through all entities
{
Dictionary<Type, IComponent> components = entity.Components;
if (components.TryGetValue(typeof(Position), out Position positionComponent))
{
if (components.TryGetValue(typeof(MovementSpeed), out MovementSpeed movementSpeedComponent))
{
// TEST: move (1 * movementspeed) units
positionComponent.X += movementSpeedComponent.Value;
positionComponent.Y += movementSpeedComponent.Value;
}
}
}
}
}
if (components.TryGetValue(typeof(Position), out Position positionComponent))
崩溃是因为字典的值 return 不是所需类型本身的组件,它 return 是接口。
我怎样才能让它发挥作用?
(是的,我知道我可以使用 ECS 框架,但出于学习目的我想自己做)
简短的回答:你不能。如果字典是 Dictionary<Type, IComponent>
类型,那么它只会 return IComponent
.
但是您可以为此创建一个扩展方法:
public static class DictionaryExtensions
{
public static TComponent GetValueOrNull<TComponent>(this Dictionary<Type, IComponent> dict) where TComponent : IComponent
{
dict.TryGetValue(typeof(TComponent), out IComponent component);
return component as TComponent;
}
}
并使用它:
internal class Movement : ISystem
{
public void Update()
{
foreach (Entity entity in EntityPool.activeEntities.Values) // Loop through all entities
{
var posComponent = entity.Components.GetValueOrNull<Position>();
if (posComponent != null)
{
// some code
}
}
}
}
如果插入 IComponent 类型的项目,则只能将项目检索为 IComponent。 如果您向字典查询特定类型,您可以直接转换为该类型。
foreach (Entity entity in EntityPool) // Loop through all entities
{
Dictionary<Type, IComponent> components = entity.Components;
if (components.TryGetValue(typeof(Position), out IComponent positionComponent))
{
Position position = (Position)positionComponent;
if (components.TryGetValue(typeof(MovementSpeed), out IComponent movementSpeedComponent))
{
MovementSpeed speed = (MovementSpeed)movementSpeedComponent;
// TEST: move (1 * movementspeed) units
position.X += speed.Value;
position.Y += speed.Value;
}
}
}
使用 linq,您可以非常有效地对列表进行操作。也许这对您来说是更好的方法。这是一个例子:
public void Update2()
{
List<IComponent> list = new List<IComponent>();
list.OfType<Position>().ToList().ForEach(p =>
{
var speed = list.OfType<MovementSpeed?>().FirstOrDefault();
if (speed.HasValue)
{
p.X = speed.Value.Value;
p.Y = speed.Value.Value;
}
});
}