Incorrect Time.deltaTime in action callback?

When are the the callbacks invoked? I have a move method invoked from an action callback. It uses delta time and behaving very erratically. I’m getting 250 frames per second, and when I do a VSync to 70 fps it starts to behave smoothly.

So clearly the Time.deltaTime is incorrect whenever the method is invoked. Howevr it could be about other timing and input value issues. The movement I’m talking about is actually camera rotation from mouse delta.

But when I remove the delta time and try again with no VSync it acts smoothly. So it’s not an incorrect mouse delta, it’s incorrect Time.deltaTime.

You should use deltaTime when you process the input, not gather it. That’s probably the cause. Can’t help a lot without your code anyway

Same as before:

inputActions.BuildMode.CameraRotation.performed += c => _cameraControl.Rotate(c.ReadValue<Vector2>());
public void Rotate(Vector2 delta)
    {
        var rotation = _cameraTransform.rotation.eulerAngles;
        rotation.x += -delta.y * _rotationSensitivity * Time.deltaTime;
        rotation.x = rotation.x > 90 && rotation.x < 180 ? 90 : rotation.x;
        rotation.x = rotation.x < -90 ? -90 : rotation.x;
        rotation.y += delta.x * _rotationSensitivity * Time.deltaTime;
        _cameraTransform.rotation = Quaternion.Euler(rotation);
    }

Just in case, in update it works fine:

public class CameraControl : MonoBehaviour
{

    void Update()
    {
        Rotate(new Vector2(10f, 0f));
    }

Okay… not it works fine… For no seeming reason. I’ll update if it happens gain, thank you for your attention :slight_smile:

Found it. Whenever there are frame time spikes it jumps in the direction of input, sometimes a lot. It overcompensates. This happens only in editor. Causes very inconsistent control behavior, for example rotating camera with small mouse movements left and right in 15 degree ark might cause up to 180 degree jumps when there are spikes (every 1-5 seconds, when editor under.

5078030--499463--upload_2019-10-17_17-5-30.png

I simplified the rotation code just to make sure problem is not there:

    public void Rotate(Vector2 delta)
    {
        _cameraTransform.Rotate(0f, delta.x * _rotationSensitivity * Time.deltaTime, 0f, Space.World);
        _cameraTransform.Rotate(-delta.y * _rotationSensitivity * Time.deltaTime, 0f, 0f, Space.Self);
    }

But if it’s just the editor and particularly when it is under extra load like when profiler is open, it’s not a big deal.

You’re using deltaTime with something that can get called many many times a frame, so it’s normal it does crazy things.

You would use delta time only if you’re calling Rotate on Update, which is not the case here

I suspected that, but cant find information on when the callbacks occur and if there can indeed be more then one per update.

So in this scenario… I’m kinda out of ideas. If I store the input and apply it on update that would be so messy. Should I accumulate mouse delta until update, pass it, nullify, repeat?

Either that or simply processing each callback separatly, without deltaTime

As a rule of thumb, every input event that changes something bound to an action will trigger the action once. There’s lots of exceptions but still, architecturally actions operate at the input event level and are oblivious to frames.

Mice are generally sampled at high frequency leading to lots of input events. Frame spikes can thus lead to an accumulation of a large number of events and thus actions firing a lot in response.

In your Update method, do

_cameraControl.Rotate(inputActions.BuildMode.CameraRotation.ReadValue<Vector2>());

Thank you. Will that account for all mouse input that happened since last frame?

If yes, good. If not wouldn’t that lead to some lost input? It wouldn’t be as bad as accumulating callbacks, but still some inconsistency with physical input.

It will read the current value only. However, I assume you have CameraRotation bound to the mouse delta. Delta controls are special in that they accumulate. Meaning that instead of just overwriting the mouse delta each time there is a new event, they will add the newly received delta to the current one and then reset the delta to (0,0) at the beginning of the next frame / input update.

So, in essence, you’ll read the final accumulated delta from the entire frame in this case.

Right. That’s great. Although, I am kinda disappointed with how inconsistent my input API usage is right now.

First I tried to do everything via PlayerInput invoking events. Turns out I can’t invoke Vector2 event.

Then I tried to do everything with callbacks. Turns out there is no callback for Input.GetKey-like event, alright I made a very awkward system that takes performed callback and cancelled callback. (8 lines of code… instead of 1)

    inputActions.BuildMode.CameraMovement.performed += c => { _movementVector = c.ReadValue<Vector2>(); _movementInProgress = true; };
        inputActions.BuildMode.CameraMovement.canceled += c => { _movementInProgress = false; };

Turns out I cant use callbacks for… moving things, because the mouse delta is not syncronized with the frame rate.

Alright, maybe I can do everything in Update with action maps, after all its the lightest api considering all the above.

        _cameraControl.Rotate(_inputActions.BuildMode.CameraRotation.ReadValue<Vector2>());
        _cameraControl.Move(_inputActions.BuildMode.CameraMovement.ReadValue<Vector2>());

The only thing then… I have a feeling that there is no way to check via action that key that triggered the action is still down. If there is, then I’m good to go.

Something like _inputActions.BuildMode.PrimaryAction.inProgress

Isn’t that the second or first most commonly needed functionality?

Also thank you, everyone, for the help. @Rene-Damm , awesome profile pic :smile: