2015-07-03 55 views
4

我遇到了一个非常奇怪的错误,我无法弄清楚。在我的比赛中,你驾驶一辆2D飞机试图避开障碍物(如摇滚或汽车)。障碍可能出现在3个不同的路径上。有时在任何路径上只有一个障碍,或者有时在三条路径中的两条路径上存在两个障碍。奇怪的SpriteKit For Loop Bug

我遇到的问题是,当两个障碍物出现,然后在他们离开屏幕时被删除,当前在屏幕上移动的障碍之一也被“删除”(我知道这是因为控制台打印“已删除对象“3次)。但是,随机“删除”的障碍不会从视图中删除。相反,它冻结了之前的地方,永远不会消失。

这里是我有问题的代码块:

var canGetScore = true 
for (num,obj) in enumerate(obstaclesToMove) { 
    obj.position.y -= CGFloat(gameSpeed) 
    if obj.position.y <= userCar.position.y && obj.name == "NotPassed" { 
     obj.name = "Passed" 
     if canGetScore { 
      canGetScore = false 
      score += 1 
      scoreLabel.text = "\(score)" 
     } 
    } 
    if obj.position.y <= -CGRectGetMidY(self.frame) { 
     obj.removeFromParent() 
     obstaclesToMove.removeAtIndex(num) 
     println("deleted object") 
    } 
} 

可变密钥:

  • “obstaclesToMove”是障碍物(SKSpriteNodes)的阵列应该向下移动屏幕。

  • “gameSpeed”是屏幕每帧移动多少个像素的整数(在这种情况下值为5)。

  • “userCar”是用户控制的字符(SKSpriteNode)。

“canGetScore”是为了消除我以前遇到的另一个错误。我知道一个事实,这不会导致我目前的错误。

有没有人有任何想法,为什么发生这种情况?如果你需要更多解释,请问。

附加说明:用户的汽车在技术上从不移动,但背景和障碍物移动。

回答

1

在我看来,这个问题是你如何从obstaclesToMove

删除你的对象想象一下,你有你的数组中的三个对象:

obstaclesToMove = [object1, object2, object3] 

您必须删除对象1 & 2,因为他们必须脱离屏幕,因此,在代码中执行的操作是首先删除对象1,然后删除对象2,除非您的代码转换为:

obstaclesToMove.removeAtIndex(0) 
obstaclesToMove.removeAtIndex(1) 

你可能会认为这是没有问题的,除了外观,同时你这样做会发生什么你的数组:

obstaclesToMove = [object1, object2, object3] 
obstaclesToMove.removeAtIndex(0) 
// obstaclesToMove = [object2, object3] 
obstaclesToMove.removeAtIndex(1) 
// obstaclesToMove = [object2] 

通常它是一个坏主意,你是循环通过数组中删除对象。你可以做,使之更安全的是:

  • 收集所有的指数,你需要在数组中删除
  • 排序它们以相反的顺序
  • 从阵列中删除项目

你可以这样做:

var indexToDelete: [MyObstacleObject] = [] 
var canGetScore = true 
for (num,obj) in enumerate(obstaclesToMove) { 
    obj.position.y -= CGFloat(gameSpeed) 
    if obj.position.y <= userCar.position.y && obj.name == "NotPassed" { 
     obj.name = "Passed" 
     if canGetScore { 
      canGetScore = false 
      score += 1 
      scoreLabel.text = "\(score)" 
     } 
    } 
    if obj.position.y <= -CGRectGetMidY(self.frame) { 
     indexToDelete.append(num) 
    } 
} 

indexToDelete.sort({ $0 > $1 }) 

for item in indexToDelete { 
    obstaclesToMove[item].removeFromParent() 
    obstaclesToMove.removeAtIndex(item) 
    println("deleted object") 
} 

这样,当你从你的数组中删除项目,你可以肯定他们会st生病有正确的索引,因为你将首先删除索引较高的项目。

+1

OP还可以使用'stride(from:through:by:)'以相反的顺序遍历'obstacToMove'中的项并避免额外的数组/循环。 – 0x141E

+1

我不知道我怎么看不到。我一定会用你的答案。谢谢! – gooroo7

1

我在我的游戏中执行的操作与您的游戏非常相似,所以我想我所做的每件事都可以应用于您的情况。我所做的使用索引从障碍物阵列消除障碍,而不是是,我用addObjectremoveObjectIdenticalTo方法(self.obstaclesNSMutableArray):

[self.obstacles addObject:asteroide]; //asteroide is subclass of SKSpriteNode 
[self.obstacles addObject:enemyShip];//enemyShip is subclass of SKSpriteNode 

当我删除它们,我只是这样做:

[self.obstacles removeObjectIdenticalTo:asteroide]; 
[self.obstacles removeObjectIdenticalTo:enemyShip]; 

这对我有效......我还想指出的另一件事是如何以不同于您的方式在屏幕外移除障碍物。这是我如何做到这一点:

SKAction *sequence = [SKAction sequence:@[moveAsteroide,[SKAction runBlock:^{[asteroide removeFromParent]; [self.obstacles removeObjectIdenticalTo:asteroide]; 
       }]]]; 

    [asteroide runAction:sequence withKey:@"moving"]; 

所以我运行的第一个移动物体到期望的位置的顺序,这是一些点,这是离屏(Y = -obstacle.size.height)和在这之后,我从母体中取出,并更新障碍数组。这适用于我,因为我使用动作来移动障碍物,但如果您以相同的方式移动障碍物,它可能适用于您。我更喜欢使用更新方法不断检查障碍物的位置。

虽然这只是我的方式,而且所有这些都可以通过很多方式完成,并且您必须选择哪一个更适合您。希望这是有道理的,并有所帮助:-)