【问题标题】:How to detect contact regarding sprite texture如何检测有关精灵纹理的接触
【发布时间】:2015-08-30 17:33:06
【问题描述】:

我有一颗子弹应该在格挡时发射。 Bullet 有 6 种不同的随机纹理来模拟不同的子弹。并且块具有随机选择的 3 种不同纹理,看起来就像有 3 个不同的块。我想在代码中指定,如果子弹纹理为红色,方块纹理为红色,那么分数应该增加,但如果子弹为红色,方块为绿色,则游戏结束。我真的不知道如何在 didBeginContact 中告诉游戏这样做。

现在我有这个: 在 GameScene 和 didMoveToView 中:

struct PhysicsCategory {
static let None      : UInt32 = 0
static let All       : UInt32 = UInt32.max
static let CgyBlock  : UInt32 = 0b1       
static let Bullet    : UInt32 = 0b10
}

bullet.physicsBody = SKPhysicsBody(texture: bullet.texture, size: self.bullet.size)
bullet.physicsBody?.categoryBitMask = PhysicsCategory.Bullet
bullet.physicsBody?.contactTestBitMask = PhysicsCategory.CgyBlock
bullet.physicsBody?.collisionBitMask = PhysicsCategory.None
bullet.physicsBody?.affectedByGravity = false
bullet.physicsBody?.usesPreciseCollisionDetection = true

在 didBeginContact 中:

func didBeginContact(contact: SKPhysicsContact) {

var firstBody: SKPhysicsBody
var secondBody: SKPhysicsBody
if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask {
firstBody = contact.bodyA
secondBody = contact.bodyB
} else {
firstBody = contact.bodyB
secondBody = contact.bodyA
}


    if ((firstBody.categoryBitMask & PhysicsCategory.CgyBlock != 0) &&
        (secondBody.categoryBitMask & PhysicsCategory.Bullet != 0)) 
  //and here I suppose I need to implement somehow something like
 // && (bullet.texture = "redBullet") && (CgyBlock.texture = "greenBlock" || "blackBlock")
 {
   gameOver()        
    }

但我知道这行不通。我还尝试在大括号内创建一个 switch 语句,但它也不起作用。如何实现?

更新:这是块的制作方式:

var cgyBlock = SKSpriteNode()

let cgyArray = ["cyanBox", "greenBox", "yellowBox"]

func addCgyLine () {
    cgyBlock = SKSpriteNode(imageNamed: "cyanBox")
    var randomCGY = Int(arc4random_uniform(3))
    cgyBlock.texture = SKTexture(imageNamed: cgyArray[randomCGY])

    cgyBlock.physicsBody = SKPhysicsBody(texture: cgyBlock.texture, size: cgyBlock.size)
    cgyBlock.physicsBody?.dynamic = true
    cgyBlock.physicsBody?.categoryBitMask = PhysicsCategory.CgyBlock
    cgyBlock.physicsBody?.contactTestBitMask = PhysicsCategory.Bullet
    cgyBlock.physicsBody?.collisionBitMask = PhysicsCategory.None

    cgyBlock.position = CGPointMake(size.width + cgyBlock.size.width/2, CGRectGetMidY(self.frame) + 60) 
    addChild(cgyBlock)

    let actionMove = SKAction.moveTo(CGPoint(x: -cgyBlock.size.width/2, y: CGRectGetMidY(self.frame) + 60), duration: 3) 
    let actionDone = SKAction.removeFromParent()
    cgyBlock.runAction(SKAction.sequence([actionMove, actionDone]))
    SKActionTimingMode.EaseOut
}

然后我在 didMoveToView 中执行 runAction。

子弹:

var cannon = SKSpriteNode(imageNamed: "cannon")
var bulletInCannon = SKSpriteNode()
var bullet = SKSpriteNode()

let bulletArray = ["redBullet","magentaBullet", "blueBullet", "cyanBullet", "greenBullet", "yellowBullet"]

//didMoveToView:
 var randomBullet = Int(arc4random_uniform(6))
 bulletInCannon = SKSpriteNode(imageNamed: bulletArray[randomBullet])
 bulletInCannon.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame))
 addChild(bulletInCannon)

 //touchesEnded:
var randomBullet = Int(arc4random_uniform(6))
        bullet = SKSpriteNode(texture: bulletInCannon.texture)
        bullet.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame))
        bullet.name = bulletArray[randomBullet]
        bullet.physicsBody = SKPhysicsBody(texture: bullet.texture, size: self.bullet.size)
        bullet.physicsBody?.dynamic = true
        bullet.physicsBody?.categoryBitMask = PhysicsCategory.Bullet
        bullet.physicsBody?.contactTestBitMask = PhysicsCategory.CgyBlock
        bullet.physicsBody?.collisionBitMask = PhysicsCategory.None
        bullet.physicsBody?.affectedByGravity = false
        bullet.physicsBody?.usesPreciseCollisionDetection = true

        addChild(bullet)
 bulletInCannon.texture = SKTexture(imageNamed: bulletArray[randomBullet])

【问题讨论】:

    标签: sprite-kit collision-detection


    【解决方案1】:

    几种方法:

    1. 您可以使用节点的userData 属性。

      bullet.userData = ["type" : "white"]
      

      要访问它:

      println(bullet.userData?["type"])
      
    2. 您可以创建自定义 Bullet 类,它是 SKSpriteNode 的子类,并创建名为“type”的属性,并在 didBeginContact 中访问该属性。

      class Bullet: SKSpriteNode {
      
          var type:String = ""
      
      
           init(type:String) {
               self.type = type //later you are accessing this with bulletNode.type
              //This is just an simple example to give you a basic idea  what you can do.
              //In real app you should probably implement some kind of security check to avoid wrong type
              let texture = SKTexture(imageNamed: type)
      
              super.init(texture: texture, color: nil, size: texture.size())
          }
      
          required init(coder aDecoder: NSCoder) {
              fatalError("init(coder:) has not been implemented")
          }
      }
      
    3. 您也可以使用bullet.name 属性,并在创建时根据项目符号/块颜色适当地设置它。稍后在 didBeginContact 中,您将检查 bullet.name 以找出项目符号类型。块也是如此。

      func spawnBulletWithType(type:String) -> SKSpriteNode{
      
           //set texture based on type
           //you can pass here something like white_bullet
      
           let atlas = SKTextureAtlas(named: "myAtlas")
      
      
           //here, if passed white_bullet string, SpriteKit will search for texture called white_bullet.png
           let bullet = SKSpriteNode(texture:atlas.textureNamed(type))
      
      
           bullet.name = type // name will be white_bullet, and that is what you will search for in didBeginContact
      
           bullet.physicsBody = SKPhysicsBody(texture: bullet.texture, size: bullet.size)
           bullet.physicsBody?.categoryBitMask = PhysicsCategory.Bullet
           bullet.physicsBody?.contactTestBitMask = PhysicsCategory.CgyBlock
           bullet.physicsBody?.collisionBitMask = PhysicsCategory.None
           bullet.physicsBody?.affectedByGravity = false
           bullet.physicsBody?.usesPreciseCollisionDetection = true
      
           return bullet
      }
      

    编辑:

    根据您最近的 cmets,您可能会选择这个:

    let bulletArray = ["redBullet","magentaBullet", "blueBullet", "cyanBullet", "greenBullet", "yellowBullet"]
    
    //didMoveToView:
     var randomBullet = Int(arc4random_uniform(6))
     let bulletType = bulletArray[randomBullet]
     bulletInCannon.name = bulletType
     bulletInCannon = SKSpriteNode(imageNamed: bulletType )
     bulletInCannon.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame))
     addChild(bulletInCannon)
    
    
    //touchesEnded:
    var randomBullet = Int(arc4random_uniform(6))
            bullet = SKSpriteNode(texture: bulletInCannon.texture)
            bullet.name = bulletInCannon.name
            bullet.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame))
    
            bullet.physicsBody = SKPhysicsBody(texture: bullet.texture, size: self.bullet.size)
            bullet.physicsBody?.dynamic = true
            bullet.physicsBody?.categoryBitMask = PhysicsCategory.Bullet
            bullet.physicsBody?.contactTestBitMask = PhysicsCategory.CgyBlock
            bullet.physicsBody?.collisionBitMask = PhysicsCategory.None
            bullet.physicsBody?.affectedByGravity = false
            bullet.physicsBody?.usesPreciseCollisionDetection = true
    
            addChild(bullet)
    let bulletType = bulletArray[randomBullet]
     bulletInCannon.texture = SKTexture(imageNamed: bulletType)
     bulletInCannon.name = bulletType
    

    【讨论】:

    • 第三种方式看起来很无害。因此,据我了解,我需要在选择纹理后立即为子弹名称制作一个关于其纹理的 switch 语句。但是我仍然不确定如何在 didBeginContact 中声明它。我试过 switch,xcode 给了我一个错误“二进制运算符'-='不能应用于操作数'String'和'SKTexture?'”我试过这个:switch cgyBlock.texture { case "redBlock" : cgyBlock.name = "redCgyBlock" default: break }
    • 我无法确切地看到你是如何创建/发射子弹的......但它可以根据类型来完成。因此,在创建子弹的方法中,将类型(即字符串)作为参数传递。切换类型并使用它来初始化具有适当纹理的子弹,设置类型(bullet.name = "type"。这些是步骤。如果你卡住了,我可以为你写一个例子。
    • 真的很好,我以前从未使用过userData。也许我应该把它放在存储这些纹理的数组中?我已经更新了这个问题,以展示我如何创建一个块,如果它有帮助的话。项目符号的创建方式相同。
    • @Burundanga 第三个示例与使用节点的名称有关,而不是 userData 属性;)我添加了有关如何使用名称属性的示例。只需访问 didBeginContact 中的名称并查看您正在处理的子弹类型。
    • 因此,在您的示例中,您可以使用 block.name = randomCGY
    【解决方案2】:

    首先你需要为子弹和方块定义一个类 然后,您可以定义一个 TextureTypes 来存储您的纹理类型(红色、绿色、...),并将您的随机方法生成的任何内容设置为该类型的类变量。 然后你应该管理联系人并找出 BodyA 和 BodyB 的节点是什么。之后很容易根据节点的纹理类型做任何你喜欢的事情,

    为了澄清我已将 Textures 定义为新类型的代码

    enum TextureTypes: String {
        case Red,Green 
        var description:String {
            switch self {
            case Red:return “Red"
            case Green:return “Green”
            case Green:return “Blue"
            }
        }
    }
    

    Blockclass 和 BulletClass 都必须从 SKNode 继承,因为它们是一个节点!

    class BlockClass:SKNode {
        var NodesTexture : TextureTypes = TextureTypes.Red
    }
    
    class BulletClass:SKNode {
        var NodesTexture : TextureTypes = TextureTypes.Red
    }
    

    将以下代码写入您的didBeginContact 方法以检测您节点的TextureType

        if (contact.bodyA.categoryBitMask == PhysicsCategory.Bullet) &&    
           (contact.bodyB.categoryBitMask == PhysicsCategory.CgyBlock)
        {
            Ablock = (BlockClass *) contact.bodyB.node;
            Abullet = (BulletClass *) contact.bodyA.node;
        }
        if (contact.bodyA.categoryBitMask == PhysicsCategory.CgyBlock) &&    
           (contact.bodyB.categoryBitMask == PhysicsCategory.Bullet)
        {
            Ablock = (BlockClass *) contact.bodyA.node;
            Abullet = (BulletClass *) contact.bodyB.node;
            if ( Ablock.NodesTexture = TextureTypes.Red )
            {
                NSLOG(“A Red Block Detected”)
    
            }
        } 
    

    不要忘记定义 BlocksClass 和 BulletClass 类型的块和子弹

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多