SpriteKit中精灵之间的碰撞
Posted
技术标签:
【中文标题】SpriteKit中精灵之间的碰撞【英文标题】:Collisions between sprites in SpriteKit 【发布时间】:2015-09-07 22:56:13 【问题描述】:我正在使用 SpriteKit 在 XCode 中制作游戏。游戏中有一个玩家和他必须避免的不同类型的射弹。当玩家与弹丸发生碰撞时,分数会发生变化,弹丸会消失。然而,当两个射弹相撞时,它们会弹开。 我想让每次两个射弹相撞时,它们就像什么都没发生一样,并且继续沿着原来的路径前进。我该怎么办?
*注意:这不是全部代码,它只是最重要的。
import SpriteKit
struct Physics
static let player : UInt32 = 1
static let missileOne : UInt32 = 2
static let missileTwo : UInt32 = 3
class GameScene: SKScene, SKPhysicsContactDelegate
var player = SKSpriteNode(imageNamed: "p1.png")
override func didMoveToView(view: SKView)
physicsWorld.contactDelegate = self
player.position = CGPointMake(self.size.width/2, self.size.height/5)
player.physicsBody = SKPhysicsBody(rectangleOfSize: player.size)
player.physicsBody?.affectedByGravity = false
player.physicsBody?.dynamic = false
player.physicsBody?.categoryBitMask = Physics.player
player.physicsBody?.collisionBitMask = Physics.missileOne
player.physicsBody?.collisionBitMask = Physics.missileTwo
var missileOneTimer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("SpawnMissileOne"), userInfo: nil, repeats: true)
var missileTwoTimer = NSTimer.scheduledTimerWithTimeInterval(1.2, target: self, selector: Selector("SpawnMissileTwo"), userInfo: nil, repeats: true)
self.addChild(player)
//When contact happens
func didBeginContact(contact: SKPhysicsContact)
var firstBody : SKPhysicsBody = contact.bodyA
var secondBody : SKPhysicsBody = contact.bodyB
if ((firstBody.categoryBitMask == Physics.player) && (secondBody.categoryBitMask == Physics.missileOne))
CollisionWithMissileOne(firstBody.node as SKSpriteNode, missileOne: secondBody.node as SKSpriteNode)
else if ((firstBody.categoryBitMask == Physics.player) && (secondBody.categoryBitMask == Physics.missileTwo))
CollisionWithMissileTwo(firstBody.node as SKSpriteNode, missileTwo: secondBody.node as SKSpriteNode)
else if ((firstBody.categoryBitMask == Physics.missileOne)&&(secondBody.categoryBitMask == Physics.missileTwo))
CollisionBetweenMissiles(firstBody.node as SKSpriteNode, missileTwo: secondBody.node as SKSpriteNode)
//For Player and MissileOne
func CollisionWithMissileOne(player: SKSpriteNode, missileOne: SKSpriteNode)
missileOne.removeFromParent()
//For Player and MissileTwo
func CollisionWithMissileOne(player: SKSpriteNode, missileTwo: SKSpriteNode)
missileTwo.removeFromParent()
//For MissileOne and MissileTwo
func CollisionBetweenMissiles(missileOne: SKSpriteNode, missileTwo: SKSpriteNode)
???WHAT SHOULD I CODE HERE???
【问题讨论】:
【参考方案1】:令人困惑的是collisionBitMask
用于定义在physicsModel 中交互的physicsBodies。你真正想要的是contactTestBitmask
。
您的物理也没有返回用于位掩码的正确值。作为纯整数,它们应该是 1,2,4,8 等。
这是您的代码已更改为(希望)有效的代码,我已对所做的更改进行了注释。
struct Physics
static let player : UInt32 = 1
static let missileOne : UInt32 = 2
static let missileTwo : UInt32 = 4 // to work properly as bit masks
如果您想检查与多个类型的physicsBody.categoryBitMask 的接触,则此更改是必要的。查看 didMoveToView 中的player.physicsBody?.contactTestBitMask = ...
:
override func didMoveToView(view: SKView)
physicsWorld.contactDelegate = self
// All your existing player-stuff is fine until...
// contactTest, not collision but contact, also: use bitwise OR
player.physicsBody?.contactTestBitMask = Physics.missileOne | Physics.missileTwo
self.addChild(player)
// It is not recommended to use NSTimer for SpriteKit, use SKActions instead
let missileOneWait = SKAction.waitForDuration(1)
let callSpawnOneAction = SKAction.runBlock( self.spawnMissileOne() )
let missileOneRepeat = SKAction.repeatActionForever(SKAction.sequence([missileOneWait, callSpawnOneAction]))
runAction(missileOneRepeat)
let missileTwoWait = SKAction.waitForDuration(1.2)
let callSpawnTwoAction = SKAction.runBlock( self.spawnMissileTwo() )
let missileTwoRepeat = SKAction.repeatActionForever(SKAction.sequence([missileTwoWait, callSpawnTwoAction]))
runAction(missileTwoRepeat)
将 didBeginContact 重写为我认为阅读和 缩放 更好的东西:
func didBeginContact(contact: SKPhysicsContact)
var firstBody = contact.bodyA
var secondBody = contact.bodyB
// Rewritten with dynamic variables
var playerNode : SKSpriteNode?
if firstBody.categoryBitMask == Physics.player
return firstBody.node as? SKSpriteNode
else if secondBody.categoryBitMask == Physics.player
return secondBody.node as? SKSpriteNode
return nil
// If you want to handle contact between missiles you need to split this
// into two different variables
var missileNode : SKSpriteNode?
let bitmask1 = firstBody.categoryBitMask
let bitmask2 = secondBody.categoryBitMask
if bitmask1 == Physics.missileOne || bitmask1 == Physics.missileTwo
return firstBody.node as? SKSpriteNode
else if bitmask2 == Physics.missileOne || bitmask2 == Physics.missileTwo
return secondBody.node as? SKSpriteNode
return nil
if playerNode != nil
collisionBetweenPlayer(playerNode, missile: missileNode)
那么你只需要一个函数来实现导弹和玩家之间的联系:
func collisionBetweenPlayer(player: SKSpriteNode?, missile: SKSpriteNode?)
missile?.removeFromParent()
【讨论】:
感谢您的回答,但它改变了一切!您(或其他人)能否向我解释一下如何使两枚导弹相互通过而不发生碰撞? 它并没有真正改变一切,你仍然可以保持你的 didBeginContact 功能,例如。如果您不想使用我的建议,那很好,但您仍然需要使用contactBitMask 而不是collisionBitMask。对于您的问题,这很简单:missileSprite.physicsBody.collisionBitMask = 0
因此,您需要从我的答案中删除的唯一内容是使用contact
而不是collisionBitMasks
来检查(您所指的)碰撞。此外,BitMask 需要具有适当的 BitMask 值 (1,2,4,8) 等,以便与 BitWise OR 正常工作...
我遵循了每一条指令,但这并不能防止两枚导弹相互碰撞并“弹跳”。很抱歉耽搁了,但感谢有关联系人的提示
它们应该有不同的 categoryBitmask,但它们的碰撞位掩码都应该为 0。您需要理清类别、接触和碰撞位掩码之间的区别...以上是关于SpriteKit中精灵之间的碰撞的主要内容,如果未能解决你的问题,请参考以下文章