Swift SpriteKit 基本接触/碰撞

Posted

技术标签:

【中文标题】Swift SpriteKit 基本接触/碰撞【英文标题】:Swift SpriteKit basic Contact / Collision 【发布时间】:2016-06-06 10:16:09 【问题描述】:

问题:当硬币生成时,它的物理体出现在 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)




【问题讨论】:

你已经问过了,不是吗? (***.com/questions/37580673/…) 您使用 0、1、2、4 和 8 的位移而不是 0、1、2、3、4 等的位移有什么特别的原因吗?继续这样下去,你将只有 16 和 32,然后你就用完了。 【参考方案1】:

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

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

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

collisionBitmask - 定义哪些类别的物理体可以与此物理体碰撞的掩码。

当两个物理体相互接触时,可能会发生碰撞。 将此主体的碰撞掩码与其他主体的类别进行比较 通过执行逻辑与运算来屏蔽。如果结果是非零 值,这个物体会受到碰撞的影响。每个身体独立 选择是否要被对方影响。为了 例如,您可以使用它来避免碰撞计算 对身体的速度进行微不足道的变化。

删除此代码以解决碰撞问题

coin.physicsBody?.collisionBitMask = ColliderType.playerCategory

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

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

【讨论】:

您好,感谢您提供的信息!我删除了硬币的碰撞位掩码,没有任何改变。硬币的排列还是和以前一样,我会在此期间修修补补。【参考方案2】:

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

这对解决您的问题没有帮助,但很高兴知道这一点。

【讨论】:

【参考方案3】:

我实际上找到了一种对我的游戏更有效的解决方法,我将 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

【讨论】:

以上是关于Swift SpriteKit 基本接触/碰撞的主要内容,如果未能解决你的问题,请参考以下文章

PhysicsBody 内的 Swift SpriteKit 接触检查

Spritekit 碰撞

SKPhysics 与 Swift 和 SpriteKit

覆盖 SpriteKit 中的碰撞

Swift SpriteKit 出现场景错误

防止具有相同 Catagorymask 的 Spritekit 节点发生碰撞