Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Simple movement javascript for hover illusion - Incomplete but functional

Discussion in 'Scripting' started by PhoenixTalon, Oct 1, 2012.

  1. PhoenixTalon

    PhoenixTalon

    Joined:
    Aug 26, 2012
    Posts:
    13
    This is my first time posting on the forums, so I'm not sure if this is the right place to post this. If not, then I'm sorry.

    I've recently begun using Unity to make a game that incorporates a hover. I've not found any script that really comes close to what I want, so I wrote my own using javascript (I happen to be more comfotable with javascript).

    I hardly have any experience in making games, and even less in coding, but this is what I was able to come up with so far.

    The code works, and the only issue I would really like to solve is to make the object tilt appropriately over uneven terrain. It goes up and down just fine, but I've had no success in rotating it, then correcting the vertical attitude back to null over a flat surface. My game doesn't currently call for uneven terrain, but that might change as it develops.

    I would also like to handle all collisions in the scene with Raycasting instead of a collider.

    I may be trying to do things the hard way, but I'm inexperienced.

    I'm posting the functional code here for advice, and for others to use. It's not 100%, but maybe someone can find value in it. With this in mind, I've added lots of comments for anyone trying to use it. Hopefully, they are easy to follow.

    V/R
    PhoenixTalon


    Code (csharp):
    1.  
    2. #pragma strict
    3.  
    4. /*This is a simple movement and hover illusion script created by Ryan Legere AKA PhoenixTalon
    5. Feel free to contact me with questions
    6. This script is not perfect by any means, but it is functional
    7. There are many places I would like to improve to make the illusion better
    8. If you come up with some code that improves this script, please let me know
    9. I love criticism (it's how I improve)
    10. If you use this, I only ask for a copy of the game you use it in
    11.  
    12. Note: This script uses positions and raycasting to perform the illusion
    13. Physics forces are not used
    14.  
    15. IMPORTANT Setup: Not doing proper setup will result in unwanted, if not comical, effects
    16. -Attach this script to the object you wish to control
    17.  Position the object close to the floor or terrain (nearly touching, but not touching)
    18.  
    19. -Attach a collider to the object, "CapsuleCollider" is used in the code by default,
    20.  this can be changed below
    21.  Keep the collider unchecked, it can have random adverse effects on the hover liftoff
    22.  
    23. -Attach a RigidBody to the object with the following settings:
    24.  Mass: Doesn't matter, depends on desired object interaction in the scene
    25.  Drag: Infinity (must be this)
    26.  Angular Drag: Infinity (must be this)
    27.  Use Gravity: Doesn't matter
    28.  Is Kinematic: Unchecked for proper collision
    29.  Interpolate: Doesn't matter
    30.  Colision Detection: Discrete works best (but not required)
    31.  Constraints:
    32.   Freeze Position: None checked
    33.   Freeze Rotation: X,Z checked (otherwise the object will do interesting flips)
    34. */
    35.  
    36. /*These variables will give total control over the MAX speed of all motions
    37. They can be changed in the script under the inspector for the object the script is attached to
    38. */
    39. var forwardSpeedMax:float=70;
    40. var reverseSpeedMax:float=40;
    41. var strafeRightSpeedMax:float=40;
    42. var strafeLeftSpeedMax:float=40;
    43. var rotationRightSpeedMax:float=50;
    44. var rotationLeftSpeedMax:float=50;
    45.  
    46. /*These variables determine the accelleration of your object
    47. These counteract with each other in the function below
    48. Depending on the desired result, these values should be equal to their opposites
    49. */
    50. var accelForwardSpeed:float=3;
    51. var accelReverseSpeed:float=1;
    52. var accelStrafeRightSpeed:float=1;
    53. var accelStrafeLeftSpeed:float=1;
    54. var accelRotationRightSpeed:float=1.5;
    55. var accelRotationLeftSpeed:float=1.5;
    56.  
    57. /*Leave these values at zero, or the object will have uncommanded inputs at startup
    58. If a startup speed is desired, enter a value in the desired direction of travel
    59. Only button inputs, or simulated friction have an impact on these values
    60. These variables(with adjustment) can be used to create a type of speedometer for movement
    61. Just have them called by another script for a GUI if desired
    62. */
    63. var moveForwardSpeed:float=0;
    64. var moveReverseSpeed:float=0;
    65. var moveStrafeRightSpeed:float=0;
    66. var moveStrafeLeftSpeed:float=0;
    67. var moveRotationRightSpeed:float=0;
    68. var moveRotationLeftSpeed:float=0;
    69.  
    70. /*This variable simulates the friction
    71. A higher number will result in a faster stop, a lower number will result in a slower stop
    72. Entering zero, will result in no stop
    73. */
    74. var slideFrictionAmount:float=0.3;
    75.  
    76. /*These variable are used to create a simple illusion to fake a hover
    77. The illusion only works on completely level surfaces
    78. All values can be changed in the inspector to deliver a better illusion
    79. */
    80. var hoverOrigin:float=20;
    81. var hoverBounceMax:float=20;
    82. var hoverBounceMin:float=-20;
    83. var hoverBounceSpeedUp:float=1;
    84. var hoverBounceSpeedDown:float=1.5;
    85. var hoverTakeOffSpeed:float=5;
    86. var fallingSpeed:float=35;
    87.  
    88. private var climbingSpeed:float=5;
    89.  
    90. /*These variables are used in the Hover function below
    91. Change to public to use with particle effects from other scripts
    92. */
    93. private var hoverStart = true;
    94. private var hoverUp = false;
    95. private var hoverDown = false;
    96. var hoverHeight = hoverOrigin - hoverOrigin;
    97.  
    98. private var ground = RaycastHit;
    99.  
    100. //Following area will be used later for variables to determine tilt over uneven surfaces, if I ever figure it out
    101.  
    102.  
    103.  
    104. //This starts the movement function
    105. function Update(){
    106.  
    107. /*Simple movement, Make sure to add/define these buttons in the Input Manager: Edit>Project Settings>Input
    108. You must increase the "Size" number to include the buttons you make
    109. For example, if you want to make 6 new buttons you must add 6 to the existing number (17 will become 23)
    110. The extra buttons are added to the bottom of the list
    111. Use the name in quotes and enter the desired keys in the "Positive Button" spot
    112.  
    113. These booleans return the directional speed of the object based on the buttons pressed
    114. They simultaneously add speed to one direction and subtract speed from the opposite direction
    115. without going over the object's max speed
    116. This positive or negative number is then later used to determine direction and speed for the object
    117.  
    118. Add particle effects or sound effects to these booleans to simulate trusters/engines
    119. */     
    120.     if(Input.GetButton("Forward")){
    121.     //Random effect for going forward entered here
    122.         if(moveForwardSpeed > forwardSpeedMax){
    123.             moveForwardSpeed = forwardSpeedMax;
    124.         }else{
    125.         moveForwardSpeed = moveForwardSpeed + accelForwardSpeed;
    126.         }
    127.         if(moveReverseSpeed < 0){
    128.             moveReverseSpeed = 0;
    129.         }else{
    130.         moveReverseSpeed = moveReverseSpeed - accelForwardSpeed;
    131.         }  
    132.     }
    133.    
    134.     if(Input.GetButton("Reverse")){
    135.         if(moveReverseSpeed > reverseSpeedMax){
    136.             moveReverseSpeed = reverseSpeedMax;
    137.         }else{
    138.         moveReverseSpeed = moveReverseSpeed + accelReverseSpeed;
    139.         }
    140.         if(moveForwardSpeed < 0){
    141.             moveForwardSpeed = 0;
    142.         }else{
    143.         moveForwardSpeed = moveForwardSpeed - accelReverseSpeed;
    144.         }  
    145.     }
    146.  
    147.     if(Input.GetButton("Right")){
    148.         if(moveStrafeRightSpeed > strafeRightSpeedMax){
    149.             moveStrafeRightSpeed = strafeRightSpeedMax;
    150.         }else{
    151.         moveStrafeRightSpeed = moveStrafeRightSpeed + accelStrafeRightSpeed;
    152.         }
    153.         if(moveStrafeLeftSpeed < 0){
    154.             moveStrafeLeftSpeed = 0;
    155.         }else{
    156.         moveStrafeLeftSpeed = moveStrafeLeftSpeed - accelStrafeRightSpeed;
    157.         }  
    158.     }
    159.  
    160.     if(Input.GetButton("Left")){
    161.         if(moveStrafeLeftSpeed > strafeLeftSpeedMax){
    162.             moveStrafeLeftSpeed = strafeLeftSpeedMax;
    163.         }else{
    164.         moveStrafeLeftSpeed = moveStrafeLeftSpeed + accelStrafeLeftSpeed;
    165.         }
    166.         if(moveStrafeRightSpeed < 0){
    167.             moveStrafeRightSpeed = 0;
    168.         }else{
    169.         moveStrafeRightSpeed = moveStrafeRightSpeed - accelStrafeLeftSpeed;
    170.         }  
    171.     }
    172.  
    173. /*These booleans return the rotation direction and speed of rotation
    174. These operate under the same principles as above, but using rotations
    175.  
    176. Again, effects should be added here
    177. */
    178.     if(Input.GetButton("RotateRight")){
    179.     //Random effect for rotating right entered here
    180.         if(moveRotationRightSpeed > rotationRightSpeedMax){
    181.             moveRotationRightSpeed = rotationRightSpeedMax;
    182.         }else{
    183.         moveRotationRightSpeed = moveRotationRightSpeed + accelRotationRightSpeed;
    184.         }
    185.         if(moveRotationLeftSpeed < 0){
    186.             moveRotationLeftSpeed = 0;
    187.         }else{
    188.         moveRotationLeftSpeed = moveRotationLeftSpeed - accelRotationRightSpeed;
    189.         }  
    190.     }
    191.  
    192.     if(Input.GetButton("RotateLeft")){
    193.         if(moveRotationLeftSpeed > rotationLeftSpeedMax){
    194.             moveRotationLeftSpeed = rotationLeftSpeedMax;
    195.         }else{
    196.         moveRotationLeftSpeed = moveRotationLeftSpeed + accelRotationLeftSpeed;
    197.         }
    198.         if(moveRotationRightSpeed < 0){
    199.             moveRotationRightSpeed = 0;
    200.         }else{
    201.         moveRotationRightSpeed = moveRotationRightSpeed - accelRotationLeftSpeed;
    202.         }  
    203.     }
    204.  
    205. /*These booleans control how simulated friction is applied
    206. Each direction is checked for motion, then has it's motion reduced based on the friction value
    207. Note: Nothing happens if friction is set to zero
    208. */
    209.     if(moveForwardSpeed < 0){
    210.         moveForwardSpeed = 0;
    211.         }else{
    212.         moveForwardSpeed = moveForwardSpeed - slideFrictionAmount;
    213.     }
    214.     if(moveReverseSpeed < 0){
    215.         moveReverseSpeed = 0;
    216.         }else{
    217.         moveReverseSpeed = moveReverseSpeed - slideFrictionAmount;
    218.     }
    219.     if(moveStrafeRightSpeed < 0){
    220.         moveStrafeRightSpeed = 0;
    221.         }else{
    222.         moveStrafeRightSpeed = moveStrafeRightSpeed - slideFrictionAmount;
    223.     }
    224.     if(moveStrafeLeftSpeed < 0){
    225.         moveStrafeLeftSpeed = 0;
    226.         }else{
    227.         moveStrafeLeftSpeed = moveStrafeLeftSpeed - slideFrictionAmount;
    228.     }
    229.     if(moveRotationRightSpeed < 0){
    230.         moveRotationRightSpeed = 0;
    231.         }else{
    232.         moveRotationRightSpeed = moveRotationRightSpeed - slideFrictionAmount;
    233.     }
    234.     if(moveRotationLeftSpeed < 0){
    235.         moveRotationLeftSpeed = 0;
    236.         }else{
    237.         moveRotationLeftSpeed = moveRotationLeftSpeed - slideFrictionAmount;
    238.     }
    239.  
    240. /*This is where the actual motion happens
    241. The values computed above are used here
    242. */ 
    243.     transform.position += transform.forward * (moveForwardSpeed - moveReverseSpeed) * Time.deltaTime;
    244.     transform.position += transform.right * (moveStrafeRightSpeed - moveStrafeLeftSpeed) * Time.deltaTime;
    245.     transform.eulerAngles.y += (moveRotationRightSpeed - moveRotationLeftSpeed) * Time.deltaTime;
    246.    
    247. /*Vector hover using Raycasting
    248. This section in progress
    249. */
    250.     var up = transform.TransformDirection(Vector3.up);
    251.    
    252.     if(!hoverStart){
    253.         if(!Physics.Raycast(transform.position, -up, (hoverOrigin))){
    254.             transform.position += -transform.up * fallingSpeed * Time.deltaTime;
    255.         }
    256.         if(Physics.Raycast(transform.position, -up, (hoverOrigin - 2))){
    257.             transform.position += transform.up * climbingSpeed * Time.deltaTime;
    258.         }  
    259.     }      
    260.  
    261. /*This boolean lifts the object to the hover origin
    262. Note: This is only the initial hover on startup
    263. Once this runs, it never runs again
    264. */
    265.     if(hoverStart){
    266.         if(hoverHeight < hoverOrigin){
    267.             if(Physics.Raycast(transform.position, -up, hoverOrigin + hoverBounceMax)){
    268.                 transform.position += transform.up * hoverTakeOffSpeed * Time.deltaTime;
    269.                 hoverHeight++;
    270.                 }
    271.             }
    272.         }
    273.         if(hoverHeight > hoverOrigin){
    274.             hoverHeight = hoverOrigin;
    275.         }
    276.         if(hoverHeight == hoverOrigin){
    277. //This is where the collider is called
    278. //Change the name of this component if something else is used
    279.             GetComponent(CapsuleCollider).enabled = true;
    280.             hoverUp = true;
    281.             hoverStart = false;
    282.         }
    283.  
    284. /*This series of booleans determines the height of the object
    285. This only checks if the object is max up or max down, and switches the direction
    286. */
    287.     if(!hoverStart){
    288.         if(hoverHeight > hoverBounceMax){
    289.             hoverHeight = hoverBounceMax;
    290.         }
    291.         if(hoverHeight == hoverBounceMax){
    292.             hoverUp = false;
    293.             hoverDown = true;
    294.         }
    295.    
    296.         if(hoverHeight < hoverBounceMin){
    297.             hoverHeight = hoverBounceMin;
    298.         }
    299.         if(hoverHeight == hoverBounceMin){
    300.             hoverDown = false;
    301.             hoverUp = true;
    302.         }
    303.     }
    304.  
    305. /*These booleans move the object up or down based on object height
    306. This continuously runs, and produces the hover bounce illusion
    307. Effects can be added here also to enhance the illusion
    308. I would eventually like to have Raycasting control this too, but I'm too lazy right now
    309. */
    310.     if(hoverUp){
    311.         //Random effect for going up
    312.         transform.position += transform.up * hoverBounceSpeedUp * Time.deltaTime;
    313.         hoverHeight = hoverHeight + hoverBounceSpeedUp;
    314.     }
    315.     if(hoverDown){
    316.         //Random effect for going down
    317.         transform.position += -transform.up * hoverBounceSpeedDown * Time.deltaTime;
    318.         hoverHeight = hoverHeight - hoverBounceSpeedDown;
    319.     }
    320.  
    321. /*This section is for Raycasting collisions, if I ever figure that out too
    322. Then the CapsuleCollider will not be needed
    323. */
    324.  
    325. }
    326.  
     

    Attached Files:

  2. CrazySi

    CrazySi

    Joined:
    Jun 23, 2011
    Posts:
    538
    I believe the term you are seeking is, Ground Clamping.
    You want to align your vehicle's up vector with the normal of the surface.
    The normal is held in the RaycastHitInfo struct, that comes back from the Raycast call.

    PS Are you sure you're a beginner? Your code is very neat and organised.
     
  3. PhoenixTalon

    PhoenixTalon

    Joined:
    Aug 26, 2012
    Posts:
    13
    CrazySi, thanks for your compliment. I am exceptionally green at programming (and Unity), and you have just seen my greatest achievement. However, I read a lot and I learn quickly. Also, I have a severe case of OCD.

    I will have to research about the RaycastHitInfo. I'm not entirely sure I follow what you are saying, but I'm thinking it's something like this: A ray shoots out, and measures the angle of the ground at the contact point. Then would I use that angle to adjust the rotation? Sounds like multiple rays would be needed from either a single point, or multiple points. Or can it be handled by a single ray?

    Maybe I could shoot 4 rays from the center position to the 45's (corners if using a cube) to the ground, and measure their ground contact. Then I guess I could take the distances and convert them to angles for rotation. Not sure if that's even possible.

    I'm wondering if Unity has some sort of way to align with a kind of global up. Then I could use that position to balance the ojbect in the absence of ground as well.

    Might be one way to do it. Think I'll go do some coding. Coffee first.
     
  4. CrazySi

    CrazySi

    Joined:
    Jun 23, 2011
    Posts:
    538
    A single ray will work just fine. Unity does the normal vector calculation for you.

    In the part where you cast a ray downwards, line 52?
    Code (csharp):
    1. Physics.Raycast(transform.position, -up, (hoverOrigin))
    You can pass in a struct that will be modified and in it have the normal vector of the surface.

    I don't do UniScript but its something like

    Code (csharp):
    1. RaycastHitInfo hit;
    2. Ray ray = new Ray(transform.position, -up);
    3. Physics.Raycast(ray, out hit....)
    4.  
    Its in one the Raycast overloads basically, lets you pass in a RaycastHitInfo struct.