Home Reference Source

src/components/PrefabInstance.js

import Component from '../systems/EntitySystem/Component';
import System from '../systems/System';
import Events from '../utils/Events';

let instancing = 0;

export default class PrefabInstance extends Component {

  static factory() {
    return new PrefabInstance();
  }

  static get propsTypes() {
    return {
      asset: 'string_null',
      count: 'integer',
      components: 'map(any)'
    };
  }

  static get instancing() {
    return instancing;
  }

  get events() {
    return this._events;
  }

  get asset() {
    return this._asset;
  }

  set asset(value) {
    if (!value) {
      this._asset = null;
      return;
    }

    if (typeof value !== 'string') {
      throw new Error('`value` is not type of String!');
    }

    this._asset = value;
  }

  get count() {
    return this._count;
  }

  set count(value) {
    if (typeof value !== 'number') {
      throw new Error('`value` is not type of Number!');
    }

    this._count = value | 0;
  }

  get components() {
    return this._components;
  }

  set components(value) {
    this._components = value;
  }

  constructor() {
    super();

    this._events = new Events();
    this._asset = null;
    this._count = 1;
    this._components = null;
  }

  dispose() {
    this._events.dispose();
    super.dispose();
  }

  onAttach() {
    const { entity, _asset, _components, _count } = this;
    if (!_asset) {
      throw new Error('There is no source prefab asset provided!');
    }

    const { AssetSystem } = System.systems;
    if (!AssetSystem) {
      throw new Error('There is no registered AssetSystem!');
    }

    if (_count > 0) {
      const asset = AssetSystem.get(`scene://${_asset}`);
      if (!asset) {
        throw new Error(`There is no asset loaded: ${_asset}`);
      }

      const { name, tag, active, parent, position, scale } = entity;
      const rotation = entity.getRotation();
      for (let i = 0; i < _count; ++i) {
        const instance = entity.owner.buildEntity(asset.data);

        ++instancing;
        instance.deserialize({
          name: name || undefined,
          tag: tag || undefined,
          active: active || undefined,
          transform: {
            position: position,
            rotation: rotation,
            scale: scale
          },
          components: _components
        });

        setTimeout(() => {
          const index = entity.indexInParent;
          instance.reparent(parent, index);
          --instancing;
        }, 0);
      }
    }

    setTimeout(() => {
      entity.parent = null;
      entity.dispose();
      this._events.trigger('instantiate');
      this._events.off('instantiate');
    }, 0);
  }

}