- Home /
Custom gravity based on normal vector and rigidbody.addForce
Hey all
I'm creating a game, where a ball is moving inside a tube. The ball should have the possible of moving along the inside of the tube all the way around, like it is stuck to the wall.
I have made a sample in 2D, which you can see a sketch of here. This shows a ball which is in the top half of the circle. Under normal gravity (one way gravity) it would fall down, but in my case, the gravity force should force the ball to stay close to the wall. The gravity axis is the negative normal vector in this case.
So, my problem is, that to ball won't stop bounce as soon as it hits the wall. The gravity axis is being set correctly..
I have based my gravity system a little on the FauxGravity.
Here is my code for the ball:
using UnityEngine; using System.Collections;
[RequireComponent(typeof(Rigidbody))] public class GravityForce : MonoBehaviour { // are we touching the surface? private int grounded = 0;
// Set to true for mono-directional gravity
private bool useLocalUpVector = false;
// Force applied along gravity up-vector (negative = down)
private float fauxGravity = 0.5f;
private float speed = 2f;
void Start()
{
rigidbody.WakeUp();
rigidbody.useGravity = false;
}
void FixedUpdate()
{
Vector3 gravityUp;
Vector3 tangent;
Vector3 moveDirection = new Vector3(0f, 0f, 0f);
// Figure out the body's up vector
if (useLocalUpVector)
{
gravityUp = transform.up;
}
else
{
RaycastHit hit;
bool hitData = Physics.Raycast(transform.position, -transform.up, out hit);
gravityUp = new Vector3(0f, 1f, 0f);
if (hitData)
{
if (hit.distance < 0.1) {
grounded++;
Debug.DrawRay(hit.point, hit.normal, Color.cyan);
gravityUp = -hit.normal.normalized;
tangent = Vector3.Cross(hit.collider.transform.right, hit.normal).normalized;
Debug.DrawRay(hit.point, tangent, Color.magenta);
Debug.Log("gravityUp: " + gravityUp);
}
}
gravityUp.Normalize();
}
// Accelerate the body along its up vector
Vector3 v = gravityUp;
rigidbody.AddForce(new Vector3(v.x, v.y, 0) * fauxGravity * rigidbody.mass);
rigidbody.drag = (grounded > 0) ? 1.0f : 0.1f;
}
}
Unity package sample (zip-file)
I hope you can help :-S
Hey man I am looking for exactly the same thing. I have had a go at scripting it myself but I just can't seem to get it right. I tried to download your zip but that didn't work for some reason. is there any chance you could send me a copy of your package or more information on how you achieved this effect.
I see the post below solved your problem. Did you implement the code below with your code OR just use the code below?
Please Help
Joe
Answer by Bunny83 · Apr 05, 2011 at 01:25 PM
I've tried your package and i've found some problems:
- You overall scale is too small. Physics needs some intersection to detect collisions properly. Your sphere collider have a radius of 0.36mm (0.00036 units) that's why the collision response doesn't work properly.
- Your raycast approach is a bit confusing. You raycast always in the same direction so you can never make a full circle.
- You inverted the gravity two times once where you get the normal vector and then you subtract it from your force.
- Your movement speed is also affected by your
fauxGravity
variable. - If you use
AddForce
you mustn't multiply with the mass.acceleration = Force/mass
that is calculated by unity, you just give the force value.
If you don't have other objects affected by gravity, I would recommend to use the default gravity and change that one accordingly. Just set Physics.gravity
to your gravity. Instead of a Raycast just use the collision info you get from the collision events. OnCollisionStay will work best in that case.
float myGravity = 9.81f; void OnCollisionStay(Collision col) { Vector3 n = Vector3.zero; foreach (ContactPoint C in col.contacts) n += C.normal; n.Normalize();
Physics.gravity = -n*myGravity;
}
If you want to work only in 2D you should reset the third axis frequently. Physics response can some add little forces in any direction.
I've tweaked it a bit and it works for me. I can roll inside or outside ;) (outside can cause some problems, if you move very fast you just start to fly)
I calculated the tangent with crossproduct between z-axis (Vector3.forward) and gravity vector.
ps. even in FixedUpdate you should use Time.deltaTime. The values will match realworld values (velocity in m/s, acceleration in m/s and not sure about the mass, if it's in kg the force would be in N (kg*m/s))
Thanks man! That was really helpful! You just fixed the problem that I have had for the last week! You are a GOD!
Hey do you have a package that I could look at. I can't find documentation on this topic. Please help
Answer by Statement · Apr 05, 2011 at 11:57 AM
Try setting Acceleration ForceMode (which gravity is).
var gravityAcc = new Vector3(gravityUp.x, gravityUp.y, 0) * fauxGravity;
rigidbody.AddForce(gravityAcc, ForceMode.Acceleration);