在使用Sprite Kit以及Sprite Kit的内置物理引擎中的接触检测的iOS游戏中,每当他与敌人接触时,我将Hero的数量减少一个。这是通过didBeginContact
方法完成的。
然而,似乎这种方法不仅仅是在接触开始时调用一次,而是在Hero和敌人重叠时连续调用:当我在该方法中设置断点时,我可以看到,它是完全相同的存在为contact.bodyA
和contact.bodyB
的物理实体实例。结果是,英雄将失去多重生命,即使他只通过一个敌人。
如果Hero稍后再遇到同一个敌人,他应该减去一个实际的生命,因此我不能只保留一个seenEnemies
散列集来处理上面的问题。
现在的问题是:你如何确保每个英雄/敌人联系人只减去一个生命?
答案 0 :(得分:16)
我遇到了同样的问题(单个敌人被摧毁的分数增加了多倍,单个伤害实例丢失了多个生命点。)Apple论坛上的用户认为它是a bug in [SKPhysicsBody bodyWithTexture:size:]但我不知道我相信是这样的,因为它也与其他建设者一起发生。
首先,显然categoryBitMask
和contactTestBitMask
非常重要。看一下Apple的SpriteKit Physics Collisions sample code:
//联系人通常是双重调度问题;您想要的效果取决于联系人中两个主体的类型。通过检查每种类型,以蛮力的方式对此进行采样。更复杂的示例可能使用对象上的方法来执行类型检查。
// 联系人可以按任意顺序出现,因此通常您需要检查 每一个对抗另一个。在此示例中,类别类型排序很好,因此 如果它们出现故障,代码会交换这两个实体。 这允许代码 只测试一次碰撞。
我要解决的是在处理每个条件后设置一个标志。就我而言,我在bodyA.node.parent
测试didBeginContact
是否为零,因为我在导弹/敌方节点上调用removeFromParent()
来销毁它们。
我认为您应该期望事件多次触发,并且您的代码必须确保它只处理一次。
答案 1 :(得分:16)
多次触发didBeginContact的原因是因为凹形上有多个接触点。
如果你看下面的图片,你会看到我有2个精灵,一个黑色的星星和一个红色的矩形。当黑色星星击中红色矩形时,它会在多个点上击中它,并以蓝色圈出。然后,Sprite Kit将为每个行交集调用,以便开发人员可以为每个联系人使用contactPoint
变量。
答案 2 :(得分:6)
我想出了简单的解决方案:
在检测到联系后立即将正文的categoryBitMask值更改为0或未使用的值。
例如:
if (firstBody.categoryBitMask == padCategory && secondBody.categoryBitMask == colorBallCategory) {
secondBody.categoryBitMask = 0;
// DO OTHER THING HERE
}
答案 3 :(得分:5)
我遇到了同样的问题。在我的情况下,一个子弹与敌人的一次接触,多次召唤didBeginContact()
(我数到5次)。由于子弹是一种简单的圆形格式,我同意@SFX它不能仅仅是纹理体中的一个错误。测试显示update()
次来电之间没有didBeginContact()
来电。所以解决方案很简单(Swift):
var updatesCalled = 0
...
internal update() {
updatesCalled ++
}
...
internal func didBeginContact(contact: SKPhysicsContact) {
NSLog("didBeginContact: (\(contact.contactPoint.x), \(contact.contactPoint.y)), \(updatesCalled)")
if(updatesCalled == 0) {return} // No real change since last call
updatesCalled = 0
... your code here ...
}
我尝试了didEndContact()
,但根本没有调用。我没有进一步调查此事。
答案 4 :(得分:1)
这是一个让玩家在被击中一段时间后无法攻击的选项:
一个。创建一个变量,使玩家在被击中几秒钟后无懈可击,失去生命。
如果isInvuln为false,请将生命设置为isInvuln为真。
if(self.isInvuln == FALSE){
self.player.lives-=1;
self.isInvuln = True;}
添加到您的updateWithCurrentTime:
if(self.isInvuln==True){
self.invulnTime += timeSinceLast;}
if (self.invulnTime > 3) {
self.isInvuln = FALSE:}
self.invulnTime= 0;
这将使得当敌人和玩家发生碰撞时,玩家失去生命并且在3秒内变得无懈可击。在3秒后,玩家可以再次受到伤害。如果敌人在3个无敌时间内与玩家联系,则联系方法不执行任何操作。希望这有助于激发想法来解决您的问题。
答案 5 :(得分:0)
根据我的经验,didEndContact& didBeginContact在对象重叠时被多次调用。这也发生在使用iOS 9的SceneKit中,因此我必须假设它是一种预期的行为。