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
#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
*/
}
1050138–39013–$SimpleMovementWithHover.unitypackage (4.15 KB)