Rigidbody2D.MoveRotation and AngularVelocity - Need help understanding procedure of use.

Hey all,

I have a habit of waffling in these posts, so I’ll cut to the chase.

Testing some prototype stuff for a new game. I’m using 2D physics to move player ‘ships’ around, but even though the rotation is ALMOST kinematic in nature, I want the ships to spin when high speed collisions occur.

So I have some code for implementing the torque using Rigidbody2D.AddTorque, and it responds well. The player’s rotating of the ships is using Rigidbody2D.MoveRotation, and this too works well. But I can’t sdeem to get them to work together.

Here’s the questions I have:

  1. In my testing it seems that when I use MoveRotation during FixedUpdate (as per the limited documentation, using DeltaFixedUpdate as per documentation) it will override the inertia involved in collisions past the initial knock. See it will rotate on the frame of the impact, but then after that there’s no inertia spin.

  2. If the answer to the above is “Yes, MoveRotation ‘blocks’ inertia/torque/whatever” how can I overcome this? I can’t adjust AndularVelocity directly as the documentation says to use AddTorque to adjust this.

I’ll add the code in the next post. I’m basing my ‘ImpactToTorque’ code from this post (Second post by Partel-Lang): How to calculate how much torque will rigidbody.addForceAtPosition add?

Like I said, the spin works on it’s own. And using MoveRotation to rotate the ship based on players input works as well, but when I combine them together the ship will only ‘budge’ a little bit from the initial collision, and then there’s no inertia-spinning.

This is the code for the spin caused by impact:

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

[RequireComponent(typeof(Rigidbody2D))]
public class PlayerImpactSpin : MonoBehaviour {
    private Rigidbody2D rb2D;
    private Rigidbody2D incomingRB;
    float nm;
    float rotInput;

    // Use this for initialization
    void Start () {
        rb2D = GetComponent<Rigidbody2D>();
        //rb2D.centerOfMass = new Vector2(0, 0.25f);
    }
 
    // Update is called once per frame
    void Update () {
    }

    private void FixedUpdate()
    {
        if (nm == 0f)
        {
            //rb2D.MoveRotation(rb2D.rotation + rotInput + (rb2D.angularVelocity * Time.fixedDeltaTime));
            //rotInput = 0f;
            return;
        }

        Debug.LogWarning("Adding " + nm + " through addtorque");
        rb2D.AddTorque(nm);

        nm = 0f;
    }

    private void OnCollisionEnter2D(Collision2D collision)
    {
        ///////////////////////////////
        //
        // other collider is always THIS collider,
        // whereas collision.collider is the object we hit
        //
        ///////////////////////////////

        ContactPoint2D[] contacts = new ContactPoint2D[1];

        incomingRB = null;

        // Populate the array of contact point for this collision
        collision.GetContacts(contacts);
     
        incomingRB = collision.collider.attachedRigidbody;

        if (incomingRB == null)
            return;

        Debug.LogError("The vector between the CoM and the impact point is " + (rb2D.centerOfMass - contacts[0].point));

        Vector2 force = contacts[0].relativeVelocity * incomingRB.mass;
        Debug.Log("The incoming mass was " + incomingRB.mass);
        Debug.Log("The relative velocity was " + contacts[0].relativeVelocity);
        Debug.Log("The relative force of the impact was " + force);
        nm = ApplyTorqueFromImpact(contacts[0].point, force);

        //if (collision.collider.CompareTag("Bullet"))
        //    Destroy(collision.collider.gameObject);

    }

    private float ApplyTorqueFromImpact(Vector2 impactPos, Vector2 impactForce)
    {
        Debug.Log("The incoming force was calculated at " + impactForce + ", and the position of the impact was " + impactPos);

        /////////////////////////////////////
        //
        //  PROCESS:
        //
        //  1. Work out the vector from impact point to CoM (Centre of Mass)
        //  2. Work out the theta angle between the line running point-CoM and
        //  line of impact with other object
        //  3. Use Pythag to find the torque component of incoming impactForce (sin[theta] * hypot[magnitude of impactForce])
        //  4. Multiply the distance to impact point (magnitude point-CoM) with torque component
        //  5. Applytorque to rigidbody
        //
        //  TODO: Take into account the stationary objects, as their velocity will be 0
        //
        //
        /////////////////////////////////////

        //1.
        Vector2 pivot = rb2D.worldCenterOfMass - impactPos;
        Debug.LogWarning("The pivot of " + pivot + " was calculated by " + rb2D.worldCenterOfMass + " - " + impactPos);

        //2.
        float angle = Mathf.Atan2(pivot.y, pivot.x) - Mathf.Atan2(impactForce.y, impactForce.x);

        Debug.LogWarning("The angle between the 2 vectors is " + angle);
     
        //3.
        float torque = pivot.magnitude * impactForce.magnitude * Mathf.Sin(angle) * Mathf.Rad2Deg;

        Debug.Log("The torque force is " + torque + ", if timed with fixeddeltatime it would be " + (torque * Time.fixedDeltaTime));

        return torque / rb2D.inertia;

        //nm *= Time.fixedDeltaTime;
    }
}

And here’s the code for the PlayerInput for the player’s ship

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


public class ControllerInput : MonoBehaviour {

    public string playerPrefix;

    public float rotationSpeed;

    public float thrust;
    public float maxSpeed;
    public float fireRate;
    public float muzzleVelocity;

    public ParticleSystem particles;
    public Transform gunBarrel;
    public GameObject bulletPrefab;

    private Rigidbody2D rb2D;
    private ParticleSystem.EmissionModule em;
    private bool firing;
    private float nextBulletTimer;
    private float rotationInput;

    // Use this for initialization
    void Start () {
        rb2D = GetComponent<Rigidbody2D>();
        particles = GetComponentInChildren<ParticleSystem>();

    }
 
    // Update is called once per frame
    void Update () {
        nextBulletTimer -= Time.deltaTime;
        rotationInput = Input.GetAxis(playerPrefix + "Horizontal");
        float thrustInput = Input.GetAxis(playerPrefix + "Vertical");

        if (thrustInput < 0f)
            thrustInput = 0f;
     
        if (particles != null)
        {
            em = particles.emission;

            float trailRate = (thrustInput / 1f) * 100f;

            em.rateOverTime = trailRate;
        }

        //transform.Rotate(Vector3.forward * Time.deltaTime * -rotationInput * rotationSpeed);

        rb2D.AddForce(transform.up * thrustInput * thrust * Time.deltaTime);

        rb2D.velocity = Vector2.ClampMagnitude(rb2D.velocity, maxSpeed);

        if (Input.GetButtonDown(playerPrefix + "Fire1"))
        {
            firing = true;
        }

        if (Input.GetButtonUp(playerPrefix + "Fire1"))
        {
            firing = false;
        }

        if (firing)
        {
            if (nextBulletTimer <= 0f)
            {
                rb2D.AddForceAtPosition(-transform.up * muzzleVelocity * 0.25f, gunBarrel.position);
                nextBulletTimer = fireRate;
                GameObject bullet = Instantiate(bulletPrefab, gunBarrel.position, Quaternion.identity);
                bullet.GetComponent<Rigidbody2D>().velocity = transform.up * muzzleVelocity;
            }
        }
    }

    private void FixedUpdate()
    {
        // Disabling the following line allows the inertia from the impact spin the ship and die down from drag
        rb2D.MoveRotation(rb2D.rotation  +  (rotationSpeed *  -rotationInput) * Time.fixedDeltaTime);
        //Debug.Log("Trying to add rotational inerta manually");
    }
}