Home > Mobile >  Jittery rotation while moving gameobject in Unity
Jittery rotation while moving gameobject in Unity

Time:04-11

I have an issue with jittery movement and I have searched the internet thin and tried countless solutions, but none have worked.

Essentially, I am moving a 2D Enemy GameObject towards my player, which involves moving and rotating at the same time.

At the start it is smooth, but when my player shoots the Enemy, causing it to fly backwards because of the RigidBody2D physics, it starts jittering when it rotates back towards my player.

Also, when my enemy tries to rotate back towards my player after getting hit, it struggles to aim/rotate directly at my player. It's just kind of struggling to rotate the last 20 degrees while jittering.

I have tried EVERY combination of using velocity and AddForce for movement, and using FromToRotation, RotateTowards, Lerp, and Slerp for rotation.

I have tried using both Update, LateUpdate, and FixedUpdate for either or both moving and rotating.

I have tried setting the GameObjects Interpolation to None, Interpolate and Extrapolate.

Nothing works.

My best guess is that my RotateEnemy() somehow gets confused about what "forward" is after getting hit, and doesn't know what to point at the player.

Here is a video showing the issue:

https://www.youtube.com/watch?v=SJwn4I74znQ&ab_channel=DanielNielsen

Here is the script I have on my Enemy gameobject:

Rigidbody2D _rb;
[SerializeField] GameObject _player;

float _moveSpeed = 2f;
Vector2 _currentVelocity;
Vector2 _targetVelocity;
Vector2 _moveDirection;
Quaternion _targetRotation;
bool _disableEnemy = false;

void Start()
{
    _rb = GetComponent<Rigidbody2D>();
}

void Update()
{
    // Move player
    _moveDirection = _player.transform.position - transform.position;
    _moveDirection.Normalize();
}

void FixedUpdate()
{
    if (!_disableEnemy)
    {
        RotateEnemy();
        MoveEnemy();
    }
}

void MoveEnemy()
{
    // Prevent redundacy
    _currentVelocity = _rb.velocity;
    _targetVelocity = _moveDirection * _moveSpeed;

    if (_currentVelocity != _targetVelocity)
    {
        _rb.velocity = _moveDirection * _moveSpeed;
    }
}

void RotateEnemy()
{
    _targetRotation = Quaternion.LookRotation(Vector3.forward, _moveDirection);
    if (transform.rotation != _targetRotation)
    {
        transform.rotation = Quaternion.Slerp(transform.rotation, _targetRotation, 10 * Time.deltaTime);
    }

}

private void OnCollisionEnter2D(Collision2D collision)
{
    if (collision.gameObject.tag == "Bullet")
    {
        StartCoroutine(Damaged());
    }
}

private IEnumerator Damaged()
{
    _disableEnemy = true;

    yield return new WaitForSeconds(0.5f);

    _disableEnemy = false;
}

CodePudding user response:

Based on your reply I would suggest you to call your RotateEnemy() in Update.

Update runs on every frame, where FixedUpdate does not - it runs per physics tick, and more or less than one of those may occur each frame.

And since we are not handling physics related stuff in RotateEnemy() we should call it in Update()

private void Update()
{
    // Move player
    _moveDirection = _player.transform.position - transform.position;
    _moveDirection.Normalize();

    if (!_disableEnemy)
    {
        RotateEnemy();
    }
}
  • Related