使用 PhysicsBodys 的基本 Swift SpriteKit 碰撞
Posted
技术标签:
【中文标题】使用 PhysicsBodys 的基本 Swift SpriteKit 碰撞【英文标题】:Basic Swift SpriteKit Collisions using PhysicsBodys 【发布时间】:2016-06-02 00:03:44 【问题描述】:问题:让我的玩家与硬币碰撞并在碰撞时为 coinLabel 添加 +1 似乎有点麻烦。玩家在接触到硬币后应该继续移动。
我现在拥有的东西:使用我现在拥有的代码,玩家穿过硬币,但没有发生碰撞,硬币标签也没有添加 +1。
我仍在学习 swift 语言,因此我很感激所提供的任何帮助。
代码:
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)
【问题讨论】:
为什么(circleOfRadius: coinOne.size.height / 10)
不应该是(circleOfRadius: coinOne.size.height / 2)
?
我以为“/”后面的数字控制着physicsBody的大小?就像你使用 /2 或 /3 一样,physicsBody 会比使用更大的数字更大。我可能是错的。
半径(这是你所追求的)是直径/2。如果硬币的高度 == 硬币的直径(可能是这样),那么这个值除以 2 可能就是你想要的尺寸。
确保您清楚自己是否需要碰撞、联系人或两者兼而有之。我怀疑你想让玩家和硬币接触而不是碰撞?
抱歉回复晚了。是的,我希望玩家和硬币接触但不要碰撞。
【参考方案1】:
你可以尝试让你的contactTestBitmasks保持不变,但删除玩家和硬币之间的collisionBitmasks:
player.physicsBody?.categoryBitMask = ColliderType.playerCategory
player.physicsBody?.contactTestBitMask = ColliderType.boundary
player.physicsBody?.collisionBitMask = ColliderType.boundary
coin.physicsBody?.categoryBitMask = ColliderType.coinCategory
coin.physicsBody?.contactTestBitMask = ColliderType.playerCategory
这样,当玩家与硬币碰撞时,它会注册,但不会“反弹”并继续朝同一方向移动。
*注意:使用这个可能需要你使用
func didBeginContact(contact: SKPhysicsContact)
方法代替
func didPlayerCollideWithCoin(player: SKSpriteNode, coin: SKSpriteNode)
但我建议先尝试使用 didPlayerCollideWithCoin() 方法。
如果你需要它,它是这样实现的:
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 == playerCategory && secondBody.categoryBitMask == coinCategory
print("Your player passes through the coin")
score = score + 1
有关更多详细信息,请参阅 Ray Wenderlich 的本教程: https://www.raywenderlich.com/123393/how-to-create-a-breakout-game-with-sprite-kit-and-swift
【讨论】:
您好 hb22,谢谢您的回答!我编辑了我的代码以匹配您在回复中所写的内容(首先使用 didPlayerCollideWithCoin 进行尝试,然后尝试使用 didBeginContact),但没有任何改变。所以我使用view.showsPhysics = true
来检查physicsBodys,我注意到玩家physicsBody 是可见的,但硬币的physicsBody 似乎没有出现,即使我用自己的physicsBody 设置了硬币节点。我认为这可能是阻止碰撞正常运行的问题。以上是关于使用 PhysicsBodys 的基本 Swift SpriteKit 碰撞的主要内容,如果未能解决你的问题,请参考以下文章