godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
88.76k stars 20.12k forks source link

[Questions 2.2] Main Loop iterations and Physics #10357

Closed Ijatsu closed 6 years ago

Ijatsu commented 7 years ago

Hello!

I'm trying to make some fancy stuff with genetic algorithm. Basically I have a scene that creates 12 SceneTrees and initiate the same given PackedScene in it. These 12 simulations are iterated by the main scene using the MainLoop's iteration function.

I do that in order to be able to speed up or slow down at will the simulations. Sadly, it seems that the physics aren't affected by this. For example, if I speed every 8 times, things handled by my scripts will be sped up 8 times, but an object falling due to gravity is going to move the exact same way instead of moving 8 time faster.

I could micro manage this by increase by 8 the gravity. But this feels bad.

Is there a way to do what I want to do? Am I using MainLoop properly? Is there separate physics server with different paces for each scene trees?

Thanks!

Causeless commented 7 years ago

This is Github issues. This isn't for Q&A - there's a section on the website for that.

Firstly, to have your scripts run in sync with physics (which is sensible for anything which you want to be consistent and deterministic, i.e simulation stuff instead of visuals), but the section of code you want to run in the physics loop by using fixed_process() instead of process().

Regardless, for the sake of having the physics be deterministic (which is especially important from evolutionary/genetic algorithms), the physics server runs at a fixed tick-rate (by default at 60fps).

You can change this under the Project settings under Physics. It can also be modified at runtime via OS:set_iterations_per_second().

However, increasing or decreasing the physics tickrate is also going to fundamentally change the behavior of the simulation, as all the physics is still scaled by the delta-time, just by a fixed delta-time. Furthermore, OS:set_time_scale() (according to the docs) seems to work by scaling the actual delta-time, so also changes physics behaviour.

You could presumably change both (doubling both iterations per second as well as time scale), however this could introduce potential rounding differences between the simulations.

I'm unsure of the best way to modify the iterations per second with a fixed delta-time.

Causeless commented 7 years ago

I've taken a look and it looks like the best method would be to use set_use_custom_integrator and add a custom integrator for the relevant rigid bodies to scale velocity by a constant instead of by the deltatime.

This would allow you to modify the physics tickrate without changing the behaviour of the simulation, so doubling the tickrate would deterministically double the sim speed (assuming you're running on your own machine - floats make cross-platform determinism less easy)

Ijatsu commented 7 years ago

Hello and thank you for your answer!

I am sorry if I have used the issues instead of the Q&A.

Using OS:set_iterations_per_second and OS:set_time_scale together works, I've not noticed rounding problems yet.

The only thing I reproach to that solution is that it's not working independently on the scene trees and instead affect all the application. I would have wished scene trees to be more independent on these aspects.

Using integrate_forces would force coding the speed-up in the simulations, while I want it to be completely unaware.

Causeless commented 7 years ago

As far as I can tell there's no real way to change the timescale or tickrate on a per-scene basis, it can only be done on the engine level.

Per-scene tickrate and timescale seem like potentially useful features, albeit admittedly sound more useful for simulations rather than games (where separate scenes are rarely going to be run in parallel, or especially at different timescales).

It may be a good addition to make to the engine but could be a fair amount of work,

RandomShaper commented 7 years ago

You can always run multiple Godot instances and add some code to sync them.

I don't know if headless Godot currently builds, but it will do eventually and you could take some advantage from it.

Ijatsu commented 7 years ago

@Causeless Note that I am using SceneTrees and not just Scenes, therefore a separated MainLoop, a separated server would have been logical.

@RandomShaper By doing so I wouldn't be able to render the viewport in a sprite I guess.

RandomShaper commented 7 years ago

You could run those instances with settings for a borderless, 1x1 window with viewport stretch. Or something like that.

Just throwing out ideas. :)

akien-mga commented 6 years ago

Closing as the discussion stalled (and also, it would be better suited on the Q&A or the subreddit/forums :)).