Map Generator- Please Critique!

Heya Mons,
Trying to squint to see your Blueprint, but are you creating an Instanced Static Mesh Component for each tile?

And to , do your grassland tiles inherit from your parent tile? If so you should be able to get any tile actor (really any actor, since just about everything inherits from it), then attempt to “Cast To” a tile type (grassland). The casts are like if/then statements, if you succeed then cool, if not, then you can execute a cast to another tile type.

I just skimmed the thread, but it looks like there’s so much awesome in here I’m going to go back up and read it all =) Just wanted to chime in right quick.

Ahh I think I see what youre getting at, I should be adding instances to the singular component for batching not 1 instance per component. Only trouble I see there is I cant access the instances at all after they are created, its mainly the relative location im wanting to change. I think I might have to change to Tile Actors so i can get at the material instance and transforn, I think I can see why was doing things a certain way if we are limited to batching meshes without transforms :cool:

When you spawn/allocate them add add incrementing integer index. Ie. global variable in level BP and each hex blueprint reads it, stores locally and then increments.
Then you do: “get all actors of type” and “for each” then compare index

PS.
did you guys/gals found how to spawn blueprints as cells in such map?
instanced meshes are easy, but i am stuck on spawning same blueprint with random seed in each hex cell.
Without that in construction bp whole idea of procedurally generated map is moot.

Mons, I went through the Math Hall content and was impressed by some of the material setups where your variable changes and it goes from grass to stone with various transitions depending on what is needed. It seemed pretty brilliant and I think I could put it to good use with my tiles. However, I still need to be able to swap between a flat mesh, a hill mesh, and a mountain mesh at a minimum. Maybe multiply that times the number of different forest types I have.

Not sure how it would affect performance when thousands of tiles are using it though.

That is the idea, but I am still trying to figure out how to implement it. Right now my tiles are basic instanced meshes and I want to change over to blueprint tiles.

I think Nawrot and I are on the same step. Trying to figure out how put class functions inside the instanced static meshes. Can you instance a blueprint, or is there a way to transfer functions into instanced components? Or have a blueprint spawn, but it’s mesh representation be instanced?

I believe we talked about this before though, and you advised the use of instanced meshes only for visuals with volume actors carrying all the information. For that to work in my setup I just need to be able to change any given mesh, such as a plains mesh to a mountain mesh. Either a Set Mesh, or Destroy Actor and replace with the updated mesh.

I already add them to an array. I just haven’t tested yet how I can interact with an individual tile using that index. I think I am going to try some simple “Get Index, Set Mesh” or “Get Index, Destroy Actor” functions to test how I can interact with them.

So I pulled a random Index from my Actor Array, and it looks like the way I am filling the array means that every actor with the same mesh in the array counts as the same actor. So if I pull an index and set it’s mesh to be a blank tile, all tiles that shared the same mesh as that index become blank.

IE, all water becomes blank and not just the Actor at the Index.

It won’t let me Destroy Actor either, since InstancedStaticMeshComponent is not compatible with ObjectActor.

This could turn out to be a pain… :stuck_out_tongue:

Replaced my “Nearest” actor used in the Biome Locator with a “Nearest Seed” Byte for use in an Enum. Then I updated my Biome Placer to use the Enum and to spawn My tile classes instead of instanced meshes.

I can now destroy the tiles and replace them as needed. However, the performance with tile actors is not as great as with the instances.

Is there any way to keep the class information and unique actor numbers but instance the actual meshes?

Updated post 2 with a zoomed out view of my Climate Flow Enum Abomination:

Precipitation = Arid, Semi-Arid, Moderate, and Wet

Vegetation ranges from Desert to Jungle, Ice to Boreal Forest, and everything in between. There are ~10 basic vegetation types.

Right now it is just high level thinking, but I will implement it when I have solidified a few other systems.

Heya ,
An instance of the mesh in an Instanced Static Mesh Component can’t be directly accessed. And, while I haven’t looked at the code, I have a feeling the way performance is really saved is that it just adds all the meshes together and removes the reference (probably uses some sort of video card batching feature).

For the work I was doing I stored things in 2 ways:

  1. During tile generation I just store everything in a number of arrays. Various ID’s define the tile type, facing, etc… just a simple int array. And then there’s the final grid array being the A* cost of the grid, which is updated during runtime as units move around or abilities that affect movement of the play area are used.

  2. Since Instanced Static Mesh Components seem to strip out collision, I have a set of collision tiles. My collision tiles, wall or floor, hold all of the tile’s currently relevant information (3x3 neighbors, A* cost, tile type, material, trap data, parent room or corridor, etc…), and can be referenced by the unit currently standing on and can be clicked using the “Get Hit Result Under Cursor by Channel” node. There’s also an array of them that matches the A* grid for future use.

So the cost of non-rendering Box Component collision blueprint actors seems to be minimal, but I haven’t tried it with non-rendering static meshes (I’ll look into it tonight). Combined with the instanced static meshes for each tile mesh/material combo, keeps things running at a good clip. Tested on a 512x512 grid with no issues.

So getting to the “destroy/create” bit you were talking about… I’ve thought about this from the stand point of having a map editor. The best I could come up with, with the restriction of Blueprints, was to:

  1. Separate the play grid and the rendering grid.
  2. Have a function that would re-create rendering grid based on changes in the play grid

There’s a Clear function for the Instanced Static Mesh Component, and then I could re-generate a map based on changes to the generation arrays, but I have no idea how fast it would be. The hitch could be terrible…

Just checked, generating a large number of hidden static mesh actors (1449) with collision meshes that were generated using the Auto Convex feature in the static mesh editor, does not affect performance in an appreciable way

So my thoughts are to have a play grid that includes your collision actors that store all your needed tile meta data, then use that data to generate your renderable grid.

Since you’re already generating all these tiles, you could just store them as an array, and as you change them, you can run a function that would read in all the tile type data, clear your instanced static meshes, and then re-create them… Or do a swap maybe? Have 2 sets of instanced static meshes, then update one and once it is complete, swap their rendering states, clear the unused ones?

, you have been an immense help! :slight_smile:

So you generally just pull the Int and dump it into an Enum? That almost seems too simple! :stuck_out_tongue:

What is the A* cost? Action Cost? A* Grid is your name for your vector map?

Nice, it seems like you have done much of what I need to do for my tiles. I think your methods make perfect sense!

Do you put any separation between your collision tiles and the render tile, or right on top of each other?

That is good to hear. Is a Box Component just what you are calling your collition blueprint actor, or is it an actual actor type? I don’t see anything by that name in the custom classes.

That might not be too bad, since the majority of actual map/tile changes would happen after the player has ended their turn. If I am just referencing an Array to pull all the tile types that need to be generated the player might not even notice anything between the turns, except for perhaps the very large maps. The AI will likely take up most of that turn rollover time.

There may be a few cases, such as nukes, where instant tile regeneration may be required, but perhaps I can do some kind of second layer for vegetation, tile improvements, and other things a disaster might take out. Those features are more likely to be added and destroyed repeatedly throughout the game anyway. Terraforming the core tile types(Water, Plains, Hills, Mountains, etc) into new types should happen far less often.

So I could have 1 Array with 20,000+ indexes and then 1 Enum with each static mesh of that layer to be generated? It could be several dozen items on the Enum if I account for the number of coastal combinations 1 hex can have.

I hear bytes/Enums can be more efficient than Ints/Int Switches. Would you recommend using bytes for something this large?

It sounds like a swap could be a good way to reduce flickering and other artifacts when regenerating the map. Are there any other benefits?

Hey Zuestiak,

Yea, basically, since I don’t have a plan to change the map during play, then it was easy to just do Int’s, though looking back on what’s in there, I wish I’d used Enums because I’m not sure what some ID’s specifically do (like which one is north…). At the same time, all that data ends up cleared once the A* Pathfinder has the array of walkable tiles.

Speaking of A*:

A Star (A*) is a path finding method. I didn’t like how nav mesh wasn’t precise when I wanted things on grid and facing specific directions. So I implemented A* in Blueprints. Also my plan is to move away from Characters and just use Pawns with my own movement logic, if for no other reason to see if I can do it.

Everything is 100x100 units, so they all fit right on top of each other. That should work just fine with a hex grid as well. The nice thing is that due to the collision being removed from the Instanced Static Mesh Components, you don’t even have to worry about hitting them with traces, it just goes straight to the collision actor.

Box Components (BoxComponent) are like Static Mesh Components, you can add them to your Blueprint through the Components Mode in the Blueprint editor, or by using the Add Box Component node in the Blueprint. But for hexes, you’ll need to use either custom collision out of your art tool, or use Auto Convex Collision Tool in the Static Mesh editor (double click one of your hexes in the Content Browser).

Yea, this would be pretty awesome. You could use cheap LOD’d/distanced culled meshes/decals to add flavor to tiles =)

I’m not sure the upper limit on the index of an array, I just generated a 300x300 map and I was getting 89999 array sizes. The nice thing about a hex grid is it’s just a square grid with an offset, so the math for doing an X,Y look up is the same. Yea, neighbor look ups are more of a hassle, but they’re not terrible.

I have no direct experience, but from what I gather, an Enum can save resources/be more performant. I find the biggest return from them is being able to remember what things are.

Well potentially, the swap could occur on another actor and it could happen in parallel to other things being processed. The biggest draw back is the memory usage of the 2 maps, sure you can clear the one that isn’t in use, but you’ll still need to have them both exist at the same time.

I’m sure there’s a way to balance performance and processing speed of generating new terrain. Maybe do a cell structure, where the super array holds all the map data, but you have smaller actors that contain the tile Instanced Static Mesh Components and while they add to draw calls, you’re not left generating the entire map every time something happens. Then you can LOD everything for big zoom outs.

This is something that has been tickling the back of my brain for some time now. How to handle waypoint/AI navigation on the hex grid. So it sounds like the Nav mesh doesn’t quite fit with grid based movement. Did you modify the Nav mesh to make this happen or did you create something from scratch?

Could you use the Nav Mesh and then have the units snap to grid at the end of the operation?

First objective would be to get a good waypoint system so a player can move units across the map and have them take logical paths to get there. I guess counting the cost of movement between A and B and choosing the best route. I already do this in my map gen in a way, so maybe it wouldn’t be that difficult.

Second Objective would be to make the whole movement system in a way that the AI could easily use as it moves potentially hundreds or thousands of units between player turns.

Ah, I think I tried the Auto Convex when I was making the collision for my meshes but when I clicked it seemed like my collision box disappeared. Now I see the convex decomposition, but how does it work? If it is setting a collision box it isn’t showing up on my mesh in a visible way. Maybe too close to the mesh?

What values for Max Hulls and Max Hull Verts would I use to cover a hexagon? I am assuming that even though my Z is almost 0 it still needs verts to cover that dimension? Would that be 12 verts?

Yeah I am definitely going to have my research cut out for me when I am figuring out the proper/best way to mesh all these layers together. :slight_smile:

What do you mean by “occur on another actor”? Do you have an actor holding your map generator? This is something I am working on right now since my map generator isn’t in the level and it is currently impeding my blueprint communication.

So instead of 1 Desert Mesh instancing the entire map, I could have say 20 Desert meshes that are each responsible for a sector of the map?

Great work guys this conversation is extremely useful for anyone creating tiled based games even if they are using boxes :slight_smile:

I finally managed to hit the iteration limit with an 800x800 field of hex columns but it didnt render the entire lot, more like 800x100 and even with the improvements to the instancing (thanks :)) I still managed to kill the framerate without any unique materials. I did however find it useful to use a seed for the random height so that when I was compiling it wasnt continually generating a new seed each time especially with larger fields. I was saving out an array of location vectors similar to where ended up and I agree that a number of arrays to kind of mirror an array of structures works so hopefully we can shed some light on improvements there when blueprint structures are alittle more to the foreground in the editor.

https://dl.dropboxusercontent.com/s/xl50kbbdxr2m0zq/HitIterationLimit.jpg

Im trying to get the climate programmatically so I’ll share some of my maths when I get there, I havent had as much time yet as Id like as I had to jump to my personal project as well as helping out on Project Divine. Ive tested modulus math so Im confident that works as expected, I’ll have to write myself a list of things I want to try and help with because I am getting a tad sidetracked with this since its kind of fun just to mess around with :slight_smile: Im not convinced that using instances is the best method for moving pillars so for my uses it will diverge so I think I’ll just leave that for now and continue to try and help you guys out :cool:

So I tried just using navmesh in the beginning, but it solves on the mesh, so it’ll cut corners and look sloppy on a grid. I was ok with it at first, but given that navmesh was in process at the time, it didn’t solve around other characters (it may do better now, haven’t checked).

So then I implemented A* to get points on the grid to move to using the navmesh and then I’d just update where the guy was moving as he got close enough. But I kind of wanted precise movement all the time, so I went ahead and just started manually moving the characters.

I can see about posting up my pathfinder stuff, but it’s really based on what I’ve been doing so there’s a ton of assumptions about offsets.

If the tile doesn’t have any depth or is not a closed surface, the Auto Convex Collision tool will probably fail. I’d advise importing a new hex specifically for collision, don’t over write your render hex, just create a new slightly extruded one.

How are you creating your map generator? Level Blueprint?

I recently moved the creation of everything to my Game Mode (btw, everything has access to the game mode, you should totally use a game mode), so in my level there is one actor, basically a bucket that just holds values for the map generator. At the start of the game, the Game Mode creates the 2 actors needed for the map generation: my random quadtree generator and the actor that will house all the renderable tiles (and that also does all the leg work for creating the tiles). Once the map is made, the Game Mode creates the pathfinder using the array of walkable tiles from the tile generator. Finally, the Game Mode makes the unit manager because it now has an array of tiles for legal spawn points. The unit manager spawns your team, then your camera actor, then a random number of other teams based on map size and individual room size.

There’s a ton of custom events, functions, and variables being passed around. So the Game Mode stores references to all the major actors for later communication (the tile generator may not know about the pathfinder, but the game mode knows both and can request from one to pass to the other).

So where my mind was at in what I mentioned is that each map (or cell) would actually be 2 actors, one hidden, one rendering, and they’d both reference each other. The Game Mode or some other uber blueprint would create them and reference them. When a major change occured on the map, you could send a custom event + the new hex array to the hidden map/cell. This event would cause it to build the new instanced static meshes, then make itself visible, and then call a function/event on its sister map. This function/event would hide that actor, and clear its instanced static mesh actors.

Then there’s some bits in figuring out which one to send to but really it could be as simple as “which one is hidden.”

Potentially, this could occur in parallel with other stuff going on, and it will just finish up and pop in.

Right, but it’s about balance. Maybe you don’t need to do that, it could be the regeneration of the map is actually really quick because all you’re doing is clearing the static mesh actors then re-adding instances, and no crazy memory stuff happens (don’t really know). The worst case for that would be Cells*Total Tile Types in draw calls. But you’d have to balance that against units, tile flare, how many cells can be visible, vfx, tiles having more than one material, lights, etc…

Nice! =) What was the generation time on that?

It actually only takes about 30 milliseconds with the seeding I think, I cant be sure because the logging for the time it takes only seems to run under certain conditions but thats how long compiling the blueprint takes so I think thats about right. Updates in the viewport are much quicker if only the length or the width are adjusted so Im pretty pleased with that for now :slight_smile: I think its the polycounts thats have an affect on the framerate, I was quite generous with the counts on the pillars so I might try something alittle lower :cool:

Cool. Maybe I will play around with nav mesh to see how it handles, but manual movement sounds fairly straightforward for a grid map too. Can’t wait to start working on units! :slight_smile:

Sounds good!

Currently using a Class Blueprint for the generator, but game mode it is! Funny, I was thinking the same thing about the bucket, though I was going to put the whole generator in it.

So your generator is in the game mode, and all the variables that it references are in a hidden actor sitting somewhere in the world? So the one of the first thing my map generator will do is spawn the actor in the world that holds all the variables my generator is about to use? This actually seems pretty brilliant since it can then spawn a different actor that holds different variable values based on what options the player chooses in game setup. So maybe in that case it could be multiple actors. An actor for each player chosen map option; Temperature, Precipitation, Geologic Age, etc.

Of course I could just use a single actor and update the variables as well. I will play around with it and see which one works out the best.

That makes sense.

Have placeholder arrays to hold all the updated information and then have them transfer their information to the main gameplay arrays at the end of the operation?

Yeah, I will definitely try your base idea out first, scale it up to some huge map sizes, and see how it handles. If it bogs down or there are other performance/graphical problems I can see about parsing up the load.

Great stuff here. There is still hope for procedurally generated maps.

Whoa hold on! Sorry, just read what I put. What I meant was that the Game Mode spawns the Blueprints that do the creation, so you’d spawn your generator using the Game Mode. By doing this, you have a location that has access to your grid spawner, and thus, it has access to anything it contains.

My GameMode looks like this:


After all that occurs the game is actually running. But I have access to everything if I ever need it again, say the array of grid collision from the GridData actor, or the Room zones from the Quadtree generator.

Also, since it’s setup like this, I can setup the HUD to change the info on the WorldData (or directly pass the world data to the GameMode), and then a “launch button” of some sort that fires all of this rather than “begin play.”

Does this make more sense?

In short: no. The Instanced Static Mesh Component can’t store individual instances.

Someone with more rendering knowledge would have to chime in here, but from what I understand, it’s actually the video card just copying the mesh around while rendering. So you lose collision, and the meshes will all have the same material, but they will all be one draw call.

There is a “per instance random” material function that can be used to make the individual instances look different, but that’s about it.

Or you can do like I am doing my stuff: level blueprint, knows every object spawned in level, so in level BP at begin play, i initialize pointer (Reference variables) to all things i want to communicate with.

I usually store all those vars inside my player controller, because it is who you are in game. When player swaps pawn or changes level, or starts different game mode variables stored in pawn or level would be lost. Yes its question which one blueprint you want to stick with. But player controller can be also accessible to HUD, so no need to duplicate variables for hud to display.

From those references i do “Cast actor to” nodes and then do my game logic.

Btw. there should be either global variables and events container, or something like bp interfaces that works for any blueprint of a class. I know its all due to optimization.
I could make for Each actor of class loop in level and trigger custom event (then put it in macro) and here is event for all of them.
Hourencees in Solus videos talks about this, they are coding global functions and variables in C++, because cast to is slow.

We could use/make some template with tutorial about how to code global vars/functions and events in C++. Its probably very easy, just takes time to research how to do that.
This will be my first thing to do in C++ (if its not done by that time).