Gradual strafe rotation with focus on mouse (circle-strafe)

As seems to be the case with many new Unity folks, I opted to try and make a 2D space shooter as my first game. Between following along with numerous tutorials like Tanks! and logging my own time tinkering in Unity with research and trial/error, I have (maybe) a grand total of 90 hours of experience - so please forgive any common errors I may make. I do welcome constructive criticism. I know my code is heavily commented and that’s a “beginner sin” - but there’s a very good reason beginners do it.

Of those 90 hours, I’ve probably I’ve been struggling to get my ship movement working for 8 of them. Originally I had the ship moving by just changing the position of the transform, but the more I played with that in testing, the less natural it felt. I wanted some heft and weight to movement. Enter ApplyForce and a change to using physics. It took about 8 hours of research and more tutorials to get 95% of my movement the way I wanted it. It feels good now - but…

The remaining 5% is getting the ship to strafe left and right slowly and smoothly while remaining aligned with where the mouse pointer is - so you can, in effect, circle-strafe an enemy easily. I’ve hammered lots of solutions into that slot, but none have done what I was trying to accomplish. I’ve included a number of failed experimental circle-strafe attempts as comments. I did not keep all of their random variables in the code as I didn’t want to confuse it with a dozen useless elements, but each was “functional” when I tested it. I’m hoping someone can assist with this as I feel like I’m really close, but just can’t find the last nudge.

using UnityEngine;
using System.Collections;

public class Space2DStrafeMove : MonoBehaviour

{
    //movement variables
    public float v_speed = 3;               
    public float v_rotationSpeed = 0.25f;
   
    //private calculation variables
    private Vector3 v_lookDirection;
    private float v_lookAngle;
   
    //object variables
    private Rigidbody2D v_rigidBody2D;

    // Use this for initialization
    void Start()
    {
        //store a reference to the attached Rigidbody2D object
        v_rigidBody2D = GetComponent<Rigidbody2D> ();
       
    }

    //FixedUpdate is called at a fixed interval and is independent of frame rate. Put physics code here.
    void FixedUpdate()
    {
        //Store the current horizontal input in the float moveHorizontal.
        float v_moveHorizontal = Input.GetAxis ("Horizontal");

        //Store the current vertical input in the float moveVertical.
        float v_moveVertical = Input.GetAxis ("Vertical");

        //strafe toggle, ship remains oriented towards mouse cursor
        if (Input.GetKey(KeyCode.LeftShift))
        {
            //Establish the mouse position in the camera relative to the position of the ship
            v_lookDirection = Camera.main.ScreenToWorldPoint(Input.mousePosition) - transform.position;

            //Create an angle that the ship will need to move towards in order to look at the mouse cursor
            v_lookAngle = Mathf.Atan2(v_lookDirection.y, v_lookDirection.x) * Mathf.Rad2Deg;

            //Use the two store floats to create a new Vector2 variable movement.
            Vector2 v_movement = new Vector2 (v_moveHorizontal, v_moveVertical);

            //Call the AddForce function of our Rigidbody2D rb2d supplying movement multiplied by speed to move our player.
            v_rigidBody2D.AddRelativeForce(v_movement * v_speed);

            //Rotate the ship towards the established angle, -90f to account for ship alignment, over time
            //Rotates instantly, not desirable
            transform.rotation = Quaternion.Euler(0f, 0f, v_lookAngle - 90f);

            //turns the ship as fast as I move the cursor, and in the right direction
            //transform.rotation = Quaternion.AngleAxis(v_lookAngle-90, Vector3.forward);
           
            //instantly snaps the ship "up"
            //transform.rotation = Quaternion.Euler(0f, 0f, v_lookAngle - 90f * Time.fixedDeltaTime) ;

            //instantly snaps the ship "up"
            //transform.rotation = Quaternion.Euler(0f, v_lookAngle - 90f * v_rotationSpeed * Time.deltaTime, 0f);

            //undesirable result
            //transform.eulerAngles = Vector3(0, v_lookAngle, 0);

            //undesirable result
            //transform.rotation = Quaternion.Slerp(v_lookAngle, v_lookDirection.y, Time.time - startTime);

            //undesirable result
            //transform.rotation = Quaternion.RotateTowards(transform.rotation, v_lookDirection, Time.deltaTime * 10f);

            //smooth rotation to the Z axis (flips the ship over)
            //transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(v_lookDirection - transform.position), v_rotationSpeed * Time.deltaTime);

            //undesirable result
            //transform.rotation = Quaternion.AngleAxis(v_lookAngle, Vector3.forward);

            //ship spins smoothly over onto it's back
             //transform.rotation = Quaternion.Slerp(this.transform.rotation, rotationA, Time.deltaTime * speed);

        }

        //this creates smooth up and down, rotate left and right, fly in direction the transform is pointing
        if (!Input.GetKey(KeyCode.LeftShift))
        {
            //Use the two store floats to create a new Vector2 variable movement.
            Vector2 v_movement = new Vector2(0, v_moveVertical);

            //rotate the transform on the horizontal axis
            transform.Rotate(0, 0, -v_moveHorizontal);

            //apply force relative to the existing heading of the ship
            v_rigidBody2D.AddRelativeForce(v_movement * v_speed);
        }
    }
}

I discovered a solution to this from this StackOverflow thread:
Rotating gradually in response to input, instead of snapping

I didn’t make use of the Coroutine they did, but the line used to update rotation was perfect after some tinkering. For some reason I also had to declare my v_rotationSpeed a second time inside my FixedUpdate if statement. This was the resulting section of code, which does exactly what I wanted.

        //strafe toggle, ship remains oriented towards mouse cursor
        if (Input.GetKey(KeyCode.LeftShift))
        {
            //set v_rotationSpeed; not sure why it's not using the public variable
            float v_rotationSpeed = 60f;

            //Establish the mouse position in the camera relative to the position of the ship
            v_lookDirection = Camera.main.ScreenToWorldPoint(v_mousePosition) - transform.position;

            //Create an angle that the ship will need to move towards in order to look at the mouse cursor
            v_lookAngle = Mathf.Atan2(v_lookDirection.y, v_lookDirection.x) * Mathf.Rad2Deg;

            //Use the two store floats to create a new Vector2 variable movement.
            Vector2 v_movement = new Vector2 (v_moveHorizontal, v_moveVertical);

            //Call the AddForce function of our Rigidbody2D supplying movement multiplied by speed to move our player.
            v_rigidBody2D.AddRelativeForce(v_movement * v_speed);

            //Update our target rotation to move towards.
            v_targetRotation = Quaternion.Euler(0f, 0f, v_lookAngle-90f);
           
            //gradually rotates the ship towards the mouse pointer
            transform.rotation = Quaternion.RotateTowards(transform.rotation, v_targetRotation, v_rotationSpeed * Time.fixedDeltaTime);

        }