Aligning FixedUpdate with user touch input

Hello everybody,

I am trying to create an endless runner where you guide a fish around deadly spikes by holding and dragging. One of the features is that the fish is supposed to rotate down or up in the direction it is moving. To achieve this effect, I measure the distance the fish has moved since the last frame and rotate it by the arctan of the y distance over x distance - basically getting the direction it has moved since the last frame. I also subtract the current rotation to get the fish to rotate correctly.

The only problem I have with this is that the fish keeps rotating back to zero seemingly arbitrarily. Every couple of frames, the fish rotates back to zero, then it goes back, and it keeps switching back and forth. This ends up making it look like it is glitching and vibrating, when it should be just a smooth rotation. Upon investigating more thoroughly, I found that the problem was that the change in y position was the thing randomly turning to zero - plugging that change through the arctan function was what made the target rotation glitch. So basically at the root of this, the only thing causing the problem was something I had put into the code previously – something that is still posing a major problem: my entire code base is built on FixedUpdate.

The main reason I wanted to do this is so that it would work with any frame rate and have the same effect. I realized after this investigation that I didn’t need to make the touch input happen during FixedUpdate, so I changed that, as well as the code measuring the change in distance. Basically I modified a ton of code to change the measuring system and remove the random zeroes.

And, for some reason, it didn’t work.

I’ll put the code down below, but I’m really unsure of the problem and would love if someone could help. Thanks in advance!

All right, here’s the code for the class “RotateByTouch” before the change:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class RotateByTouch : MonoBehaviour {
    public TrackObjectMotion trackObjectMotion;
    public GameObject thisObject;

    public float rotationValue;

    void FixedUpdate() {
        rotationValue = Mathf.Atan(trackObjectMotion.DeltaY / trackObjectMotion.DeltaX) * Mathf.Rad2Deg;

        thisObject.transform.Rotate(Vector3.forward, rotationValue - thisObject.transform.rotation.eulerAngles.z);
    }
}

Here it is afterwards:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class RotateByTouch : MonoBehaviour
{

    public TrackObjectMotion trackObjectMotion;
    public GameObject thisObject;

    public float rotationValue;

    void Update()
    {

        rotationValue = Mathf.Atan(trackObjectMotion.DeltaY / trackObjectMotion.DeltaX) * Mathf.Rad2Deg;

        thisObject.transform.Rotate(0, 0, rotationValue - transform.rotation.eulerAngles.z);

    }

    void FixedUpdate()
    {

        rotationValue = Mathf.Atan(trackObjectMotion.DeltaY / trackObjectMotion.DeltaX) * Mathf.Rad2Deg;

        thisObject.transform.Rotate(0, 0, rotationValue - transform.rotation.eulerAngles.z);

    }

}

Here’s the code for “TrackObjectMotion” before the change:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TrackObjectMotion : MonoBehaviour {
    public Vector3 CurrentPosition;
    public Vector3 PreviousPosition;

    public float DeltaX;
    public float DeltaY;

    // Update is called once per frame
    void FixedUpdate() {
        PreviousPosition = CurrentPosition;
        CurrentPosition = this.gameObject.transform.position;

        DeltaX = CurrentPosition.x - PreviousPosition.x;
        DeltaY = CurrentPosition.y - PreviousPosition.y;
    }
}

And here’s afterwards:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TrackObjectMotion : MonoBehaviour
{

    public Vector3 CurrentPosition;
    public Vector3 PreviousPosition;

    public float DeltaX;
    public float DeltaY;

    void Update()
    {
        PreviousPosition.Set(PreviousPosition.x, CurrentPosition.y, PreviousPosition.z);
        CurrentPosition.Set(CurrentPosition.x, transform.position.y, CurrentPosition.z);

        DeltaY = CurrentPosition.y - PreviousPosition.y;
    }

    void FixedUpdate()
    {
        PreviousPosition.Set(CurrentPosition.x, PreviousPosition.y, PreviousPosition.z);
        CurrentPosition.Set(transform.position.x, CurrentPosition.y, CurrentPosition.z);

        DeltaX = CurrentPosition.x - PreviousPosition.x;
    }
}

And finally, here’s the code for the class “PlayerMovementController” before and after the change:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerMovementController : MonoBehaviour
{

        public float horizontalMovement;
        public float verticalMovement;
        public float verticalMovementSpeed;

    // Update is called once per frame
    void FixedUpdate()
    {
        foreach (Touch touch in Input.touches) {
                if(touch.phase == TouchPhase.Moved) {
                        verticalMovement = touch.deltaPosition.y * verticalMovementSpeed;
                } else {
                        verticalMovement = 0;
                }
        }
        transform.Translate(horizontalMovement, verticalMovement, 0)
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerMovementController : MonoBehaviour
{


        public float horizontalMovement;
        public float verticalMovement;
        public float verticalMovementSpeed;

    // Update is called once per frame
    void Update()
    {
        foreach (Touch touch in Input.touches) {
                if(touch.phase == TouchPhase.Moved) {
                        verticalMovement = touch.deltaPosition.y * verticalMovementSpeed;
                } else {
                        verticalMovement = 0;
                }
        }
        transform.Translate(0, verticalMovement, 0)
    }

    void FixedUpdate()
    {
        transform.Translate(horizontalMovement, 0, 0)
    }
}

Also please note that the fish is being moved by other forces than just touch, so I can’t just take the variables right out of this script.

just a guess… divide by zero?

are you getting any errors?

When working with fixed update, the general advice is to get the input values during update and then move your objects with those values in fixed update.

What I see in your player controller is that you’re getting the input value in Update and immediately moving the object in the same method. Instead, you want to merely store the touch position in update, then calculate and translate your vertical movement inside of fixed update.

Alternatively, if all you want from the fixed update loop is framerate indepedence (as opposed to physics interaction and other fixed needs), then I suggest you can achieve similar results with a lot less complication by utilizing Time.deltaTime. If you move your horizontal movement translation into Update, and multiply the movement values by Time.deltaTime, you will achieve the effect you’re looking for. As a bonus, your movement values can be declared as a movement-per-second, which is a lot easier to understand than movement-per-frame.

void Update {
    // .. calculate vertialMovement
    transform.translate(horizontalmovement*Time.deltaTime, verticalMovement*Time.deltatime; 0);
}

Unfortunately, I can’t just switch off of FixedUpdate, as a lot of things depend on it and I am relatively close to the release of the game, so I don’t have the time to rework the entire code base. I did change the input into Update and the motion in FixedUpdate, but it didn’t quite work. I’m beginning to think that this is a problem unrelated to the FixedUpdate / Update issue, seeing as nothing I do works, but I have no other idea what it could be! If you have any other ideas, I’d love to hear them.

No, I am not getting any errors.