Advertisement
Ihmemies

Untitled

Feb 13th, 2023
17
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
GDScript 3.40 KB | Source Code | 0 0
  1. class_name ChunkHandler
  2. extends Node2D
  3.  
  4. # one tilemap is one chunk
  5. # map consists of many chunks
  6. # chunks are loaded to view when needed
  7. # chunks are deleted after they are no longer needed (in view)
  8.  
  9. # This is done to speed up game loading and avoiding setting one large tilemap in one go
  10. # which is extremely slow in godot 4.0, 4096x4096 takes minutes to fill with set_cell() commands
  11.  
  12. var chunks:Dictionary = {}
  13. var window_width = DisplayServer.window_get_size(0).x
  14. var distance = abs((window_width/(Globals.CHUNK_SIZE.x*Globals.TILE_SIZE_X)) / 2 +1 )
  15.  
  16. # for threading
  17. var chunk_queue:Array = []
  18. var mutex:Mutex
  19. var semaphore:Semaphore
  20. var thread:Thread
  21. var exit_thread = false
  22.  
  23.  
  24. func _exit_tree():
  25.     mutex.lock()
  26.     exit_thread = true
  27.     mutex.unlock()
  28.  
  29.     semaphore.post()
  30.     thread.wait_to_finish()
  31.  
  32.  
  33. func _init() -> void:
  34.     self.name = "ChunkHandler"
  35.    
  36.    
  37. func _process(_delta):
  38.     update_chunks()
  39.     clean_up_chunks()
  40.     reset_chunks() 
  41.    
  42.    
  43. func _ready():
  44.     mutex = Mutex.new()
  45.     semaphore = Semaphore.new()
  46.     exit_thread = false
  47.    
  48.     thread = Thread.new()
  49.     thread.start(start_chunkgen, Thread.PRIORITY_NORMAL)
  50.  
  51.  
  52. func start_chunkgen():
  53.     while true:    
  54.         semaphore.wait()
  55.  
  56.         mutex.lock()
  57.         var should_exit = exit_thread # Protect with Mutex.
  58.         mutex.unlock()
  59.  
  60.         if should_exit:
  61.             break
  62.        
  63.         # work on emptying the generation queue
  64.         if chunk_queue.size() > 0:
  65.             mutex.lock()
  66.             var vars = chunk_queue.pop_front()
  67.             mutex.unlock()
  68.  
  69.             load_chunk(vars[0].y, vars[0].x, vars[1])
  70.    
  71.  
  72. func clean_up_chunks():
  73.     for key in chunks:
  74.         var chunk = chunks[key]
  75.         if chunk.should_remove:
  76.             chunk.queue_free()
  77.             chunks.erase(key)
  78.  
  79.  
  80. func correction_factor(d) -> float:
  81.     if Globals.CAMERA_ZOOM_LEVEL < 0.6:
  82.         return d * 2.0 
  83.     elif Globals.CAMERA_ZOOM_LEVEL > 1.0:
  84.         return d
  85.     else:
  86.         return d * ( 1 + 2 * (1-Globals.CAMERA_ZOOM_LEVEL) )
  87.  
  88.  
  89. func get_chunk(x:int, y:int):
  90.     var key = str(y) + "," + str(x)
  91.     if self.chunks.has(key):
  92.         return chunks.get(key)
  93.        
  94.     return null
  95.  
  96.  
  97. func load_chunk(y:int, x:int, key):
  98.     var chunk = Chunk.new(y, x, false) 
  99.     call_deferred("add_child", chunk)
  100.        
  101.     mutex.lock()   
  102.     chunks[key] = chunk
  103.     mutex.unlock()
  104.  
  105.    
  106. func reset_chunks():
  107.     # avoid trying to edit already removed chunk keys
  108.     mutex.lock()
  109.     for key in chunks:
  110.         chunks[key].should_remove = true
  111.     mutex.unlock()
  112.        
  113.    
  114. func update_chunks():  
  115.     var p_x = int(Globals.CAMERA_POSITION.x- Globals.CHUNK_SIZE.x) / Globals.TILE_SIZE_X / Globals.CHUNK_SIZE.x
  116.     var p_y = int(Globals.CAMERA_POSITION.y- Globals.CHUNK_SIZE.y) / Globals.TILE_SIZE_Y / Globals.CHUNK_SIZE.y
  117.    
  118.     # When updating chunks, adjust chunk rendering distance
  119.     # based on current zoom level.
  120.     var zoom_corrected = correction_factor(distance)
  121.  
  122.     # iterate through all the chunks. if a chunk is in camera range,
  123.     # and it exists, it should not be removed
  124.     # if chunk should be in range and it doesn't exist, it will be
  125.     # created by adding the coords to a work queue
  126.     for y in Globals.map_size/Globals.CHUNK_SIZE.y:
  127.         for x in Globals.map_size/Globals.CHUNK_SIZE.x:
  128.             if (abs(x - p_x) <= zoom_corrected && abs(y - p_y) <= zoom_corrected):             
  129.                 var key = str(y) + "," + str(x)
  130.                
  131.                 if chunks.has(key):
  132.                     var chunk = get_chunk(x,y)
  133.                     if chunk != null:
  134.                         chunk.should_remove = false
  135.                 else:
  136.                     mutex.lock()
  137.                     chunk_queue.push_back([Vector2i(x, y), key])
  138.                     mutex.unlock()             
  139.                     semaphore.post()
  140.  
  141.  
  142.  
  143.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement