所以我试图在我的框架中为游戏对象添加一个组件系统,我希望能够将所有组件存储在一个数组中(或映射......等),所以他们都可以可以轻松更新,并且类不必使用组件的预定义插槽,因此我创建了一个基本组件类,并创建了类型组件的映射,然后有其他组件扩展基本组件,如果可以正常工作我想要做的只是在所有这些上调用一个更新方法,但我希望他们都能够拥有他们想要的任何方法。当然,这不起作用,因为编译器不知道每个组件可能是哪个类。然后我发现我可以通过使用类似的东西(如果我知道它的类型)将组件强制转换为自己的类型:return cast(components.get("transform"), TransformComponent);
然后访问子功能。这是一种好的做事方式,还是一个可怕的设计决定,我应该重新设计组件的整个结构?
对不起,如果这是一个非常缺乏经验的问题,谢谢,
尼科
(注意我正在使用haxe,但我相信这适用于所有oop语言)
答案 0 :(得分:2)
我个人认为这很好,只要你绝对确定你正在使用正确的类型 - 我已经看到其他一些Haxe库(例如minject)使用这种方法。
使用Haxe,您可以使用类似参数:
var c:Map<String,BaseComponent>;
public function getComponent<T:BaseComponent>( name:String, type:Class<T> ):T {
if ( components.exists(name) ) {
var c = components[name];
if ( Std.is(c, type) ) {
return cast c;
}
}
return null; // the component with that name didn't exist, or was the wrong type
}
这样您的用法可以是:
var transform = componentManager.getComponent( "transform", TransformComponent );
if ( transform!=null ) {
transform.doSomething();
}
在这种情况下,transform将完全输入为“TransformComponent”,编译器将允许您访问所有方法等。
最后一点,如果你只有每种类型组件的一个实例,你可以使这更容易:
public function addComponent<T:BaseComponent>( component:T ) {
var type = Type.getClass( component );
var name = Type.getClassName( type );
components[name] = component;
}
public function getComponent<T:BaseComponent>( type:Class<T> ):T {
var name = Type.getClassName( type );
return cast components[name]; // Either the component with the correct type name, or null.
}
componentManager.addComponent( new TransformComponent() );
var t = componentManager.get( TransformComponent );
$type( t ); // TransformComponent, it is correctly typed