Search Unity

Question Need help using spherical collider and raycast to make spherical gravity...

Discussion in 'Physics' started by CatDadJynx, Jan 16, 2021.

  1. CatDadJynx

    CatDadJynx

    Joined:
    Apr 16, 2020
    Posts:
    249
    Hello, I'm struggling a bit trying to figure out how to do this... before even trying to implement the raycasting operations I wanted to make a spherical collider marked 'is trigger' and execute the raycasting operations ontriggerenter (or ontriggerstay), but my raycasting and physics operations need to be in fixedupdate (while ontrigger is executed on foxedupdate but cant be used inside of it)... I didnt want to rely on raycasting alone due to cost, so I was hoping I might be able to execute it if the trigger condition was met... unless I'm going about this the wrong way? If anyone could point me in the right direction.

    Also, before anyone mentions it, I'm restricted to using unity 5.6 and don't have access to any standard assets (or most other assets, for that matter). But any help is appreciated. Thanks!
     
  2. Sab_Rango

    Sab_Rango

    Joined:
    Aug 30, 2019
    Posts:
    121
    Hey!
    I don't know how to help with the specific conditions. But making small planet gravity is pretty easy!
    here the sample code to attach a small objects
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class grav : MonoBehaviour
    6. {
    7.     // Start is called before the first frame update
    8.     public Transform planet;
    9.     public float Gscale = 5f;
    10.     Vector3 gravitydirection;
    11.     Rigidbody smallrigid;
    12.     void Start()
    13.     {
    14.        
    15.         smallrigid = GetComponent<Rigidbody>();
    16.     }
    17.  
    18.     // Update is called once per frame
    19.     void Update()
    20.     {
    21.         gravitydirection = (planet.position - transform.position).normalized;
    22.  
    23.         smallrigid.velocity += gravitydirection * Gscale;
    24.     }
    25. }
    26.  
     
  3. Sab_Rango

    Sab_Rango

    Joined:
    Aug 30, 2019
    Posts:
    121
    create a sphere without rigidbody,
    create small objects with rigidbody(gravity use =false) +collider

    attach the script to the small objects, then attach the planet object to the script's public "planet " object
     
  4. CatDadJynx

    CatDadJynx

    Joined:
    Apr 16, 2020
    Posts:
    249
    That seems to want to make my player flop around and kind of twitch around a little bit as it goes. I did have a fair amount of luck with this, now my only issue is that my camera transform.up doesnt match my player's as it goes around the sphere (and since my movement script relies partly on camera orientation), so long as i hold my inputs down my player y axis matches the cameras (when it should be vice versa), then when I let go of my inputs my player y snaps to where it should be oriented on the sphere from this script (and if i press my inputs again it snaps back to my cameras y axis)... trying to figure out how to make this work but after weeks of trying to get the 3 scrips working together (movement, camera, and gravity) im so so close-

    Code (CSharp):
    1.  
    2.  
    3. using System.Collections;
    4. using System.Collections.Generic;
    5. using UnityEngine;
    6.  
    7. public class Gravity : MonoBehaviour {
    8.  
    9.     public GameObject planet;
    10.  
    11.     public Transform pivot;
    12.  
    13.     public float gravity = 9.8f;
    14.  
    15.     bool onGround = false;
    16.  
    17.     float distanceToGround;
    18.     Vector3 groundNormal;
    19.  
    20.     Rigidbody rb;
    21.  
    22.     // Use this for initialization
    23.     void Start () {
    24.         rb = GetComponent<Rigidbody>();
    25.         rb.freezeRotation = true;
    26.     }
    27.    
    28.     // Update is called once per frame
    29.     void FixedUpdate () {
    30.         RaycastHit hit = new RaycastHit();
    31.         if(Physics.Raycast(transform.position, -transform.up, out hit, 10))
    32.         {
    33.             distanceToGround = hit.distance;
    34.             groundNormal = hit.normal;
    35.  
    36.             if (distanceToGround <= 0.2f)
    37.             {
    38.                 onGround = true;
    39.             }
    40.             else
    41.             {
    42.                 onGround = false;
    43.             }
    44.         }
    45.  
    46.         Vector3 gravDirection = (transform.position - planet.transform.position).normalized;
    47.  
    48.         if (onGround == false)
    49.         {
    50.             rb.AddForce(gravDirection * -gravity);
    51.         }
    52.  
    53.         Quaternion toRotation = Quaternion.FromToRotation(transform.up, groundNormal) * transform.rotation;
    54.         transform.rotation = toRotation;
    55.  
    56.         //pivot.eulerAngles.y = transform.localRotation.y;
    57.  
    58.         //float desiredYAngle = pivot.eulerAngles.y;
    59.         //pivot.transform.localRotation = Quaternion.Euler(x,y,z);
    60.     }
    61.  
    62.     private void OnTriggerEnter(Collider collision)
    63.     {
    64.         planet = collision.transform.gameObject;
    65.  
    66.         Vector3 gravDirection = (transform.position - planet.transform.position).normalized;
    67.  
    68.         Quaternion toRotation = Quaternion.FromToRotation(transform.up, gravDirection) * transform.rotation;
    69.         transform.rotation = toRotation;
    70.  
    71.         rb.velocity = Vector3.zero;
    72.         rb.AddForce(gravDirection);
    73.     }
    74. }
    75.  
     
  5. MrExillion

    MrExillion

    Joined:
    Mar 24, 2018
    Posts:
    10
    The easiest would be addforce -9,82 and have direction of force be vector3 (rb.centerofmass.pos - origoofgavity.pos) add quaternion with orientation if needed, but the psudo above should do the trick. I wont reccomend using velocity rather than force in this case.

    See G*(m1-m2)/(r1^2-r2^2)=g the equation may be slightly wrong but if you google it and find something similar you thats the right onr. Point is if you want multiple orbital bodies you need to consider their mass, and centre of mass. Especially if you want a cluster of objects. But its really simple if you just want earth grav, its 9.82 * direction.normalized in an addforce.
     
  6. CatDadJynx

    CatDadJynx

    Joined:
    Apr 16, 2020
    Posts:
    249
    I thought the above code *was* doing what you described between the raycasting and the ontriggerenter (attempting to use only one or the other doesnt work).

    I'm not trying to making anything orbit, literally all I want is my player to be able to walk around my sphere with the camera following accordingly in the y axis, but I've been unable to make my camera and/or pivot a child of my player without causing issues (because my player movement is in relation to my camera axes, in turn), so I'm just trying to script it the rest of the way since I'm already so close, unless theres a better way to go about it

    Edit: Sorry, been screwing with this so much I got a little mixed up and didnt even realize the 'ontriggerenter' part of my code doesnt even do anything, when I comment it out my script behaves the same (though oddly enough I added that part because the first part wasnt working on it's own at the time, but now it is, aside from my camera still not rotating how I need it to)
     
    Last edited: Jan 20, 2021
  7. MrExillion

    MrExillion

    Joined:
    Mar 24, 2018
    Posts:
    10
    Well it it only works as long as center of mass is equal to the position of your sphere. And the code can be simplified. I can try to send the thread to my cousin, he has done something like this before, though i'm not sure he didnt just rotate the sphere. In any case have you tried nesting the camera to the player in the hierearchy? If it doesnt work a simp rotation around z should dothe trick, check out the lookat method. Or slerp.
     
    Last edited: Jan 20, 2021
  8. CatDadJynx

    CatDadJynx

    Joined:
    Apr 16, 2020
    Posts:
    249
    The raycasting method i have above works just fine for my player, the only issue is the camera doesnt reflect the player rotation and the player rotation snaps back and forth between camera rotation on input (since my player movement and rotation is somewhat reliant on my camera and pivot orientations) so if I child them to my player it goes crazy. I'm not worried about slerping it until I get the camera rotation correct in the first place otherwise that's trying to overcomplicate it a bit before I've figured out the basis of it. But I was trying to use the player and camera Y axes (since y is up) but I'll try messing around with the z axes a bit and see if I have any better luck (since I've been stuck on this for like over a month now its not like I have much else to do but keep messing with it anyway lol)
     
  9. MrExillion

    MrExillion

    Joined:
    Mar 24, 2018
    Posts:
    10
    In that case if you have to use the local up, you do that by getting camera.transform.up iirc, but its hard to truly grasp what the camera is doing by your description. In theory you could sync the transforms every late fixed update in the LateFixedUpdate() call. That way you can set it non kinematically to a projected point from a raycast by the end of every frame, and you can then 'copy' the local behaviour over by using the properties calculated locally earlier that frame/physics frame, such that you apply the same changes relative to the new position, by simply using the target destination of the raycast and use that point as the relative reference to a local transformation, and reapply that after you move "reset" the camera to the new position, new raycast same ray properties, then reset all the changes in a relative form and Slerp or set the properties, with this psudo-local. Point is you don't have to mess with a functioning camera, but all you need is to rotate it again relative to the new point, using the raycast as a pseudo parent that both player and camera have equal relation by. So something like this:

    PseudoTransform(imaginary made from raycast 1)
    >Camera
    PseudoTransform(imaginary made from raycast 2 identical to raycast 1 but different origin)
    > Player

    Update() something not with physics
    FixedUpdate() something with physics
    Do gravity

    Raycast1 ... From player to point A

    Save var changes on player relative to A
    Save changes of player position change relative camera


    LateUpdate() do something no physics at end of frame
    LateFixedUpdate()
    Do something at the end of physics frame

    Move camera by same ammount as player
    Raycast 2 same properties as with players raycast
    Apply relative changes caused by gravity dir change of player to camera relative to Point B given by raycast 2.

    Next frame

    This is a bit rough and unedited i apologize, but essentially this gives you a chance to affect the camera the same as the player once a frame, but without interfeering with the script during its actual functionality, and only once every time gravity is calculated anyway, so you dont tank performance. At least in theory i havent tested this myself, but im fairly confident it'll work, if i understand your problem that is.
     
  10. CatDadJynx

    CatDadJynx

    Joined:
    Apr 16, 2020
    Posts:
    249
    Hmm, I think I see what you're saying. I tried changing the camera.main.transform.up and the pivot.transform.up to the player.transform.up (as well as adding since realistically I want the camera to be at the players transform.up plus the cameras initial transform.up) but I didnt try it in the way I think you're describing so I'll mess around with that a bit, thanks!
     
  11. CatDadJynx

    CatDadJynx

    Joined:
    Apr 16, 2020
    Posts:
    249
    Also my mistake, I thought Id included the other two scripts in my reply above (the player and camera movement). Here are those as well
     

    Attached Files:

  12. CatDadJynx

    CatDadJynx

    Joined:
    Apr 16, 2020
    Posts:
    249
    Actually, now Im not so sure my camera script is even the issue. If I remove it and just make the camera a child of my player object, my player object still behaves the same. Its got to be something with my gravity or player movement script.