Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Planetary Gravity

Discussion in 'Scripting' started by Zuzeko, Sep 1, 2010.

  1. Zuzeko

    Zuzeko

    Joined:
    Sep 1, 2010
    Posts:
    3
    Hello to the forums!
    And dear god hopefully someone can help me a little on this :/

    I'm quite new to unity, only being aware of it's existence for little over a month and with only a dismal scrap of a game to my name. And I of course made my next project for uni as hard as possible by passively absorbing Super Mario Galaxy 2 gameplay into my subconscious.

    I need to set up a scene where I have one large planetary mass which creates it's own field of gravity.
    I need to have a character object that can traverse the planet sticking to it's surface. And by stick, I mean remain feet-first on the surface.
    Likewise I need enemy ai objects that can chase the character, but I'm sure I can work that out on my own steam.

    I want the gameplay to be limited to a 2D platformer with 3D graphics, thus restricting the movement controls to forwards, backwards and up(jump).


    Being able to jump between planets would be nice, but is optional.

    Research that I have done includes Podperson's faux gravity thread
    http://forum.unity3d.com/viewtopic.php?t=9476&postdays=0&postorder=asc&start=0
    Where I got the whole system to work, (I really loved how well they worked)
    Except that the character controllers consistently caused objects to launch themselves into orbit or even to fall off of the base of the planet for no particular reason. It was very difficult to control where the character was going, and that's precisely what I need to fix first.



    The whole basis of the game that I'm trying to create is based of of a little physics notion that if you got everybody (providing there was enough collective mass) on the planet to walk in one direction, it could affect the rotation of the earth. It's based in Newton's third law, that for every action there's an equal and opposite reaction. (Yes, I know it's rather unlikely and full of conjecture, but the thing is in a game, don't sweat the details)




    Essentially, I've been running round the forums and testing and tweaking snippets of code. I've included a small picture diagram of what I'm trying to achieve, rotation of the actual planet isn't necessary for in game, I can make cutscenes illustrating that point.
    You're the yellow thing and you run. Fast. Carrying delicious bait.

    Can anybody tell me how they've gotten characters to be properly controllable when working under faux gravity constraints?
    Or do I have to try a more realistic approach and recalculate the individual y axis for the character?
    And if so, any help?
    meep!
     

    Attached Files:

  2. Jesse Anders

    Jesse Anders

    Joined:
    Apr 5, 2008
    Posts:
    2,857
    The exact specifications of your project aren't entirely clear to me, but a typical approach to this problem is to raycast straight down from the character, move the character so that its feet (or whatever) are on the surface below it (if any), and then align the character correctively with the surface normal (typically using a function such as Quaternion.FromToRotation()). This is discussed quite frequently on the forums; a search for (e.g.) 'mario galaxy' should turn up quite a few threads on the topic.

    If that doesn't help, perhaps you could go into a bit more detail about exactly what behavior you need.
     
  3. Zuzeko

    Zuzeko

    Joined:
    Sep 1, 2010
    Posts:
    3
    Yeah, I can be a little obtuse like that (sorry)

    The gamestyle is to be a little cute/quirky, think Katamari or yoshi's story.

    Somewhere in a universe, there's a solar system where all the planets have stopped rotating/orbiting, it's basically in stasis. All the native fauna have died out, and there are just dead planets hanging in space. You are sent out to go and roll them back into orbit by populating them with enemies and getting them to run after you, thus rotating the planet and bringing the solar system to life.

    What I'm struggling with right now, is making one level in particular.

    There is a character object on a three dimensional planet.
    The planet is static.
    The camera is static, looking at the planet from a side view.
    There are checkpoints on the top and the bottom of the planet, represented as little flags.

    Three enemy characters spawn, and start to head for the character, character runs.
    The character must run around the circumference of the planet, guiding the enemies into the checkpoints in the correct order. Completing a set number of checkpoints in the right order will cause you to win the level.

    Optionally,
    Each correctly reached checkpoint will incrementally cause the planet to rotate opposite to the motion of the character until completion of the level.


    So what I need help with is making sure that the character actually sticks to the underside of the planet, not falls of when they run there.
    Also, I need to be able to get the character to be able to run there. Most of the character controllers I've used have not been able to deliver reliable predictable results, and I guess this is just because left isn't left anymore when you're on the underside of a planet. But it's the part I'm having most difficulty with :/

    Also, I have listed all of the useful links on this subject that I've been able to dig out




    http://answers.unity3d.com/questions/6266/how-do-i-make-a-small-planet-with-gravitational-pull

    http://answers.unity3d.com/questions/17667/how-can-i-implement-planet-gravity-in-my-game

    http://forum.unity3d.com/viewtopic.php?p=238203

    http://answers.unity3d.com/questions/6682/run-around-a-ball-heeelp

    http://www.scottpetrovic.com/blog/2010/06/unity3d-planetary-gravity-daylight-system-wsource/

    http://www.gamasutra.com/view/feature/3593/games_demystified_super_mario_.php

    http://forum.unity3d.com/viewtopic.php?p=268519

    http://forum.unity3d.com/viewtopic.php?p=219859
     
  4. Jesse Anders

    Jesse Anders

    Joined:
    Apr 5, 2008
    Posts:
    2,857
    Sounds like a neat idea for a game :)

    Well, it looks like you've done your research, which is good :) However, at this point I can't offer much beyond what I described in my previous post, which is really the standard solution to this sort of problem, more or less.

    If my earlier post and the threads you linked to aren't providing the info you need, could you narrow down your question a bit? What have you tried so far? And what sort of problems, specifically, are you running into?

    Also, if you can reduce the problem to a relatively short bit of code, you might post it here so that we can take a look at it.
     
  5. Zuzeko

    Zuzeko

    Joined:
    Sep 1, 2010
    Posts:
    3
    Ok, so I think I've nailed what my problem is at the moment.

    Using the FauxGravity attractors and bodies scripts, I can't use a character controller for my motion.
    Character controllers use their own gravity and it conflicts with the false one I'm implementing. I can't have motion that relies on being grounded, at least in the sense that the character controller scripts like FPSwalker use. Also, I can't just move along the axes, because x won't be x anymore when i'm upside down. So... I need a script to enable my character to move, without it being a character controller script. I think. Still not entirely sure.

    A friend of mine suggested directions based from the normals, and we came up with this:
    ____________________________________________________________
    function Update () {
    var direction = transform.TransformDirection(Vector3.forward);
    var hit : RaycastHit;

    Physics.Raycast (transform.position, direction, hit, range);
    MyCharacter.transform.rotation = Quaternion.FromToRotation(Vector3.up, hit.normal);
    }
    ----------------------------------------------------------------------------------------------------------

    But yes, if you can't determine from this messy thing that we're absolute novices then... well I didn't really think that statement through.

    This is the Code I've been using, just with a simple capsule and large sphere set up so far.


    =================================================================================================
    Posted: Sat Jan 02, 2010 9:21 am Post subject:
    I made some edits to the faux gravity scripts if anyone else needs them.

    The first one adds a fadeout radius to the gravities pull, with gizmos to show you the fade.

    Code:
    -----------------------------------------------------------------------------------------------
    /*
    FauxGravityAttractor.js
    Written by Tonio Loewald ©2008

    Attach this script to objects you want to exert Faux Gravity
    */

    // Force applied along gravity up-vector (negative = down)
    var fauxGravity = -10.0;

    //everything within this radius is pulled towards the center at a constant rate in all areas
    var gravityRadius : float;

    //gravityRadius will fade out to zero pull by the time it reaches this radius ( make bigger than gravityRadius)
    var gravityRadiusFade : float;

    //makes the gravityRadius's proportionate to the objects scale
    var RadiiProportionateToScale : boolean = true;

    //controls ratio of gravityRadius var to the objects scale
    var radiusProportion : float = .75;

    //controls ratio of gravityRadiusFade var to the objects scale
    var radiusFadeProportion : float = 1.5;

    function Attract ( body : FauxGravityBody ){

    var gravityUp : Vector3;
    var localUp: Vector3;
    var localForward : Vector3;

    var t : Transform = body.transform;
    var r : Rigidbody = body.rigidbody;

    var shipDistance : float = Vector3.Distance(transform.position, body.transform.position);

    // Figure out the body's up vector
    gravityUp = t.position - transform.position;
    gravityUp.Normalize();

    gravityRadius = transform.localScale.x * .75;
    gravityRadiusFade = transform.localScale.x * 1.5;


    // Accelerate the body along its up vector
    if (shipDistance < gravityRadius)
    {
    r.AddForce(gravityUp * fauxGravity);
    }
    else if ( shipDistance > gravityRadius shipDistance < gravityRadiusFade)
    {
    //percentage of position inbetween radius
    r.AddForce(gravityUp * (fauxGravity * (1 -(shipDistance - gravityRadius) / (gravityRadiusFade - gravityRadius))));
    }

    if (body.grounded){
    r.drag = 0;
    }

    }


    function OnDrawGizmos () {

    if (RadiiProportionateToScale)
    {
    gravityRadius = transform.localScale.x * radiusProportion;
    gravityRadiusFade = transform.localScale.x * radiusFadeProportion;
    }

    Gizmos.color = Color.white;

    Gizmos.DrawWireSphere(transform.position, gravityRadius);
    Gizmos.DrawWireSphere(transform.position, gravityRadiusFade);
    }
    -----------------------------------------------------------------------------------------------

    The second one lets you put multiple fauxGravityAttractors onto one fauxGravityBody

    Code:
    -----------------------------------------------------------------------------------------------
    /*
    FauxGravityBody.js
    Written by Tonio Loewald ©2008

    Attach this script to objects you want to be affected by FauxGravity
    */

    // this is the thing we're gravitationally attracted to
    var attractor : FauxGravityAttractor[];

    // are we touching the surface?
    var grounded : int;

    var attract : boolean = true;

    function Start () {
    rigidbody.WakeUp();
    rigidbody.useGravity = false;
    }

    // obviously this is crude since we might want to be able to stand on (and jump off) random objects
    // should probably filter based on tag in future
    function OnCollisionEnter (c : Collision) {
    if( c.gameObject.layer == 10 ){
    grounded ++;
    }
    }

    function OnCollisionExit (c : Collision) {
    if( c.gameObject.layer == 10 grounded > 0 ){
    grounded --;
    }
    }

    function FixedUpdate () {

    if (attract)
    {
    for ( i=0; i < attractor.length; i++){

    if(attractor){
    attractor.Attract(this);
    }
    }
    }

    }

    @script RequireComponent(Rigidbody)
    -------------------------------------------------------------------------------------------------