来自不同图层的场景中的节点不会互动

时间:2017-01-13 20:00:33

标签: sprite-kit swift2 collision-detection game-physics

提前道歉,因为这个问题涉及分配代码。 我有一个GameScene,有多个层,用于HUD / Scores等的Nodes / SpriteNodes。一层LayerProjectile拥有一个武器实体。

所述实体具有Sprite和Physics Components。 问题是LayerProjectile中的Projectile节点不与GameScene的主层(worldLayer)中的节点交互。

所有物理机构都是动态的,GameScene有它的PhysicWorldDelgate

class GamePlayMode: SGScene, SKPhysicsContactDelegate {...

//武器恩赐(SGEntity是一个GKEntity)

类ThrowWeapon: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(entity: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,并处理添加到GameScene的所有武器实体

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()
            }

        }

添加LayerProjectile和worldLayer的实例(保存所有其他节点,其中一些节点将catBitMask设置为在与武器实体联系时通知),添加到GameScene(GamePlayMode的实例,SGScene)

class GameSceneState: GKState {
  unowned let gs: GamePlayMode
  init(scene: GamePlayMode) {
    self.gs = scene
  }
}
gs.physicsWorld.contactDelegate = gs
    gs.physicsWorld.gravity = CGVector(dx: 0.0, dy: -1.0)
//Layers
    gs.layerProjectile = LayerProjectiles();
    gs.worldLayer = TileLayer(levelIndex: gs.levelIndex, typeIndex: .setMain)
    gs.backgroundLayer = SKNode()
    gs.overlayGUI = SKNode()
    gs.addChild(gs.worldLayer)
   gs.addChild(gs.layerProjectile);// For throwing wepaons, made in GamePlayMode

最后是Destrutable实体的物理/精灵组件设置,它是worldLayer的子项(与LayerProjectile一起添加到GaemScene中)

    class Destructable : SGEntity{

        var spriteComponent: SpriteComponent!
        var animationComponent: AnimationComponent!
        var physicsComponent: PhysicsComponent!
        var scrollerComponent: FullControlComponent!

        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: false);
            physicsComponent.setCategoryBitmask(ColliderType.Destroyable.rawValue , dynamic: true);
            physicsComponent.setPhysicsCollisions(ColliderType.Wall.rawValue | ColliderType.Player.rawValue | ColliderType.Destroyable.rawValue); // collides with so bpounces off
           physicsComponent.setPhysicsContacts(ColliderType.Wall.rawValue | ColliderType.Player.rawValue | ColliderType.Projectile.rawValue);
            physicsComponent.setEffectedByGravity(true);

            addComponent(physicsComponent);

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

            //spriteComponent.node.userData = ["startX" : position.x];



        }

// Handle contacts
 override func contactWith(entity: SGEntity) {
        // 
        if entity.name == "weapon"{

            print("Crate hit Projectile");
    }


}

当初始化GameScene并添加所有精灵节点时,武器射弹(当用户在游戏期间点击投掷按钮时)和可破坏实体的实施:

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

任何意见都赞赏。

已添加:ColliderTypes的类别位掩码枚举:

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

}

//在实体(武器,可破坏)类中调用和覆盖处理Enities物理联系人的函数的SGEnity类

class SGEntity:GKEntity {

var name =“”

func contactWith(entity:SGEntity){     //由子类重写

}

// PhyscisComponent

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是通过GameScene的PhysicsDelage调用的:

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,这失败了,并且从未调用与弹丸实体有关的......。所有其他SGEnities(Destructible)都没有问题地投射到SGEntity。,...

0 个答案:

没有答案