Reputation:
I am encountering a very strange bug that I just can't figure out. In my game, you are driving a car on a 2D plane trying to avoid obstacles (like a rock or car). The obstacles can appear on 3 different paths. Sometimes there is just one obstacle on any of the paths or sometimes there is two obstacles on two of the three paths.
The problem I am experiencing is that when two obstacles appear and then get deleted when they go off the screen, one of the obstacles currently moving on the screen is also "deleted" (I know this because the console prints "deleted object" 3 times). But, the obstacle that is randomly "deleted" is not removed from view. Instead, it freezes where it previously was and never goes away.
Here is the code block I am having problems with:
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")
}
}
Variable Key:
"obstaclesToMove" is an array of obstacles(SKSpriteNodes) that should be moved down the screen.
"gameSpeed" is an integer of how many pixels the screen moves every frame (the value is 5 in this instance).
"userCar" is the character that the user controls (SKSpriteNode).
The "canGetScore" thing is to eliminate another bug I was experiencing before. I know for a fact this is not causing the current bug I am having.
Does anyone have any ideas to why this is happening? If you need any more explanation just ask.
EXTRA NOTE: The user's car technically never moves, but the background and the obstacles move.
Upvotes: 4
Views: 106
Reputation: 13665
I had the same thing to implement in my game which is very similar to yours, so I guess that everything I've done can be applied to your situation. What I did instead of using indexes to remove obstacles from array of obstacles is that I've used addObject and removeObjectIdenticalTo methods(self.obstacles
is NSMutableArray
):
[self.obstacles addObject:asteroide]; //asteroide is subclass of SKSpriteNode
[self.obstacles addObject:enemyShip];//enemyShip is subclass of SKSpriteNode
And when I removing them, I just do something like:
[self.obstacles removeObjectIdenticalTo:asteroide];
[self.obstacles removeObjectIdenticalTo:enemyShip];
This worked for me... One more thing I would like to point is how you can remove obstacles when offscreen in a different way than yours. This is how I do that:
SKAction *sequence = [SKAction sequence:@[moveAsteroide,[SKAction runBlock:^{[asteroide removeFromParent]; [self.obstacles removeObjectIdenticalTo:asteroide];
}]]];
[asteroide runAction:sequence withKey:@"moving"];
So I run the sequence which first move object to desired location, and that is some point which is offscreen (y = -obstacle.size.height
) and after that, I remove it from parent and update obstacles array. This works for me because I use actions to move obstacles, but maybe it can work for you if you are moving obstacles in same way. I like this more than constantly checking the location of obstacle in update method.
This is just my way though, and all this can be done in many ways, and you have to choose which one suits you better. Hope this make sense and helps a bit :-)
Upvotes: 1
Reputation: 2810
It seems to me that the problem is in how you remove your object from obstaclesToMove
Imagine you have three objects in your array:
obstaclesToMove = [object1, object2, object3]
You have to remove object 1 & 2 because they have to go off screen, so what you do in your code is first remove object 1 then object 2, except in your code it translates to :
obstaclesToMove.removeAtIndex(0)
obstaclesToMove.removeAtIndex(1)
You would think this isn't a problem, except look what happens to your array while you do that:
obstaclesToMove = [object1, object2, object3]
obstaclesToMove.removeAtIndex(0)
// obstaclesToMove = [object2, object3]
obstaclesToMove.removeAtIndex(1)
// obstaclesToMove = [object2]
Usually it is a bad idea to remove object from an array that you are looping through. What you could do to make it safer is:
You could do it like that:
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")
}
That way when you delete items from your array you can be sure that they will still have the right index since you will be first deleting items with a higher index.
Upvotes: 0