Messages with set_time_step and factor > 1

I need to scale up my time in the game.
Like a “x2 game speed” switcher:

Screenshot 2021-06-28 at 19.08.39

The problem:
If I use set_time_step with factor > 1, then I get updates with dt > 1/60.
My game logic uses messages (msg.post()) and there is a problem when I have factor > 1.

Example:
I have a gun. It shoots 60 times per second.
When factor == 1, every frame gun script sends message:
msg.post("#bullets", “createBullet”)

When I set factor = 4, then gun script on every frame will generate 4 messages in update per frame.
But only once per frame entire messages stack executes.

It causes a problem, that in case with factor == 4, gun will shoot 4 bullets at the same time (and at the same position too).

Solutions?

  1. First idea: on factor > 1 and mode == 3 (create a new one) do updates and messages more than once per frame.

  2. Second idea: create engine-function like msg.executeEntireStack()

How about having a separate collection proxy where time_step is always 1, and use that collection to fire bullets?

The problem, that I need to do in this order:

  1. frame start
  2. update
  3. messages
  4. update
  5. messages
  6. update
  7. messages
  8. frame end
    (factor == 3 in this example)

Is the factor arbitrary (e.g. 1.2x, 2.7x), or is it locked at integers? (1x, 2x, 3x)
What’s the max factor?

Do you need to use 60fps? Can you set it to the max fps instead, and then use factors <= 1 in game?

  1. In my case - only integers.
  2. Max factor - something about 360. So i need to run 1 hour of gameplay logic in 10 seconds of realtime. (I think that I have enough performance reserve for that)
  3. I don’t need to draw my game in fps more than 60. I just need that game logic works with faster speed. Like rewind.
1 Like

Do you have to generate four messages? What about one message with a bullet count instead?

Or send four messages and then one “end of frame” message. You cache the messages on the receiving end and process them when you receive the end message.

This way you can space out the bullets.

2 Likes

I think you’ll need to explicitly handle this in your own code. Send time values for things and calculate them as if they were happening at different times during a frame. For example you could send one message (or one function call) that means: “fire 20 bullets over the last 0.3 seconds.”

Something like this:

function fireOverTime(duration, bulletCount, bulletVelocity, startPos)
	local timeIncrement = duration / bulletCount
	for i=1,bulletCount do
		local time = i * timeIncrement
		local pos = startPos + bulletVelocity * time
		spawnBullet(pos, bulletVelocity)
	end
end

Of course if the bullets are being fired from a moving gun, you’ll also have to take that into account, and anything else that changes over time. And be careful of off-by-1 errors (you probably want to start with i=0) (and be certain whether you are projecting forward in time, or backward?)

With a gun that fires 60 rounds/sec, you should probably do this anyway, since there’s no guarantee that your game will maintain a perfect 60fps in every situation.

Another point, if you’re really trying to simulate your game at 360x speed, you probably can’t use messages every “frame”. There’s a limited number of messages that get processed each frame, and messages are slow to begin with. It can be a pain, but you should start trying to work around them where you can. Use modules and function calls instead.

4 Likes