Search Unity

Gradual rotation change

Discussion in 'Scripting' started by MinatureCookie, Sep 19, 2010.

  1. MinatureCookie

    MinatureCookie

    Joined:
    Jun 13, 2010
    Posts:
    25
    Hey guys,

    I'm trying to get an object to look towards my character at all times - but gradually, rather than looking instantly.

    I know this isn't a really clear description; but I mean like Quaternion.Slerp - except if that function had a maximum speed of rotation. What happens is if you walk towards the object and then past it, it shoots around and is looking directly at you. I want it to turn around at a constant speed.

    I've tried checking the euler angles and increasing or decreasing by a fixed amount according to their difference... But it gets really messy and starts breaking.

    I'm hoping there is a better way to go about doing this?

    Thanks for any help in advance, it's greatly appreciated.
    Stephen
     
  2. Slem

    Slem

    Joined:
    Jan 28, 2009
    Posts:
    191
    http://unity3d.com/support/documentation/ScriptReference/Quaternion.LookRotation.html

    This method creates the rotation and then you can use Quaternion.Lerp. To achieve constant rotation you can use Time.time multiplied by a variable Speed for example to get a constant rotation.

    Not tested code:
    Code (csharp):
    1.  
    2. public float RotationSpeed = 0.01f;
    3.  
    4. void Update()
    5. {
    6.  
    7. //create rotation
    8. Quaternion wantedRotation = Quaternion.LookRotation(player.position - transform.position);
    9.  
    10. //then rotate
    11. transform.rotation = Quaternion.Lerp(transform.rotation, wantedRotation, Time.time * RotationSpeed);
    12.  
    13. }
     
  3. MinatureCookie

    MinatureCookie

    Joined:
    Jun 13, 2010
    Posts:
    25
    Sorry - I probably wasn't clear enough.

    That code you just provided is basically what I already have. The problem with that being that when you pass right by the rotating object, rather than it spinning round at a steady speed until it finds you... It hurtles round ridiculously fast.
    And if I decrease the rotationSpeed in the Lerp function - then it turns too slowly normally.

    What I want is for it to do the Lerp function, but, say, at a constant turning rate of 5 degrees per second or something? How could I go about achieving this?
     
    Cambesa likes this.
  4. Jesse Anders

    Jesse Anders

    Joined:
    Apr 5, 2008
    Posts:
    2,857
    I'm assuming this is essentially a 2-d problem, and that the character remains aligned with the world 'up' vector while rotating.

    One way to do this would be to transform the position of the target object into the local space of the agent, and use the resulting point to determine which direction to turn. Strictly speaking you don't actually have to perform a full transformation, but to keep things simple I'd recommend using Transform.InverseTransformPoint() for this.

    Once you have the local-space position of the target, you can use the x element to determine which way to turn, e.g. (untested):

    Code (csharp):
    1. Vector3 localTarget = transform.InverseTransformPoint(target.position);
    2. if (localTarget.x < -threshold) {
    3.     transform.Rotate(0f, -rotationSpeed * Time.deltaTime, 0f);
    4. } else if (localTarget.x > threshold) {
    5.     transform.Rotate(0f, rotationSpeed * Time.deltaTime, 0f);
    6. }
    The threshold value is intended to keep the agent from 'jittering' when the target is more or less directly ahead. There are better ways to handle that aspect of things; the above is only intended to serve as a simple example.

    Note also that with the above code, the agent will not respond when the target is directly behind them. That can easily be fixed with a little extra code. Another option would be to add a field-of-view check, so that the agent only turns towards the player if the player is within the agent's field of view.
     
  5. MinatureCookie

    MinatureCookie

    Joined:
    Jun 13, 2010
    Posts:
    25
    Ahhh that's brilliant! :D

    I'm pretty sure I can handle the rest. If the objects behind you, then you just need to check the z axis, if it's negative, then keep turning until it no longer is. Right?
     
  6. tomvds

    tomvds

    Joined:
    Oct 10, 2008
    Posts:
    1,028
    I find these problems easier solved without using rotation at all. This script looks at 'target' rotating with a maximum speed. It does not have any limitation to the rotation axis. It works for every positioning of the target, except that it will probably have some strange jumps when the target is directly above or below it (due to not managing the objects up vector at all).

    Code (csharp):
    1. sing UnityEngine;
    2. using System.Collections;
    3.  
    4. public class LookAtRotator : MonoBehaviour
    5. {
    6.     // the target too look at
    7.     public Transform    target;
    8.     // rotationSpeed is the usual slerp speed factor
    9.     // maxAnglePerSecond is the maximum angle travelled per second (in degrees)
    10.     public float        rotationSpeed        = 2f,
    11.                         maxAnglePerSecond    = 10f;
    12.     void Update()
    13.     {
    14.         // first calculate the look vector as normal
    15.         Vector3 targetDirection = (target.position - transform.position).normalized;
    16.         Vector3 currentForward = transform.forward;
    17.         Vector3 newForward = Vector3.Slerp(currentForward, targetDirection, Time.deltaTime * rotationSpeed);
    18.  
    19.         // now check if the new vector is rotating more than allowed
    20.         float angle = Vector3.Angle(currentForward, newForward);
    21.         float maxAngle = maxAnglePerSecond * Time.deltaTime;
    22.         if (angle > maxAngle)
    23.         {
    24.             // it's rotating too fast, clamp the vector
    25.             newForward = Vector3.Slerp(currentForward, newForward, maxAngle / angle);
    26.         }
    27.  
    28.         // assign the new forward to the transform
    29.         transform.forward = newForward;
    30.     }
    31. }
    32.  
     
    Jasperle likes this.