Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

[SOLVED] Player Rigidbody Walking Around Planet

Discussion in 'Scripting' started by Jenkins6161, Jul 9, 2014.

  1. Jenkins6161

    Jenkins6161

    Joined:
    Jul 31, 2013
    Posts:
    19
    I've got a sphere(planet) and a capsule(player) using Fuax gravity. So I can run around the circumference of the sphere if I wished. I'm running into a problem with getting the rigid body to be able to walk past the equator of the planet. The RigidbodyFPSWalker is what I'm using for my movement script. The problem is that script adds force as if the player is on level ground, so when it gets to the equator the x axis is now up instead of forward. Now I could modify the script so that it applies force in the local directions of the player but that comes with its own problems. For example if the player was looking up or down they wouldn't move forwards or backwards when pushing the respective keys.

    How do I go about solving this? My current idea is to make a gimbal child object that remains level with the surface and forces are acted upon that to move the player around. I don't think this is a very elegant solution and frankly don't really know how to go about even attempting that. So here I am!

    What you guys do in this situation?

    [Solution] This is a slightly modified RigidbodyFPSWalker script: Movement.js
    Code (JavaScript):
    1. #pragma strict
    2.  
    3. var walkspeed: int;
    4. var jumpHeight: int;
    5. var distToGround: float;
    6. var maxVelocityChange: float;
    7.  
    8. var hit : RaycastHit;
    9. var castPos; //ray start
    10.  
    11. var planet: GameObject; //set in inspector
    12.  
    13. function Start(){
    14.     // Get the distance to ground
    15.     distToGround = collider.bounds.extents.y;
    16. }
    17.  
    18. function FixedUpdate () {
    19.     if(IsGrounded()){
    20.         // Calculate how fast we should be moving
    21.         var targetVelocity = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
    22.         targetVelocity = transform.TransformDirection(targetVelocity);
    23.         targetVelocity *= walkspeed;
    24.  
    25.         // Apply a force that attempts to reach our target velocity
    26.         var velocity = rigidbody.velocity;
    27.         var velocityChange = (targetVelocity - velocity);
    28.         Debug.DrawRay(transform.position, velocityChange*5, Color.magenta);
    29.         Debug.DrawRay(transform.position, velocity*5, Color.green);
    30.         velocityChange.x = Mathf.Clamp(velocityChange.x, -maxVelocityChange, maxVelocityChange);
    31.         velocityChange.z = Mathf.Clamp(velocityChange.z, -maxVelocityChange, maxVelocityChange);
    32.         velocityChange.y = Mathf.Clamp(velocityChange.y, -maxVelocityChange, maxVelocityChange);
    33.         rigidbody.AddForce(velocityChange, ForceMode.VelocityChange);
    34.    
    35.         // Jumping (this is borked atm but idc)
    36.         if (Input.GetButtonDown("Jump")){
    37.             rigidbody.velocity = Vector3(velocity.x, CalculateJumpVerticalSpeed(), velocity.z);
    38.         }
    39.     }
    40. }
    41.  
    42. function Update() {
    43.     // Orient player upright
    44.     var down = (planet.transform.position - transform.position).normalized;
    45.     var forward = Vector3.Cross(transform.right,down);
    46.     transform.rotation = Quaternion.LookRotation(-forward, -down);
    47. }
    48.  
    49. function IsGrounded(): boolean {
    50.     // Check if player is close to ground
    51.     Debug.DrawRay (transform.position, -transform.up*(distToGround+0.1), Color.red);
    52.     return Physics.Raycast(transform.position, -transform.up, distToGround + 0.1);
    53. }
    54.  
    55. function CalculateJumpVerticalSpeed ()
    56. {
    57.     // From the jump height we deduce the upwards speed
    58.     // for the character to reach at the apex.
    59.     return Mathf.Sqrt(2 * jumpHeight);
    60. }
    This is my gravity script for those wondering: Gravity.js
    Code (JavaScript):
    1. #pragma strict
    2.  
    3. // Anything with a rigidbody and inside the planets trigger collidor will be effected by gravity
    4.  
    5. var gravity: float = -9.81;
    6. function OnTriggerStay(other: Collider) {
    7.     // get the direction vector and normalize it (magnitude = 1)
    8.     var direction: Vector3 = other.transform.position - transform.position;
    9.     var force: Vector3 = direction.normalized * gravity;
    10.  
    11.     // accelerate the object in that direction
    12.     other.rigidbody.AddForce(force, ForceMode.Acceleration);
    13. }
     
    Last edited: Jul 10, 2014
  2. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
    instead of trying to use axes or local forward, wouldn't the direction of force simply be "centre of planet - center of mass of player"?
     
  3. Jenkins6161

    Jenkins6161

    Joined:
    Jul 31, 2013
    Posts:
    19
    I think you misunderstood the problem. I'm trying to be able to walk around the planet but the script for movement assumes the player is on a plane not a sphere.

    Illustration
     
  4. Jenkins6161

    Jenkins6161

    Joined:
    Jul 31, 2013
    Posts:
    19
    I've been able to simplify the gravity/orientation scripts and I've got an idea one how to attack movement. I'll apply movement forces against the normal of the planet so that forward is always perpendicular and up is away from the planet.
     
  5. bigmisterb

    bigmisterb

    Joined:
    Nov 6, 2010
    Posts:
    4,221
    1) turn gravity off on all your rigidbody objects.

    2) use this in the FixedUpdate
    Code (csharp):
    1.  
    2. Vector3 gravity = (transform.position - world.position).normalized;
    3. rigidbody.AddForce(gravity * Physics.gravity.y * rigidbody.mass * Time.fixedTime);
    4.  
    I think thats right. but it should be close. ;)
     
  6. Jenkins6161

    Jenkins6161

    Joined:
    Jul 31, 2013
    Posts:
    19
    I'm not having problems with gravity its with movement. Gravity is working great I can put my character anywhere on the sphere and it will fall towards it. The problem is with moving completely around the sphere in any direction. The movement script runs off global directions and I can't change it to local directions without introducing more problems. I think I have a solution tho and will post it if it works.
     
  7. rrh

    rrh

    Joined:
    Jul 12, 2012
    Posts:
    331
    Hmm. If you know which way is down, then you know which way is up. If you pass the up vector as the second parameter in Quaternion.LookRotation(forward, up) I think you can get a rotation oriented the right way. And then do the rest of the movement using local directions based on that?
     
  8. Jenkins6161

    Jenkins6161

    Joined:
    Jul 31, 2013
    Posts:
    19
    This is the relevant code for movement that I'm having issues with. I took this code(in FixedUpdate) from the wiki here
    Code (JavaScript):
    1. function FixedUpdate() {
    2.   // Calculate how fast we should be moving
    3.   var targetVelocity = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
    4.   targetVelocity = transform.TransformDirection(targetVelocity);
    5.   targetVelocity *= walkspeed;
    6.  
    7.   // Apply a force that attempts to reach our target velocity
    8.   var velocity = rigidbody.velocity;
    9.   var velocityChange = (targetVelocity - velocity);
    10.   velocityChange.x = Mathf.Clamp(velocityChange.x, -maxVelocityChange, maxVelocityChange);
    11.   velocityChange.z = Mathf.Clamp(velocityChange.z, -maxVelocityChange, maxVelocityChange);
    12.   velocityChange.y = 0;
    13.   rigidbody.AddForce(velocityChange, ForceMode.VelocityChange);
    14. }
    15.  
    16. function Update() {
    17.   // Orient player upright
    18.   var down = (planet.transform.position - transform.position).normalized;
    19.   var forward = Vector3.Cross(transform.right,down);
    20.   transform.rotation = Quaternion.LookRotation(-forward, -down);
    21. }
    The problem is on line 9. Since I'm moving around a sphere as I get closer to the equator targetVelocity-velocity approaches 0. I'm guessing I'll have to flip between sine and cosine to move around the sphere smoothly. Gonna have to think about this more since my trig is a little rusty. Doesn't help that I don't completely understand whats happening with the velocityChange code. :confused:
     
  9. Jenkins6161

    Jenkins6161

    Joined:
    Jul 31, 2013
    Posts:
    19
    Welp that was way easier then I thought! All I had to do was replace line 12 with
    Code (JavaScript):
    1. velocityChange.y = Mathf.Clamp(velocityChange.y, -maxVelocityChange, maxVelocityChange);
     
  10. Iron-Warrior

    Iron-Warrior

    Joined:
    Nov 3, 2009
    Posts:
    836
    Hey Jenkins, it just so happens I have a couple scripts that do this...

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4.  
    5. public class ThirdPersonSpaceWalker : MonoBehaviour {
    6.  
    7.     public Transform LookTransform;
    8.  
    9.     public float speed = 6.0f;
    10.     public float maxVelocityChange = 10.0f;
    11.     public float jumpForce = 5.0f;
    12.     public float GroundHeight = 1.1f;
    13.     private float xRotation;
    14.     private float yRotation;
    15.  
    16.     // Use this for initialization
    17.     void Start () {
    18.  
    19.     }
    20.  
    21.     // Update is called once per frame
    22.     void FixedUpdate () {
    23.  
    24.         RaycastHit groundedHit;
    25.         bool grounded = Physics.Raycast(transform.position, -transform.up, out groundedHit, GroundHeight);
    26.  
    27.         if (grounded)
    28.         {
    29.             // Calculate how fast we should be moving
    30.             Vector3 forward = Vector3.Cross(transform.up, -LookTransform.right).normalized;
    31.             Vector3 right = Vector3.Cross(transform.up, LookTransform.forward).normalized;
    32.             Vector3 targetVelocity = (forward * Input.GetAxis("Vertical") + right * Input.GetAxis("Horizontal")) * speed;
    33.  
    34.             Vector3 velocity = transform.InverseTransformDirection(rigidbody.velocity);
    35.             velocity.y = 0;
    36.             velocity = transform.TransformDirection(velocity);
    37.             Vector3 velocityChange = transform.InverseTransformDirection(targetVelocity - velocity);
    38.             velocityChange.x = Mathf.Clamp(velocityChange.x, -maxVelocityChange, maxVelocityChange);
    39.             velocityChange.z = Mathf.Clamp(velocityChange.z, -maxVelocityChange, maxVelocityChange);
    40.             velocityChange.y = 0;
    41.             velocityChange = transform.TransformDirection(velocityChange);
    42.  
    43.             rigidbody.AddForce(velocityChange, ForceMode.VelocityChange);
    44.  
    45.             if (Input.GetButton("Jump"))
    46.             {
    47.                 rigidbody.AddForce(transform.up * jumpForce, ForceMode.VelocityChange);
    48.             }
    49.         }
    50.     }
    51. }
    52.  
    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4.  
    5. public class Gravity : MonoBehaviour {
    6.  
    7.     //credit some: podperson
    8.  
    9.     public Transform planet;
    10.     public bool AlignToPlanet;
    11.     private float gravityConstant = 9.8f;
    12.  
    13.     void Start () {
    14.      
    15.     }
    16.  
    17.     void FixedUpdate () {
    18.         Vector3 toCenter = planet.position - transform.position;
    19.         toCenter.Normalize();
    20.  
    21.         rigidbody.AddForce(toCenter * gravityConstant, ForceMode.Acceleration);
    22.  
    23.         if (AlignToPlanet)
    24.         {
    25.             Quaternion q = Quaternion.FromToRotation(transform.up, -toCenter);
    26.             q = q * transform.rotation;
    27.             transform.rotation = Quaternion.Slerp(transform.rotation, q, 1);
    28.         }
    29.     }
    30. }
    31.  
    You need to attach both to your character to make it work. Set anything as your planet (a sphere, obviously). The second script exerts a force of gravity on the character and then aligns his transform to be standing on top of the planet. The first script is pretty run-of-the-mill rigidbody walkering.

    EDIT: Didn't see you figured it out. Good job!
     
  11. sean3Dmonkey

    sean3Dmonkey

    Joined:
    Oct 21, 2014
    Posts:
    69
    Hello, has anyone received this error on the gravity script? Is there a fix for the error?

    error CS1061: Type `UnityEngine.Component' does not contain a definition for `AddForce' and no extension method `AddForce' of type `UnityEngine.Component' could be found. Are you missing an assembly reference?

    Sean
     
  12. sean3Dmonkey

    sean3Dmonkey

    Joined:
    Oct 21, 2014
    Posts:
    69
    Did a Google Search.
    This edit fixed the compiler error but the character does not move.

    public Transform planet;
    public bool AlignToPlanet;
    private float gravityConstant = 9.8f;

    void Start()
    {

    }

    void FixedUpdate()
    {
    Vector3 toCenter = planet.position - transform.position;
    toCenter.Normalize();

    Rigidbody lRigid = GetComponent<Rigidbody>();
    lRigid.AddForce(toCenter * gravityConstant, ForceMode.Acceleration);

    if (AlignToPlanet)
    {
    Quaternion q = Quaternion.FromToRotation(transform.up, -toCenter);
    q = q * transform.rotation;
    transform.rotation = Quaternion.Slerp(transform.rotation, q, 1);
    }
    }
    }
     
  13. sean3Dmonkey

    sean3Dmonkey

    Joined:
    Oct 21, 2014
    Posts:
    69
    In the player's inspector, I need to assign something to the Look Transform of the ThirdPersonSpaceWalker script.
    Assigning the character or the camera did not work.

    What do you assign to the Look Transform?
    Sean
     
  14. LogCatGames

    LogCatGames

    Joined:
    Jul 12, 2018
    Posts:
    2
    Thanks A Lot It Work Great Love U !
     
  15. bindhamk

    bindhamk

    Joined:
    Dec 31, 2021
    Posts:
    1
    Hi,
    I'm also playing around with "walking on a sphere". "Gravity.cs" works perfectly, but with "ThirdPersonSpaceWalker.cs" I have the problem that my players does not move at all.
    (yes, I have assigned "Lock Transform" to "Player")

    Has anyone an idea how to fix this problem and make the player move; or maybe do you know a different script which allows a player to be moved on a shere?

    thanks in advance for your help
    bindhamk
     
  16. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,505
    Instead of necro-posting to a thread from 2014, please start your own fresh post. It's FREE!

    When you post, keep this in mind:

    How to report your problem productively in the Unity3D forums:

    http://plbm.com/?p=220

    If you want to debug what you have, you must find a way to get the information you need in order to reason about what the problem is.

    What is often happening in these cases is one of the following:

    - the code you think is executing is not actually executing at all
    - the code is executing far EARLIER or LATER than you think
    - the code is executing far LESS OFTEN than you think
    - the code is executing far MORE OFTEN than you think
    - the code is executing on another GameObject than you think it is
    - you're getting an error or warning and you haven't noticed it in the console window

    To help gain more insight into your problem, I recommend liberally sprinkling Debug.Log() statements through your code to display information in realtime.

    Doing this should help you answer these types of questions:

    - is this code even running? which parts are running? how often does it run? what order does it run in?
    - what are the values of the variables involved? Are they initialized? Are the values reasonable?
    - are you meeting ALL the requirements to receive callbacks such as triggers / colliders (review the documentation)

    Knowing this information will help you reason about the behavior you are seeing.

    You can also put in Debug.Break() to pause the Editor when certain interesting pieces of code run, and then study the scene

    You could also just display various important quantities in UI Text elements to watch them change as you play the game.

    If you are running a mobile device you can also view the console output. Google for how on your particular mobile target.

    Another useful approach is to temporarily strip out everything besides what is necessary to prove your issue. This can simplify and isolate compounding effects of other items in your scene or prefab.

    Here's an example of putting in a laser-focused Debug.Log() and how that can save you a TON of time wallowing around speculating what might be going wrong:

    https://forum.unity.com/threads/coroutine-missing-hint-and-error.1103197/#post-7100494

    Finally, tutorials and example code are great, but keep this in mind to maximize your success and minimize your frustration:

    How to do tutorials properly, two (2) simple steps to success:

    Tutorials are a GREAT idea. Tutorials should be used this way:

    Step 1. Follow the tutorial and do every single step of the tutorial 100% precisely the way it is shown. Even the slightest deviation (even a single character!) generally ends in disaster. That's how software engineering works. Every step must be taken, every single letter must be spelled, capitalized, punctuated and spaced (or not spaced) properly, literally NOTHING can be omitted or skipped.

    Fortunately this is the easiest part to get right: Be a robot. Don't make any mistakes.
    BE PERFECT IN EVERYTHING YOU DO HERE!!

    If you get any errors, learn how to read the error code and fix your error. Google is your friend here. Do NOT continue until you fix your error. Your error will probably be somewhere near the parenthesis numbers (line and character position) in the file. It is almost CERTAINLY your typo causing the error, so look again and fix it.

    Step 2. Go back and work through every part of the tutorial again, and this time explain it to your doggie. See how I am doing that in my avatar picture? If you have no dog, explain it to your house plant. If you are unable to explain any part of it, STOP. DO NOT PROCEED. Now go learn how that part works. Read the documentation on the functions involved. Go back to the tutorial and try to figure out WHY they did that. This is the part that takes a LOT of time when you are new. It might take days or weeks to work through a single 5-minute tutorial. Stick with it. You will learn.

    Step 2 is the part everybody seems to miss. Without Step 2 you are simply a code-typing monkey and outside of the specific tutorial you did, you will be completely lost. If you want to learn, you MUST do Step 2.

    Of course, all this presupposes no errors in the tutorial. For certain tutorial makers (like Unity, Brackeys, Imphenzia, Sebastian Lague) this is usually the case. For some other less-well-known content creators, this is less true. Read the comments on the video: did anyone have issues like you did? If there's an error, you will NEVER be the first guy to find it.

    Beyond that, Step 3, 4, 5 and 6 become easy because you already understand!

    Finally, when you have errors...