【问题标题】:Removing a Entities GKComponent from a Scene从场景中移除实体 GKComponent
【发布时间】:2017-01-26 22:01:30
【问题描述】:

我正在使用 GamePlay 套件实体 - 用于 2d 游戏的组件系统。 每个实体都有一系列 GKComponents - spriteComponent、physicComponent 等和一个 GKComponent (ChaseScrollMovement.swift),它接收一个 Entities spriteComponent 并将其在屏幕上移动。

向 Enemy Enity 添加 ChaseScrollMovment 组件

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

问题是当我从 GameScence 中移除 EnemyEnity 时(与 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;

....从 GameScene 中移除 EnemeyEnitiy,GameScene 更新方法然后调用 Component 更新方法....

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 组件无法找到 EnemyEntity 的 spriteCompnment,因为它已从场景中移除,并在此处引发异常......

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(场景中有很多)并允许组件在游戏场景生命周期。

提前致谢

更新: 尝试从系统中删除组件,以便在游戏场景更新中不会调用组件 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;
    }

因此似乎仍然无法从系统中删除组件,因为它的更新仍被调用或无法从系统中删除实体。

【问题讨论】:

  • GKComponentSystem 有一个 removeComponent(foundIn:) 函数,您可以在删除实体时尝试调用该函数,这应该会从系统中删除组件引用。
  • 谢谢,但是当实体本身被移除时,实体组件是否应该从场景中移除?
  • 我会明确删除它,尽管您没有在代码中显示如何将组件与系统关联。
  • 在类 ThrowWeaponEntity ..... entityRemoveComponentForClass .....但我开始怀疑这是否实际上是在删除实体,因为有对 CKComponents remianjng 的引用
  • 是的,您移除了节点,但留下了实体。

标签: sprite-kit swift2 gameplay-kit


【解决方案1】:

以下是我如何在ECS 中初始化系统的示例。此代码位于 GameScene 中。请注意,实体会创建自己的组件。

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
    ]
}

当一个实体需要完成移除时,GKComponentSystem上有一个函数removeComponent(foundIn:)。这是 Swift 3,所以预计 Swift 2 的命名会有所不同。

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

与此实体关联的组件现在已从ECS 中的所有系统中移除,并且可以从场景中移除实体节点。

【讨论】:

  • 谢谢,func temoveComponents(foundIn:..,),我们是从这里的 tej Entity 中删除组件吗?这与调用 entity.removeComponentForClass 是否相同...我的问题是我已经删除了一个实体的所有组件,但该实体仍然存在于场景中,当在其他地方调用该实体的组件时,它返回 nil 并崩溃
  • 这是在更新组件函数中调用的,所以我在考虑是否可以从场景中删除实体,当我更新组件时,它对组件的引用不会被调用
  • 函数removeComponent(foundIn:)在系统上被调用,而不是在实体上。它删除了对属于实体的组件的所有引用,因此不会调用组件更新函数。
猜你喜欢
  • 2021-01-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-04-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-11
相关资源
最近更新 更多