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?
The way I would do it is with trigonometry (unless someone has a better built-in solution). Code (csharp): //this is if you are coding in Javascript...C# shouldn't be much different #pragma strict; var prefab:Transform; var centerX:float=100.0; //feel free to change these numbers var centerY:float=0.0; var centerZ:float=100.0; var radiusOfOrbit:float=25.0; var speedOfOrbit:int=5; //keep this number between 1-15 var convert:float=0.0; //needed later for type casting in JS var Xs = new List.<float>(); var Zs= new List.<float>(); function radiansToDegrees(degrees:float){ //just so that Mathf.sin/cos give us something we can work with return degrees * (3.14159265 / 180); } for(var i:int=0;i<=180;i+=speedOfRotation){ convert=parseFloat(j); Xs.Add(centerX+(radiansToDegrees(Mathf.cos(convert)*radiusOfOrbit))); Zs.Add(centerZ+(radiansToDegrees(Mathf.sin(convert)*radiusOfOrbit))); Xs.Add(centerX-(radiansToDegrees(Mathf.cos(convert)*radiusOfOrbit))); Zs.Add(centerZ-(radiansToDegrees(Mathf.sin(convert)*radiusOfOrbit))); Instantiate(prefab, Xs[j],centerY,Zs[j],Quaternion.identity); //this may cause the ball to rotate in an odd way, srry } //yes,yes this is very inefficient code
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): Physics.gravity = Vector3.zero Add the respective force to each "little object" to the center of the planet in the fixed update Code (csharp): Transform planet //you need a reference to the planet float gravityForce = 10; void FixedUpdate() { Vector3 gravityDirection = (transform.position - planet.position).normalize; rigidbody.AddForce(gravityDirection * gravityForce); } Then you just can add relativeForces to the "little objects" and they allways will be "falling" to the center of the planet.
You can also add a sphere trigger to the "planet", which is the simulated gravity field and in the Code (csharp): public class PlanetGravitation : MonoBehaviour { public float gravity = -9.81f; void OnTriggerStay(Collider other) { // get the direction vector and normalize it (magnitude = 1) Vector3 direction = other.transform.position - planetaryCenter; Vector3 force = direction.normalized * gravity; // accelerate the object in that direction other.rigidbody.AddForce(force, ForceMode.Acceleration); } } @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.
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.
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.
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): var ScurrySpeed = 30; private var testChange = -1; //during production the mobs should run away from the camera, but during development I want to see //them all run at the camera hence the -1 modifier during testing private var DistanceX : float; private var DistanceY : float; private var DistanceZ : float; private var gravityForce = -10; private var ParentVector : Vector3; ParentVector = transform.parent.position; function FixedUpdate(){ //check location of spheres and keep them close to the world var gravityDirection : Vector3; gravityDirection.x = (transform.position.x - ParentVector.x); gravityDirection.y = (transform.position.y - ParentVector.y); gravityDirection.z = (transform.position.z - ParentVector.z); rigidbody.AddForce(gravityDirection * gravityForce); } function Update () { var GoalX = GameObject.Find("DarkSide").transform.position.x; var GoalY = GameObject.Find("DarkSide").transform.position.y; var GoalZ = GameObject.Find("DarkSide").transform.position.z; DistanceX = Mathf.Abs(GoalX - transform.position.x); DistanceY = Mathf.Abs(GoalY - transform.position.y); DistanceZ = Mathf.Abs(GoalZ - transform.position.z); if((transform.position.x < 10 transform.position.x > -10) (transform.position.y < 10 transform.position.y > -10) transform.position.z < (testChange * 100)) { Debug.Log(transform.name + " is here."); transform.renderer.material.color = Color.green; // do nothing we are at the right location } else { if (transform.name == "Sphere2") { Debug.Log("S2 X: " + transform.position.x + " Y: " + transform.position.y + " Z: " + transform.position.z); Debug.Log("Target X: " + GoalX + " Y: " + GoalY + " Z: " + GoalZ); } transform.renderer.material.color = Color.red; MoveSphere(); } } function MoveSphere () { if (transform.position.x == 0 transform.position.y == 0 transform.position.z < 0) //assume we are at 0,0,-100 { transform.RotateAround(Vector3.zero, Vector3.up, ScurrySpeed * Time.deltaTime); } else if (transform.position.y < 0) //we are in the southern hemisphere { if(transform.position.x < 0) // we are on the left { transform.RotateAround(Vector3.zero, Vector3(testChange * -1,testChange * 1,testChange * 0), ScurrySpeed * Time.deltaTime); } else // we are on the right { transform.RotateAround(Vector3.zero, Vector3(testChange * -1,testChange * -1,testChange * 0), ScurrySpeed * Time.deltaTime); } } else // we are in the northern hemisphere { if(transform.position.x < 0) // we are on the left { transform.RotateAround(Vector3.zero, Vector3(testChange * 1,testChange * 1,testChange * 0), ScurrySpeed * Time.deltaTime); } else // we are on the right { transform.RotateAround(Vector3.zero, Vector3(testChange * 1,testChange * -1,testChange * 0), ScurrySpeed * Time.deltaTime); } } } The only other code I have is my world code: Code (csharp): private var h : float = 0; private var v : float = 0; var RotateSpeed = 2; function Start() { Physics.gravity = Vector3.zero; } function Update () { Physics.gravity = Vector3.zero; v = Input.GetAxis("Horizontal") * Time.deltaTime * RotateSpeed; h = Input.GetAxis("Vertical") * Time.deltaTime * RotateSpeed; transform.Rotate(h,(v * -1),0,0); } 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.
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.
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): var gravityDirection : Vector3; gravityDirection.x = (transform.position.x - ParentVector.x); gravityDirection.y = (transform.position.y - ParentVector.y); gravityDirection.z = (transform.position.z - ParentVector.z); // can be done as var gravityDirection : Vector3 = transform.position - ParentVector; Short, clear and easier to read. And last one. There is no need to use RotateAround. Use transform.Translate, i.e. Code (csharp): transform.Translate(Vector3.forward * forwardSpeed); 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 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.