Машинный движок на основе Typescript. Получение компонентов из GameObjects - PullRequest
0 голосов
/ 08 января 2020

TL; DR Попытка создать движок, подобный Unity, но в машинописном тексте и только для браузерных игр. Я делаю это правильно?

Итак, я создаю игровой движок. Это шаблон на основе сущностей / компонентов, который я использую, но мой вопрос в том, правильно ли я его строю? Дело в том, что у меня есть основная игра l oop, которая в первую очередь сама по себе Init, gameObjects и компоненты, связанные с gameObject через события. После этого он запускает игру, gameObjects и компоненты таким же образом. В конце метода Start он также запускает обновление l oop, которое также обновляет gameObject и т. Д.

Пользователь, который создает игру, управляет gameObject только через компоненты, которые он создает сам, наследуя базовый класс компонентов. Это намеренно похожая система, подобная движку Unity. Основная демография c - это люди, знакомые с Unity. Все gameObjects хранятся в классе сцены, который не имеет отношения к вопросу.

Actual Question : Я борюсь с отношением между gameObject и компонентом. Есть ли способ сделать это лучше? Любой шаблон проектирования, который я могу использовать?

note : функция уничтожения в данный момент не работает. все еще выясняю это.

Класс приложения:

class Application implements IStartable, IUpdatable {
  private onAppInit: SignalDispatcher = new SignalDispatcher();
  public get OnAppInit(): ISignal {
    return this.onAppInit.asEvent();
  }

  private onAppStart: SignalDispatcher = new SignalDispatcher();
  public get OnAppStart(): ISignal {
    return this.onAppStart.asEvent();
  }

  private onAppUpdate: SignalDispatcher = new SignalDispatcher();
  public get OnAppUpdate(): ISignal {
    return this.onAppUpdate.asEvent();
  }

  private onAppClose: SignalDispatcher = new SignalDispatcher();
  public get OnAppClose(): ISignal {
    return this.onAppClose.asEvent();
  }

  private currentScene: Scene;
  constructor() {
    this.currentScene = new Scene(this);
  }

  public AddGameObject(object: GameObject) {
    this.currentScene.AddGameObject(object);
  }

  public Start() {
    this.onAppInit.dispatch();

    this.onAppStart.dispatch();

    this.Update();
  }

  public Close() {
    this.onAppClose.dispatch();
  }

  public Update() {
    this.onAppUpdate.dispatch();

    window.requestAnimationFrame(() => {
      this.Update();
    });
  }
}

Класс GameObject:

class GameObject extends EngineObject {
  public name: string;
  public transform: undefined;
  private components: Component[] = [];
  private onAwake: SignalDispatcher = new SignalDispatcher();
  private onStart: SignalDispatcher = new SignalDispatcher();
  private onUpdate: SignalDispatcher = new SignalDispatcher();
  private onDestroy: SimpleEventDispatcher<
    EngineObject
  > = new SimpleEventDispatcher();
  constructor(name: string, transform = undefined) {
    super();
    this.name = name;
    this.transform = transform;
  }

  Awake() {
    super.Awake();
    this.onAwake.dispatch();
  }

  Start() {
    super.Start();
    this.onStart.dispatch();
  }

  Update() {
    super.Update();
    this.onUpdate.dispatch();
  }

  Destroy(object: EngineObject = this) {
    this.onDestroy.dispatch(object);
    super.Destroy(object);
  }

  public AddComponent<T extends Component>(component: T) {
    component.GameObject = this;
    component.UniqueId = this.components.length;
    this.onAwake.asEvent().sub(component.Awake.bind(component));
    this.onStart.asEvent().sub(component.Start.bind(component));
    this.onUpdate.asEvent().sub(component.Update.bind(component));
    this.onDestroy.asEvent().sub(component.Destroy.bind(component));
    this.components.push(component);
  }

  public GetComponent<T extends Component>(instance: T): Component | undefined {
    let found: boolean;
    let returnComponent: Component | undefined;
    this.components.forEach(component => {
      if (found) return;
      if (typeof component === typeof instance) {
        found = true;
        returnComponent = component;
        return;
      }
    });
    return returnComponent;
  }
}

Класс компонента:

export class Component extends EngineObject {
  private uniqueId = -1;
  public get UniqueId(): number {
    if (this.uniqueId < 0)
      console.warn("Component has no gameobject reference");
    return this.uniqueId;
  }

  public set UniqueId(amount: number) {
    if (this.uniqueId >= 0) {
      console.error("Id already set");
      return;
    }
    this.uniqueId = amount;
  }

  protected gameObject!: GameObject;
  public get GameObject(): GameObject {
    return this.gameObject;
  }

  public set GameObject(gameObject: GameObject) {
    if (this.gameObject) {
      console.error("GameObject already set");
      return;
    }
    this.gameObject = gameObject;
  }

  constructor() {
    super();
  }

  public Destroy(object: EngineObject = this) {
    super.Destroy(object);
  }
}
...