- Home /
Hovering Tank
I have a sci-fi themed tank that I need to make it look like it's hovering up and down through C# script. How do I go about applying force to the rigidbody giving it the impression that it's hovering up and letting gravity bring it back down again all without increasing or editing the collider box? Where do I start?
EDIT
So I was playing around with the code I gave in the link below to see if it was an all in one solution and I think my freak of nature gravity value (-500) is affecting the code badly and my craft still sticks to the ground does anyone have a clue?
Converted Code:
using UnityEngine;
using System.Collections;
public class ScifiHover : MonoBehaviour { float forwardPower;
float steerPower;
float landingPower;
float jumpingPower;
float hoverHeight;
float stability = 1;
public GameObject body;
public float speedUpdate;
private Vector3[] hitNormal = new Vector3[5];
private Quaternion rotation;
private float increment;
private Vector3[] lastNormals = new Vector3[5];
private bool physicsSetup = false;
private Vector3 boxDim;
private Vector3[] cornersPoint = new Vector3[5];
private Transform[] corners = new Transform[5];
private BoxCollider boxCollider;
private float yBounce;
private Vector3 lastPosition;
private float distance;
private Vector3 average;
void Awake()
{
InitializePhysics();
}
void Update()
{
CalculateSpeed();
}
void FixedUpdate()
{
if (physicsSetup)
{
RaycastHit hit;
for (int i = 0; i <= corners.Length - 1; i++)
{
if (Physics.Raycast(corners[i].position, -corners[i].up, out hit, hoverHeight + 100.0f))
{
if (hit.collider.gameObject.tag == "Floor")
{
hitNormal[i] = body.transform.InverseTransformDirection(hit.normal);
if (lastNormals[i] != hitNormal[i])
{
increment = 0;
lastNormals[i] = hitNormal[i];
}
distance = hit.distance;
if (hit.distance < hoverHeight)
{
constantForce.relativeForce = (-average + transform.up) * rigidbody.mass * jumpingPower * rigidbody.drag * Mathf.Min(hoverHeight, hoverHeight / distance);
}
else
{
constantForce.relativeForce = -(transform.up) * rigidbody.mass * landingPower * rigidbody.drag / Mathf.Min(hoverHeight, hoverHeight / distance);
}
}
}
}
average = -(hitNormal[0] + hitNormal[1] + hitNormal[2] + hitNormal[3] + hitNormal[4]) / 2;
if (increment != 1) { increment += 0.03f; }
rotation = Quaternion.Slerp(body.transform.localRotation, Quaternion.Euler(average * Mathf.Rad2Deg), increment);
Quaternion temp = rotation;
temp.y = transform.up.y * Mathf.Deg2Rad;
body.transform.localRotation = temp;
float fwdForce = Input.GetAxis("Vertical") * forwardPower;
rigidbody.AddForce(transform.forward * fwdForce);
float steerForce = Input.GetAxis("Horizontal") * steerPower;
rigidbody.AddTorque(transform.up * steerForce);
}
}
void CalculateSpeed()
{
if (lastPosition != transform.position)
{
float distance = Vector3.Distance(transform.position, lastPosition);
speedUpdate = (distance / 1000) / (Time.deltaTime / 3600); //Km/h
}
}
void InitializePhysics()
{
//Store the box dimenssion of the hovering object.
boxCollider = body.AddComponent<BoxCollider>();
boxDim = new Vector3(boxCollider.size.x * body.transform.localScale.x, boxCollider.size.y * body.transform.localScale.y, boxCollider.size.z * body.transform.localScale.z) * stability;
cornersPoint[0] = new Vector3(transform.position.x - boxDim.x / 2, transform.position.y - boxDim.y / 2, transform.position.z + boxDim.z / 2);
cornersPoint[1] = new Vector3(boxDim.x / 2 + transform.position.x, transform.position.y - boxDim.y / 2, transform.position.z + boxDim.z / 2);
cornersPoint[2] = new Vector3(boxDim.x / 2 + transform.position.x, transform.position.y - boxDim.y / 2, transform.position.z - boxDim.z / 2);
cornersPoint[3] = new Vector3(transform.position.x - boxDim.x / 2, transform.position.y - boxDim.y / 2, transform.position.z - boxDim.z / 2);
cornersPoint[4] = transform.position;
Destroy(boxCollider);
for (int i = 0; i <= cornersPoint.Length - 1; i++)
{
GameObject stablePlatform = GameObject.CreatePrimitive(PrimitiveType.Sphere);
stablePlatform.name = "StablePlatform" + "(" + i + ")";
stablePlatform.transform.parent = body.transform;
stablePlatform.transform.localPosition = transform.InverseTransformPoint(cornersPoint[i]);
corners[i] = stablePlatform.transform;
Destroy(stablePlatform.GetComponent<MeshRenderer>());
Destroy(stablePlatform.GetComponent<Collider>());
}
cornersPoint = null;
physicsSetup = true;
}
}
I believe animation would work better and provide more predictable results in this case.
Answer by AlucardJay · May 16, 2012 at 03:37 AM
Here's a part of my Hoverboard script.
What it does is check the distance down to the ground; if it is less than the specified height, it applies upward force at a percentage of the force needed to lift it up. The - Time.deltaTime is actually just a small number that is used to make sure the hoverForceMultiplier doesn't go above 1.
I have a Rigidbody of Mass 1, Use Gravity is Enabled (ticked).
EDIT - here's the C# version :
using UnityEngine;
using System.Collections;
public class HoverScript : MonoBehaviour
{
public float hoverDistance = 0.75f;
public float hoverForce = 10.0f;
private float currentHeight = 0.0f;
private float hoverForceMultiplier = 0.0f;
private Vector3 hoverForceApplied = Vector3.zero;
void FixedUpdate()
{
// -- find hover distance and add force to make hover
RaycastHit rayHit;
if (Physics.Raycast(transform.position, Vector3.down, out rayHit))
{
currentHeight = rayHit.distance;
if (currentHeight < (hoverDistance - Time.deltaTime))
{
// find percentage of currentHeight below hoverDistance
hoverForceMultiplier = (hoverDistance - currentHeight) / hoverDistance;
hoverForceApplied = (Vector3.up * hoverForce * hoverForceMultiplier) + (Vector3.up * 9.8f);
rigidbody.AddForce(hoverForceApplied);
} else {
// apply anti-gravity force for half distance above hoverDistance
if ((currentHeight - hoverDistance - Time.deltaTime) < (hoverDistance / 2))
{
hoverForceApplied = (Vector3.up * 9.8f) * ((hoverDistance - (currentHeight - hoverDistance)) / hoverDistance);
rigidbody.AddForce(hoverForceApplied);
}
}
}
}
}
Original Post :
It's in JS and right now I have no time to convert and check it. I shall make a C# vesion when I get home tonight =]
#pragma strict
var hoverDistance : float = 0.75;
var hoverForce : float = 10.0;
private var currentHeight : float = 0.0;
private var hoverForceMultiplier : float = 0.0;
private var hoverForceApplied : Vector3 = Vector3(0, 0, 0);
function FixedUpdate ()
{
// -- find hover distance and add force to make hover
var rayHit : RaycastHit;
if(Physics.Raycast(transform.position, Vector3.down, rayHit))
{
currentHeight = rayHit.distance;
if (currentHeight < (hoverDistance - Time.deltaTime))
{
// find percentage of currentHeight below hoverDistance
hoverForceMultiplier = (hoverDistance - currentHeight) / hoverDistance;
hoverForceApplied = (Vector3.up * hoverForce * hoverForceMultiplier) + (Vector3.up * 9.8);
rigidbody.AddForce(hoverForceApplied);
} else {
// apply anti-gravity force for half distance above hoverDistance
if ((currentHeight - hoverDistance - Time.deltaTime) < (hoverDistance / 2))
{
hoverForceApplied = (Vector3.up * 9.8) * ((hoverDistance - (currentHeight - hoverDistance)) / hoverDistance);
rigidbody.AddForce(hoverForceApplied);
}
}
}
}
example : http://www.alucardj.net16.net/unityquestions/HoverBoard6.html
Wow ok thanks a million! I'll run it through a converter and work out the bugs and get back to you.
EDIT
Initial conversion successful however the vehicle just kept increasing it's hover height. I will continue to tweak and get back. Also I have to turn off gravity?
I just converted and tested this , and it seems to be working ok.
I have a Rigidbody of $$anonymous$$ass 1, Use Gravity is Enabled (ticked).
using UnityEngine;
using System.Collections;
public class HoverScript : $$anonymous$$onoBehaviour
{
public float hoverDistance = 0.75f;
public float hoverForce = 10.0f;
private float currentHeight = 0.0f;
private float hoverForce$$anonymous$$ultiplier = 0.0f;
private Vector3 hoverForceApplied = Vector3.zero;
void FixedUpdate()
{
// -- find hover distance and add force to make hover
RaycastHit rayHit;
if (Physics.Raycast(transform.position, Vector3.down, out rayHit))
{
currentHeight = rayHit.distance;
if (currentHeight < (hoverDistance - Time.deltaTime))
{
// find percentage of currentHeight below hoverDistance
hoverForce$$anonymous$$ultiplier = (hoverDistance - currentHeight) / hoverDistance;
hoverForceApplied = (Vector3.up * hoverForce * hoverForce$$anonymous$$ultiplier) + (Vector3.up * 9.8f);
rigidbody.AddForce(hoverForceApplied);
} else {
// apply anti-gravity force for half distance above hoverDistance
if ((currentHeight - hoverDistance - Time.deltaTime) < (hoverDistance / 2))
{
hoverForceApplied = (Vector3.up * 9.8f) * ((hoverDistance - (currentHeight - hoverDistance)) / hoverDistance);
rigidbody.AddForce(hoverForceApplied);
}
}
}
}
}
I also updated the answer , let me know if you're still having problems with the gravity.
You probably don't want to use physics, because transform.Translate(...) do not work well with non-kinematic rigid bodies and I really doubt that you want to move all of your units with physics (rigidbody.AddForce)
I agree physics is probably not the way to go , but with no script in the question , and the asker stated "How do I go about applying force to the rigidbody", I had this script already made and it wasn't hard to convert, so I thought I would post it and maybe there would be some other ideas that could come out of it.
Thanks for all the replies, I really appreaciate it. $$anonymous$$y apologies for not thoroughly giving more for you to help, I've just been working on it for awhile and have not familiarised myself with everything inside the project.
Ok, so after testing $$anonymous$$ $$anonymous$$ay's converted C# script, $$anonymous$$y tank does NOT hover when it starts with gravity on and mass of 1. I had to increase the force to a ridiculous number and it will fly into the air upon colliding with a static object or going up the ramp.
Testing it with alucardj's conversion also results in the same situation.
Both code makes the tank fall slower but it still sticks to the ground. Should I make it check for tags and tag my floors?
Increasing the hover distance alone pulls the tank up forever only when going up a ramp.
Sorry to be vague with my question but essentially I have controls and camera's all set however all I need left to do is to have the model bob up and down constantly even through movement and up ramps but without adding animation in $$anonymous$$aya or something. I was suggested to add force for rigidbodies and since posted the question but what I want to know really is the best and simplest way to achieve this effect. Is there a way to not do it through physics or rather a "Hard-coded" method to achieving this?
Edit
Ok so I might have found the problem or part of it. When I print out the currentHeight variable, the results I get is weird. $$anonymous$$y tank starts at Y position 138 and the highest point in the entire map is 180 however according to the print I get 138 for my lowest point (correct) but when I am going up ramps or even on any slight descending or ascending planes, it gives me a single digit print.
Ok I'm still having the gravity problem however in one of the test's I noticed that it hovered (I had to add like 3000 force) but highly unbalanced. How do I prevent this? I saw this guy's video (http://virtualrealitydesign4.blogspot.com/2012/01/script-for-hovercraft-mechanics.html) where he used spheres at the corners for balancing.
$$anonymous$$AJOR EDIT
I've just been told that the project's gravity value was editted to -500. So do i change the value of 9.8 inside the code to 500 as I'm guessing that's the gravity value by default.
Ok so if I changed that value to 500, It works! With Hover Distance at 10 it will float and bob up and down! However the movements like how II feared. Highly unstable when going up ramps. Is there any work around to this problem?
Answer by Tseng · May 15, 2012 at 12:35 PM
As asafsitner mentioned, it's best to do it via animation, as it allows you to add unsteady hovering which also depends on the current state of the tank (i.e. moving, shooting, standing, searching).
You can always use Mathf.Cos or Mathf.Sin, as they will produce a periodical value which ranges from -1 to 1.
I would love to do it through animation however the current circumstance is not allowing me to do so and thus has to be done by script. I'm not too good with C# and unity so if you could help me get started on how to use $$anonymous$$athf.Cos or $$anonymous$$athf.Sin I would really appreaciate it.
What I'm trying to achieve is something like on this video (http://www.youtube.com/watch?v=JE0ZLq5bobc) however my controller and camera are all set I just simply need to make the tank hover up and down by time intervals.
Your answer
![](https://koobas.hobune.stream/wayback/20220613071510im_/https://answers.unity.com/themes/thub/images/avi.jpg)
Follow this Question
Related Questions
Multiple Cars not working 1 Answer
Distribute terrain in zones 3 Answers
A Proper Way To Pause A Game 9 Answers
UI 4.6 add pointer enter event to button, c# (Not using Editor) 1 Answer
playerprefs won't save scores when you close the game 2 Answers