Skip to content

Instantly share code, notes, and snippets.

@rburing
Created May 4, 2020 17:20
Show Gist options
  • Save rburing/6ec80f44da7319ff8b9524dc486761b1 to your computer and use it in GitHub Desktop.
Save rburing/6ec80f44da7319ff8b9524dc486761b1 to your computer and use it in GitHub Desktop.
# WorldChunkLoader
# Dynamically load and unload chunks on a 3D grid.
#
# Direct children should be scenes with Load As Placeholder checked.
# Direct children should be aligned on a grid.
# (To align in 3d scene editor: Transform -> Configure Snap -> Translate Snap.)
# Player should have a WorldChunkGPS component, which sends a signal to here.
#
# Algorithm: load current chunk and all neighbors around it; unload the rest.
extends Spatial
const CHUNK_SIZE = 100
const CHUNK_EXTENT = CHUNK_SIZE/2
var chunks = {}
class Chunk:
var name: String
var transform: Transform
var path: String
var loaded: bool
var scene = null
func _init(new_name, new_transform, new_path, new_loaded = false):
name = new_name
transform = new_transform
path = new_path
loaded = new_loaded
func _ready():
SceneLoader.connect("on_scene_loaded", self, "_scene_loaded")
_init_chunks()
func _init_chunks():
for placeholder in get_children(): # TODO: generalize?
if not placeholder is InstancePlaceholder:
continue
var child_transform = Transform()
var stored_values = placeholder.get_stored_values()
if 'transform' in stored_values:
child_transform = stored_values['transform']
# TODO: check grid alignment here and/or in separate tool script
var int_pos = Vector3(floor(child_transform.origin.x/CHUNK_SIZE), floor(child_transform.origin.y/CHUNK_SIZE),floor(child_transform.origin.z/CHUNK_SIZE))
chunks[int_pos] = Chunk.new(placeholder.name, child_transform, placeholder.get_instance_path())
remove_child(placeholder)
placeholder.queue_free()
func _player_moved_to(int_pos):
if OS.is_debug_build(): print('Player moved to ', int_pos)
var neighbors = []
for y in [0,-1,1]: # y = 0 first, probably most stuff is at the same vertical level
for x in [0,-1,1]:
for z in [0,-1,1]:
neighbors.push_back(int_pos + Vector3(x,y,z))
for neighbor in neighbors:
if neighbor in chunks and not chunks[neighbor].loaded:
if OS.is_debug_build(): print('Start loading ', chunks[neighbor].name, ' at ', neighbor)
SceneLoader.load_scene(chunks[neighbor].path, { position = neighbor })
for position in chunks:
if not position in neighbors and chunks[position].loaded:
if OS.is_debug_build(): print('Unloading instance ', chunks[position].scene, ' of ', chunks[position].name, ' from ', position)
remove_child(chunks[position].scene)
chunks[position].scene.queue_free()
chunks[position].loaded = false
func _scene_loaded(scene):
var position = scene.props.position
chunks[position].scene = scene.instance
chunks[position].scene.transform = chunks[position].transform
add_child(chunks[position].scene)
chunks[position].loaded = true
if OS.is_debug_build(): print('Loaded instance ', chunks[position].scene, ' of ', chunks[position].name, ' at ', position)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment