Getting an asset pipeline together

Getting brush texturing and meshes working has taken a bit of figuring out, as I'm relying on an external BSP-style editor (TrenchBroom 2025.4) for levels so everything needs to be compatible with that workflow and not just the Godot editor.

Materials are all modifications of samples from material maker which seemed like a cool FOSS alternative to substance, so I'm using this chance to learn it a bit even though asset creation isn't my forte. I'm also using Blockbench for meshes (the doors in the video below) since I want to be able to throw simple meshes together very quickly. I do not consider myself much of an artist, so I really just need to be able to get across the basic idea of whatever prop I need.

Part of this work ended up being coming up with a solution for generating collision for imported meshes. Unlike Unreal, Godot does not pack collision information together with mesh assets and instead expects you to create a separate collision shape node for meshes. This is nice as it means mesh nodes don't need collision logic, but makes it more difficult when you're trying to auto-generate the hierarchy of nodes required for a prop. Generating collision is easy within godot itself - it's a couple of clicks to auto-generate various forms of collision - but that only results in the current scene getting that collision. Nothing ties it to the mesh asset on disk which is what I actually need because that's what I specify in TrenchBroom. Additionally, it isn't particularly memory efficient to have tons of copies of the same collision shape scattered around if you have a lot of copies of the same mesh. It also isn't great because it doesn't update automatically if you modify the mesh.

Yes, you can define collision meshes within a gltf (or other) file via the -col or -colonly suffix so that you can define your collision geometry within your choice of DCC tool, but the problem is this only works in Godot when you import that mesh as an entire scene as opposed to just a mesh. I could work around that, but you need to decide at import-time what kind of physics the mesh will have - whether it's a RigidBody3D or a StaticBody3D or something else, and separate objects within the scene can't be joined into a single physics object.

The solution I came up with is to auto-generate mesh collision on map import if necessary, but to also support auto-discovering and loading a separate collision scene that defines the collision shape node. The auto-generated collision is always a simple box to keep the cost down (though I may add a way to choose what type of collision to generate in the future), while the collision scene can contain any shape.

This door only needs a simple box, so it's using the auto-generated collision.
Right now the creation of the collision scenes is manual, but I plan to eventually automate this process with either an editor tool or a custom importer.

I've also rewritten the animation system used for enemy sprites - it's now driven by animation players + state machines, and setup in a way such that I only need to make a single animation timeline to handle all directional variations of an animation. This is done by having the animation player drive the frame number of the animated sprite, but the animation inside the sprite frames resource is driven programmatically given a "base" animation name + a suffix based on the angle that the sprite is being viewed from (front/back/left/right for now, though I'd like to add some in-between directions eventually).

The animation timeline for a melee attack sets a base animation name and goes through each frame as appropriate, with function calls to trigger events.
But the sprite frames resource actually contains 4+ animations per base animation name, to cover every direction the sprite and camera could be facing. These get swapped out automatically by a script.

Moving to AnimationPlayer lets me trigger events, VFX, audio, and animate other nodes if necessary so getting this done now will help in the long run. It also lets me move to AnimationTree to setup a state machine for triggering animations.

Basic state machine for this enemy. melee is triggered by code, hence why there is no transition leading to it. I do miss Unreal's montage system for one-shot animations like this, but I haven't seen a built-in system for montages in Godot yet and this is good enough for the simple sprite animations I need. At least I get a state machine for use with sprite animations at all, unlike with Paper2D!

And here's a quick showcase of the various materials, physics props (doors), and enemy sprites working.

Show Comments