Hey all, thanks for the kind words! It helps with the motivation
@franktech currently the navigation mesh is set to be fully dynamic and so far I have no problems. Take's about half a second or less after pressing generate for the 2x2 option which is still a pretty large space, the 4x4 option is enormous and takes a few seconds longer but you can't tell since it's all done in the background, and I'll probably set it up so that when a new level is destroyed/created, there will be some sort of nice camera transition that'll give the navmesh a couple of seconds to generate before enabling the AI. Such as the camera going into an overview, then transitioning down to the player in the very first test, following a police car moving into the gameplay area, or a simple fade-to-black for example. We're still talking a few seconds max though, so the transition will be more of a game polish thing with navmesh finishing generation during the time as more of a little bonus.
I will say I did have issues with the navmesh on a different more expensive generator I did awhile ago for a different game prototype, where the game generated 200x200 individually destroyable instances with a large tile size sort of like rimworld/minecraft; but that was mostly solved for that particular example just by finding the sweet spot in the navigation generator’s project settings of how big the sizes/tightness/chunk size the navmesh would generate. Generally the larger the area, the larger you’ll want the navigation mesh’s chunk/misc settings to be. Though I doubt I’ll run into that issue with this particular game since it deals with relatively small-medium map sizes, there are other tricks you can do for larger games such as navmesh generation around Invokers, moving the navmesh volume periodically to the players position(haven’t actually tried that but it might work), or having the AI fallback to simple vector/position updates or node pathing if outside of the navmesh for an open-world game (think fallout/elderscrolls, where its a mixture of navmesh and nodes/hints, and how the AI “walks” across the whole map via their AI Schedule. I’m pretty sure they don’t actually physically walk when out of the players loaded cell area, the game probably just does simple vector math projected to a grid of the world size, and then loads the AI/spawns it at a point in the cell if the projection is detected to be within a loaded cell by the player. No idea if that’s how it does it though, just a guess.) I think at one point for that specific project I was considering using breadth-first search to find a path using nearby points instead of using the navmesh, but scaling down the size of the map for that project and increasing the navigation mesh cell/chunk sizes seemed to be good enough.
Making a new level literally just calls a function that destroys all child classes of “GenericCell”, which basically all structures are some child of in a tree, or an actor is a child component of a GenericCell child so everything is destroyed; as well as destroying all actors of class humanoid which the player and enemies are based from. Since the level generation and even player assignment all stem from functions called from an initial map generation event in the game mode, calling that event once causes everything to be rebuilt again from a new seed. Oh, and map layout/buildings/etc all use randomize from stream whenever any randomizing or shuffling occurs, the exceptions being grass instances (because why bother) and enemy AI. I’ll probably split certain functions to not be from the seed though, such as specific enemy placement so if the player dies and the map reloads from the same seed, the enemies initial positions can be a little different. I like the whole seed stream thing though, as it’ll give me the option to have a mode where players can share seeds if they wanted, test out changes to the procedural design, or specifically force the game to use a specific seed in an order of difficulty or a tutorial/intro series of levels.
I also plan on the actual progression of the game using specific parameters in the initial generation as the levels progress. So just as an example, missions 1-5 would maybe use a “low” enemy setting of 1-4 possible enemies with pistols and smgs as their weapons, levels 5-10 3-8 enemies, 11+ 10-20 etc. Or make it so the level settings tend to favor a percentage/pick an option out of a hat until it’s empty before refilling. So say out of a list of 7 options there’s 3 robbery, 1 bank heist, 2 investigate murder missions, 1 diffuse bombs, it’ll randomly select from that list and remove element until the list is empty; preventing things such as the player having a horrible random percentage chance where they roll 20 robbery levels and never even got to play a bank heist mission.
@HeadClot My procedural generation is split into a bunch of smaller functions across multiple classes, so it would be a bit hard to share as a simple screenshot. I will tell you Epic's video tutorial on procedural generation is what first got me started doing this sort of stuff awhile back which you can find here: https://www.youtube.com/watch?v=mI7eYXMJ5eI&t=660s
I also tend to rely on a specific math function which can turn an array’s element index into physical x, y coordinates, as well as do the opposite to take an x, y value and convert it back into an index. It’s a very useful math function as its insanely faster to specifically identify an index from the start, rather than finding a specific coordinate via a foreachloop with break function. You can find where I found the math I used at this link: math - Treating a 1D data structure as 2D grid - Software Engineering Stack Exchange
I’ll also mention since my cells are based on very large road pieces, it’s easy for me to fill a large space without having too many active actors/collisions/whatevahs. (I think mine currently is about 200 actors for a filled 4x4 scene?) But if you have very small tile sizes like minecraft, or anything that needs large numbers getting into the thousands, you’ll want to use instance static meshes. And if you need those instance static meshes to be dynamically built/destroyed during runtime with no lag spike, you’ll need to split those instances into chunks of 100 elements or whatever instead of having 20 thousand entries in one instance (as instances technically have to recreate everything each time an instance index of it is created or destroyed, recreating 100 in a frame is much faster than 20,000) Which is why you’ll see things like quadtrees/tile chunks/whatever in games like minecraft or spore. I mention collision, because collision can also become expensive if you have ridiculously large amounts of objects with collision turned on. I wouldn’t worry about that one though unless it becomes an issue, then you’d have to look into simplifying your collision or disabling collision on objects far away.
You can sort of see in this screenshot how the game relies on a grid, and depending on that grid will assign a specific road. In this case it made everything a road, so it filled up with X-Intersection pieces, as each roads adjacent/nearest neighbors in the grid were also marked as roads. And then the road spawns a grass and silewalk built to fit on one corner of that XRoad, and since the origin of that actor is offseted to match the center of the intersection while placed in the corner, all the road does is spawn the same class 4 times, each time rotating it by 90 degrees so all corners are filled. The straight road piece does the same, except it spawns 2 sidewalk classes built to line with the straight road, and rotates the second 180 degrees. Then the children classes of these sidewalk/zone classes will be filled with buildings or trees/whatever.
Later I might expand it so the game will include dead end roads and 90 degree corners so it’s not all just X and Straight but that’s another “addon.” Zone height varation so roads slope up or down might be nice too, but I’m probably going to just keep that in the nice-to-have pile instead of required-features pile. If I do add any Z-axis to the height it might be just on empty forest tiles, or if I decide to make a border/background LOD for the game so the view distance isn’t just cut off. I probably in that instance would make a new zone creation method based around spline meshes, where an intersection would be a flat/level cell, where as the spline end points would match up to it and raycast downwards to align with the bordering terrain height.
Additional bonus is Operation Sour lemon is just a randomized name pulled from a CSV file, inspired from X-Com’s loading screen mission names. Final polish type stuff if it was a police game in the end would be to randomize names and assign them to the suspects at the opening briefing. For some reason giving names to NPCs just seems cool to me even though its such a simple function, such as in RimWorld or your soldiers in X-Com. Perhaps the game saves the names and appearances of an arrested suspect in an array when a mission is completed, so 5 missions later you have a chance of seeing him again or have him spawned in at an inbetween mission police station? Food for thought on how I might add some flavor further to a procedural shooter I guess that would fall into making a “story generator” that pairs with the mission generator as well. E.G. game generates the Purple Tiger Gang who favor mac-10s, pistols wear purple, and only appear during drug related-missions while the Fancy Professionals carry mostly shotguns and assault rifles, suit and tie, and tend to spawn on bank heists. Complete enough missions and the gang is locked up forever/new one is created. Also would have to be tied into a sort of Law-And-Order template that tracks time and seasons, so 5 months later, game is in the winter at night, and Jimmy who you arrested 10 missions ago made bail and instead of becoming part of society, decided to rob the nearest gas station for the thrill of it all. Darn it Jimmy!
And with that, I have typed too much and should get back to focusing on basic building interiors