Swift SpriteKit基本接触/碰撞

时间:2016-06-06 10:16:09

标签: swift sprite-kit collision-detection skspritenode skphysicsbody

问题:当硬币产生时,它的physicalBody就出现在spriteNode下面。此外,当玩家接触到硬币的物理身体时,玩家会从物理身体反弹并且游戏结束。

输出应该是什么:硬币的physisBody应该与硬币spriteNode正确对齐。当玩家接触到硬币时,硬币应该消失,并且+1应该添加到正确的标签上。

当前代码:

struct ColliderType {

static let playerCategory: UInt32 = 0x1 << 0

static let boundary: UInt32 = 0x1 << 1
​  
​static let coinCategory: UInt32 = 0x1 << 2
​
​static let bodyA: UInt32 = 0x1 << 4
​
​static let bodyB: UInt32 = 0x1 << 8

}

override func didMoveToView(view: SKView) {

var coinInt = 0
​
​
​
​self.physicsWorld.gravity = CGVectorMake(0.0, -7.0)
physicsWorld.contactDelegate = self

player = SKSpriteNode(imageNamed: "player")
player.zPosition = 1
player.position = CGPoint(x: CGRectGetMidX(self.frame), y: CGRectGetMidY(self.frame))
player.physicsBody = SKPhysicsBody(circleOfRadius: player.size.width / 5.12)
player.physicsBody?.dynamic = true
player.physicsBody?.allowsRotation = false

self.addChild(player)

generateCoins()

​
​
coin = SKSpriteNode( imageNamed: "coin")
coin.physicsBody? = SKPhysicsBody(circleOfRadius: coin.size.height / 10)
coin.physicsBody?.dynamic = false
coin.physicsBody?.allowsRotation = false
coin.zPosition = 1
​self.addChild(coin)
​
player.physicsBody?.categoryBitMask = ColliderType.playerCategory
​player.physicsBody?.contactTestBitMask = ColliderType.boundary
player.physicsBody?.collisionBitMask = ColliderType.coinCategory | ColliderType.boundary

coin.physicsBody?.categoryBitMask = ColliderType.coinCategory
coin.physicsBody?.contactTestBitMask = ColliderType.playerCategory
coin.physicsBody?.collisionBitMask = ColliderType.playerCategory

func didPlayerCollideWithCoin(player: SKSpriteNode, coin: SKSpriteNode) {



self.coin.removeFromParent()

self.coin += 1

coinLabel.text = "\(coinInt)"

}

​
​    
​
​func generateCoins()  {

if(self.actionForKey("spawning") != nil){return}

let coinTimer = SKAction.waitForDuration(7, withRange: 2)

let spawnCoin = SKAction.runBlock {

self.coin = SKSpriteNode( imageNamed: "coin")

self.coin.physicsBody = SKPhysicsBody(circleOfRadius: self.coin.size.height / 10)

self.coin.name = "coin"

self.coin.physicsBody?.dynamic = false

self.coin.physicsBody?.allowsRotation = false

var coinPosition = Array<CGPoint>()

coinPosition.append((CGPoint(x:340, y:103)))

coinPosition.append((CGPoint(x:340, y:148)))

coinPosition.append((CGPoint(x:340, y:218)))

coinPosition.append((CGPoint(x: 340, y:343)))

let spawnLocation = coinPosition[Int(arc4random_uniform(UInt32(coinPosition.count)))]

let action = SKAction.repeatActionForever(SKAction.moveToX(+self.xScale, duration: 4.4))

self.coin.runAction(action)

self.coin.position = spawnLocation

self.addChild(self.coin)

print(spawnLocation)

}

let sequence = SKAction.sequence([coinTimer, spawnCoin])

self.runAction(SKAction.repeatActionForever(sequence), withKey: "spawning")

}
​​
func didBeginContact(contact:SKPhysicsContact)  {

let bodyA: SKPhysicsBody = contact.bodyA

let bodyB: SKPhysicsBody = contact.bodyB

if ((bodyA.categoryBitMask == ColliderType.playerCategory) &&     (bodyB.categoryBitMask == ColliderType.coinCategory)){

didPlayerCollideWithCoin(bodyA.node as! SKSpriteNode, coin: bodyB.node as! SKSpriteNode)

}

}

3 个答案:

答案 0 :(得分:4)

我建议您先阅读这些文档!

contactTestBitMask - 一个掩码,用于定义哪些类别的物体会导致与当前物理体的交叉通知。

  

当两个物体共享相同的空间时,每个物体的类别掩码都是   通过执行逻辑来测试另一个身体的接触面罩   和操作。如果任一比较结果为非零值,则为   创建SKPhysicsContact对象并将其传递给物理世界   代表。为获得最佳性能,仅在触点掩码中设置位   您感兴趣的互动。

collisionBitmask - 一个掩码,用于定义哪些类别的物理实体可以与此物理实体发生碰撞。

  

当两个物理实体相互接触时,可能会发生碰撞。   该身体的碰撞面具与其他身体的类别进行比较   通过执行逻辑AND操作进行掩码。如果结果是非零   值,这个身体受到碰撞的影响。每个身体独立   选择是否想要受到其他身体的影响。对于   例如,您可以使用它来避免碰撞计算   对身体的速度做出微不足道的改变。

删除此代码以解决相互冲突的问题

coin.physicsBody?.collisionBitMask = ColliderType.playerCategory

尝试查看这是否解决了您的SpriteNode对齐问题

 var coinTexture = SKTexture(imageNamed: "coin")
 coin = SKSpriteNode(texture:coinTexture)

答案 1 :(得分:1)

另外,我建议您更改定义类别位掩码的方式。由于您已经使用<<进行了位移,因此您不需要以2的幂移位。这就是变换为你做的事情。尝试将代码更改为:

static let playerCategory: UInt32 = 0x1 << 0    
static let boundary: UInt32 = 0x1 << 1    ​  
​static let coinCategory: UInt32 = 0x1 << 2    ​
​static let bodyA: UInt32 = 0x1 << 3    ​
​static let bodyB: UInt32 = 0x1 << 4

这对你的问题没有任何帮助,但这很有用。

答案 2 :(得分:0)

我实际上找到了一种对我的游戏更好的解决方法,在其中我将SKNode细分为代表具有不同损坏,地形单元等导弹的对象。我将所有对象的碰撞位掩码都设置为相同(也就是说,它们都需要相互交互。然后遍历与播放器的所有碰撞,并获得指向与之碰撞的适当对象的指针,我可以执行以下操作

for (int i=0; i<[self.physicsBody.allContactedBodies count]; i++) { SKPhysicsBody* contactedBody = self.physicsBody.allContactedBodies[i]; if (contactedBody != NULL && [contactedBody.node isKindOfClass:[TerrainCell class]]) { NSLog(@"BUMPED INTO TERRAIN"); TerrainCell* collisionObject = (TerrainCell*)contactedBody.node; // do more stuff specific to TerrainCell } }