Making an object rotate to face another

Discussion in 'Scripting' started by jeremyace, Jan 18, 2006.

  1. jeremyace

    jeremyace

    New Member

    Joined:
    Oct 12, 2005
    Messages:
    1,661
    Hey guys,

    I want my object to rotate to face a moving target object BUT I want it to turn slowly towards the target with a lag. Like a huge rock rotating, it isn't going to happen instantly.

    transform.LookAt doesn't work because it obviously 'snaps' to the target, and I can't figure out how to use RotateTowards. I even tried modifying eulerAngles, and so on but I was out to lunch. The only useful thing I can do with vector math right now is get a vector that points from one object to another by subtracting one from the other. Wow, skill. :eek:

    If someone could point me in the right direction it would be great, I have a pretty good idea of what needs to happen, but no clue on implementing it with Unity.

    Thanks guys,
    -Jeremy
  2. NicholasFrancis

    NicholasFrancis

    Member

    Joined:
    Apr 8, 2005
    Messages:
    1,588
  3. jeremyace

    jeremyace

    New Member

    Joined:
    Oct 12, 2005
    Messages:
    1,661
    Wow, certainly beyond me. Thanks a lot Nicholas, I will try this tomorrow and try to figure out how it all works. I am fine up until the Math.Min and the Lerp. :eek:

    Thanks a lot,
    -Jeremy
  4. NicholasFrancis

    NicholasFrancis

    Member

    Joined:
    Apr 8, 2005
    Messages:
    1,588
    The trick is to remember that a Quaternion is a rotation.

    This line figures out the rotation from this object to the target
    Code (csharp):
    This line Lerps the rotation from where we're looking now towards the object. 'str' is how much we lerp.
    Code (csharp):
    1.  
    2. transform.rotation = Quaternion.Lerp (transform.rotation, targetRotation, str);
    3.  
    You want to be framerate-independant, so how much you lerp will be the 'strength' property multiplied by the time of the last frame. Thing is: if you have a very strong strength a very slow machine, you might end up with a lerp factor that is greater than one, causing overshoot. This line figures out how much you want to lerp, and makes sure that doesn't happen.

    Code (csharp):
    1.  
    2. str = Mathf.Min (strength * Time.deltaTime, 1);
    3.  
    EDIT: Oh, and you might want to rename Update to LateUpdate. This will make sure the rotation gets fixed just before rendering, so you don't risk that you look at where the object is before the object moves - resulting in a 1-frame lag.
  5. jeremyace

    jeremyace

    New Member

    Joined:
    Oct 12, 2005
    Messages:
    1,661
    Thanks a lot for taking the time to explain that to me Nicholas. I think I am understanding it now, and I googled Lerp to find out what it does. I just figured out I will have to use similar concepts in the next part of my script so this is very good.

    Thank you very much for your time, this makes me very happy as I have been working for quite a while as it's 6:00am here. :)

    -Jeremy
  6. jeremyace

    jeremyace

    New Member

    Joined:
    Oct 12, 2005
    Messages:
    1,661
    UPDATE: All is working perfectly. Thanks.

    I am working on learning AI in Unity and this code was for Steering behaviours. I will put my finished code on the wiki later as someone may get some use out of it. What I have already is good for a space game.

    I may even get to writing flocking code and other group behaviours eventually :)

    -Jeremy
  7. Ajaxamander

    Ajaxamander

    New Member

    Joined:
    Jul 5, 2005
    Messages:
    36
    So, to carry this out to another direction (no pun intended.) Can you "average" quaternions? I'm working on a flocking behaviour for some of my game objects, and I'm curious if I can take the raw rotations and average several of them and still come out with a legit rotation. Can quaternions be divided?
  8. jeremyace

    jeremyace

    New Member

    Joined:
    Oct 12, 2005
    Messages:
    1,661
    You would probably want to use euler angles for that to simplify things as euler angles are Vector3's and quats have 4 elements (x,y,z,w). You can do just about everything to a Vector3. Take a look at the docs for the Vector3 class and Quaternion.ToEulerAngles().

    For the steering behaviour stuff I did, I used Vectors to calculate the steering force for whatever behaviour, and I had a seperate locomotion function to apply the force to my agent. That way for your flocking you can calculate the behaviours needed for flocking (alignment, seperation, cohesion, etc), mix the behaviours with whatever method, and do your movement seperately.

    I haven't done flocking just yet, The main hurdle seems to be figuring a way to partition the game world for speed. Just out of curiosity, how many objects are going to be flocking? What type of behaviour(s) are you going to implement? I would really be interested to hear how you get this going.

    Hope that helps a bit,
    -Jeremy
  9. Ajaxamander

    Ajaxamander

    New Member

    Joined:
    Jul 5, 2005
    Messages:
    36
    My gut instinct was to use Euler angles, but what happens when the Boid I'm currently examining for an update is heading due north (0°), and hir neighbors are aimed slightly to the left and right... 355° and 5° respectively. When I average those, I'll end up with the boid wanting to steer due south (180°) which clearly isn't what it should be doing (for the Alignment component of the behaviour)

    Is there some clever trick I'm overlooking? Adding some value or doing some RMS kind of thing... or are Euler angles just shot?

    Oh, and it might be helpful to point out that it's going to be a herd of cattle, so the behaviour is essentially "in the plane" of the ground (So only the Euler[1] really matters, as far as I can tell)
  10. jeremyace

    jeremyace

    New Member

    Joined:
    Oct 12, 2005
    Messages:
    1,661
    It would really help to figure it out if you posted a code snippet.

    It is really nice that you are just working on a flat plane so you only have to worry about the x and z components of the vector.

    I still think you can do this with euler angles...

    The way I learned to do flocking (have never written the code just learned it) is you calulate the three behaviours I mentioned (alignment, seperation, cohesion) and then through a method to combine them (prioritized dithering, etc) you calculate the steering force Vector (direction and force) of each boid.

    But to script cows, you could probaly go a LOT simpler. For example, are they going to be used to fill an area and basically eat and wander around, or are they going to be running? If they are just in a field, you could just use a wander behaviour for each cow and you check that your cow stays within a distance from the "lead" cow. When it get too far away from the lead, it will turn towards lead and move towards it (arrive behaviour) and then resume wander once it is back in the radius.

    If they are running, then it will be harder.

    -Jeremy
  11. jeremyace

    jeremyace

    New Member

    Joined:
    Oct 12, 2005
    Messages:
    1,661
    Actually, I think you could get away with using my suggestion above for running cows as well with a few adjustments. You would want to mix the Arrive behaviour with the seperation behaviour, cohesion would already be taken care of because of arrive, and that way when your lead cow starts running, all of the other follow suit. Then when they are stopped, the wander behaviour kicks in automatically.

    -Jeremy
  12. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Messages:
    3,526
    Basically yes you can. There is one thing you need to watch out for called the double cover operator, it means quaternions have 720 degrees of rotation.

    Thus you need to adjust for it.
    You can check if two quaternions are more than 360 degrees arpart using
    Quaternion.Dot (a, b) < 0

    To make a quaternion go to the right side of the 720 degrees you multiply all components by -1.

    So yes it is possible and it is not completely straightforward too. Thats why we haven't exposed all math operators to our quaternion class. Except for multiplying rotations and Lerp/Slerp it is not really intuitive what you can do with quaternions and what not.

    If you just use Slerp and multiplication the dirty stuff will be handled for you.

    Code (csharp):
    1.  
    2. var Quaternion[] quats;
    3.  
    4. Quaternion avg = Quaternion(0,0,0,0);
    5. for (var q : Quaternion in quats)
    6. {
    7.     if (Quaternion.Dot (q, avg) > 0)
    8.     {
    9.        avg.x += q.x;
    10.        avg.y += q.y ;
    11.        avg.z += q.z;
    12.        avg.w += q.w;
    13.     }
    14.     else
    15.     {
    16.        avg.x += -q.x;
    17.        avg.y += -q.y;
    18.        avg.z += -q.z;
    19.        avg.w += -q.w;
    20.     }
    21. }
    22.  
    23. var mag = Mathf.Sqrt(avg.x* avg.x + avg.y* avg.y + avg.z * avg.z + avg.w * avg.w);
    24.  
    25. if (mag > 0.0001)
    26. {
    27.    avg.x /= mag;
    28.    avg.y /= mag;
    29.    avg.z /= mag;
    30.    avg.w /= mag;
    31. }
    32. else
    33.    avg = quats[0];
    34.  
    Edit: I edited the code not to multiply by weights
  13. Ajaxamander

    Ajaxamander

    New Member

    Joined:
    Jul 5, 2005
    Messages:
    36
    Holy crap. This is the part where I wish I'd taken that Linear Algebra class in school.

    But, it does make sense conceptually (the averaging, not necessarily the multiplication)

    Once again, Joe, you've proven that you are, without a doubt The Man
  14. Ajaxamander

    Ajaxamander

    New Member

    Joined:
    Jul 5, 2005
    Messages:
    36
    Wait... perhaps excuse my early morning stupidity... but what language is that snippet in? It looks like a sort of blend of C# and JavaScript. Or is it more of a "Forum Pseudocode" kind of thing?

    Or have I just been stuck in PHP land for so long that my language skills are eroding?
  15. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Messages:
    3,526
    It's supposed to be javascript but i didn't try it before posting it.
    Actually the weight multiplication is kind of weird and not necessary since we renormalize the quaternion at the end anyway.