Question

So I'm trying to put in a component system, for gameobjects in my framework, and I was hoping to be able to store all the components in one array(or map...et.), so they can all be updated easily, and the classes don't have to use predefined slots for components, so I made a base component class, and created a map of the type component, and then had other components that extend the base component, which works fine if all I want to do is call an update method on all of them, but I want them to all be able to have any methods they want. Of course, that can't work, because the compiler does not know what class each component might be. Then I found that I can cast the component to its own type by using something like this (if I know its type): return cast(components.get("transform"), TransformComponent); and then access the childs functions. Is that an ok way of doing things, or is a horrible design decision and I should rework the whole structure of the components? sorry if this is a very inexperienced question, and thanks, Nico

(note I'm using haxe, but I believe this applies to all oop languages)

Was it helpful?

Solution

I personally think this is fine, as long as you are absolutely sure you are casting to the correct type - I have seen a few other Haxe libraries (such as minject) use this approach.

With Haxe, you can use type parameters like so:

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
}

This way your usage can be:

var transform = componentManager.getComponent( "transform", TransformComponent );
if ( transform!=null ) {
    transform.doSomething();
}

In this case, transform will be fully typed as a "TransformComponent" and the compiler will let you access all of it's methods etc.

On a final note, if you only ever have one instance of each type of component, you could make this even easier:

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
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top