Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a property to make Engine.time_scale ignore certain nodes #9068

Open
TheContainer opened this issue Feb 10, 2024 · 5 comments
Open

Add a property to make Engine.time_scale ignore certain nodes #9068

TheContainer opened this issue Feb 10, 2024 · 5 comments

Comments

@TheContainer
Copy link

Describe the project you are working on

A 3D sandbox game where you will be able to slow down time around you but not yourself.

Describe the problem or limitation you are having in your project

With Engine.time_scale, you can slow down time, but you can't add exceptions, which means that not only you as the Player will be in slowmotion speeds (which I don't want), but also every UI element.

Describe the feature / enhancement and how it helps to overcome the problem or limitation

Each node will have a boolean variable, and when this variable is set to true, the time_scale variable will be ignored, and the node will run at normal speed, similar to process_mode.

Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams

The variables value can be changed in the property editor of the node, maybe in the "process" tab.

If this enhancement will not be used often, can it be worked around with a few lines of script?

For simple animations, tweens for example, you can balance the speed out with some math manually, to give it the illusion of ignoring the time_scale value, but with physics movement for example, you can't.

Is there a reason why this should be core and not an add-on in the asset library?

This is very useful overall and belongs to the core in my opinion.

@Calinou
Copy link
Member

Calinou commented Feb 10, 2024

This was also proposed in #7775, but I'll leave this one open as to make the discussion more specific in this proposal.

@Calinou Calinou changed the title Exceptions for Engine.time_scale Add a property to make Engine.time_scale ignore certain nodes Feb 10, 2024
@KoBeWi
Copy link
Member

KoBeWi commented Feb 10, 2024

with physics movement for example, you can't.

You can, by modifying the delta. Though it's not possible with move_and_slide() until godotengine/godot#84665

@Mickeon
Copy link

Mickeon commented Feb 11, 2024

I sorta agree with this, but I wonder if it could be expanded to be a float multiplier, instead of a boolean. The problem with both solutions may hurt performance a bit even for nodes that are set to the default.

@thanasip
Copy link

thanasip commented Feb 27, 2024

I had a need for this exact thing, and in the end I just did this (I'm in .NET world so I'll show a C# example, but I imagine this is perfectly doable in GDScript)

Create an Autoload (in my example, FrameTimer). Define an event and a DateTime private field:

public partial class FrameTimer : Node
{
    public static event Action<double> FrameRendered;
    
    private DateTime _lastFrameDt;
}

In that Autoload's _EnterTree(), set your _frameTimeDt initial value, and hook the RenderingServer's FramePostDraw event, which you'll use to calculate the delta:

public override void _EnterTree()
{
    _lastFrameDt = DateTime.Now;

    // Hook the event with a lambda (or assign an Action delegate)
    RenderingServer.FramePostDraw += () => {
        var now = DateTime.Now;
        var delta = (now - _lastFrameDt).TotalSeconds;
        _lastFrameDt = now; // Set your last frame time to now
        FrameRendered?.Invoke(delta); // safely invoke the event (does nothing if not hooked)
    };
}

And that's pretty much it... Now all you have to do is in any script where you want the delta independent of Engine.TimeScale, just define a handler, and in your _EnterTree() or _Ready(), hook the event in FrameTimer (or whatever you called it) and use that handler instead of _Process(double delta):

public partial class SomeClass : Node
{
    /*... other class stuff ...*/

    public override void _Ready()
    {
        FrameTimer.FrameRendered += TimeScaleIndependent_Process;
        // other _Ready() stuff...
    }

    private void TimeScaleIndependent_Process(double delta)
    {
        // whatever you want to do independent of Engine.TimeScale
    }

    /*... other class stuff ...*/
}

The one caveat to this advice: I've literally been using Godot for like, 3 weeks and am not fully aware of any subtleties I may be tripping over - but this seems to be working just fine for me so far.

@Calinou
Copy link
Member

Calinou commented Feb 27, 2024

I sorta agree with this, but I wonder if it could be expanded to be a float multiplier, instead of a boolean. The problem with both solutions may hurt performance a bit even for nodes that are set to the default.

This was proposed before and rejected: godotengine/godot#29861

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants