1
votes

I'm creating a game as a small project and i'm trying to make it so after ever 5 points the walls will generate more but when playing the game, it crashes at reaching around 24 points with the the error "fatal error: Array index out of range"

GameScene.swift

 if pointsLabel.number % kNumberOfPointsPerLevel == 0 {
                    currentLevel++
                    wallGenerator.stopGenerating()
                    wallGenerator.startGeneratingWallsEvery(kLevelGenerationTimes[currentLevel])
                }

Constants.swift

let kNumberOfPointsPerLevel = 5
let kLevelGenerationTimes: [NSTimeInterval] = [1.0, 0.8, 0.6, 0.4, 0.3]
3
So what is the currentLevel when it crashes?dudeman

3 Answers

3
votes

You're calling kLevelGenerationTimes[currentLevel] where currentLevel gets incremented every time pointsLabel.number % kNumberOfPointsPerLevel == 0.

kLevelGenerationTimes only has 5 elements ([1.0, 0.8, 0.6, 0.4, 0.3]) and with the rate at which you increase the level

Points: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
Level : 0 0 0 0 0 1 1 1 1 1  2  2  2  2  2  3  3  3  3  3  4  4  4  4  4  5

At 25 points, currentLevel becomes 5 which is an invalid index for your array.

2
votes

It happens because you have an array with 5 cells with index from 0 to 4.

If you try to access the array with a index outside this range the app will crash.

Example:

let kLevelGenerationTimes: [NSTimeInterval] = [1.0, 0.8, 0.6, 0.4, 0.3]

kLevelGenerationTimes[0] // ok
kLevelGenerationTimes[1] // ok
kLevelGenerationTimes[2] // ok
kLevelGenerationTimes[3] // ok
kLevelGenerationTimes[4] // ok
kLevelGenerationTimes[5] // crash!!!
1
votes

It looks like the error is here:

wallGenerator.startGeneratingWallsEvery(kLevelGenerationTimes[currentLevel])

when currentLevel is equal to or greater than the number of elements in kLevelGenerationTimes.

I don't know what the correct solution is, depending on your game logic - I would propose 2 versions, the first restarting from the first element of that array once the end is reached:

wallGenerator.startGeneratingWallsEvery(kLevelGenerationTimes[currentLevel % kLevelGenerationTimes.count])

whereas the second is to always use the last element of the array (I take that as an increasing complexity as the player progresses):

let index = currentLevel < kLevelGenerationTimes.count ? currentLevel : kLevelGenerationTimes.count - 1
wallGenerator.startGeneratingWallsEvery(kLevelGenerationTimes[index])