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