我想我将对代码中的某些内容进行案例研究,以说明我的意思。
现在,我正在为基于组件的游戏系统开发行为/ Action 系统。 GameObject可以具有附加的IBehaviorComponent和IActionComponent,它们仅显示相关细节,并提供以下内容:
public interface IBehaviorComponent : IBaseComponent
{
IBehavior Behavior { get; }
}
public interface IActionComponent : IBaseComponent
{
IAction Action { get; }
void ExecuteAction(IGameObject target = null);
}
现在,到目前为止一切都很好(至少对我来说!)。但是,当我查看IActionComponent的实现时,麻烦就开始冒出来。
例如,一个简单的IActionComponent实现:
public class SimpleActionComponent : IActionComponent
{
public IAction Action { get; protected set; }
public void ExecuteAction(IGameObject target = null)
{
Action.Execute(target);
}
public void Update(float deltaTime) { } //from IBaseComponent
}
但是,比方说,我想介绍一个更复杂的IActionComponent实现,该实现允许按时间表执行操作:
public class TimedActionComponent : IActionComponent
{
public IAction Action { get; protected set; }
public float IdleTime { get; set; }
public float IdleTimeRemaining { get; protected set; }
public void ExecuteAction(IGameObject target = null)
{
IdleTimeRemaining = IdleTime;
}
public void Update(float deltaTime)
{
if (IdleTimeRemaining > 0f)
{
IdleTimeRemaining -= deltaTime;
}
else
{
Action.Execute(target);
}
}
}
现在,假设我要公开IdleTime,以便可以通过外部影响对其进行更改。我最初的想法是创建一个新界面:
public interface ITimedActionComponent : IActionComponent
{
float IdleTime { get; set; }
float IdleTimeRemaining { get; set; }
}
但是,这里的问题是我的组件系统将所有内容从IBaseComponent向上存储了一层。因此,将GameObject的 Action 组件作为IActionComponent而不是ITimedActionComponent或IRandomizedActionComponent甚至ICrashTheProgramActionComponent进行检索。我希望其原因显而易见,因为我希望任何东西都能够查询GameObject的组件之一,而不必知道组件基本类型(IActionComponent,IRenderableComponent,IPhysicsComponent等)之外到底想要什么。
有没有更清洁的方法来处理此问题,从而使我可以公开在子类中定义的这些属性,而无需将所有检索到的IActionComponent强制转换为它感兴趣的类型?还是这仅仅是实现这一目标的唯一/最佳方法。就像是:
public void IWantYouToAttackSuperSlow(IGameObject target)
{
//Let's get the action component for the gameobject and test if it's an ITimedActionComponent...
ITimedActionComponent actionComponent = target.GetComponent<IActionComponent>() as ITimedActionComponent;
if (actionComponent != null) //We're okay!
{
actionComponent.IdleTime = int.MaxValue; //Mwhaha
}
}
现在,我正在考虑这是唯一的方法,但我认为我会发现我是否不知道木器中是否藏有某种图案,或者是否有人可以提出一种更好的方法来实现这一目标。
谢谢!
最佳答案
您所展示的将IActionComponent
转换为ITimedActionComponent
的代码是(据我所知)是不可避免的-您必须知道IdleTime
属性才能使用它们,对吗?
我认为这里的诀窍是隐藏不太好看的代码,使使用IActionComponent
的类不必处理它。
我对如何执行此操作的第一个想法是使用Factory
:
public void IWantYouToAttackSuperSlow(IGameObject target)
{
//Let's get the action component for the gameobject
IActionComponent actionComponent = ActionComponentsFactory.GetTimedActionComponentIfAvailable(int.MaxValue);
}
和您工厂的方法:
public IActionComponent GetTimedActionComponentIfAvailable(IGameObject target, int idleTime)
{
var actionComponent = target.GetComponent<IActionComponent>() as ITimedActionComponent;
if (actionComponent != null) //We're okay!
{
actionComponent.IdleTime = int.MaxValue; //Mwhaha
}
return (actionComponent != null)? actionComponent : target.GetComponent<IActionComponent>();
}