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.