I want to build a platformer game with the following asset: Platformer Kit · Kenney
How can I build my worlds with all of these assets quickly and effectively that will go a long way, to a point where future me will spend the least amount of time creating platformer worlds?
Google Gemini says I should use a MeshLibrary, but I am not sure how to set it up, and I feel like it will take a lot of time with the sheer amount of assets this pack provides 
No source I found helped me find the right answer
Godot Version: 4.7
Maybe have a look here (3D Platformer Starter kit…) from the Godot Assets Library..? It will give you a head start, surely..?
Hope this helps.
Yeah, I agree with Gemini. Use a mesh library. It’s not that hard.
I would use a GridMap, but if you take a look at the assets, there are uneven sizes, so I can’t just determine one cell size to the entire map. The video you attached shows if every model has the same size, but mine uses unique ones for every mesh, so they can’t fit like a puzzle
The demo doesn’t really help with what I am looking for right now, but can definitely help me later. Thank you for finding this!
Use snapping vertex by pressing “B” . Make parent node of individual meshes and then make scene out of parents nodes .
Easiest if you have uneven sizes.
I didn’t look at the models. There’s an addon called object placer if you build a big floor or several layers of floors, the objects will place pretty easy. Then you could just delete the floor. Might be worth a try. The whole thing is with jumpers the spacing is pretty critical. You want it to be just far enough so you can make it but not so close it’s too easy.
I don’t like how I need to get centimeter perfer spacing, I prefer to not worry about small things and instead go into an uninterupted flow state
Why group meshes into one parent node? This could get quite bulky in file manager. Should I throw assets directly into the world scene?
Scenes and file hierarchy are two things.
I mean use empty node as parent of meshes if you be reusing them and save as scene, those can be parented to another empty node etc.
If you be using only individual meshes then I still parenting them by logic as static, dynamic, to keep it organised .
This way you can use manual placement with vertex snap but keep it logical , and if you need refer some in code it be easier to do so .
GridMaps and MeshLibraries are really nice things in theory. In practice, you either have to have a separate one of each for every different-sized object, or just not use them. I recommend not using them, and just sorting various items by putting them under Node3Ds with names. Then if you end up with complex scenes you want to duplicate, group them, make a scene by dragging the top node into FileSystem and keep using it.
Here is what I will do:
I vibecoded this tool
@tool
extends EditorScript
const SOURCE_DIR = "res://Levels/Assets/Models/Mesh/"
const TARGET_DIR = "res://Levels/Assets/Models/"
func _run():
var dir = DirAccess.open(SOURCE_DIR)
if dir:
dir.list_dir_begin()
var file_name = dir.get_next()
while file_name != "":
# Match both .glb and files that Godot might have appended .import to during directory reads
if not dir.current_is_dir() and file_name.ends_with(".glb"):
convert_glb_mesh_to_static_body(file_name)
file_name = dir.get_next()
print("Custom batch conversion complete!")
else:
print("An error occurred when trying to access the path: ", SOURCE_DIR)
func convert_glb_mesh_to_static_body(file_name: String):
var glb_path = SOURCE_DIR + file_name
var tscn_path = TARGET_DIR + file_name.replace(".glb", ".tscn")
# 1. Load the GLB file (Loaded as an ArrayMesh based on your import settings)
var loaded_resource = load(glb_path)
if not loaded_resource:
print("Failed to load: ", file_name)
return
var mesh_data: Mesh = null
# Handle case where it's an ArrayMesh or a PackedScene
if loaded_resource is Mesh:
mesh_data = loaded_resource
elif loaded_resource is PackedScene:
var instance = loaded_resource.instantiate()
var found_mesh_inst = find_mesh_instance(instance)
if found_mesh_inst:
mesh_data = found_mesh_inst.mesh
instance.queue_free()
if not mesh_data:
print("Skipping (No mesh data could be extracted): ", file_name)
return
# 2. Build our clean StaticBody3D scene structure
var root_static_body = StaticBody3D.new()
root_static_body.name = file_name.replace(".glb", "")
var mesh_child = MeshInstance3D.new()
mesh_child.name = "Mesh"
mesh_child.mesh = mesh_data # Assign our mesh data
root_static_body.add_child(mesh_child)
# 3. Generate the Collision Shape from the mesh data
var collision_child = CollisionShape3D.new()
collision_child.name = "Collision"
# Generates a precise trimesh shape.
# Swap to 'mesh_data.create_convex_shape(true, true)' if you want optimized shapes!
var collision_shape = mesh_data.create_trimesh_shape()
collision_child.shape = collision_shape
root_static_body.add_child(collision_child)
# 4. Set correct owners for serialization
mesh_child.owner = root_static_body
collision_child.owner = root_static_body
# 5. Pack and Save
var packed_scene = PackedScene.new()
var result = packed_scene.pack(root_static_body)
if result == OK:
ResourceSaver.save(packed_scene, tscn_path)
print("Successfully generated: ", tscn_path)
else:
print("Failed to pack scene for: ", file_name)
# Clean up node from memory
root_static_body.queue_free()
# Fallback helper just in case some files are imported as scenes
func find_mesh_instance(node: Node) -> MeshInstance3D:
if node is MeshInstance3D:
return node
for child in node.get_children():
var found = find_mesh_instance(child)
if found:
return found
return null
That will pull all the .glb files (imported as a single mesh) and will create scenes out of them, and generate collisions for them, so that I can just drag and drop into my world very easily. I’ve already spent way too much time on figuring out mesh libraries, I will just simply do it like that, and face the consequence of having an amplitude of nodes in my scene. Maybe not the best practice, but I recommend @dragonforge-dev and @artemisia comment(s) right above for people who want best practices.