Search Unity

controlling rotation of object attached to camera

Discussion in 'Scripting' started by kakubei2, Jun 29, 2009.

  1. kakubei2

    kakubei2

    Joined:
    Jun 10, 2009
    Posts:
    31
    Hello again,

    I have a bird that is a child of a First Person Controller. This controller has a camera and has a mouselook and an FPSWalker script attached to it so that it acts as a first person controller camera.

    When I rotate the controller, the bird (gameObject) rotates with it, perfect.

    What I want to do is tilt the bird when the controller moves sideways and vertically.

    I am using this script from the manual:
    Code (csharp):
    1.    
    2. var halcon = GameObject;
    3. var tiltAroundZ = Input.GetAxis("Horizontal") * tiltAngle;
    4.     var tiltAroundX = Input.GetAxis("Vertical") * tiltAngle;
    5.     var target = Quaternion.Euler (tiltAroundX, 0, tiltAroundZ);
    6.     // Dampen towards the target rotation
    7.     halcon.transform.rotation = Quaternion.Slerp(transform.rotation, target,    Time.deltaTime * smooth);
    but the gameObject is jittery because since it is a child of the controller, the controller is told to point in the direction of the mouse, so the bird is tilting then going back to zero, then tilting, then going back to zero, every frame.

    So obviously I'm doing this wrong. What would be the simplest approach to tilt said bird?

    I'm thinking that getting the current rotation of the controller then adding some more tilt to the bird might do the trick, but this eludes me at the moment.

    I should clarify that the only way I was able to get the camera trick to work was to add the script that controls the bird to the controller and then (since the bird is a child of the camera) calling it's properties with a GameObject variable where I drag the bird game object to.

    Hope this makes sense and thanks in advance.
     
  2. attilam

    attilam

    Joined:
    Jun 2, 2007
    Posts:
    86
    Hm... not sure if this is what you'd like to see, but wouldn't using transform.localRotation instead of transform.rotation solve this problem?

    so basically changing the last line in your example to

    Code (csharp):
    1.  
    2. transform.localRotation = Quaternion.Slerp(transform.localRotation, target,   Time.deltaTime * smooth);
    3.  
     
  3. kakubei2

    kakubei2

    Joined:
    Jun 10, 2009
    Posts:
    31
    Hello, the localRotation change makes it less jittery, but there is still jitter in the rotation.
     
  4. attilam

    attilam

    Joined:
    Jun 2, 2007
    Posts:
    86
    I just tried this:

    I got an FPS controller from Standard Assets, parented an object representing the bird on the camera and I created a small script based on your snippet, which I put on the bird:

    Code (csharp):
    1.  
    2. var tiltAngle : float = 30.0;
    3. var smooth : float = 5.0;
    4.  
    5. function Update () {
    6.  
    7.     var tiltAroundZ = Input.GetAxis("Horizontal") * tiltAngle;
    8.     var tiltAroundX = Input.GetAxis("Vertical") * tiltAngle;
    9.     var target = Quaternion.Euler (tiltAroundX, 0, tiltAroundZ);
    10.     // Dampen towards the target rotation
    11.     transform.localRotation = Quaternion.Slerp(transform.localRotation, target,   Time.deltaTime * smooth);
    12. }
    13.  
    Nice and smooth, no jitter (maybe there's a misunderstanding here, I assume you want to create something that looks as if the bird would "lean into" turning).
     
  5. kakubei2

    kakubei2

    Joined:
    Jun 10, 2009
    Posts:
    31
    That is correct. I just tried you code, which as far as I can see the only change is the localRotation, and I get the same thing. 2 problems:

    1. Jittery movement.
    2. instead of leaning into the turn the bird rotates completely.

    I need to limit the rotation so that it only leans into the turn a bit. I realize I am missing some limiter scripting here, but am not sure how to do it.

    It does bother me that you don't get the jittery movement but I do. I am attaching an image of the hierarchy of the bird.
     

    Attached Files:

  6. attilam

    attilam

    Joined:
    Jun 2, 2007
    Posts:
    86
    Hm... I attached the bird under the Camera object in my hierarchy, but the only difference should be, that in your version the bird would stay at the same height relative to the player (since it's only affected by MouseX rotation in the MouseLook component).

    Maybe it has to do with the values you set for tiltAngle and smooth?
     
  7. cyb3rmaniak

    cyb3rmaniak

    Joined:
    Dec 10, 2007
    Posts:
    162
    The mouselook script rotates your FPS parent object every frame... If you assign your bird rotation script to the parent as you posted it, it will try to turn the bird object based on the parent's local rotation...

    This is not what you want...

    You need the hierarchy to look like this:

    Parent FPS (MouseLook, Character Controller, FPSWalker)
    |
    --- Bird (BirdLocalRotator)
    --- Camera

    Imagine that if you didn't have the script that rotates the bird - it's local rotation would always be 0,0,0. Since it's not really rotating relative to it's parent.

    What you want your script to do is exactly that - rotate it locally from 0,0,0 (which is when the bird is looking straight ahead) to some other angle.
    So take the edited script that indy138 posted (with the localRotation, instead of rotation) and assign it to the bird game object. Not the parent.

    Why couldn't you get it to work when the script was directly on the bird? Why did you need to put it on the parent and turn the bird using a reference?
     
  8. kakubei2

    kakubei2

    Joined:
    Jun 10, 2009
    Posts:
    31
    Sorry, I was out yesterday afternoon:

    1. cyb3r, that's the hieararchy I have.
    2. I didn't explain myself properly: the reason I didn't attach the script to the bird was because I needed to get some values from its parent and using the parent functions was not working, so I attached it to the parent and was able to get the child's values no problem. If I change the script I believe it will be the exact same thing as this (which by the way is what I have, let me ammend the code):

    Code (csharp):
    1. var halcon = GameObject;
    2. halcon.transform.localRotation...
    and don't think it will change anything, but I can certainly give it a try.

    indy138,
    The values I have for tiltAngle and smooth are the default of the manual example. Sure, I could change them, but all they do is multiply. There is something that is calling my bird back to the direction the controller is facing and that's what I can't figure out.

    I should also clarify that that is part 1 of the mystery, part 2 is making the bird just tilt to an angle (say 20 degrees max), not rotate, but one thing at a time :)

    And thanks for all the suggestions. Keep them coming please.
     
  9. cyb3rmaniak

    cyb3rmaniak

    Joined:
    Dec 10, 2007
    Posts:
    162
    It will really help if you attach a sample scene to check out. When I tried to reproduce your scene from the description I didn't have the problem you described...
    It behaved just fine.

    Just create an empty scene with a textured plain that the character is standing on, and export it with dependencies so we can get exactly what you're getting...

    And tilting will be easy enough once your problem goes away BTW :)
     
  10. kakubei2

    kakubei2

    Joined:
    Jun 10, 2009
    Posts:
    31
    Will do. I'll simplify things a bit and upload it.

    Thanks!
     
  11. kakubei2

    kakubei2

    Joined:
    Jun 10, 2009
    Posts:
    31
    Hello, wasn't able to export the scene successfully because it is too filled with copyrighted material which made it a nightmare.

    Anyway, I am getting closer. I've discovered that if I attach the script to the bird it works, if I attach it to the controller it doesn't work, even if I specify the bird game object.

    So, the following works great when I press the keys:
    Code (csharp):
    1.     var tiltAroundZ = Input.GetAxis("Horizontal") * tiltAngleHorizontal * -1;
    2.     var tiltAroundX = Input.GetAxis("Vertical") * tiltAngleVertical;
    3.     var target = Quaternion.Euler (tiltAroundX, 0, tiltAroundZ);
    4.     // Dampen towards the target rotation
    5.     transform.localRotation = Quaternion.Slerp(transform.localRotation, target, Time.deltaTime * smooth);
    But I want the bird to tilt when I move the mouse, I have this and it, of course rotates crazily:

    Code (csharp):
    1.     var cameraX = fps.transform.eulerAngles.x;
    2.     var cameraY = fps.transform.eulerAngles.y;
    3.    
    4.         // Smoothly tilts a transform towards a target rotation.
    5.     var tiltAroundZ = cameraX * tiltAngleHorizontal * -1;
    6.     var tiltAroundX = cameraY * tiltAngleVertical;
    7.     var target = Quaternion.Euler (tiltAroundX, 0, tiltAroundZ);
    8.     // Dampen towards the target rotation
    9.     transform.localRotation = Quaternion.Slerp(transform.localRotation, target, Time.deltaTime * smooth);
    fps is the controller.

    So I'm getting closer. If any kind soul can direct me to limit the rotation of the bird I think I'll have this licked.
     
  12. attilam

    attilam

    Joined:
    Jun 2, 2007
    Posts:
    86
    Looking at your script, multiplying the cameraX Y variables with the tiltAngle ones in the second script looks very suspicious, and could be the cause for the jittery movement :)

    If the only difference you need is that the bird reacts to mouse movement instead of key press, then you could just change the GetAxis() calls in the first script so they refer to Mouse X and Mouse Y instead of Horizontal and Vertical (assuming you have the default Input Manager settings of course).
     
  13. cyb3rmaniak

    cyb3rmaniak

    Joined:
    Dec 10, 2007
    Posts:
    162
    You don't need this... you don't really care about the rotation of the parent. You're working with the local rotation of the bird, so no need to reference the parent at all... All you need to do is read the mouse axis.
    Even if you wanted to skip this, and use the rotation of the parent, you would have to store the last rotation of the parent and only if it changed calculate the tilting (since I imagine you want the bird to come back to no-tilt when the rotation is over).

    To make things short, try putting this on the duck:
    Code (csharp):
    1.  
    2.    var fSensitivity: float = 5.0;
    3.    var tiltAroundZ = Mathf.Clamp(Input.GetAxis("Mouse X") * fSensitivity) * tiltAngleHorizontal * -1, -1, 1);
    4.    var tiltAroundX = Mathf.Clamp(Input.GetAxis("Mouse Y") * fSensitivity) * tiltAngleVertical, -1, 1);
    5.    var target = Quaternion.Euler (tiltAroundX, 0, tiltAroundZ);
    6.    // Dampen towards the target rotation
    7.    transform.localRotation = Quaternion.Slerp(transform.localRotation, target,   Time.deltaTime * smooth);
    8.  
    You might need to play around with the sensitivity since the mouse axis is not between 0 and 1, it's a delta that is multiplied by the sensitivity settings you set in your project's Input preferences panel.
     
  14. kakubei2

    kakubei2

    Joined:
    Jun 10, 2009
    Posts:
    31
    Ok, I'm back. Sorry for the absence, had to go away and teach a Shake course...

    Thanks for all the suggestions.

    cyb3rmaniak, your code produces a bunch of errors I'm sorry to say:

    The first is unexpected token for the comas after titAngleHorizontal * -1,

    so I rewrote it like this:
    Code (csharp):
    1.    var tiltAroundZ = Mathf.Clamp(Input.GetAxis ("Mouse X") * fSensitivity * tiltAngleHorizontal * -1 ,1 ,1);
    2.    var tiltAroundX = Mathf.Clamp(Input.GetAxis ("Mouse Y") * fSensitivity * tiltAngleVertical * -1, 1, 1);
    It seems to like that. But the code doesn't work. All that happens is that the bird tilts a bit to the 0 position when I start playing the level. That is, its position is slightly tilted upward and with the code it slides down (very nicely) to stare straight on. But moving the mouse does nothing.

    Aha! Got it, the clamp function was preventing the code from doing its thing. That makes sense since it would get rid of any values that are not 1. So I got rid of the clamp and it works beautifully!

    Thank you sooooo much for all the help. I am very happy with my little bird now.

    Stay tuned for more asinine questions from me though, there's a bunch of other stuff I need it to do :D
     
  15. cyb3rmaniak

    cyb3rmaniak

    Joined:
    Dec 10, 2007
    Posts:
    162
    Good to hear it's working. Sorry about the typos, was (and still am) a bit tired lately.

    And about the clamp - the idea is to make the mouse input to act like the values you get from GetAxis() - which are between -1 and 1. I just didn't get the tiltAngleHorizontal outside the parenthesis...
    Without the typos and errors on my part, it should look something like this:

    Instead of:
    Code (csharp):
    1.  
    2. var tiltAroundZ = Mathf.Clamp(Input.GetAxis ("Mouse X") * fSensitivity * tiltAngleHorizontal * -1 ,1 ,1);
    3. var tiltAroundX = Mathf.Clamp(Input.GetAxis ("Mouse Y") * fSensitivity * tiltAngleVertical * -1, 1, 1);
    4.  
    Write:
    Code (csharp):
    1.  
    2. var tiltAroundZ = Mathf.Clamp(Input.GetAxis ("Mouse X") * fSensitivity * -1 ,1 ,1) * tiltAngleHorizontal;
    3. var tiltAroundX = Mathf.Clamp(Input.GetAxis ("Mouse Y") * fSensitivity * -1, 1, 1) * tiltAngleVertical;
    4.  
    Let's take tiltAroundZ as an example. This way, if the sensitivity is set as it should be:
    1. When the value returned from the Clamp functions is -1 -> The duck will get the exact rotation of -tiltAngleHorizontal.
    2. When the value returned from the Clamp functions is 1 -> The duck will get the exact rotation of +tiltAngleHorizontal.
    3. Any value between -1 and 1 will get an angle between -tiltAngleHorizontal and +tiltAngleHorizontal. This will happen when you move your mouse slowly.

    Obviously if you have it working just as you like it, leave it be. Just thought you might wanna learn this trick for future use :)
     
  16. kakubei2

    kakubei2

    Joined:
    Jun 10, 2009
    Posts:
    31
    Yes, the trick is great, I'll try it. I had actually simplified the code so as not to have 2 variables affecting the rotation.

    But I'll try it your way and see what happens.

    Thanks again.