Search Unity

  1. Unity 2019.2 is now released.
    Dismiss Notice

A Free Simple Smooth Mouselook

Discussion in 'Scripting' started by FatiguedArtist, Jan 7, 2011.

  1. Stardog

    Stardog

    Joined:
    Jun 28, 2010
    Posts:
    1,374
    It's free code.
     
  2. AdamGoodrich

    AdamGoodrich

    Joined:
    Feb 12, 2013
    Posts:
    3,638
    As it was posted here I figured this was the case and thanks :)
     
  3. Prestij2k17

    Prestij2k17

    Joined:
    Jul 8, 2017
    Posts:
    1
    when i select a character body camera doesnt turn right and left?
     
  4. indevious

    indevious

    Joined:
    Nov 29, 2017
    Posts:
    16
    Works for me as-is in latest stable Unity 2017.2.
     
  5. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    807
    The coding is a little odd. I'd say this maybe (to quote SM) "is not a good script" for someone wanting to study it to learn rotations and non-Unity coding. But that's not why you posted it. But just to answer you Q, little things:

    o targetDirection is useless in 2 ways. It converts the starting rotation to eulerAngles, but you never use eulerAngles (like 90 degrees... ) for anything. All it does is convert back into the original rotation. You could just put "Quaternion targetOrientation = transform.rotation;" in Start.

    o Notice how I changed your "var" in the declaration into "Quaternion" in the line above. When people see "var" they think "long, complex type which I won't need to know anyway." Now, I realize javascript encouraged this, and Quaternion _was_ considered a confusing type, and the script works the exact same ether way.

    o IMHO, "if(characterBody==null)" is more common. It emphases we're checking existence of a pointer. Otherwise it looks more like checking a boolean (like your use of "if(lockCursor)".)

    o Use of single ampersand(&) inside if's (not a big deal here, but you can look up how && and || are slightly better, and & is really a hack.)

    But again, the only possible reason this might matter is for someone trying to use this script to teach themselves non-Unity coding. And I'd argue we shouldn't encourage people to learn coding-by-example anyway. Otherwise it looks like a standard old-style Unity script. There's plenty of worse stuff people are copying and using.
     
    indevious likes this.
  6. flintmech

    flintmech

    Joined:
    Sep 29, 2011
    Posts:
    15
    I've been trying to implement a simple mouselook script with one particular caveat:

    I only want the camera to rotate with the mouse when a button is held down, and when the button is not held down, the mouse cursor should unlock and the user can then interact with UI without the camera rotating.

    The problem is that when toggling Cursor.lockState to Locked, the mouse pointer jumps to the center of the window and this screws with the calculations, resulting in a very jarring jump in rotation of the camera every time the button is pressed and the mouse is moved. This isn't even unique to toggling locked on/off - having the script lock the mouse cursor from the get-go causes the jump to occur as soon as the script initializes in play mode.

    Another user posted a thread describing what sounds like the same issue here and later announced that the fix for their problem had been incorporated in @FatiguedArtist's script, but it still doesn't seem to be working for me.

    I have tried OP's script in this thread, as well as others online and the MouseLook.cs from StandardAssets/Characters/FirstPersonCharacter. All of these scripts are written to track the mouse at all times. Any attempt I've made to restrict it to a condition and with the Cursor locked has failed.

    The underlying problem itself seems to be the jump of the mouse cursor to the screen center when locked. I don't know if it's a Unity bug or not, but I'm at my wit's end. Anybody have any ideas?
     
    Last edited: Jan 3, 2018
  7. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,713
    I have not paid any attention to the script from this thread, but...

    This is what I use to move my mouse (well, obviously just a tiny part of my script), but it works with the cursor locked & hidden.
    Code (csharp):
    1.  
    2. float x = Input.GetAxis("Mouse X");
    3. transform.rotation *= Quaternion.Euler(new Vector3(0, x * mouseSensitivity, 0));
    4.  
    Hope that helps.
     
  8. flintmech

    flintmech

    Joined:
    Sep 29, 2011
    Posts:
    15
    The rotation logic itself isn't the problem. The issue is that, after locking the cursor, for just one frame there is a jump in rotation that doesn't match the mouse movement, seemingly because the cursor's travel distance to the center of the window (a result of the locking) is factored into the GetAxis value.
     
  9. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,713
    Hm.. Not sure; afaik, that doesn't appear to happen with my mouse look.
     
  10. yamiyammes

    yamiyammes

    Joined:
    Dec 31, 2017
    Posts:
    1
    Wow, Your script is Amazing!
    Thank you so much, this is just what I needed for my school project.

    I'll be sure to mention your name.
     
  11. Invertex

    Invertex

    Joined:
    Nov 7, 2013
    Posts:
    927
    A user was requesting help making this script have a relative UP axis so that they could rotate their character and have the camera work relative to that rotation. I have proposed a small change and a toggle for such a feature in this version of it:

    Code (csharp):
    1. using UnityEngine;
    2.  
    3. [AddComponentMenu("Camera/Simple Smooth Mouse Look ")]
    4. public class SimpleMouseLook : MonoBehaviour
    5. {
    6.     Vector2 _mouseAbsolute;
    7.     Vector2 _smoothMouse;
    8.  
    9.     public Vector2 clampInDegrees = new Vector2(360, 180);
    10.     public bool lockCursor;
    11.     public Vector2 sensitivity = new Vector2(2, 2);
    12.     public Vector2 smoothing = new Vector2(3, 3);
    13.     public Vector2 targetDirection;
    14.     public Vector2 targetCharacterDirection;
    15.     //Rotate camera relative to its parent's rotation so the camera can work in any relative orientation
    16.     //Does nothing if the camera has no parent
    17.     public bool relativeUpAxis = true;
    18.     // Assign this if there's a parent object controlling motion, such as a Character Controller.
    19.     // Yaw rotation will affect this object instead of the camera if set.
    20.     public GameObject characterBody;
    21.  
    22.     void Start()
    23.     {
    24.         // Set target direction to the camera's initial orientation.
    25.         targetDirection = transform.localRotation.eulerAngles;
    26.  
    27.         // Set target direction for the character body to its inital state.
    28.         if (characterBody)
    29.             targetCharacterDirection = characterBody.transform.localRotation.eulerAngles;
    30.     }
    31.  
    32.     void Update()
    33.     {
    34.         // Ensure the cursor is always locked when set
    35.         if (lockCursor)
    36.         {
    37.             Cursor.lockState = CursorLockMode.Locked;
    38.         }
    39.  
    40.         // Allow the script to clamp based on a desired target value.
    41.         var targetOrientation = Quaternion.Euler(targetDirection);
    42.         var targetCharacterOrientation = Quaternion.Euler(targetCharacterDirection);
    43.  
    44.         // Get raw mouse input for a cleaner reading on more sensitive mice.
    45.         var mouseDelta = new Vector2(Input.GetAxisRaw("Mouse X"), Input.GetAxisRaw("Mouse Y"));
    46.  
    47.         // Scale input against the sensitivity setting and multiply that against the smoothing value.
    48.         mouseDelta = Vector2.Scale(mouseDelta, new Vector2(sensitivity.x * smoothing.x, sensitivity.y * smoothing.y));
    49.  
    50.         // Interpolate mouse movement over time to apply smoothing delta.
    51.         _smoothMouse.x = Mathf.Lerp(_smoothMouse.x, mouseDelta.x, 1f / smoothing.x);
    52.         _smoothMouse.y = Mathf.Lerp(_smoothMouse.y, mouseDelta.y, 1f / smoothing.y);
    53.  
    54.         // Find the absolute mouse movement value from point zero.
    55.         _mouseAbsolute += _smoothMouse;
    56.  
    57.         // Clamp and apply the local x value first, so as not to be affected by world transforms.
    58.         if (clampInDegrees.x < 360)
    59.             _mouseAbsolute.x = Mathf.Clamp(_mouseAbsolute.x, -clampInDegrees.x * 0.5f, clampInDegrees.x * 0.5f);
    60.  
    61.         // Then clamp and apply the global y value.
    62.         if (clampInDegrees.y < 360)
    63.             _mouseAbsolute.y = Mathf.Clamp(_mouseAbsolute.y, -clampInDegrees.y * 0.5f, clampInDegrees.y * 0.5f);
    64.  
    65.         transform.localRotation = Quaternion.AngleAxis(-_mouseAbsolute.y, targetOrientation * Vector3.right) * targetOrientation;
    66.  
    67.         // If there's a character body that acts as a parent to the camera
    68.         if (characterBody)
    69.         {
    70.             var yRotation = Quaternion.AngleAxis(_mouseAbsolute.x, Vector3.up);
    71.             characterBody.transform.localRotation = yRotation;
    72.         }
    73.         else
    74.         {
    75.             var upAxis = (relativeUpAxis && transform.parent != null) ? transform.parent.up : Vector3.up;
    76.             var yRotation = Quaternion.AngleAxis(_mouseAbsolute.x, transform.InverseTransformDirection(upAxis));
    77.             transform.localRotation *= yRotation;
    78.         }
    79.     }
    80. }
    81.  
    What version of Unity are you using? I am not seeing this issue in 2017.3.
     
  12. Enrico-Monese

    Enrico-Monese

    Joined:
    Dec 18, 2015
    Posts:
    56
    I also get that weird jump in rotation. Not locking the cursor doesn't fix it so I don't thunks thats the problem. It only started occurring recently. I'm on 2018.1 beta 4, maybe its a new regression if it doesn't occur in older versions.

    Edit: This has been fixed as of beta 11
     
    Last edited: Mar 24, 2018
  13. yotingo

    yotingo

    Joined:
    Jul 10, 2013
    Posts:
    38
    How would I unlock the camera from the character body at run-time, without causing the camera to jump?

    I want the ability to unlock and freely spin the camera around the character, then re-align the character to the camera direction. It's okay if the character jumps to camera rotation but not the camera jumping to character. I can't figure it out for the life of me.

    Thanks for the script! I have been using it with my character controller for months now.
     
  14. CallumEdwards

    CallumEdwards

    Joined:
    Apr 4, 2018
    Posts:
    1
  15. HonoraryBob

    HonoraryBob

    Joined:
    May 26, 2011
    Posts:
    1,101
    I've been using this script, which works fine except when I unlock the mouse to allow the user to access a menu and then lock it again to resume the game, the camera either moves upwards toward the ceiling (if the last click on a menu option was above middle of screen) or snaps back to facing backwards if I try to compensate for that. What's the proper method of setting it to the correct direction after relocking the mouse?
     
  16. Marrt

    Marrt

    Joined:
    Feb 7, 2012
    Posts:
    528
    I didn't test it but just skip the code in Update entirely as long as you are unlocked. Because this line will continue to fetch mousemovements
    Code (CSharp):
    1.  _mouseAbsolute += _smoothMouse;

    But how about a completely different script:
    It is a compressed version of the stuff i mostly use i just cobbled together for you to test. The buffer-class contained is needed for framerate independent smoothing

    Features:
    - frame rate independent smoothing
    - pitch clamping
    - smoothing-bypass
    - on/off switch
    - cursor LockState control coupled to on/off, if needed

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. //Marrt's simplest Mouselook for https://forum.unity.com/threads/a-free-simple-smooth-mouselook.73117/page-2
    4.  
    5. public class SimplestSmoothedMouseLook : MonoBehaviour {
    6.  
    7.     [Header("CameraTransform")]
    8.     public    Transform    targetTrans;
    9.     [Header("On/Off & Settings")]
    10.     public    bool        inputActive        = true;
    11.     public    bool        controlCursor    = false;
    12.     public    bool        pitchClamp        = true;
    13.     [Header("Smoothing")]
    14.     public    bool        byPassSmoothing    = false;
    15.     public    float        mLambda            = 20F;    //higher = less latency but also less smoothing
    16.     [Header("Sensitivity")]
    17.     public    float        hSens            =  4F;
    18.     public    float        vSens            =  4F;
    19.     public    BufferV2    mouseBuffer        = new BufferV2();
    20.  
    21.     void Update ()
    22.     {
    23.         if(controlCursor){    //Cursor Control
    24.             if(  inputActive && Cursor.lockState != CursorLockMode.Locked)    { Cursor.lockState = CursorLockMode.Locked;    }
    25.             if( !inputActive && Cursor.lockState != CursorLockMode.None)    { Cursor.lockState = CursorLockMode.None;    }
    26.         }
    27.         if(!inputActive){ return; }    //active?
    28.  
    29.         //Update input
    30.         UpdateMouseBuffer();
    31.         targetTrans.rotation        = Quaternion.Euler( mouseBuffer.curAbs );
    32.     }
    33.  
    34.     //consider late Update for applying the rotation if your game needs it (e.g. if camera parents are rotated in Update for some reason)
    35.     void LateUpdate() {}
    36.  
    37.     private    void UpdateMouseBuffer()
    38.     {
    39.         mouseBuffer.target    += new Vector2( vSens * -Input.GetAxisRaw("Mouse Y"), hSens * Input.GetAxisRaw("Mouse X") );//Mouse Input is inherently framerate independend!
    40.         mouseBuffer.target.x = pitchClamp?Mathf.Clamp(mouseBuffer.target.x,-80F,+80F) :mouseBuffer.target.x;
    41.         mouseBuffer.Update( mLambda, Time.deltaTime, byPassSmoothing );
    42.     }
    43. }
    44.  
    45.  
    46.  
    47. #region Helpers
    48. [System.Serializable]
    49. public class BufferV2{
    50.  
    51.     public BufferV2(){
    52.         this.target = Vector2.zero;
    53.         this.buffer = Vector2.zero;
    54.     }
    55.     public BufferV2( Vector2 targetInit, Vector2 bufferInit ) {
    56.         this.target = targetInit;
    57.         this.buffer = bufferInit;
    58.     }
    59.  
    60.     /*private*/public    Vector2    target;
    61.     /*private*/public    Vector2    buffer;
    62.  
    63.     public    Vector2    curDelta;    //Delta: apply difference from lastBuffer state to current BufferState        //get difference between last and new buffer
    64.     public    Vector2    curAbs;        //absolute
    65.  
    66.  
    67.  
    68.     /// <summary>Update Buffer By supplying new target</summary>
    69.     public    void UpdateByNewTarget( Vector2 newTarget, float dampLambda, float deltaTime ){
    70.         this.target        = newTarget;
    71.         Update(dampLambda, deltaTime);
    72.     }
    73.     /// <summary>Update Buffer By supplying the rawDelta to the last target</summary>
    74.     public    void UpdateByDelta( Vector2 rawDelta, float dampLambda, float deltaTime ){
    75.         this.target        = this.target +rawDelta;    //update Target
    76.         Update(dampLambda, deltaTime);
    77.     }
    78.  
    79.     /// <summary>Update Buffer</summary>
    80.     public    void Update( float dampLambda, float deltaTime, bool byPass = false ){
    81.         Vector2 last    = buffer;            //last state of Buffer
    82.         this.buffer        = byPass? target : DampToTargetLambda( buffer, this.target, dampLambda, deltaTime);    //damp current to target
    83.         this.curDelta    = buffer -last;
    84.         this.curAbs        = buffer;
    85.     }
    86.     public static Vector2        DampToTargetLambda( Vector2    current,        Vector2        target,        float lambda, float dt){
    87.         return Vector2.        Lerp(current, target, 1F -Mathf.Exp( -lambda *dt) );
    88.     }
    89. }
    90.  
    91.     #endregion Helpers
    if you also have the jump problem with this script, a definite fix for above script would be adding "return;" after setting the Lockstate to stop the current frame from fetching mouse deltas. "CursorLockMode.Locked; return;" But the problem didn't appear for me so i left it out for now because the Lockstate might be controlled from elsewhere.

    You can also just switch .rotation for .localRotation if you need it. It won't breaking anything.

    The only thing that might be missing is angle wrapping since this script controls via a degree angle. Floating point inaccuracies might therefore bite you at angle values of more than 100000F
     
    Last edited: Jun 20, 2018
    HonoraryBob likes this.
  17. HonoraryBob

    HonoraryBob

    Joined:
    May 26, 2011
    Posts:
    1,101
    Thank you. I just needed to make sure the above line is only run when mouse is locked, and it fixed the problem.
     
  18. Marrt

    Marrt

    Joined:
    Feb 7, 2012
    Posts:
    528
    Did you try my script too :D? The smoothing of the script you currently use is totally frame rate dependent, and that is bad.
     
  19. ngerbens

    ngerbens

    Joined:
    Nov 20, 2017
    Posts:
    16
    Thanks for this great script!
    I have one question. When in press X in my script it makes my player/camera turn towards the nearest enemy. But when I release X the player/camera turn back to the old position of this script.

    How can I make this script 'refresh/update' the position of the mouse after there has been a transform/rotation outside this script?
     
  20. FlipperCanoe163

    FlipperCanoe163

    Joined:
    Dec 22, 2018
    Posts:
    1
    Oh my god... I've been struggling to make the camera look at the mouse, and you made the script and allowed people to use it... You're literally my hero! :)
     
  21. Invertex

    Invertex

    Joined:
    Nov 7, 2013
    Posts:
    927
    Late response, but changing Update() to LateUpdate() should solve that for most cases. But if there are also LateUpdate() scripts changing positions, then another option is to put this script very late in your Script Execution Order in Project Settings.
     
    ngerbens likes this.
  22. ngerbens

    ngerbens

    Joined:
    Nov 20, 2017
    Posts:
    16
    Thank you very much!
     
  23. Marrt

    Marrt

    Joined:
    Feb 7, 2012
    Posts:
    528
    Has anyone tested this so far?

    Features:
    - frame rate independent smoothing
    - pitch clamping
    - smoothing-bypass
    - on/off switch
    - cursor LockState control coupled to on/off, if needed
     

    Attached Files:

  24. ben_unity214

    ben_unity214

    Joined:
    May 7, 2018
    Posts:
    4
    I stumbled onto this via a Google search after recommendations I smooth out the mouse following publishing a trailer for my game. I somebody able to give me a totally idiot-proof guide into how to incorporate this into a game where I'm already using a (slightly modified) version of the standard Unity mouselook.cs script? Any attempt to copy/paste the code yields a load of compiler errors, suggesting I would have to completely re-write my first person controller, which I'd rather avoid if I can help it. Big thanks in advance.
     
  25. saltysquid

    saltysquid

    Joined:
    May 1, 2017
    Posts:
    26
    Marrt - I tested your script and it works well for what I'm doing (Thank You!). I'm playing with it now trying to get the mouse movement to control the camera so my player can look straight up or down. I still want side-to-side motion to rotate the player, but if they were to move up or down I want to "look around" :D This of course also needs to be constrained so they can't look up so far the world goes upside down.

    EDIT: It seems the script posted by Invertex does what I described. A combination of both scripts solved my issue. Thanks Marrt and Invertex
     
    Last edited: Jun 16, 2019
  26. Marrt

    Marrt

    Joined:
    Feb 7, 2012
    Posts:
    528
    If i understood you correctly you need to restrict pitch? I can offer you my expert script, it allows for a special softPitchClamp.

    I need it for my gyroscope-aim games. There, the player can easily hit the clamping pitch by rotating his phone. When this happens, every additional movement will get dropped of course. This causes the normal point of aim to change. (After hitting the bottom pitch clamp, when you rotate the phone back to the original rotation you will now aim higher) . With my Soft-clamp you make hitting the clamp value much harder thereby retaining the natural pitch when returning from high or low aims.


    How does it work? The soft pitchClamp remaps the pitch after input to a broader range:
    • RED: When your pitch is below half of your pMax ( about 40° in graph), the mapping is 1:1, nothing differs from normal input
    • BLUE: When your pitch exceeds half of you pMax, the amount of pitch-change your input would create will be remapped.
    upload_2019-6-16_14-28-6.png

    Now, in order to hit the direction where the pitch gets clamped, the player needs about 50% more mousemovement. I would advice this only for games where you don't need to aim up and down a lot.
     

    Attached Files: