How can I precisely synchronise events in very small time increments regardless of framerate?

Hey, I’m new to unreal and blueprints, and I thought getting a proper understanding of delta time would be a good starting point to start fiddling and getting familiar with all the tools and interfaces. I had no trouble adjusting movements and animations to different framerates and time dilations, but spawning moving objects is giving me trouble.

I thought about the classic bullet hells, where the position and timing of dozens of bullets on the screen is incredibly important. Much like fighting games though, many classic shmups function on a per-frame basis to maintain the integrity of the game elements, so the action slows down when the game can’t maintain a steady framerate. I thought recreating a shmup scenario without the slowdown would be an interesting learning experience, and so I began a new project.

I started with a very simple setup with the hopes of escalating things from there. I made an actor that will adjust its Z coordinates according to a value in a linear timeline, and it will destroy itself when the timeline ends; I used this as a projectile. I then made two actors: one that spawned a projectile every N seconds, and one that spawned a projectile in half as much time. I knew using the tick event and checking to see how much time had passed would bring trouble with framerate and time dilation down the line, so I tried using a “delay” function instead, but it didn’t work: the spawners got off-sync pretty much immediately. Then I had the idea to use timelines to manage the timing of the shots and it worked, but not too well.

With lower frequencies, the spawners worked perfectly in sync. But as the frequncy of the shots got higher and the framerates lower, clumping began to happen:

1

Notice how the discs on the left aren’t evenly spaced, but appear to come in pairs, instead. It might not seem like too much, but it’s definitely noticeable, and I can replicate worse results.

I got these results by having a 0.1 second timeline in each spawner, and having one event node in the right one, at the 0 second mark, and having two event nodes in the left one; one at the 0 second mark, and another at the 0.05 second mark. I chose these numbers because 30 fps gives an average delta time of 0.033 seconds and 15 fps gives and average delta time of 0.066 seconds, so I thought if framerate was to be an issue, this would be an easy way to check. The results in the image above were captured at 30 fps.

I thought it might have something to do with the two event nodes having exactly 0.05 seconds between them, when the time between the second node and the first node of the next loop could waver because of the engine. So I tried changing the timeline of the second actor: now it had a single event node, but the timeline was half the length. And ta-dah! The clumping was gone. But now the two actors got immediately off-sync, as it happened when I was using delays:

2

Again, this was captured at 30 fps. If you can’t see the problem, look at the top left disc and see how it’s pretty much at level with the right disc. Then, on the left, check every other disc, and see how the one on the right goes a little bit up every time.

I can’t tell if these problems stem from some float-number fuckery, or because the tools I’m using are susceptible to engine delays and I should be using something else. Does anyone have any suggestions, or resources I could look up to try and combat this? Thank you very much in advance.
For this problem in particular I could try to combat this by offsetting the spawners depending on delta time, but I can see this sync problem becoming a long term issue on other very different kind of areas, so I’d like to learn a more robust way of managing these kind of events from the get-go.

1 Like

I’m guessing the deviations from the patters you are expecting may be due to unreal having to spawn and des-pawn many actors at the same time. Perhaps an object pooling system would help in this case.

It would cut down on memory fragmentation. The update of the objects would probably be best to do in c++ as it will probably involve a loop over all objects which is slower in BP.

It’s definable doable. Returnal was made in Unreal and that’s pretty much a bullet hell on the ground.

1 Like

yea if you’re spawning new things at an incredible rate like that you’re going to be tanking your fps from the spawns as well, so you’ll really want to mitigate that through reusable pooling, combining components, or other methods

also, if you’re needing to fire at rates that are faster than per frame, you’ll need to be able to handle that, calculating how many to fire per frame, and where to start them at, based on tick time.

much of the reason for old school things being frame locked is because that’s how the hardware worked. The screen is going to redraw every 16ms or whatever, and if you don’t have the data you need there, when it’s time to update, you’re displaying garbage or crashing. In some cases, that may have also been their equivalent to “Tick” - the hardware signals drawing is complete, releases control to the software, and you’ve got til the next tick to have everything in order.

1 Like