2
\$\begingroup\$

From the image below, I would like to rotate a game object C around a point A of a line (made using a line renderer) by an angle d to position p1 till C is on the same line joining points A and B over a given period of time. Preferably using a coroutine. Please note that the angle d is not known. How can I achieve this?

enter image description here

\$\endgroup\$
0
\$\begingroup\$

Try the following script :

using UnityEngine;
using System.Collections;

public class RotateScript : MonoBehaviour
{
    public float rotationSpeed;

    public void StartAlign( Vector3 pointA, Vector3 pointB )
    {
        StartCoroutine( Align(pointA, pointB) );
    }

    private IEnumerator Align( Vector3 pointA, Vector3 pointB )
    {
        // Compute the rotation axis
        Vector3 axis = Vector3.Cross( pointB - pointA, transform.position - pointA );

        // Compute the rotation angle
        float totalAngle = -Vector3.SignedAngle(pointB - pointA, transform.position - pointA, axis );
        float sign = totalAngle < 0 ? -1 : 1;
        float angle = 0;

        // Rotates smoothly the object
        for ( float cumulativeAngle = 0 ; sign * cumulativeAngle < sign * totalAngle ; cumulativeAngle += angle )
        {
            angle = sign * Mathf.Min( sign * (totalAngle - cumulativeAngle), Time.deltaTime * rotationSpeed );
            transform.RotateAround( pointA, axis, angle );
            yield return null;
        }
    }

}

If your pointC must be a vector, try the following script:

using UnityEngine;
using System.Collections;

public class RotateScript : MonoBehaviour
{
    public float rotationSpeed;

    // This is an example function to show how StartAlign must be called
    // The last parameter must be a function taking a Vector3 as only parameter
    public void Foo()
    {
        StartAlign( pointC, pointA, pointB, OnPointCChanged );
    }

    public void StartAlign( Vector3 pointC, Vector3 pointA, Vector3 pointB, System.Action<Vector3> SetNewPointCPosition )
    {
        StartCoroutine( Align( pointC, pointA, pointB, SetNewPointCPosition ) );
    }

    private IEnumerator Align( Vector3 pointC, Vector3 pointA, Vector3 pointB, System.Action<Vector3> SetNewPointCPosition )
    {
        // Compute the rotation axis
        Vector3 direction = pointC - pointA;
        Vector3 axis = Vector3.Cross( pointB - pointA, direction );

        Quaternion startRotation = Quaternion.identity;
        Quaternion endRotation = Quaternion.FromToRotation( direction, pointB - pointA );

        Debug.Break();

        // Rotates smoothly the object
        for ( float time = 0 ; time < 1 / rotationSpeed ; time += Time.deltaTime )
        {
            Quaternion rotation = Quaternion.Slerp( startRotation, endRotation, time * rotationSpeed );
            Vector3 d = rotation * direction;
            SetNewPointCPosition( d + pointA );

            yield return null;
        }
    }

    private void OnPointCChanged( Vector3 newPosition )
    {
        Debug.Log( newPosition );
    }
}
\$\endgroup\$
  • \$\begingroup\$ I am not too sure how to get the transform for A and B. \$\endgroup\$ – SuperHyperMegaSomething Dec 12 '17 at 15:26
  • \$\begingroup\$ You have to attach this script to the objectC, and then drag & drop the objects A and B into the public fields, in the inspector. \$\endgroup\$ – Hellium Dec 12 '17 at 15:32
  • \$\begingroup\$ Okay, maybe I didn't explain it well enough. C is an object but A and B are the end points of a line made with a line renderer. \$\endgroup\$ – SuperHyperMegaSomething Dec 12 '17 at 15:37
  • \$\begingroup\$ My bad, I've edited my answer so that you can pass two vectors as end points of your LineRenderer \$\endgroup\$ – Hellium Dec 12 '17 at 15:42
  • 1
    \$\begingroup\$ Thanks, it's working. I'd like to know. What happens if A and C are points and also form a line. How would line AC be aligned to line AB? \$\endgroup\$ – SuperHyperMegaSomething Dec 12 '17 at 16:53
0
\$\begingroup\$

The signed angle between two 2d vectors A and B is

angle = atan2(-B.y * A.x + B.x * A.y, B.x * A.y + B.y * A.y)

If you have a signed angle between the point and the line, then rotating the former towards the latter is as simple as checking for the sign of the angle. If it's positive, then subtract from the current angle. If it's negative, then add to it.

In code (step is the angle the point rotates in one frame):

IEnumerator Rotate(Vector2 A, Vector2 B) {
    float angle;
    do {
        angle = Mathf.atan2(-B.y * A.x + B.x * A.y, B.x * A.y + B.y * A.y);
        if (angle < 0) {
            // Rotate the point by 1 step in the positive direction
        } else {
            // Rotate the point by 1 step in the negative direction
        }
    } while (angle > step);
    // Set the angle of the point to the angle of the line
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.