问题描述
好的-我确定这是重复的,并且Whirlwind或KnightOfDragons已经发布了一个解决方案,但我找不到它。
OK - I’m sure this is a duplicate and that Whirlwind or KnightOfDragons has posted a solution, but I can’t find it.
我在写使用Sprite-Kit在Swift中复制Space Invader。我的问题是,当入侵者炸弹袭击我的飞船时,代码有时会记录2或3次碰撞,从而立即结束游戏。以下是 didBeginContact中处理炸弹/船只碰撞的部分:
I’m writing a clone of Space Invader in Swift using Sprite-Kit. The problem I have is that when a invader bomb hits my ship, the code sometimes registers 2 or 3 collisions, immediately ending the game. Here’s the section of ‘didBeginContact’ that handles the bomb/ship collision:
case category.bomb.rawValue | category.ship.rawValue:
print("Bomb hit ship!")
let bomb = contact.bodyA.categoryBitMask == category.bomb.rawValue ? contact.bodyA.node : contact.bodyB.node
bomb?.physicsBody?.contactTestBitMask = 0 // Seems to prevent multiple contacts with same bomb
ship.physicsBody!.contactTestBitMask = 0 // We'll reset this after the death animation
bomb?.removeAllActions()
ship.removeAllActions()
bomb?.removeFromParent()
ships -= 1
if ships == 0 { endScene(won: false, withMessage: "A bomb got you!") }
,当我运行游戏时,我会看到:
and when I run the game I see:
Bomb hit ship!
2 ships left.
一枚炸弹命中后(这是正确的)
after 1 bomb hit (this is correct)
Bomb hit ship!
1 ships left.
Bomb hit ship!
0 ships left.
在第二枚炸弹命中后(错误)。
after a 2nd bomb hit (which is wrong).
我从未没有注册过联系人,有时(50%?)可以正常工作。有时候我看到自己有-4艘船!我确定这是明显的/根本的,但是我犯了错。
I never have the contact NOT being registered, and sometimes (50%?) it works perfectly. Other times I’ve seen myself with -4 ships! I’m sure it’s something obvious/fundamental that I’m getting wrong though.
我对将炸弹和飞船的contactTestBitMask设置为0的评论显然是错误的。我知道这不是必须的,因为我会在接触发生时移开炸弹,所以它不会再次发生。
My comments about setting the contactTestBitMask to 0 for the bomb and the ship are obviously wrong. I know this shouldn’t be necessary, as I remove the bomb when the contact occurs, so it shouldn’t occur again.
我如何保证接触是
============================== =
================================
更新:我添加了2条 print
语句以提供更多调试信息:
Update: I added 2 print
statements to provide more debugging information:
print("bodyA is \(contact.bodyA.node!.name)")
print("bodyB is \(contact.bodyB.node!.name)")
这是在 let炸弹之后= contact.bodyA.category
...语句,现在我得到:
This is after the let bomb = contact.bodyA.category
... statement and now I get:
Bomb hit ship!
bodyA is Optional("bomb")
bodyB is Optional("playerShip")
1 ships left.
在炸弹被击中后,并且:
after 1 bomb hit, and :
Bomb hit ship!
fatal error: unexpectedly found nil while unwrapping an Optional value
时意外发现零。那么在第二次碰撞之后,bodyA为零,所以我不明白为什么Sprite-Kit实际上已经记录了碰撞?
after a 2nd bomb hit. So after the second collision, bodyA is nil, so I don't see why Sprite-Kit has actually registered a collision?
任何想法?
推荐答案
确定-看起来很简单:
if bomb == nil {return}
仅需这些。应该添加以下内容:
is all that's required. This should be added as follows:
let bomb = contact.bodyA.categoryBitMask == category.bomb.rawValue ? contact.bodyA.node : contact.bodyB.node
if bomb == nil {return}
这可以防止在 didBeginContact
中 removeFromParent
的节点发生多次冲突。如果不删除节点,但仍在注册多个冲突,则使用节点的 userData
属性设置某种标志,指示该节点交替处于活动状态,将其子类化为SKSPriteNode并添加自定义 isActive属性,这是我为解决子弹从入侵者一侧掠过并取出该入侵者及其上方一个入侵者的问题所做的工作。
This works to prevent multiple collisions for a node that you removeFromParent
in didBeginContact
. If you don;t remove the node but are still registering multiple collisions, then use the node's userData
property to set some sort of flag indicating that the node i s'anactive' Alternately, subclass SKSPriteNode and add a custom 'isActive' property, which is what I did to solve my problem of bullets passing up the side of an invader and taking out that invader and the one above it. This never happens on a 'direct hit'.
它没有回答关于为什么 SK正在记录多个碰撞的根本问题,但是这确实意味着我可以删除所有有关将contactTestBitMasks设置为0,然后再返回到以后的内容的其他代码。
It doesn't answer the underlying question as to why SK is registering multiple collisions, but it does mean that I can remove all the extra code concerning setting contactTestBitMasks to 0 and then back to what they should be later etc.
编辑:所以看来,如果您删除didBeginContact中的一个节点,该节点将被删除,但物理实体不会被删除。因此,您必须要小心,因为Sprite-Kit似乎会建立一系列物理接触,然后多次调用dBC,每个接触一次。因此,如果要处理节点并以dBC形式删除它们,请注意,如果强行解开节点的属性,可能会遇到问题。
So it appears that if you delete a node in didBeginContact, the node is removed but the physics body isn't. So you have to be careful as Sprite-Kit appears to build an array of physicsContacts that have occurred and then calls dBC multiple times, once for each contact. So if you are manipulating nodes and also removing them in dBC, be aware that you might run into an issue if you force unwrap a node's properties.
这篇关于Sprite-Kit为单个接触记录了多个碰撞的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!