Search Unity

Physics/Input Questions

Discussion in 'Scripting' started by droderick, Sep 17, 2008.

  1. droderick

    droderick

    Joined:
    Aug 25, 2008
    Posts:
    169
    Hi All,

    I'm trying to set a scene up where the user can rotate/spin the object (by selecting the object with the left mouse button around with an organic-type feel ). Meaning if the user selects an object and moves the mouse quickly, then the object spins faster and takes longer to slow down.

    Can someone point me in the right direction for this? I looked through the forums and scripting reference to no avail. much appreciated.
     
  2. DannyJ

    DannyJ

    Joined:
    Sep 3, 2007
    Posts:
    40
    I was working on the same thing a while ago and it still feels a bit rough, although it basically works.

    Here is a link to a webplayer demo:
    http://www.grayboxgames.com/GBG/Tests/GrabNRotate.html

    Have a look at this script to see how it works and then i would be happy to answer any questions. It needs to be attached to an object with a sphere collider. Number Averages can be tweaked to make the rotation continue more naturally after releasing the mouse button.

    Code (csharp):
    1. var numberAverages : int = 3;
    2.  
    3. private var originalRotation : Quaternion;
    4. private var offsetRotation : Quaternion;
    5.  
    6. // Make sure there is always a Rigidbody
    7. @script RequireComponent (Rigidbody)
    8. @script RequireComponent (SphereCollider)
    9.  
    10.  
    11. function Awake () {
    12.    
    13.     numberAverages = Mathf.Clamp (numberAverages, 1, numberAverages);
    14.    
    15. }
    16.  
    17.  
    18. function OnMouseDown () {
    19.     var hit : RaycastHit;
    20.     var dir : Vector3;
    21.    
    22.     // Stop spinning
    23.     rigidbody.angularVelocity = Vector3.zero;
    24.    
    25.     // Record initial variables
    26.     if (Physics.Raycast (camera.main.ScreenPointToRay(Input.mousePosition), hit)) {
    27.         originalRotation = transform.rotation;
    28.         dir = hit.point - transform.position;
    29.         offsetRotation = Quaternion.Inverse (Quaternion.LookRotation (dir));
    30.         Spin (dir);
    31.     }
    32. }
    33.  
    34.  
    35. function Spin (dir : Vector3) {
    36.     var hit : RaycastHit;
    37.     var previousDirList : Array = new Array ();
    38.     var currentDir : Vector3;
    39.    
    40.     // Initialize previous dir list
    41.     for (var i : int = 0; i < numberAverages; i++) {
    42.         previousDirList.Add (currentDir);
    43.     }
    44.    
    45.     currentDir = dir;
    46.    
    47.     // Make the object rotate with the cursor while we are grabbing it
    48.     while (Input.GetButton ("Fire1")  Physics.Raycast (camera.main.ScreenPointToRay(Input.mousePosition), hit)) {
    49.         // Remove first element of the array
    50.         previousDirList.RemoveAt (0);
    51.         // Add current dir to the end
    52.         previousDirList.Add (currentDir);
    53.         currentDir = hit.point - transform.position;
    54.         transform.rotation =  Quaternion.LookRotation (currentDir) * offsetRotation * originalRotation;
    55.         yield;
    56.     }
    57.    
    58.     // User let go of the mouse so make the object spin on its own
    59.     var avgPreviousDir : Vector3 = Vector3.zero;
    60.     for (dir in previousDirList) {
    61.         avgPreviousDir += dir;
    62.     }
    63.     avgPreviousDir /= numberAverages;
    64.     Kick (currentDir, avgPreviousDir);
    65. }
    66.  
    67.  
    68. function Kick (r2 : Vector3, r1 : Vector3) {
    69.     var linearVelocity : Vector3;
    70.     var angVelocity : Vector3;
    71.    
    72.     // Calculate the angular velocity:  omega = r x v / r^2
    73.     linearVelocity = (r2 - r1) / Time.deltaTime;
    74.     rigidbody.angularVelocity = Vector3.Cross (r2, linearVelocity) / r2.sqrMagnitude;
    75.  
    76. }
    -Dan
     
  3. droderick

    droderick

    Joined:
    Aug 25, 2008
    Posts:
    169
    Oh my! This is really great and is going to work out well. Thanks!

    Couple of questions:

    1. I have 4 sliders in my scene. Three control the X,Y and Z position of the object relative to the camera. one controls the FOV settings of the camera.

    If I change the FOV settings so the object is "larger" in the viewport, then the sphere collider gets larger as well. This then changes the "physics" of the rotation of the object by the user. Meaning if the object is larger, then the same "click and drag" will move the object at a noticeable slower rate. Is there a way to dynamically set the radius of the sphere collider so that as the FOV increases or decreases, so does the radius?

    2. Is there a way to set a clamp (i think this is the right teminology) to the rotation of a specific axis? Meaning can this be modified so the user can only rotate something 90 degrees in one axis but spin the object freely in the other axes?

    Thanks again so much for the script :)

    danny
     
  4. DannyJ

    DannyJ

    Joined:
    Sep 3, 2007
    Posts:
    40
    You're welcome :)

    The script rotates the sphere so that the point on the sphere that was under the cursor when the mouse was clicked remains directly under the cursor until the user releases the mouse button. FOV doesn't change this. On the other hand, if you want to make the rotation proportional to mouse delta movements, which is what i think you are after, then the whole script would be different.

    Clamping the rotation could be done the way the MouseLook script found in the Standard Assets folder does it, so my script could be modified to clamp the angle.
     
  5. droderick

    droderick

    Joined:
    Aug 25, 2008
    Posts:
    169
    thanks much for the info. I'll try tweaking things so the clamp function works as well.
    thanks again for the help,
    daniel
     
  6. cedrico

    cedrico

    Joined:
    May 4, 2009
    Posts:
    40
    Hello, sorry to bump in but this a very cool thread, very helpful, thx very much for sharing such a nice example and giving the code with very nicely commented lines.
    You guys in Wisconsin rock!
    THX a bunch!
     
  7. Mats

    Mats

    Joined:
    Nov 30, 2009
    Posts:
    6
    Hi there!
    I have a question for DannyJ.
    I am quite new to Unity and interactive 3D programming, coming from the animation/modelling end of the field. It was great finding your grabNRotate script, that more or less achieved half of what I want to do. Many thanks! Next step would be to have clickable hotspots on the surface of the object. Imagine for example a mobile phone that you can spin around in space, and be able to interact with the buttons. How would I go about doing this?
    I have tried adding child objects (cubes) with simple test scripts attached to them (for example switching a colour on mouseDown), but they become inactive when parented to the main object (the sphere), and furthermore they inherit the grabNRotate behavior instead.
    I know, I am very much a programming newbie, so please bear with me. Maybe there is something basic that I have missed.

    Cheers,
    Mats
     
  8. wgrand

    wgrand

    Guest

    Joined:
    Mar 11, 2010
    Posts:
    14
    Did you update your GrabNRotate script? It's exactly what I was looking for!
     
  9. Halo212

    Halo212

    Joined:
    Feb 17, 2010
    Posts:
    60
    Great Script !!!

    I Desperately need a very similar script for my 2d Disc. How simple would it be to convert this script to rotate a 2d disc like a wheel?

    Any Suggestions welcomed ! :D
     
  10. spaceMan-2.5

    spaceMan-2.5

    Joined:
    Oct 21, 2009
    Posts:
    710
    It is possible to modify the script to get the object only rotates in horizontal axys?

    Thanks.
     
  11. andeeeee

    andeeeee

    Joined:
    Jul 19, 2005
    Posts:
    8,768
    Since it's a rigidbody object, the easiest way to limit rotation to one axis is to add a hinge joint to it.
     
  12. wingrider888

    wingrider888

    Joined:
    Oct 27, 2010
    Posts:
    38
    Could you please update us on how we could make it rotate only on horizontal axis by editing the rotate script?
     
    Last edited: Jan 24, 2011
  13. pwilster

    pwilster

    Joined:
    Jun 3, 2011
    Posts:
    4
    Many thanks for the insight.... too bad the script doesn't work on Android devices...

    Tried and failed.... anybody knows why?
     
  14. sushanta1991

    sushanta1991

    Joined:
    Apr 3, 2011
    Posts:
    305
    thanks buddy its a great script i tried it, and works perfect, I tried to move it only in horizontal direction but it works little bit wired .......
    let me try more.
     
  15. Savannah95

    Savannah95

    Joined:
    Jul 20, 2011
    Posts:
    6
    Anyone have a thought on how to add to this script...

    I need to be able to use player input to gradually build up the rotation speed of an object. So to get the object moving fast, the player would have to swipe many times in the same direction. If the player started swiping in the opposite direction of the current spin, it would take a while to slow down, and then build back up in the other direction.
     
  16. Deadguy71

    Deadguy71

    Joined:
    Jul 14, 2011
    Posts:
    10