Swift SpriteKit 基本接触/碰撞

Swift SpriteKit basic Contact / Collision

问题:当硬币产生时,它的物理体出现在 spriteNode 的正下方。此外,当玩家接触硬币的 physicsBody 时,玩家会从 physicsBody 弹开,游戏结束。

输出应该是什么:硬币的 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)

}

}

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

contactTestBitMask - 定义哪些类别的物体会导致与当前物理物体相交通知的掩码。

When two bodies share the same space, each body’s category mask is tested against the other body’s contact mask by performing a logical AND operation. If either comparison results in a nonzero value, an SKPhysicsContact object is created and passed to the physics world’s delegate. For best performance, only set bits in the contacts mask for interactions you are interested in.

collisionBitmask - 定义物理物体类别可以与该物理物体碰撞的遮罩。

When two physics bodies contact each other, a collision may occur. This body’s collision mask is compared to the other body’s category mask by performing a logical AND operation. If the result is a nonzero value, this body is affected by the collision. Each body independently chooses whether it wants to be affected by the other body. For example, you might use this to avoid collision calculations that would make negligible changes to a body’s velocity.

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

coin.physicsBody?.collisionBitMask = ColliderType.playerCategory

试试看这是否能解决您的 SpriteNode 对齐问题

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

此外,我建议您更改定义类别位掩码的方式。由于您已经在使用 << 进行位移,因此不需要按 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

这对您的问题没有帮助,但知道这一点很好。

我实际上找到了一个更适合我的游戏的变通方法,我将 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 } }