- Home /
How to program gravity around a cylinder? (Vine growing up a tree)
With the player as the Vine growing up a tree, and other moving Rigidbodies (enemies/obstacles) along the tree, how would I go about programming gravity around the tree? Would I need unique moving gravity vectors for each Rigidbody?
Note: Need the game objects to interact like rigid bodies, so forced transform would not work,I know that this code is simple with a sphere, since there is a single, stationary center point, but how could this be done for movement around a cylinder? Would it require a moving gravity vector for each moving RigidBody along the cylinder?
Note: The player and other NPCs all need to be able to move around this cylinder, and be able to interact with each other like normal rigid bodies (no forced transform).
Answer by Bunny83 · Nov 29, 2018 at 11:48 PM
It works almost the same. However instead of using a single point as the center of gravity you just need to project the objects position onto the cylinders axis. To ger the point of gravity for an object you could just use Vector3.Project. However to get the actual direction of gravity you would then need to subract the object position from the specific center of gravity for this object. This can be achieved by just using the new Vector3.ProjectOnPlane which basically does this step already for you,
So for a sphere you would do something like:
Vector3 grav = sphereCenter - objPos;
For a cylinder you would do:
Vector3 grav = Vector3.ProjectOnPlane(cylinderCenter - objPos, cylinderAxis);
Here "cylinderCenter" can be any point that lies on the center axis of the cylinder and "cylinderAxis" is simply the direction vector / axis of the cylinder
Note that this of course only works for the "side" of a cylinder. So we assume an infinitely long cylinder. If you also want to be able to walk on the "base" disks of a finite cylinder, that's another story. However it's difficult to get a smooth transition between the gravity vector on the side surface of the cylinder and the top / bottom surface. It's also hard to tell when to switch between those. If this is needed you would probably do something like this:
Here we have to be more precise where our cylinderCenter is located. For this solution the center need to be the actual center. So the center point need to be the same distance from the top and bottom surface. Now we would do this:
// given
Vector3 cylinderCenter;
Vector3 cylinderAxis; // need to be normalized
float cylinderHalfLength;
float cylinderRadius;
// calculate gravity
Vector3 v = cylinderCenter - objPos;
float d = Vector3.Dot(v, cylinderAxis);
Vector3 grav = v - cylinderAxis * d;
if (Mathf.Abs(d) > cylinderHalfLength && grav.sqrMagnitude < cylinderRadius*cylinderRadius)
{
grav = -Mathf.Sign(d) * cylinderAxis;
}
The first 3 lines of the calculation essentially is the same what "ProjectOnPlane" does. However we get some of the intermediate values which we need to determine when an object is beyond the end of the cylinder and has entered the radius of the cylinder (so he's essentially on top / or bottom of the cylinder). Note that this implementation allows an object to easily leave the curved side of the cylinder and land on the top / bottom side. However the reverse is pretty tricky. The player would need to jump at the right moment off the base disk in order to land on the side. It's possible to reverse this so it's easy to get from the top / bottom disk surface onto the curved side surface but in this case it would be tricky to get back onto the top / bottom surface. For this you just would do:
if (Mathf.Abs(d) > cylinderHalfLength)
{
grav = -Mathf.Sign(d) * cylinderAxis;
}
In this case when the player goes beyond the cylinder length gravity would switch immediately to the top / bottom surface and push him back.
If you have a different case that isn't covered by my answer, you need to be more specific about your requirements and about your desired behaviour.