So, I’m trying to generate blocks and chunks like Minecraft, but after finishing my initial blueprint logic for a chunk, the editor has already started to slow down. I fear I’m definitely not handling it in a best-practice sort of way
- A “Chunk” blueprint contains 16 Child Actor Component variables, each of class “Block Layer”
- A “Block Layer” blueprint contains 16 Child Actor Component variables, each of class “Block Row”
- A “Block Row” blueprint contains 16 Child Actor Component variables, each of class “Block”
- The “Block” blueprint is just a Cube attached to the scene root, and some switch logic in the constructor that assigns a material based on the block type (like grass, air, dirt, etc).
So ultimately my “Chunk” Blueprint has 4096 individual Child Actor Components of class “Block”, and already any changes to my Chunk blueprint take my computer like 3-4 seconds to think about, 15 seconds to compile, and like 30 seconds to spawn into my level.
So before I go any further, I just wanted to check and see if I happen to be doing this the most inefficient way possible, lol. Would best practice be wildly different than this?
- Chunk Blueprint
- Layer Blueprint
- Row Blueprint
- Block Blueprint:
Having made something involving a lot of cubes, but not like MC, I’d say, maybe focus in the area of materials and collision and instancing.
I can’t give you the exact details without looking them up, but
- All blocks that are supposed to be the same thing should have the same material. Maybe even just one actual material that’s held somewhere central and assigned from there.
The simpler you can make the collision, the better. If the blocks only have to look out for one kind of actor, things will go faster than if you have all kinds of overlaps set ( default for BP ).
Maybe the blueprints don’t actually need to contain cubes, but can add an instance to an already existing HISM when they spawn. Something like that.
Of course, the ultimate answer is write it in C++, as I’m sure someone will drop by and point out…
That many child actors is gonna be a beast to chew through, esp if you are welding your collision. Even with c++ this will run SLOW…
Look into using a HeirarchicalInstancedStaticMeshComponent, and add and remove instances there… refactor your code to create a manager that programatically adds the static meshes to the HISM. If you need to interact with an instance, there are functions in the HISM that allow you to find a specific instance. Remove that instance, and replace only that instance with an actor that you need the interactivity for… or if you can just use the custom data variables.
Alternatively, look into the free voxel plugin on the marketplace… it has a way to set up cubic mode to emulate minecraft type worlds.
So, I’m just going to collect whatever comes to mind right away while looking through the blueprints in no particular order, you’ll have to pick and choose which way to go:
Consider using arrays and HISM instead of multiple nested actors/variables; remember to reserve the required memory before entering the loop that will add the array elements. (“Reserve” in C++, “Resize” should effectively do the same thing in BPs)
Exposing the block type when spawning the actors will mean you only have to loop once.
Exposing the Z-layer variable will allow you to skip the casting. Even better: You can calculate the Z-layer based on position when needed, which means you don’t necessarily need this variable. (Same goes for X and Y)
Small “nitpick”: You can multiply a vector with an int by right clicking the second vector pin and converting it to integer.
p.s. Using a single array & a single HISM to hold all your data and meshes for each chunk will involve maths, but will make the data much more accessible to the CPU.
I ended going with your HISM suggestion. My Chunk blueprint now contains one HISM component for every block type that I’ll have. So, if I’ll have Grass, Dirt, & Stone, then I’d make a “Grass_HISM”, “Dirt_HISM”, & “Stone_HISM” component so that I can set the appropriate material to each.
Then when I create a new block, I add an instance to the appropriate HISM and set its location.