Sprite kit 场景中来自不同层的节点将不会交互

Sprite kit 场景中来自不同层的节点将不会交互,sprite-kit,swift2,collision-detection,game-physics,Sprite Kit,Swift2,Collision Detection,Game Physics,提前道歉,因为这个问题涉及代码分配。 我有一个游戏场景,有多个层包含HUD/分数/等的节点/精灵节点。其中一个层,LayerProjectile,包含一个武器实体 所述实体具有精灵和物理组件。 问题是LayerProjectle中的投射节点不与游戏场景的主层(worldLayer)中的节点交互 所有物理实体都是动态的,游戏场景有其物理世界大门 class GamePlayMode: SGScene, SKPhysicsContactDelegate {... //武器属性(SGEntity是G

提前道歉,因为这个问题涉及代码分配。 我有一个游戏场景,有多个层包含HUD/分数/等的节点/精灵节点。其中一个层,LayerProjectile,包含一个武器实体

所述实体具有精灵和物理组件。 问题是LayerProjectle中的投射节点不与游戏场景的主层(worldLayer)中的节点交互

所有物理实体都是动态的,游戏场景有其物理世界大门

class GamePlayMode: SGScene, SKPhysicsContactDelegate {...
//武器属性(SGEntity是GK实体)

类throwEapon:SGEntity{

    var spriteComponent: SpriteComponent!
    var physicsComponent: PhysicsComponent
    init(position: CGPoint, size: CGSize, texture:SKTexture){

            super.init();

            //Initilse Compnemnets
            spriteComponent = SpriteComponent(entity: self, texture: texture, size: size, position: position);
            addComponent(spriteComponent);
            physicsComponent = PhysicsComponent(entity: self, bodySize: CGSize(width: spriteComponent.node.size.width * 0.8, height: spriteComponent.node.size.height * 0.8), bodyShape: .square, rotation: true);
            physicsComponent.setCategoryBitmask(ColliderType.Projectile.rawValue, dynamic: true);
            physicsComponent.setPhysicsCollisions(ColliderType.None.rawValue);
            physicsComponent.setPhysicsContacts( ColliderType.Destroyable.rawValue | ColliderType.Enemy.rawValue);
            physicsComponent.setEffectedByGravity(false);
            addComponent(physicsComponent);

            //Final Steps of compnements
            spriteComponent.node.physicsBody = physicsComponent.physicsBody;
            spriteComponent.node.name = "weapon";
            name = "weapon";
            spriteComponent.node.zPosition = 150;

            spriteComponent.node.userData = ["startX" : position.x];
//处理联系人

覆盖func contactWith(实体:SGEntity){ //如果与GemeScene中的Enity接触

    switch entity.name {

    case "destructableEntity":

        //Remove from Scsene  self.parent?.parent?.runAction(SKAction.playSoundFileNamed("110548__noisehag__comp-cover-02.wav", waitForCompletion: false))
        if let spriteComponentDestructable = entity.componentForClass(SpriteComponent.self){

            let pos = spriteComponentDestructable.node.position;

            spriteComponent.node.removeFromParent();


            spriteComponentDestructable.node.parent?.runAction(SKAction.playSoundFileNamed("110548__noisehag__comp-cover-02.wav", waitForCompletion: false));
            spriteComponentDestructable.node.removeAllActions();
            spriteComponentDestructable.node.removeFromParent();

            emitterExplosion(pos);

        }

       // self.runAction(SKAction.sequence([SKAction.fadeAlphaTo(0.0, duration: 0.5), SKAction.removeFromParent()]))
       break;
         case "enemyEntity":
        if let spriteComponentEnemy = entity.componentForClass(SpriteComponent.self){

                let pos = spriteComponentEnemy.node.position;

                spriteComponent.node.removeFromParent();
    spriteComponentEnemy.node.parent?.runAction(SKAction.playSoundFileNamed("110548__noisehag__comp-cover-02.wav", waitForCompletion: false));
                spriteComponentEnemy.node.removeAllActions();
               spriteComponentEnemy.node.removeFromParent();

                emitterExplosion(pos);

            } break;
      default:
        //
        break;
    }
LayerProjectile,继承自Layer-a SKNode,处理添加到游戏场景中的所有武器实体

class LayerProjectiles: Layer { 

        override func updateNodes(delta:CFTimeInterval,childNumber:Int,childNode: SKNode) {

print("Player movenment direction: \(playerMovingRighToLeft)");

            if playerMovingRighToLeft {

                // player moving to right so throw weapon same direction
                childNode.position = childNode.position + CGPoint(x: delta * -weaponSpeed, y: 0.0);
                childNode.zRotation = childNode.zRotation - (CGFloat(delta) * 10);



            } else{

            childNode.position = childNode.position + CGPoint(x: delta * weaponSpeed, y: 0.0)
            childNode.zRotation = childNode.zRotation - (CGFloat(delta) * 10)

            }


            // When arrow within this layer moves out of the screen remove it, and the reverse
            if childNode.position.x > ((childNode.userData!["startX"] as! CGFloat) + (SKMSceneSize!.width * 1.2)) || childNode.position.x < ((childNode.userData!["startX"]as! CGFloat) - (SKMSceneSize!.width * 1.2)){
                childNode.removeFromParent()
            }

        }
最后是可破坏实体的物理/精灵组件设置,该实体是worldLayer的子实体(与LayerProject一起添加到GaemScene)

初始化游戏场景并添加所有精灵节点时武器投射物(当用户在游戏中点击投掷按钮时)和可破坏实体的实例化:

let throwWeapon = ThrowWeapon(position: CGPoint(x: self.spriteComponent.node.position.x, y: self.spriteComponent.node.position.y + (self.spriteComponent.node.size.height / 2)), size: CGSize(width: 9, height: 40),  texture: textureAtlas.textureNamed("kunai"));

        playerEnt.gameScene.layerProjectile.addChild(throwWeapon.spriteComponent.node);
//可破坏实体

gs.worldLayer.enumerateChildNodesWithName("placeholder_Destructable")  { (node, stop) -> Void in
        let crate = Destructable(position:  node.position, size: CGSize(width: 32, height: 32),  texture: tileAtlasInstance.textureNamed("Crate"));
        //crate.name = "placeholder_Destructable";
        //crate.spriteComponent.node.zPosition = GameSettings.GameParams.zValues.zWorldFront;
        self.gs.addEntity(crate, toLayer: self.gs.worldLayer)
    }
欢迎您的任何意见

添加:碰撞类型的类别位掩码枚举:

enum ColliderType:UInt32 {
  case Player        = 0
  case Destroyable   = 0b1
  case Wall          = 0b10
  case Collectable   = 0b100 // get points
  case EndLevel      = 0b1000
  case Projectile    = 0b10000
  case None          = 0b100000
  case KillZone      = 0b1000000
  case arrow         = 0b10000000;
  case fire =          0b100000000; // die
  case blueFire =      0b1000000000; // die
  case greenCrystal =  0b10000000000; //more points like collectables
  case barrel1 =       0b100000000000; //die
  case barrell2 =      0b1000000000000; //die
  case swordPoints =   0b10000000000000; //points
  case spikes =        0b100000000000000; //die
  case Enemy =         0b1000000000000000; // see Eneemy Entity


    // against arrow and fire

}
//SGEnity类,其中在实体(武器、可破坏性)类中调用并重写处理ENITY的物理触点的func

类SGEntity:GKEntity{

var name=“”

func联系人(实体:SGEntity){ //被子类覆盖

}

//物理成分

enum PhysicsBodyShape {
  case square
    case squareOffset;// so the player knowns where the tile physics body is
  case circle
  case topOutline
  case bottomOutline
}

class PhysicsComponent: GKComponent {

  var physicsBody = SKPhysicsBody()

  init(entity: GKEntity, bodySize: CGSize, bodyShape: PhysicsBodyShape, rotation: Bool) {

    switch bodyShape {
    case.square:
      physicsBody = SKPhysicsBody(rectangleOfSize: bodySize)
      break
    case.squareOffset:
      physicsBody = SKPhysicsBody(rectangleOfSize: bodySize, center: CGPoint(x: 0, y: bodySize.height/2 + 2))
      break
    case .circle:
      physicsBody = SKPhysicsBody(circleOfRadius: bodySize.width / 2)
      break
    case .topOutline:
      physicsBody = SKPhysicsBody(edgeFromPoint: CGPoint(x: (bodySize.width/2) * -1, y: bodySize.height/2), toPoint: CGPoint(x: bodySize.width/2, y: bodySize.height/2))
      break
    case .bottomOutline:
      physicsBody = SKPhysicsBody(edgeFromPoint: CGPoint(x: (bodySize.width/2) * -1, y: (bodySize.height/2) * -1), toPoint: CGPoint(x: bodySize.width/2, y: (bodySize.height/2) * -1))
      break
    }

    physicsBody.allowsRotation = rotation




    //Defaults
    physicsBody.dynamic = true
    physicsBody.contactTestBitMask = ColliderType.None.rawValue
    physicsBody.collisionBitMask = ColliderType.None.rawValue
  }



  func setCategoryBitmask(bitmask:UInt32, dynamic: Bool) {

    physicsBody.categoryBitMask = bitmask
    physicsBody.dynamic = dynamic

  }

  func setPhysicsCollisions(bitmask:UInt32) {

    physicsBody.collisionBitMask = bitmask

  }

  func setPhysicsContacts(bitmask:UInt32) {

    physicsBody.contactTestBitMask = bitmask

  }

    func setEffectedByGravity (gravity: Bool){
        physicsBody.affectedByGravity = gravity;
    }

}
因此,contactsBegan通过游戏场景的物理层调用:

if let bodyA = contact.bodyA.node as? EntityNode, //SpriteNode
      let bodyAent = bodyA.entity as? SGEntity,       // COnverted to SGEntity
      let bodyB = contact.bodyB.node as? EntityNode, //SprtiteNode
      let bodyBent = bodyB.entity as? SGEntity //ERROR HERE : Cast to SGEnity

    {
        print("SGENity Description: \(bodyBent)");
        contactBegan(bodyAent, nodeB: bodyBent)
        contactBegan(bodyBent, nodeB: bodyAent)
    }else{
        print("Cast error")
    }

问题似乎是将射弹实体强制转换为SGEntity,此操作失败,并且从未调用射弹实体的…联系。所有其他SGEntity(可销毁)首先,你确定你的碰撞类型设置了正确的类别吗?例如,1,2,4…而不是1,2,3?正如我在上一个问题中所说的,检查是否至少有一个物体是动态的-这意味着,如果你的射弹与可摧毁的物体碰撞,至少其中一个物体必须是动态的。是的,你有set投射和可破坏节点为Dynamic,当我看到以下内容时,已将类别位掩码发布到Question:case“destructableEntity”:,我想到的第一个想法是-typo:)如果重复使用同一个字符串,请使用常量。现在,在处理投射对象和可破坏对象之间的接触的方法中放置一个断点,然后查看它在哪一点失败。您是否确定所有实体都设置了名称?我看不到处理项目之间接触的部分ectile&Destructurable实际上是可以的,但是如果它没有被调用,那么你应该仔细检查这些对象上的联系人和类别位掩码。我不知道还能说什么。代码太多了,所以我可能遗漏了一些东西。一个问题…你在哪里处理联系人?哪个类实现了didBeginContact和didEndContact方法?编辑:哦,我明白了…你处理每个实体中的联系人,对吗?是什么触发了contactWith:(entity:)方法?我的意思是,在你的代码中,你有类似于didBeginContact的东西,它会被物理引擎自动调用?
enum PhysicsBodyShape {
  case square
    case squareOffset;// so the player knowns where the tile physics body is
  case circle
  case topOutline
  case bottomOutline
}

class PhysicsComponent: GKComponent {

  var physicsBody = SKPhysicsBody()

  init(entity: GKEntity, bodySize: CGSize, bodyShape: PhysicsBodyShape, rotation: Bool) {

    switch bodyShape {
    case.square:
      physicsBody = SKPhysicsBody(rectangleOfSize: bodySize)
      break
    case.squareOffset:
      physicsBody = SKPhysicsBody(rectangleOfSize: bodySize, center: CGPoint(x: 0, y: bodySize.height/2 + 2))
      break
    case .circle:
      physicsBody = SKPhysicsBody(circleOfRadius: bodySize.width / 2)
      break
    case .topOutline:
      physicsBody = SKPhysicsBody(edgeFromPoint: CGPoint(x: (bodySize.width/2) * -1, y: bodySize.height/2), toPoint: CGPoint(x: bodySize.width/2, y: bodySize.height/2))
      break
    case .bottomOutline:
      physicsBody = SKPhysicsBody(edgeFromPoint: CGPoint(x: (bodySize.width/2) * -1, y: (bodySize.height/2) * -1), toPoint: CGPoint(x: bodySize.width/2, y: (bodySize.height/2) * -1))
      break
    }

    physicsBody.allowsRotation = rotation




    //Defaults
    physicsBody.dynamic = true
    physicsBody.contactTestBitMask = ColliderType.None.rawValue
    physicsBody.collisionBitMask = ColliderType.None.rawValue
  }



  func setCategoryBitmask(bitmask:UInt32, dynamic: Bool) {

    physicsBody.categoryBitMask = bitmask
    physicsBody.dynamic = dynamic

  }

  func setPhysicsCollisions(bitmask:UInt32) {

    physicsBody.collisionBitMask = bitmask

  }

  func setPhysicsContacts(bitmask:UInt32) {

    physicsBody.contactTestBitMask = bitmask

  }

    func setEffectedByGravity (gravity: Bool){
        physicsBody.affectedByGravity = gravity;
    }

}
if let bodyA = contact.bodyA.node as? EntityNode, //SpriteNode
      let bodyAent = bodyA.entity as? SGEntity,       // COnverted to SGEntity
      let bodyB = contact.bodyB.node as? EntityNode, //SprtiteNode
      let bodyBent = bodyB.entity as? SGEntity //ERROR HERE : Cast to SGEnity

    {
        print("SGENity Description: \(bodyBent)");
        contactBegan(bodyAent, nodeB: bodyBent)
        contactBegan(bodyBent, nodeB: bodyAent)
    }else{
        print("Cast error")
    }