Help with hover script?

Hi guys,

Very new to Unity and scripting. My Oculus is on its way and I want to have my prototype up and running for its arrival.

I’ve been trying to create a hover chair. I really like this script I found posted by PhoenixTalon:

#pragma strict

/*This is a simple movement and hover illusion script created by Ryan Legere AKA PhoenixTalon
Feel free to contact me with questions
This script is not perfect by any means, but it is functional
There are many places I would like to improve to make the illusion better
If you come up with some code that improves this script, please let me know
I love criticism (it's how I improve)
If you use this, I only ask for a copy of the game you use it in

Note: This script uses positions and raycasting to perform the illusion
Physics forces are not used

IMPORTANT Setup: Not doing proper setup will result in unwanted, if not comical, effects
-Attach this script to the object you wish to control
 Position the object close to the floor or terrain (nearly touching, but not touching)

-Attach a collider to the object, "CapsuleCollider" is used in the code by default,
 this can be changed below
 Keep the collider unchecked, it can have random adverse effects on the hover liftoff

-Attach a RigidBody to the object with the following settings:
 Mass: Doesn't matter, depends on desired object interaction in the scene
 Drag: Infinity (must be this)
 Angular Drag: Infinity (must be this)
 Use Gravity: Doesn't matter
 Is Kinematic: Unchecked for proper collision
 Interpolate: Doesn't matter
 Colision Detection: Discrete works best (but not required)
 Constraints: 
  Freeze Position: None checked
  Freeze Rotation: X,Z checked (otherwise the object will do interesting flips)
*/

/*These variables will give total control over the MAX speed of all motions
They can be changed in the script under the inspector for the object the script is attached to
*/
var forwardSpeedMax:float=70;
var reverseSpeedMax:float=40;
var strafeRightSpeedMax:float=40;
var strafeLeftSpeedMax:float=40;
var rotationRightSpeedMax:float=50;
var rotationLeftSpeedMax:float=50;

/*These variables determine the accelleration of your object
These counteract with each other in the function below
Depending on the desired result, these values should be equal to their opposites
*/
var accelForwardSpeed:float=3;
var accelReverseSpeed:float=1;
var accelStrafeRightSpeed:float=1;
var accelStrafeLeftSpeed:float=1;
var accelRotationRightSpeed:float=1.5;
var accelRotationLeftSpeed:float=1.5;

/*Leave these values at zero, or the object will have uncommanded inputs at startup
If a startup speed is desired, enter a value in the desired direction of travel
Only button inputs, or simulated friction have an impact on these values
These variables(with adjustment) can be used to create a type of speedometer for movement
Just have them called by another script for a GUI if desired
*/
var moveForwardSpeed:float=0;
var moveReverseSpeed:float=0;
var moveStrafeRightSpeed:float=0;
var moveStrafeLeftSpeed:float=0;
var moveRotationRightSpeed:float=0;
var moveRotationLeftSpeed:float=0;

/*This variable simulates the friction
A higher number will result in a faster stop, a lower number will result in a slower stop
Entering zero, will result in no stop
*/ 
var slideFrictionAmount:float=0.3;

/*These variable are used to create a simple illusion to fake a hover
The illusion only works on completely level surfaces
All values can be changed in the inspector to deliver a better illusion
*/
var hoverOrigin:float=20;
var hoverBounceMax:float=20;
var hoverBounceMin:float=-20;
var hoverBounceSpeedUp:float=1;
var hoverBounceSpeedDown:float=1.5;
var hoverTakeOffSpeed:float=5;
var fallingSpeed:float=35;

private var climbingSpeed:float=5;

/*These variables are used in the Hover function below
Change to public to use with particle effects from other scripts
*/
private var hoverStart = true;
private var hoverUp = false;
private var hoverDown = false;
var hoverHeight = hoverOrigin - hoverOrigin;

private var ground = RaycastHit;

//Following area will be used later for variables to determine tilt over uneven surfaces, if I ever figure it out



//This starts the movement function
function Update(){

/*Simple movement, Make sure to add/define these buttons in the Input Manager: Edit>Project Settings>Input
You must increase the "Size" number to include the buttons you make
For example, if you want to make 6 new buttons you must add 6 to the existing number (17 will become 23)
The extra buttons are added to the bottom of the list
Use the name in quotes and enter the desired keys in the "Positive Button" spot

These booleans return the directional speed of the object based on the buttons pressed
They simultaneously add speed to one direction and subtract speed from the opposite direction
without going over the object's max speed
This positive or negative number is then later used to determine direction and speed for the object

Add particle effects or sound effects to these booleans to simulate trusters/engines
*/		
	if(Input.GetButton("Forward")){
	//Random effect for going forward entered here
		if(moveForwardSpeed > forwardSpeedMax){
			moveForwardSpeed = forwardSpeedMax;
		}else{
		moveForwardSpeed = moveForwardSpeed + accelForwardSpeed;
		}
		if(moveReverseSpeed < 0){
			moveReverseSpeed = 0;
		}else{
		moveReverseSpeed = moveReverseSpeed - accelForwardSpeed;
		}	
	}
	
	if(Input.GetButton("Reverse")){
		if(moveReverseSpeed > reverseSpeedMax){
			moveReverseSpeed = reverseSpeedMax;
		}else{
		moveReverseSpeed = moveReverseSpeed + accelReverseSpeed;
		}
		if(moveForwardSpeed < 0){
			moveForwardSpeed = 0;
		}else{
		moveForwardSpeed = moveForwardSpeed - accelReverseSpeed;
		}	
	}

	if(Input.GetButton("Right")){
		if(moveStrafeRightSpeed > strafeRightSpeedMax){
			moveStrafeRightSpeed = strafeRightSpeedMax;
		}else{
		moveStrafeRightSpeed = moveStrafeRightSpeed + accelStrafeRightSpeed;
		}
		if(moveStrafeLeftSpeed < 0){
			moveStrafeLeftSpeed = 0;
		}else{
		moveStrafeLeftSpeed = moveStrafeLeftSpeed - accelStrafeRightSpeed;
		}	
	}

	if(Input.GetButton("Left")){
		if(moveStrafeLeftSpeed > strafeLeftSpeedMax){
			moveStrafeLeftSpeed = strafeLeftSpeedMax;
		}else{
		moveStrafeLeftSpeed = moveStrafeLeftSpeed + accelStrafeLeftSpeed;
		}
		if(moveStrafeRightSpeed < 0){
			moveStrafeRightSpeed = 0;
		}else{
		moveStrafeRightSpeed = moveStrafeRightSpeed - accelStrafeLeftSpeed;
		}	
	}

/*These booleans return the rotation direction and speed of rotation
These operate under the same principles as above, but using rotations

Again, effects should be added here
*/
	if(Input.GetButton("RotateRight")){
	//Random effect for rotating right entered here
		if(moveRotationRightSpeed > rotationRightSpeedMax){
			moveRotationRightSpeed = rotationRightSpeedMax;
		}else{
		moveRotationRightSpeed = moveRotationRightSpeed + accelRotationRightSpeed;
		}
		if(moveRotationLeftSpeed < 0){
			moveRotationLeftSpeed = 0;
		}else{
		moveRotationLeftSpeed = moveRotationLeftSpeed - accelRotationRightSpeed;
		}	
	}

	if(Input.GetButton("RotateLeft")){
		if(moveRotationLeftSpeed > rotationLeftSpeedMax){
			moveRotationLeftSpeed = rotationLeftSpeedMax;
		}else{
		moveRotationLeftSpeed = moveRotationLeftSpeed + accelRotationLeftSpeed;
		}
		if(moveRotationRightSpeed < 0){
			moveRotationRightSpeed = 0;
		}else{
		moveRotationRightSpeed = moveRotationRightSpeed - accelRotationLeftSpeed;
		}	
	}

/*These booleans control how simulated friction is applied
Each direction is checked for motion, then has it's motion reduced based on the friction value
Note: Nothing happens if friction is set to zero
*/
	if(moveForwardSpeed < 0){
		moveForwardSpeed = 0;
		}else{
		moveForwardSpeed = moveForwardSpeed - slideFrictionAmount;
	}
	if(moveReverseSpeed < 0){
		moveReverseSpeed = 0;
		}else{
		moveReverseSpeed = moveReverseSpeed - slideFrictionAmount;
	}
	if(moveStrafeRightSpeed < 0){
		moveStrafeRightSpeed = 0;
		}else{
		moveStrafeRightSpeed = moveStrafeRightSpeed - slideFrictionAmount;
	}
	if(moveStrafeLeftSpeed < 0){
		moveStrafeLeftSpeed = 0;
		}else{
		moveStrafeLeftSpeed = moveStrafeLeftSpeed - slideFrictionAmount;
	}
	if(moveRotationRightSpeed < 0){
		moveRotationRightSpeed = 0;
		}else{
		moveRotationRightSpeed = moveRotationRightSpeed - slideFrictionAmount;
	}
	if(moveRotationLeftSpeed < 0){
		moveRotationLeftSpeed = 0;
		}else{
		moveRotationLeftSpeed = moveRotationLeftSpeed - slideFrictionAmount;
	}

/*This is where the actual motion happens
The values computed above are used here
*/	
	transform.position += transform.forward * (moveForwardSpeed - moveReverseSpeed) * Time.deltaTime;
	transform.position += transform.right * (moveStrafeRightSpeed - moveStrafeLeftSpeed) * Time.deltaTime;
	transform.eulerAngles.y += (moveRotationRightSpeed - moveRotationLeftSpeed) * Time.deltaTime;
	
/*Vector hover using Raycasting
This section in progress
*/
	var up = transform.TransformDirection(Vector3.up);
	
	if(!hoverStart){
		if(!Physics.Raycast(transform.position, -up, (hoverOrigin))){
			transform.position += -transform.up * fallingSpeed * Time.deltaTime;
		}
		if(Physics.Raycast(transform.position, -up, (hoverOrigin - 2))){
			transform.position += transform.up * climbingSpeed * Time.deltaTime;
		}	
	}		

/*This boolean lifts the object to the hover origin
Note: This is only the initial hover on startup
Once this runs, it never runs again
*/
	if(hoverStart){
		if(hoverHeight < hoverOrigin){
			if(Physics.Raycast(transform.position, -up, hoverOrigin + hoverBounceMax)){
				transform.position += transform.up * hoverTakeOffSpeed * Time.deltaTime;
				hoverHeight++;
				}
			}
		}
		if(hoverHeight > hoverOrigin){
			hoverHeight = hoverOrigin;
		}
		if(hoverHeight == hoverOrigin){
//This is where the collider is called
//Change the name of this component if something else is used
			GetComponent(CapsuleCollider).enabled = true;
			hoverUp = true;
			hoverStart = false;
		}

/*This series of booleans determines the height of the object
This only checks if the object is max up or max down, and switches the direction
*/
	if(!hoverStart){
		if(hoverHeight > hoverBounceMax){
			hoverHeight = hoverBounceMax;
		}
		if(hoverHeight == hoverBounceMax){
			hoverUp = false;
			hoverDown = true;
		}
	
		if(hoverHeight < hoverBounceMin){
			hoverHeight = hoverBounceMin;
		}
		if(hoverHeight == hoverBounceMin){
			hoverDown = false;
			hoverUp = true;
		}
	}

/*These booleans move the object up or down based on object height
This continuously runs, and produces the hover bounce illusion
Effects can be added here also to enhance the illusion
I would eventually like to have Raycasting control this too, but I'm too lazy right now
*/
	if(hoverUp){
		//Random effect for going up
		transform.position += transform.up * hoverBounceSpeedUp * Time.deltaTime;
		hoverHeight = hoverHeight + hoverBounceSpeedUp;
	}
	if(hoverDown){
		//Random effect for going down
		transform.position += -transform.up * hoverBounceSpeedDown * Time.deltaTime;
		hoverHeight = hoverHeight - hoverBounceSpeedDown;
	}

/*This section is for Raycasting collisions, if I ever figure that out too
Then the CapsuleCollider will not be needed
*/

}

The movement is just want I was looking for. A nice light-friction ‘floaty-ness’. Reading through the notes even gave me some insight into scripting.

Problem: The chair floats up into the air about 100 feet. It just takes off! I want it to float about 6 inches from the ground. I read through the notes, but don’t know what is controlling the upward thrust, so can’t turn it down. Can anyone provide some help?

Also, I think I would like for the chair to be able to short-boost into the air. Sort of like a jump. How would I add that into the script?

Thanks so much!

My first thought would be the variable hoverHeight, but it’s set to hoverOrigin - hoverOrigin; which I don’t understand, if you subtract something from itself that will always just be 0

It uses raycast, and looks like it uses hoverOrigin to set the distance, does changing hoverOrigin change the height it hovers at?

Thanks for the quick reply!

Okay, so that definitely helped. You are right: hover Origin is the hover height. I set it to 1, and I am a meter off the ground.

A new problem though. When I hit that max height (1m), the vehicle “hiccups” back down (not smoothly, instant) and then rises again. It repeats this constantly. Something in the coat is make it instantly move down when it hits its hover origin.

I think it has something to do with Hover Height. playing with it in the inspector didn’t change anything. I am getting the error code: “The maximum distance must be greater than zero” in regards to:

var up = transform.TransformDirection(Vector3.up);
	
	if(!hoverStart){
		if(!Physics.Raycast(transform.position, -up, (hoverOrigin))){
			transform.position += -transform.up * fallingSpeed * Time.deltaTime;
		}
		if(Physics.Raycast(transform.position, -up, (hoverOrigin - 2))){
			transform.position += transform.up * climbingSpeed * Time.deltaTime;
		}	
	}

What is this code doing? Is my problem here?

Thanks!

Whoever wrote teh script must have assumed you’d be hovering higher than 2, so lower that number so you don’t get negatives.

Also falling speed is very high compared to climbing speed. If you make them the same the might help.

var fallingSpeed:float=35;
private var climbingSpeed:float=5;

I changed the number to 0.5, I’m no longer getting the error.

I made climbing and falling speed the same. It is jittering just as violently. I wish I understood the script better…

Here’s a question: Can I simplify this so that I understand the script but also have something fairly usable? Basically, I am making a hover chair. I want it to gently glide around and have a little bit of glide. Ideally, it would be able to float up gently a the press of a botton and then glide back down to resting height.

Is this something that can be achieved more simply with some basic controls and a rigid body experiencing physics?

Thanks again!

PS - Of course, if I can just get this script working, that’d be just as good.