TypeScript 中基于组件的架构

Component based architecture in TypeScript

我正在使用 Phaser 和 TypeScript 制作游戏。我想为 Actors 实现一个基于组件的架构。 我想要实现的是这样的:

var component:AwesomeComponent = actor.getComponent<AwesomeComponent>();

我知道 通过构造类型 T 的对象。但我不喜欢它,因为我可能需要定义大量不同的构造函数来表示所有不同类型的组件。

我目前所做的 是传递一个字符串类型(当然数字会更好,但我仍在制作原型):

getComponent<T>(componentType:string): T 
{
    for (let i = 0; i < this.components.length; i++) 
    {
        if (componentType == this.components[i].componentType)
        {
            return <T><any>this.components[i];
        }
    }
    return undefined;
}

有效,但效果不佳,您必须输入两次 class 名称:

var animComp = actor.getComponent<AnimationComponent>("AnimationComponent");

有什么解决方法的建议吗?

感谢您的宝贵时间!

我在 Phaser 论坛上得到了一些很好的建议,用户@flyovergames 显示的解决方案正是我要找的:

<script src="https://raw.githubusercontent.com/photonstorm/phaser/master/v2/src/Phaser.js"></script>
class Component {
    public actor: Actor;
}

interface ComponentType<T extends Component> { new(...args: any[]): T }

class Actor {
    public components: Component[] = [];

    private getComponentIndex<T extends Component>(type: ComponentType<T>): number {
        for (let i = 0; i < this.components.length; ++i) {
            const component: Component = this.components[i];
            if (component instanceof type) {
                return i;
            }
        }
        return -1;
    }

    public hasComponent<T extends Component>(type: ComponentType<T>): boolean {
        return this.getComponentIndex(type) !== -1;
    }

    public getComponent<T extends Component>(type: ComponentType<T>, ...args: any[]): T {
        const index: number = this.getComponentIndex(type);
        if (index !== -1) {
            return this.components[index] as T;
        }
        return this.addComponent(type, ...args);
    }

    public addComponent<T extends Component>(type: ComponentType<T>, ...args: any[]): T {
        if (this.hasComponent(type)) { return this.getComponent(type); }
        const component: T = new type(...args); // this needs ES5
        component.actor = this;
        this.components.push(component);
        return component;
    }

    public delComponent<T extends Component>(type: ComponentType<T>): T {
        const component: Component = this.getComponent(type);
        this.components.splice(this.components.indexOf(component), 1);
        component.actor = undefined;
        return component as T;
    }
}

class AwesomeComponent extends Component {
    public message: string;
    constructor(message: string) {
        super();
        this.message = message;
    }
    public alert(): void {
        console.log(this.message);
    }
}

function test(): void {
    const actor: Actor = new Actor();
    if (actor.hasComponent(AwesomeComponent)) { throw new Error(); }
    actor.addComponent(AwesomeComponent, "awesome!");
    const awesome: AwesomeComponent = actor.getComponent(AwesomeComponent); // automatic cast!
    awesome.alert();
    actor.delComponent(AwesomeComponent);
    if (actor.hasComponent(AwesomeComponent)) { throw new Error(); }
}

test();

Link 到全线程: Solution