I’m working on migrating my Bomberman-like game to 4.12 and in doing so, I’m re-factoring everything again. I’ve decided to re-create my grid generator using an entirely different approach to make generation and performance a lot better - but in doing so, I’ve run into some obstacles.
Currently, every grid is an ISM instead of previously being a separate actor. This made things considerably faster, but in return made it more convoluted as well. I’m now using line traces since they very conveniently provide me with the Hit Item integer which works wonderfully for ISM’s.
However, it’s not so wonderful when removing instances as the array for all the instances seem to get shuffled randomly in doing so*(despite it saying the order is maintained)*. Currently it’s setup like this;
Very simple, I do a trace in every direction - if it collides, I check if the Hit Actor is BP_GridGenerator, if true, I check if the Hit Component is ISM_Boxes - if true, I get the Hit Item integer and store it in an array. I then loop through this array of integers to remove those instances.
This is where I’m currently stuck at. The first instance is always removed successfully, the others however are very, very unreliable. Sometimes they are, sometime they are not. Seeing as how the tooltip says the array “may shrink”, I tried a simple solution of subtracting the integer by 1 after the first index - but it’s hard to tell if it actually did any difference as it’s still very, very unreliable.
Anyone out there that has a clue as to what’s going on and if there’s a way to fix it?
As far as I’m aware the Remove Item node can not be used on Instanced Static Mesh components. To remove an instance, I need to provide the index at which the instance is located. The tooltip for Remove Instance say that the order is maintained - but the array may shrink in size. But it does in fact seem it also reshuffles it…? Or maybe I’ve simply been awake for too long and am overlooking things
Actually I can run this node through instanced static mesh components. Still it wouldn’t matter much, because I found out that it doesn’t clean the array entirely, which is odd.
However, I used my approach above and changed it slightly. As far as I know you also want to get rid of the content (the instances itself being hit), right?
Then you should just use a “ForEachLoop” node, plug your instanced static mesh components array into the Array slot of the ForEachLoop node. The “Array Element” pin should be dragged out and then search for “Destroy component”. Atleast I got rid of all the instances I spawned in runtime and as far as the print command told me, I was back to 0 entries after running my “DeleteInstances” function.
I guess I didn’t properly describe what my problem was, these brown boxes on the image all belong to 1 ISM component.
Let’s take the image above for example;
I left-click and my bomb BP fire off traces in each direction. It collides with a mesh in all 4 directions, those with Grid ID 164, 146, 124 and 143.
I store these 4 integers in an array.
I loop through this array, and supply Remove Instance with the integer.
What happens here is when I remove for example the instance at index 164, the instance at index 146 will no longer be the same. It sometimes move down to 145, keyword; sometimes.
Sometimes it works, sometimes it does not. And I can’t seem to figure out why that is.
As far as I know we can’t really access the ISM’s array itself via blueprints, I only use Remove Instance. It works the way I want it, I just can’t seem to figure out why sometimes it will shrink the array like the tooltip says and sometimes not.
I have the feeling that everytime you do something to the blueprint actor/call something within it, the actor is being updated. And as far as I know, the ISMs/grids are components of your BP_GridGenerator. That means if you remove an entry or even add an existing one, the array will update itself and start from scratch and give the components a new order/new index.
I don’t know, if this would change anything, but what will happen, if you create an array inside your BP_GridGenerator and add every instance/component being run through it? You will get an array populated by the right instances, but it won’t dynamicly change the order, if you update your actor in any way.
Ah, thanks for the clarification! Will check this out later today and return with results
Edit:
I decided to go with the easier method of comparing their transforms. Since I break the loop once a match is found - the performance is pretty nice, though I haven’t tried it with super large grids yet. I captured a quick little video to showcase the results;
Some more testing, then I need to re-create all the interfaces I made for 4.11.2 and hook everything up for multiplayer. Hopefully we can do some multiplayer testing in a few days :rolleyes:
Yes, removing an instance index from the component effectively makes every instance with a higher index than the one removed to go down one position.
If you have your instances indexed (which i really recommend you to) with a class or struct that holds their data (component index, instance index, transform, etc), you should decrease every instance index that has a higher instance index than the one removed to keep your data on par.
Explanation:
The Int Array stores the indexes we wish to remove. Since removing a lower number will make the instances go down one position, we remove them from highest to lowest.
We store the values that Max Of Int Array returns so we don’t have to run that function over and over (well, twice, instead of thrice).
After removing the returned Max Value, we set the *Item *of the Index that the Max Value had to -1 so that it will not be chosen again as the max value.
Also I suggest clearing the Int Array after it’s all completed.
I thought it would be worth mentioning that the Hierarchical Instanced Static Mesh Component uses RemoveAtSwap() where the regular Instanced Static Mesh Component uses RemoveAt() so you’ll have to handle it differently for that. This actually worked much better for me because I wanted to have a setup where only a limited number of instances were allowed and the oldest ones are removed as newer ones are added (like a limited size queue). RemoveAtSwap is much easier to handle in this case because I can just start a RemoveIndex at 0 and iterate it every time I remove an instance to have RemoveIndex point to the oldest instance. If OldestInstanceIndex >= MaxInstances then I reset it to 0 (where we swapped an instance in a while ago). With the regular Instanced Mesh Component I’d have to keep track of all the active indices and decrement every one greater than the one I was removing to account for the shrinking.
It’s a rare edge case and I didn’t need the Hierarchical Comp features otherwise but it saved me in this case and might be useful to know for someone else. Also I hope future engine versions could have more transparent ways of handling instance removal because the current system makes it really difficult to use if you’re trying to remove instances continually.
UseDynamicInstanceBuffer didn’t help in my case, so I solved this differently. Whenever I need to destroy instance with index X, I find the object that uses the mesh instance with the highest index and make that object use instance X instead. I move instance X to the location that the last instance is at and destroy the last instance. This avoids changing all indices above X.
I’ll add a quick tip regarding that - a dirty workaround, but it does the job in most cases, where we don’t want the indices to shift after removing an instance:
Instead of removing the instance, use the UpdateInstanceTransform and set the scale to 0.
Not ideal, it still probably needs to process the instance for all the culling/LOD queries, etc. but at least it practically ‘removes’ it without shifting indices
You can also add an extra ‘FreeIndices’ int array and add any ‘removed’ index to it. Then, when you add new instances, you can check for free indices and use the UpdateInstanceTransform with desired instance transform, using the free index, instead of adding it normally. This way the pseudo-removed instances will be replaced by new instances.
I think I used a similar approach in the end, but instead of scaling it to 0 - I moved it to some world space coordinates far away from the playable area. I think even if you set the scale to 0, collision will remain - albeit very small, but enough to potentially block a player.
Haven’t used instanced static meshes in a while, but is this still the case? I noticed the dynamic buffer option has been removed, maybe it’s enabled by default now?
Sure, moving it far outside of visible area would be a 100% safe approach.
Hm, I never checked the dynamic buffer option so I’m not sure if that worked/works. I don’t know, maybe these workarounds are not needed anymore, but I’d need to test that. I’ve ‘invented’ the scaling-to-0 workaround in like 4.14 or lower, so maybe it’s not needed in new versions.
Dealman, I didn’t read all this, so maybe you’ve already sussed it. But the easy way to bin items from an array is just loop over it backwards. Then you can throw aways items without having to worry…
The original topic was from 2016. Fairly sure enough as changed where this wouldn’t be an issue in the first place.
It sure enough is not for my foliage addon.
The gist of it all is that a hit result returns the ID of the component instance, which can be used to remove or pull relative data for it.
have yet to test this since i’m developing other aspects and have had no need for it yet, but I believe this would work flawlessly now even with the procedural foliage volumes.