Okay so I managed to use threads to go through the while loops several rows in parallel. For example, here's what my _ready()
and initializeMap()
methods changed into:
_ready():
#make a bunch of threads for parrallel processing
for i in range(numParallelThreads):
parallelThreads.append(Thread.new())
#make a map where every cell has the same chance to spawn alive
func initializeMap():
var map = []
var x = 0
while(x < mapSize):
#assign each parallel thread to process a row
var active = 0
while(active < numParallelThreads and x < mapSize):
map.append([])
parallelThreads[active].start(self, "initializeRow", x)
active += 1
x += 1
#wait for each thread to finish (note that this isn't the main thread, so waiting this long is okay)
var i = active-1
while(active > 0):
insertRowFromThread(map, parallelThreads[i].wait_to_finish())
i -= 1
active -= 1
return map
func initializeRow(x):
var row = []
var y = 0
while(y < mapSize):
row.append(randf()<initialChance)
y += 1
return [x,row]
func insertRowFromThread(map, data):
#map[x] = row
map[data[0]] = data[1]
Basically, how it works is instead of making one row at a time (like a double for loop would do), I instead made an array of threads (20 seemed to work the best, any more and performance starts to drop) and assigned a row to each thread, then waited for each one to return it's value. This way I can process 20 rows at a time.
The result was a huge speed improvement, although it's still nowhere near instant, but I figured out a way to hide it. (By generating the next map while you play, and loading the first map from a save file, which was generated when you last played) Here are some benchmarks I made (which are in milliseconds, so for example: 1k = 1000 milliseconds):
#size = 1000
#steps = 5
#1:67k
#2:48k
#10:39k
#20:38k
#100:39k
#size = 1000
#steps = 0
#1:0.7k
#2:0.6k
#10:0.6k
#20:0.6k
#100:0.6k
#size = 1000
#steps = 1
#1:14k
#2:10k
#10:8k
#20:8k
#100:8k
#size = 1000
#steps = 10
#1:133k
#2:97k
#10:80k
#20:78k
#100:80k small FPS drops
#size = 3000
#threads = 20
#5:342k
#3:215k
#2:142k
#1:72k
#0:3k
#69k per step
Also note that these benchmarks get the time from when the game launches to when the map generated. (so before the tilemap begins loading the images... this part doesn't appear to work in a thread, so I'm planning to call set_cell
on nearby tiles as the player walks by)