Удаление объекта GKComponent из сцены

Я использую наборы GamePlay Entity - Система компонентов для 2D-игры. Каждая сущность имеет набор GKComponents — spriteComponent, physicComponent и т. д., а также GKComponent (ChaseScrollMovement.swift), который берет спрайт-компонент Entities и перемещает его по экрану.

Добавление компонента ChaseScrollMovment к вражескому объекту

addComponent(physicsCompnment);
        scrollerComponent = ChaseScrollComponent(entity: self, isEnemey : true);
        addComponent(scrollerComponent);

Проблема в том, что когда я удаляю EnemyEnity из GameScence (при контакте с WeaponEnity):

Class ThrowWeaponEnity.....didBginContact...
case "enemyEntity":
  if let spriteComponentEnemy = entity.componentForClass(SpriteComponent.self){
                       let pos = spriteComponentEnemy.node.position;
                        //Remove enemy sprote and its entiy
                        spriteComponentEnemy.node.parent?.runAction(SKAction.playSoundFileNamed("110548__noisehag__comp-cover-02.wav", waitForCompletion: false));
                        spriteComponentEnemy.node.removeAllActions();
                       spriteComponentEnemy.node.removeFromParent();

                        //Remove the entire entity
                        entity.removeComponentForClass(SpriteComponent.self);
                        emitterExplosion(pos);
                     }
      break;

....EnemeyEnitiy удаляется из GameScene, затем метод обновления GameScene вызывает метод обновления компонента....

Компоненты в GameScene

lazy var componentSystems: [GKComponentSystem] = {
    let parallaxSystem = GKComponentSystem(componentClass: ParallaxComponent.self)
    let animationSystem = GKComponentSystem(componentClass: AnimationComponent.self)
    let scrollerSystem = GKComponentSystem(componentClass: ChaseScrollComponent.self)
    return [animationSystem, parallaxSystem, scrollerSystem]
  }()
  let scrollerSystem = FullControlComponentSystem(componentClass: FullControlComponent.self).......


//MARK: Life Cycle
  override func update(currentTime: CFTimeInterval) {
    if !pauseLoop {........

// Update Components
      for componentSystem in componentSystems {
        componentSystem.updateWithDeltaTime(deltaTime)
      }

..... так что тогда компонент ChaseScroll не может найти spriteCompnment EnemyEntity, поскольку он удаляется из сцены, и здесь возникает исключение....

class ChaseScrollComponent: GKComponent {
   var spriteComponent: SpriteComponent {
    //Called after Init() and during GaemplayMode.updat / componments.udate
    guard let spriteComponent = entity?.componentForClass(SpriteComponent.self)
        else{
            fatalError("SpriteCompnemnet Missing");

    }
    print("SpriteCompnemnt for CHaseScroll GKConponent : \(spriteComponent.node.name)")
    return spriteComponent;
    }

Я новичок в системе Enity-Compnent, поэтому мне интересно, как лучше всего предотвратить исключение, когда один EnemyEntity (их много в сцене) удаляется из сцены и позволяет компонентам успешно обновляться в течение жизненного цикла GameScene .

Заранее спасибо

Обновление: Попытался удалить компоненты из системы, чтобы метод upDate компонентов не вызывался в обновлении игровой сцены:

//В нашей игровой сцене

func removeEntity(entity : GKEntity){

        print("Enity hashValue and \(entity.hash)description:  \(entities.count)");

        if entities.contains(entity){
            //Remove the entities components
            let entiyRemoved = entities.remove(entity);
            entity.removeComponentForClass(PhysicsComponent.self);
            entity.removeComponentForClass(ChaseScrollComponent.self);

        }

        //Remove entity from array of enities
        entities.remove(entity); print(entities.count);


        for componentsytem in self.componentSystems{
            //Remove componment is from the system not the entity, so if removed the component update will not be called
            componentsytem.removeComponentWithEntity(entity);            }

    }

Но компонент, который должен быть удален, все еще вызывается своим обновлением, в рамках этого обновления инициализация объекта spriteComponent завершается неудачно, как и ожидалось, потому что мы удалили компонент из объекта (и попытались удалить из системы!):

 var spriteComponent: SpriteComponent {
    guard let spriteComponent = entity?.componentForClass(SpriteComponent.self)
        else{
            fatalError("SpriteCompnemnet Missing");
     }
    print("SpriteCompnemnt for CHaseScroll GKConponent : \(spriteComponent.node.name)")
    return spriteComponent;
    }

Таким образом, по-прежнему не удается удалить компонент из системы, поскольку его обновление все еще вызывается, или не может удалить сущность из системы.


person dancingbush    schedule 26.01.2017    source источник
comment
В GKComponentSystem есть функция removeComponent(foundIn:), которую вы можете попробовать вызов, когда вы удаляете объект, который должен удалить ссылку на компонент из системы.   -  person Mark Brownsword    schedule 27.01.2017
comment
Спасибо, но разве компоненты сущностей не должны быть удалены из сцены, когда удаляется сама сущность?   -  person dancingbush    schedule 27.01.2017
comment
Я бы удалил его явно, хотя вы не показали в своем коде, как вы связываете компоненты с системами.   -  person Mark Brownsword    schedule 27.01.2017
comment
В классе ThrowWeaponEntity ..... entityRemoveComponentForClass ..... но я начинаю задаваться вопросом, действительно ли это удаление сущности, поскольку есть ссылка на CKComponents remianjng   -  person dancingbush    schedule 27.01.2017
comment
Да, вы удалили узел, но оставили сущность.   -  person Mark Brownsword    schedule 27.01.2017
comment
Так как же удалить саму сущность?   -  person dancingbush    schedule 27.01.2017
comment
Сущность — это просто переменная, поэтому установите для нее значение nil.   -  person Mark Brownsword    schedule 27.01.2017
comment
Проблема заключается в том, что при назначении различных свойств, например позиции CGpoint, компонентам сущности сущность должна быть принудительно развернута, поэтому компилятор не позволит присвоить nil   -  person dancingbush    schedule 28.01.2017
comment
Не могу найти метод removeComponent (foundIn) для Entity, но есть removeComponentForClass, но при реализации этого все еще возникает та же проблема.   -  person dancingbush    schedule 28.01.2017
comment
Кажется, вы можете удалить компоненты сущности без проблем, но удаление сущности — это совсем другое дело.   -  person dancingbush    schedule 28.01.2017


Ответы (1)


Ниже приведен пример того, как я инициализировал системы в файле ECS. Этот код находится в GameScene. Обратите внимание, что Entity создает свои собственные компоненты.

var entities: [GKEntity]!
var componentSystems: [GKComponentSystem<GKComponent>]!

override func didMove(to view: SKView) {
    self.setupEntities()
    self.setupComponentSystems()
}

override func update(_ currentTime: TimeInterval) {
    // Update ComponentSystems
    for componentSystem in componentSystems {
        componentSystem.update(deltaTime: dt)
    }
}

func setupEntities() {
    self.entities = [GKEntity]()

    // Initialise Rover
    self.roverEntity = RoverEntity()
    self.entities.append(self.roverEntity as! GKEntity)

    // Add entites to scene
    for entity in self.entities {
        if let visualEntity = entity as? VisualEntity {
            self.addChild(visualEntity.node)
        }
    }
}

func setupComponentSystems() {
    self.healthSystem = HealthSystem()
    self.healthSystem.addComponents(from: self.entities)
    self.healthSystem.delegate = self

    self.moveSystem = MoveSystem()
    self.moveSystem.addComponents(from: self.entities)
    self.moveSystem.delegate = self

    self.selectionSystem = SelectionSystem()
    self.selectionSystem.addComponents(from: self.entities)
    self.selectionSystem.delegate = self

    self.componentSystems = [
        self.healthSystem,
        self.moveSystem,
        self.selectionSystem
    ]
}

Когда объект необходимо удалить, есть функция removeComponent(foundIn:) на GKComponentSystem. Это Swift 3, поэтому ожидайте, что названия Swift 2 будут другими.

for componentSystem in componentSystems {
    componentSystem.removeComponent(foundIn: self.roverEntity as! GKEntity)
}

Эти компоненты, связанные с этим объектом, теперь удалены из всех систем в ECS, а узел объектов может быть удален со сцены.

person Mark Brownsword    schedule 30.01.2017
comment
Спасибо, функция temoveComponents(foundIn:..,), мы удаляем компонент из tej Entity здесь? Это то же самое, что и вызов entity.removeComponentForClass... моя проблема в том, что я удалил все компоненты для объекта, но объект все еще существует в сцене, когда компонент для этого объекта вызывается в другом месте, он возвращает ноль и вылетает - person dancingbush; 30.01.2017
comment
Это вызывается в функции обновления компонентов, поэтому я полагаю, что если я могу удалить объект со сцены, ссылка на компонент не будет вызываться при обновлении компонентов. - person dancingbush; 30.01.2017
comment
Функция removeComponent(foundIn:) вызывается в системе, а не в объекте. Он удаляет все ссылки на компоненты, принадлежащие объекту, поэтому функция обновления компонентов не будет вызываться. - person Mark Brownsword; 30.01.2017