Search Unity

2D Orbiting Black Hole

Discussion in 'Physics' started by rxmarccall, Mar 14, 2015.

  1. rxmarccall

    rxmarccall

    Joined:
    Oct 13, 2011
    Posts:
    353
    I am trying to create a 2D gravity attractor that orbits objects towards its center as shown in the following image:

    Here is the code that I have so far to try and accomplish this. (Its attached to objects I want to "orbit" a chosen object. It only begins to orbit once it enters a trigger collider of the source of the gravity)

    Code (CSharp):
    1.  
    2. [Header ("Faux Grav Props")]
    3.     public float gravityForce = 50;
    4.  
    5.     private Transform blackHoleCenter;
    6.     private Rigidbody2D rigidbody;
    7.     private bool fauxGravityEnabled = false;
    8.  
    9.     // Use this for initialization
    10.     void Start () {
    11.         blackHoleCenter = GameObject.FindGameObjectWithTag("Oven").transform;
    12.         rigidbody = this.GetComponent<Rigidbody2D>();
    13.     }
    14.  
    15.     void FixedUpdate(){
    16.         if (fauxGravityEnabled){
    17.             TransformLookat2D();
    18.             rigidbody.AddForce(transform.forward*gravityForce);
    19.             rigidbody.AddForce(transform.right*gravityForce);
    20.         }
    21.     }
    22.  
    23.     void OnTriggerEnter2D(Collider2D coll){
    24.         if (coll.gameObject.tag == "Oven"){
    25.             rigidbody.velocity = Vector2.zero;
    26.             fauxGravityEnabled = true;
    27.         }
    28.     }
    29.  
    30.     void OnTriggerExit2D(Collider2D coll){
    31.         if (coll.gameObject.tag == "Oven"){
    32.             fauxGravityEnabled = false;
    33.         }
    34.     }
    35.  
    36.     void TransformLookat2D(){
    37.         Vector3 dir = blackHoleCenter.position - transform.position;
    38.         float angle = Mathf.Atan2(dir.y,dir.x) * Mathf.Rad2Deg;
    39.         transform.rotation = Quaternion.AngleAxis(angle, Vector3.forward);
    40.     }
    41.  
    42.  
    This code however acts more like the following image, springing the object back and forth but not actually orbiting towards the center:


    Any thoughts or ideas on how to do this correctly would be appreciated!
     
  2. mangax

    mangax

    Joined:
    Jul 17, 2013
    Posts:
    336
    that's because you made the object approach the chosen object very directly as if it will hit it head to head...
    what i suggest is to make it approach it from side ..far away from center of gravity...
     
  3. rxmarccall

    rxmarccall

    Joined:
    Oct 13, 2011
    Posts:
    353
    Yea, ideally I would like to find a way to achieve that affect no matter what angle the object comes at, I guess thats where the real problem is...
     
  4. sleekdigital

    sleekdigital

    Joined:
    May 31, 2012
    Posts:
    133
    Then using physics might not be the best way. It looks like you want more of a whirlpool effect rather than an orbit effect. An orbit doesn't behave as you describe. The approach vector absolutely matters for an orbit. An object doesn't enter an orbit if it is already headed directly at a planet. If you sail directly toward a whirlpool, however, you get swept up in the current and move in the sort of path you describe. Creating a whirlpool force with physics sounds pretty tricky. Doing it with tweening should be pretty simple though.

    One approach is to parent the object to an empty gameobject that is positioned at the center. Animate that central gameobject to simply rotate. I often use LeanTween for this sort of thing. Here is the code you might use for continuous 360 rotation...
    rotateTween = LeanTween.rotateAround(rotator, Vector3.back, 360, 4f).setRepeat(-1).setLoopClamp();

    Now when you first parent the object to this rotating empty game object, if you make sure that the x or y axis of the object is pointing at the center of the "planet", all you have to do is make a second tween that moves the object along that local axis.

    There is one tricky part to this approach. The rotation is based on the time per rotation... the code above would make one full rotation in 4 seconds. So a larger orbit will make the object move faster. You probably want the opposite effect. That might be doable with a predetermined number of rotations. Maybe something like this...

    rotateTween = LeanTween.rotateAround(rotator, Vector3.back, 1080, 4f)

    ...And set the easing to one of the ease in variants.
     
  5. rxmarccall

    rxmarccall

    Joined:
    Oct 13, 2011
    Posts:
    353
    @sleekdigital
    Thanks for your thoughts, you are right, I should have described what I want as more of a whirlpool effect. I am starting to lean towards a non physics based approach as well. I think I'll attempt what you have suggested and disable the rigidbody of the object once its supposed to "whirlpool" and try using tweening. Will let you know how it goes.
     
    Last edited: Mar 16, 2015
  6. Partel-Lang

    Partel-Lang

    Joined:
    Jan 2, 2013
    Posts:
    2,556
    Hi,

    Gravitational acceleration depends on the (squared) distance from the black hole.
    In a very basic way:

    Code (CSharp):
    1. void FixedUpdate() {
    2.             Vector3 direction = blackHole.position - transform.position;
    3.             float gForce = blackHoleMass / direction.sqrMagnitude;
    4.             rigidbody.AddForce(direction.normalized * gForce * Time.deltaTime);
    5.         }
    That is just normal gravitation that will make your spaceship orbit around the black hole (or slingshot away if you have too much velocity) If you need it to be sucked in like a vortex, all you need to do is add a bit of drag to the Rigidbody. Slowing down will gradually lower it's orbit which will simultaneously speed it up the closer it gets to the center like in a real vortex.
     
  7. sleekdigital

    sleekdigital

    Joined:
    May 31, 2012
    Posts:
    133
    Yes, but I think you are missing some key points of the discussion. It seems to me, that code is going to result in the same problem as the original post. If an object is already heading for the center of a black hole, no orbiting will happen, it will just fall straight into the black hole. The OP is looking for something more like a whirlpool effect. If an object is heading straight toward the center of a whirlpool, it gets swept up in the current and the movement is more similar to what the OP described.
     
  8. jimthegiant

    jimthegiant

    Joined:
    Mar 13, 2015
    Posts:
    9
    What Partel said!

    Gravity doesn't behave like that even for black holes. Stars will orbit quite happily around a black hole in a stable orbit unless they get close enough for spaghettification to happen or enter the event horizon (in which case you should simply delete object and maybe increase the gravity and area of effect around the "black hole".
     
  9. sleekdigital

    sleekdigital

    Joined:
    May 31, 2012
    Posts:
    133
    Why doesn't anyone actually read the discussion? The OP is looking for the specific motion described, not a realistic black hole simulation
     
  10. jimthegiant

    jimthegiant

    Joined:
    Mar 13, 2015
    Posts:
    9
    If your comment was directed at me then the first thing I said was
    Partel of course mentioned
    .

    Furthermore Op hasn't made it clear exactly why (s)he wants this effect. There are two likely answerers:

    1. Op has a valid reason for wanting this effect
    2. Op want this effect because they believe that black holes behave this way.

    If it's number two then educating them about the physics of black holes is a valid response.
     
  11. Partel-Lang

    Partel-Lang

    Joined:
    Jan 2, 2013
    Posts:
    2,556
    @OP
    If you want to go from physics to tweening, don't have to make the rigidbody kinematic, it's difficult to get a smooth result like that. Instead you can smoothly take control of it's velocity by

    Code (CSharp):
    1. rigidbody.velocity = Vector3.Lerp(rigidbody.velocity, whirpoolVelocity, whirpoolWeight);
    whirpoolWeight can be function of the spacecraft's distance from the black hole.

    You can probably get a procedural whirpooling effect with a few lines of code:
    Code (CSharp):
    1. Vector3 whirpoolVelocity = Vector3.Cross(transform.position - blackHole.position, Vector3.forward) * rigidbody.velocity.magnitude;
    2.         whirpoolVelocity -= whirpoolVelocity * drag * Time.deltaTime;
    3.  
    The second line should suck the spacecraft in using drag.
     
  12. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,500
    In Unity 5 there's a PointEffector2D that can attract or repel stuff to at least help give you this effect. You can even select different force modes of constant, inverse-linear or inverse-squared as well as specific drag coefficients.

    If you were to add a tangent velocity that was scale relative to the distance from the gravity source then it may give you want you require.
     
    Last edited: Mar 19, 2015
  13. jimthegiant

    jimthegiant

    Joined:
    Mar 13, 2015
    Posts:
    9
    How about having the gravityForce increase over time while the body is within the trigger collider rather than adding a drag force? You would still want gravity to be be inversely proportional to the square of distance though, just with an added modifier.

    Should give the same effect.
     
  14. rxmarccall

    rxmarccall

    Joined:
    Oct 13, 2011
    Posts:
    353
    Thanks for the suggestions and ideas everyone. In the end I was looking for a rather specific whirlpool effect without a lot of variance so I ended up using a translation approach rather than physics approach.

    When my object enters a "black holes" collider I remove the objects rigidbody2D and then allow the following code to run in Update:

    Code (CSharp):
    1. transform.RotateAround(blackHoleCenter.position, Vector3.forward, rotationSpeed * Time.deltaTime );
    2.  
    3.             Vector3 dir = transform.position - blackHoleCenter.position;
    4.  
    5.             dir.Normalize();
    6.  
    7.             transform.Translate(dir * encroachSpeed * Time.deltaTime, Space.World);
    8.  
    Pretty simple solution but it gives me the desired effect I was looking for, im sure it could be improved as well to make the transition from using a physics body, disabling it and then translating better.

    Thanks again everyone.
     
  15. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,500
    You're still using physics and as such, you should not be moving static colliders. Just set the rigid-body to be kinematic, it's far faster and designed to be moved. When you remove the rigid-body, all the colliders attached to it are recreated and attached to the ground-body at the origin. Whenever you move static colliders, they are recreated which gives you bad perforance and doesn't scale well.
     
  16. rxmarccall

    rxmarccall

    Joined:
    Oct 13, 2011
    Posts:
    353
    Thanks MelvMay I'll do that.