Search Unity

moving around a sphere

Discussion in 'Scripting' started by ghreef, Apr 10, 2012.

  1. ghreef

    ghreef

    Joined:
    Sep 20, 2011
    Posts:
    46
    Can anyone give guidance on how I can manage moving a rigidbody around a sphere? Very similar to Mario World from Wii - I have a sphere (earth) and I want little objects to basically walk around on the surface. At first I have the "earth" sphere at 0,0,0 and had the "people" under the "earth's" hierarchy. I then used a transform.rotatearound(vector3.zero...) but that won't work when I want the "people" to turn and walk on an angle. Can anyone provide a suggestion? Is there a way to say the "people" should use "earth" as the gravity point?
     
  2. symentax4797

    symentax4797

    Joined:
    Mar 14, 2012
    Posts:
    9
    The way I would do it is with trigonometry (unless someone has a better built-in solution).
    Code (csharp):
    1.  
    2. //this is if you are coding in Javascript...C# shouldn't be much different
    3. #pragma strict;
    4. var prefab:Transform;
    5. var centerX:float=100.0; //feel free to change these numbers
    6. var centerY:float=0.0;
    7. var centerZ:float=100.0;
    8. var radiusOfOrbit:float=25.0;
    9. var speedOfOrbit:int=5; //keep this number between 1-15
    10. var convert:float=0.0; //needed later for type casting in JS
    11. var Xs = new List.<float>();
    12. var Zs= new List.<float>();
    13.  
    14. function radiansToDegrees(degrees:float){ //just so that Mathf.sin/cos give us something we can work with
    15.      return degrees * (3.14159265 / 180);
    16. }
    17.  
    18. for(var i:int=0;i<=180;i+=speedOfRotation){
    19.        convert=parseFloat(j);
    20.        Xs.Add(centerX+(radiansToDegrees(Mathf.cos(convert)*radiusOfOrbit)));
    21.        Zs.Add(centerZ+(radiansToDegrees(Mathf.sin(convert)*radiusOfOrbit)));
    22.        Xs.Add(centerX-(radiansToDegrees(Mathf.cos(convert)*radiusOfOrbit)));
    23.        Zs.Add(centerZ-(radiansToDegrees(Mathf.sin(convert)*radiusOfOrbit)));
    24.        Instantiate(prefab, Xs[j],centerY,Zs[j],Quaternion.identity); //this may cause the ball to rotate in an odd way, srry
    25. }
    26. //yes,yes this is very inefficient code
    27.  
     
  3. Metalero91

    Metalero91

    Joined:
    Mar 19, 2012
    Posts:
    83
    Yes you can, and this would be a simple solutions (depending on what king a moves you want the "little objects" to do)

    Basically you need 2 things:

    set the gravity to zero

    Code (csharp):
    1.  
    2. Physics.gravity = Vector3.zero
    3.  
    Add the respective force to each "little object" to the center of the planet in the fixed update

    Code (csharp):
    1.  
    2. Transform planet //you need a reference to the planet
    3.  
    4. float gravityForce = 10;
    5.  
    6. void FixedUpdate()
    7. {
    8.   Vector3 gravityDirection = (transform.position - planet.position).normalize;
    9.   rigidbody.AddForce(gravityDirection * gravityForce);
    10. }
    11.  
    Then you just can add relativeForces to the "little objects" and they allways will be "falling" to the center of the planet.
     
  4. Tseng

    Tseng

    Joined:
    Nov 29, 2010
    Posts:
    1,217
    You can also add a sphere trigger to the "planet", which is the simulated gravity field and in the

    Code (csharp):
    1.  
    2. public class PlanetGravitation : MonoBehaviour {
    3.     public float gravity = -9.81f;
    4.  
    5.     void OnTriggerStay(Collider other) {
    6.         // get the direction vector and normalize it (magnitude = 1)
    7.         Vector3 direction = other.transform.position - planetaryCenter;
    8.         Vector3 force = direction.normalized * gravity;
    9.  
    10.         // accelerate the object in that direction
    11.         other.rigidbody.AddForce(force, ForceMode.Acceleration);
    12.     }
    13. }
    14.  
    @Metalero91:
    It's bad creating objects (i.e. player) which depend on some outside object. It makes it harder to reuse and the logic gets more complicated than necessary. Doing it with a trigger the logic gets separated correctly.

    It makes no sense for the player object to be aware of gravity and how the gravity works. The gravity is related to the planet and the player is only affected by it. the player object do not needs to know how gravity works. This is a much cleaner approach.
     
    Last edited: Apr 11, 2012
    Harinezumi and Habitablaba like this.
  5. ghreef

    ghreef

    Joined:
    Sep 20, 2011
    Posts:
    46
    Tseng:

    Are you assuming the little objects are the player? There is no "player". Really just a camera looking at the world, watching smaller objects "orbit" the larger world on it's surface. Not sure if this changes your approach to the situation.

    Use case:

    1 camera - looking a "earth"
    earth as Vector2.zero
    lots of little objects (I'll call them moons for simplicity) will move around the "earth" on it's surface.

    That's all I'm trying to accomplish. I thought I could just rotate the moons around their parent transform (the earth) but they seem to wiggle when they reach their destination and start to drift off the earth's surface, so I'm trying to force them to stay in contact with the earth.

    In a later variation, I may make it so they can be pushed off the surface and should return (again much like a gravitational pull) to the surface and continue on their path to their destinations.
     
  6. Tseng

    Tseng

    Joined:
    Nov 29, 2010
    Posts:
    1,217
    Player was an example, as it's the most obvious thing to mean. And I think you meant Mario Galaxy not Mario World.

    Like this
    http://www.youtube.com/watch?v=qg-0ff7L7hw&feature=player_detailpage#t=364s

    Something like that I guess, where you have a small planet and want have the player (or enemies, or other script controlled objects).

    What the gravity script does is simply accelerating the objects within it's radius toward the "planet center". Everything else you must control your self (i.e. walking forward/turning left/right).

    What the script doesn't do (yet) is rotating the object, but that shouldn't be to hard, since you already have a direction, just the players up (or down) axis toward the gravitation direction.
     
  7. ghreef

    ghreef

    Joined:
    Sep 20, 2011
    Posts:
    46
    Yes, Mario Galaxy - sorry.

    Here's my code - it works great for 1 sphere, but as soon as I add more spheres, everything goes to crap. Any clues what I did wrong? (basically this script is attached to all my spheres)

    Code (csharp):
    1. var ScurrySpeed = 30;
    2.  
    3. private var testChange = -1; //during production the mobs should run away from the camera, but during development I want to see
    4.                                 //them all run at the camera hence the -1 modifier during testing
    5. private var DistanceX : float;
    6. private var DistanceY : float;
    7. private var DistanceZ : float;
    8. private var gravityForce = -10;
    9. private var ParentVector : Vector3;
    10.     ParentVector = transform.parent.position;
    11.  
    12. function FixedUpdate(){
    13. //check location of spheres and keep them close to the world
    14.     var gravityDirection : Vector3;
    15.     gravityDirection.x = (transform.position.x - ParentVector.x);
    16.     gravityDirection.y = (transform.position.y - ParentVector.y);
    17.     gravityDirection.z = (transform.position.z - ParentVector.z);
    18.     rigidbody.AddForce(gravityDirection * gravityForce);
    19. }
    20.  
    21.  
    22. function Update () {
    23.  
    24. var GoalX = GameObject.Find("DarkSide").transform.position.x;
    25. var GoalY = GameObject.Find("DarkSide").transform.position.y;
    26. var GoalZ = GameObject.Find("DarkSide").transform.position.z;
    27.  
    28. DistanceX = Mathf.Abs(GoalX - transform.position.x);
    29. DistanceY = Mathf.Abs(GoalY - transform.position.y);
    30. DistanceZ = Mathf.Abs(GoalZ - transform.position.z);
    31.  
    32.  
    33. if((transform.position.x < 10  transform.position.x > -10)  
    34.     (transform.position.y < 10  transform.position.y > -10)  
    35.         transform.position.z < (testChange * 100))
    36.     {
    37.     Debug.Log(transform.name + " is here.");
    38.     transform.renderer.material.color = Color.green;
    39.     // do nothing we are at the right location
    40.     }
    41. else
    42.     {
    43.     if (transform.name == "Sphere2")
    44.     {
    45.         Debug.Log("S2 X: " + transform.position.x + " Y: " + transform.position.y + " Z: " + transform.position.z);
    46.         Debug.Log("Target X: " + GoalX + " Y: " + GoalY + " Z: " + GoalZ);
    47.        
    48.     }
    49.     transform.renderer.material.color = Color.red;
    50.     MoveSphere();
    51.     }
    52. }
    53.  
    54. function MoveSphere () {
    55.  
    56. if (transform.position.x == 0  transform.position.y == 0  transform.position.z < 0) //assume we are at 0,0,-100
    57.     {
    58.     transform.RotateAround(Vector3.zero, Vector3.up, ScurrySpeed * Time.deltaTime);
    59.     }
    60. else if (transform.position.y < 0) //we are in the southern hemisphere
    61.     {
    62.     if(transform.position.x < 0) // we are on the left
    63.         {
    64.         transform.RotateAround(Vector3.zero, Vector3(testChange * -1,testChange * 1,testChange * 0), ScurrySpeed * Time.deltaTime);
    65.         }
    66.     else // we are on the right
    67.         {
    68.         transform.RotateAround(Vector3.zero, Vector3(testChange * -1,testChange * -1,testChange * 0), ScurrySpeed * Time.deltaTime);
    69.         }
    70.     }
    71. else // we are in the northern hemisphere
    72.     {
    73.     if(transform.position.x < 0) // we are on the left
    74.         {
    75.         transform.RotateAround(Vector3.zero, Vector3(testChange * 1,testChange * 1,testChange * 0), ScurrySpeed * Time.deltaTime);
    76.         }
    77.     else // we are on the right
    78.         {
    79.         transform.RotateAround(Vector3.zero, Vector3(testChange * 1,testChange * -1,testChange * 0), ScurrySpeed * Time.deltaTime);
    80.         }
    81.     }
    82.  
    83. }
    84.  
    85.  

    The only other code I have is my world code:
    Code (csharp):
    1. private var h : float = 0;
    2. private var v : float = 0;
    3.  
    4. var RotateSpeed = 2;
    5.  
    6. function Start() {
    7.     Physics.gravity = Vector3.zero;
    8. }
    9.  
    10. function Update () {
    11.  
    12. Physics.gravity = Vector3.zero;
    13.  
    14. v = Input.GetAxis("Horizontal") * Time.deltaTime * RotateSpeed;
    15. h = Input.GetAxis("Vertical") * Time.deltaTime * RotateSpeed;
    16.    
    17. transform.Rotate(h,(v * -1),0,0);
    18.  
    19. }
    20.  
    The world is at vector3.zero and all the spheres are children of the world. I then have a camera pointing at 0,0,100 of the world and the sphere's target (darkside) sitting exactly opposite from the camera 0,0,-100. Basically, I want the spheres to hide from the camera.

    any help would be appreciated.
     
  8. Tobias J.

    Tobias J.

    Joined:
    Feb 21, 2012
    Posts:
    423
    I'm getting confused. You now seem to refer to both the 'little objects' and the larger objects they 'belong' to, as 'spheres'?

    In any case you'll need to tell the 'little objects' which of the 'larger objects' they should refer to.

    You could keep a list of little objects on each of the larger objects, and then iterate over that list and update the behaviour of each little object.
     
  9. Tseng

    Tseng

    Joined:
    Nov 29, 2010
    Posts:
    1,217
    What is the "ParentVector"? The Planet? And you still use the RotateAround. And you ignored my argument that gravity calculation doesn't belong in the objects, it makes your "Objects walking on the planet"-script unnecessary complicated.

    Gravity is something, that is associated with the planet, hence the planet must determinate the direction and apply it, not the objects on it.

    Simply place the script I've posted above in your planet and add a sphere trigger to it. Make the sphere colider as big as required (everything within that collider will be affected by the gravity, everything outside won't.

    This one script will apply gravity to all objects within the sphere collider. And your object scripts will be cleaner, because you don't have unnecessary trash inside it.

    Second: Why are you calculating each position yourself? You can do that in one line
    Code (csharp):
    1.  
    2.     var gravityDirection : Vector3;
    3.     gravityDirection.x = (transform.position.x - ParentVector.x);
    4.     gravityDirection.y = (transform.position.y - ParentVector.y);
    5.     gravityDirection.z = (transform.position.z - ParentVector.z);
    6.  
    7. // can be done as
    8.     var gravityDirection : Vector3 = transform.position - ParentVector;
    9.  
    Short, clear and easier to read.

    And last one. There is no need to use RotateAround. Use transform.Translate, i.e.

    Code (csharp):
    1.  
    2.     transform.Translate(Vector3.forward * forwardSpeed);
    3.  

    Though, while writting this, I realized a few... "problems".

    a) one shouldn't normally use transform.Translate (or any form of moving the position or rotation) with an non-kinematic, because translate ignores the physics (i.e. it can moves an object into another object which can't be done normally, which results into it "bouncing" off very fast) and leads to undesired behaviour
    b) if you use kinematic rigidbodies, then you don't have the side effecets, but you can't use AddForce to simulate gravity and your object will walk through other static objects. Then instead you'd have the planet to move all objects in it's raidus towards the center. Shouldn't be a problem. Main problem is, that a kinematic body would fall through the planet using this :p
    c) character controler doesn't seem to work neither in this scenario

    Well you could try the transform.Translate route, in a quick modification of one of my project it seemd to work farily ok, though the controls are bit weird.