Does anyone know how to create a vector field in Blueprint? I am looking at better ways to procedurally generate a hex map. I think generating a vector field prior to actually generating the map could let me set more boundaries and have more control over the final product.
Here are some images of my current highly random generation:
I see there is an Add VectorFieldComponent function in blueprint but it has a drop-down for a Vector Field asset so it seems like it is more for imported assets…
Looking into things, Arrays seem like the way to go but I am still working to understand how they work. Putting info into them seems straightforward enough, but intelligently drawing that info back out is a little harder to understand for me.
Yes I do believe vector fields are only for use inside of particles at the moment. That’s not to say you couldn’t create a blueprint that makes its own vector field using generic data. One of the tech artists on Fortnite made a blueprint that lets you author vector fields inside of the editor and use them In blueprints. It lets you create splines within the field and the splines ‘stroke’ the vectors into form depending on proximity. It is likely not ready for prime time though so I wouldn’t expect to see it soon.
It just depends on what you want to use it for. I am not 100% sure I can visualize your usage case. Generating random vectors in 3d space should be simple enough though. You just need to create a 3d array. It will actually be a 1d array and you need to do some math to convert from 3d to 1d each time you use the index. I would make a macro if there isn’t one already. I made a macro to convert from 2d index to 1d although it may not be exposed. Making it 3d should not be hard. Let me see if that macro is available to you guys.
Regarding putting stuff into arrays, you can make an array of any type. You can even make an array of specific other blueprint classes then pull out any information about that class, including all the variables etc. if the array is another BP you may need to come off the “get” node using a “cast to” with the right class selected.
Usually though for simple data arrays like int, float or vector you simply do “get” and supply the index.
Also, I have been doing some work on hexmap art for Fortnite. We randomize our hexmap too although we don’t get crazy advanced for the random generation part. We did get the hexes to tile and seamlessly blend though so feel free to ask me any questions.
Yeah not really what I had in mind, thanks. If I could alter it to work on mesh actors and/or volumes that would be awesome though!
That sounds pretty interesting, especially since I may need some splines for rivers and other stuff at some point. Not sure how to work splines in UE4, though it is on my list of stuff to learn about.
Right now my generator places each tile sequentially up the Y, shifts over in the X by ~1.5 hex, and repeats to the end of the map. Then it repeats it except it offsets(roughly diagonally) the next set so they mesh with the first set. So essentially it stripes my hexes together in 2 sets.
What I would like to do is seed information out into the field and then grow the terrain from that seeded information. Right now my generator doesn’t know how to reference the space it is generating into in order to place things more organically(or geologically as it were). It has been terrifically easy to generate a random 2D map, but getting it to generate more intelligently has been the hard part.
And yeah, the math for this setup makes me wish I had given a **** about math back in high school.
Also, I am generating 2D hexmaps, so the array setup should be pretty simple right? I am still learning arrays so I am trying to figure out the process of retrieving information intelligently from the array. I also don’t know much about how macros work so I will have to do some research there as well.
So if I am trying to simulate a field, then I should already have a good idea of the index for each vector on my map right? For instance, say a square tiled map is 10x10, then X1 is Index 1-10, X2 is 11-20, etc? Then I could just references the indexes based on what I already know and self-reference the rest of the generation against the seeds?
Of course, the math for a hex map is quite a bit more complicated than a plain square map…
Yes, you just need to to make a function to converts from an X and Y value to a 1D array value. As you said it is easier for square grids, but the solution for hexes is not too different and it sounds like you have it figured out already with the half offset thing. This type of thins is what “Pure Functions” are made for. They are functions that have no flow execution nodes, just variable inputs so you can execute a few math functions and get the result.
You may need to occasionally be able to identify neighbors using the 2D too which is why it can be useful to look up values by X and Y. So to find one of the neighbors in the next row you could just subtract 1X the number of hexes in a row. You will either have to add or subtract one to find both of the diagonal neighbors etc. Neighbors in the same row will just be the same index + or -1.
Yeah now that I am getting into the hard math, pure functions sound like a pretty good idea.
I modified my vector generator to better fit an array and each vector is fed into it as it is created. The array should look like this:
So now I am trying to wrap my brain around the math of jumping around this grid.
M = Map Size (10 in the above case)
Latitude(Lat) Range = 0 to M
Longitude(Long) Range= 0 to 2M
Index = (Long*M) + Lat
Move Up/Down = +/- Lat
Move Left/Right = +/- M
If I wanted to move from 0 to 72 it would be (+7M) + (+2). From 13 to 91 would be (+8M) + (-2). On each move I would essentially be adding or subtracting 2 separate numbers from my baseline index.
On the hex grid, moving left is equivalent to alternating upper-left and lower-left hex movements. 0 being the baseline, 10 is upper-left offset from 0, and 20 is lower-left offset from 10. For the purposes of the math I shouldn’t have to factor this offset in other than to erase any repeated patterns that show up in the generation.
Somehow I need to factor in going from Index 9 to 10 where adding 1 Lat changes the long. Anyone have a good method for handling this?
classic example would be saving a tree graph(yours would be node with 6 neighbors) and just manually link boarder wrapping, if the map is always fixed in size then just do the boundry check then set to min/max. tree graph has the advantage of getting route with lowest cost, let you change tile material, etc later on.
I will have to research tree graphs, thanks. The map will vary based on the map size that players choose so I am trying to weave my map size variable into everything. So right now I am testing with 10, but it could go 20, 40, 80, etc.
Dynamically changing the tile material is one thing I was thinking about. Right now I procedurally place static meshes that already have their material set. I was thinking of placing blank tiles and then making a second pass to add material and other information. The procedural generation of instanced tiles seems to create 1 single actor though so I will have to see how that works out…
So are you talking about using tree graphs on each tile in the map or just the boundary tiles? If I could link each tile to it’s neighbors, I could use it for quite a few mechanics besides wrapping such as unit movement, city ownership, etc.
Do you have any Blueprint examples of how this would be handled?
So using the array posted above, as well as a biome map generator I found, I have been able to make significant progress with my generation:
One problem I have right now is that while I can get any Random X or Random Y, I don’t have a good method of doing a range check on all the indexes in a row. For example, my Southern Tropical latitude has indexes that all end in 4. Hard to do an InRange check on that.
Anyone know of a function or piece of math that could do such a check?
Edit: Actually, I just remembered I can still do a range check as the vector gets applied to the transform on the Add Instance. Additionally, I worked out a way to use a ForLoopWithBreak to run through each index in a row if I really really need to. Probably not though, as the number of loops could hit a few hundred or thousand PER tile(x 12-20K tiles) to be generated. I will probably just flesh out that piece and sock it away in a function for another day.