Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
0
Question by AWOL_01 · Jan 01, 2016 at 04:10 PM · c#rigidbodygravityground detection

Gravity and Grounding

I've been working on the TANKS! Tutorial that Unity came out with and I'm trying to modify it so that the tanks can move on uneven terrain. By default they had rotation in the x- and z-directions turned off so that the tank wouldn't pitch or roll. I turned this off so that tank could move uphill or along the side of a hill without remaining level and if the tank tries to climb a surface that is too steep it can flip. After doing this I found that if the tank is at an angle it will continue to move into the air, and if it is vertical it can climb straight up. To fix this I tried to make it so that if the tank isn't grounded the controls will be turned off, and the only thing affecting the tank will be gravity. The tanks use a Rigidbody, so I can't use isGrounded. I tried using Raycasting but it either makes the tank not move at all, or it does nothing and lets the tank move while it's still in the air.

I'd like some help on how to write the script so that if the tank becomes airborne it will keep its velocity in the x- and z-direction (without the player being able to control it), and have it accelerate due to gravity in the y-direction until it is grounded and the player can control the tank again.

My script so far is: using UnityEngine;

 namespace Complete
 {
     public class TankMovement : MonoBehaviour
     {
         public int m_PlayerNumber = 1;              // Used to identify which tank belongs to which player.  This is set by this tank's manager.
         public float m_Speed = 12f;                 // How fast the tank moves forward and back.
         public float m_TurnSpeed = 180f;            // How fast the tank turns in degrees per second.
         public AudioSource m_MovementAudio;         // Reference to the audio source used to play engine sounds. NB: different to the shooting audio source.
         public AudioClip m_EngineIdling;            // Audio to play when the tank isn't moving.
         public AudioClip m_EngineDriving;           // Audio to play when the tank is moving.
         public float m_PitchRange = 0.2f;           // The amount by which the pitch of the engine noises can vary.
         public float m_MaxRay = 0.1f;                // Distance to ground where tank will be "Grounded"
         public bool m_isGrounded = true;            // True/False, is tank on the ground?
 
 
         private string m_MovementAxisName;          // The name of the input axis for moving forward and back.
         private string m_TurnAxisName;              // The name of the input axis for turning.
         private Rigidbody m_Rigidbody;              // Reference used to move the tank.
         private float m_MovementInputValue;         // The current value of the movement input.
         private float m_TurnInputValue;             // The current value of the turn input.
         private float m_OriginalPitch;              // The pitch of the audio source at the start of the scene.
 
 
         private void Awake ()
         {
             m_Rigidbody = GetComponent<Rigidbody> ();
         }
 
 
         private void OnEnable ()
         {
             // When the tank is turned on, make sure it's not kinematic.
             m_Rigidbody.isKinematic = false;
 
             // Also reset the input values.
             m_MovementInputValue = 0f;
             m_TurnInputValue = 0f;
         }
 
 
         private void OnDisable ()
         {
             // When the tank is turned off, set it to kinematic so it stops moving.
             m_Rigidbody.isKinematic = true;
         }
 
 
         private void Start ()
         {
             // The axes names are based on player number.
             m_MovementAxisName = "Vertical" + m_PlayerNumber;
             m_TurnAxisName = "Horizontal" + m_PlayerNumber;
 
             // Store the original pitch of the audio source.
             m_OriginalPitch = m_MovementAudio.pitch;
         }
 
 
         private void Update ()
         {
             // Store the value of both input axes.
             m_MovementInputValue = Input.GetAxis (m_MovementAxisName);
             m_TurnInputValue = Input.GetAxis (m_TurnAxisName);
 
             EngineAudio ();
         }
 
 
         private void EngineAudio ()
         {
             // If there is no input (the tank is stationary)...
             if (Mathf.Abs (m_MovementInputValue) < 0.1f && Mathf.Abs (m_TurnInputValue) < 0.1f)
             {
                 // ... and if the audio source is currently playing the driving clip...
                 if (m_MovementAudio.clip == m_EngineDriving)
                 {
                     // ... change the clip to idling and play it.
                     m_MovementAudio.clip = m_EngineIdling;
                     m_MovementAudio.pitch = Random.Range (m_OriginalPitch - m_PitchRange, m_OriginalPitch + m_PitchRange);
                     m_MovementAudio.Play ();
                 }
             }
             else
             {
                 // Otherwise if the tank is moving and if the idling clip is currently playing...
                 if (m_MovementAudio.clip == m_EngineIdling)
                 {
                     // ... change the clip to driving and play.
                     m_MovementAudio.clip = m_EngineDriving;
                     m_MovementAudio.pitch = Random.Range(m_OriginalPitch - m_PitchRange, m_OriginalPitch + m_PitchRange);
                     m_MovementAudio.Play();
                 }
             }
         }
 
 
         private void FixedUpdate ()
         {
             // Send ray from bottom of tank.
             Vector3 m_Ray = transform.TransformDirection (Vector3.down);
             float m_RayLength = m_Ray.magnitude;
 
             if (m_RayLength < m_MaxRay)
             {
                 m_isGrounded = false;
 
             }
 
             else if (m_RayLength > m_MaxRay)
             {
                 m_isGrounded = true;
             }
 
             // Adjust the rigidbodies position and orientation in FixedUpdate.
             Move ();
             Turn ();
         }
 
 
         private void Move ()
         {
             if (m_isGrounded == true)
             {
                 // Create a vector in the direction the tank is facing with a magnitude based on the input, speed and the time between frames.
                 Vector3 movement = transform.forward * m_MovementInputValue * m_Speed * Time.deltaTime;
 
                 // Apply this movement to the rigidbody's position.
                 m_Rigidbody.MovePosition (m_Rigidbody.position + movement);
             }
 
             else if (m_isGrounded == false)
             {
                 Vector3 movement = transform.forward * 0;
                 m_Rigidbody.MovePosition (m_Rigidbody.position + movement);
             }
         }
 
 
         private void Turn ()
         {
             if (m_isGrounded == true)
             {
                 // Determine the number of degrees to be turned based on the input, speed and time between frames.
                 float turn = m_TurnInputValue * m_TurnSpeed * Time.deltaTime;
 
                 // Make this into a rotation in the y axis.
                 Quaternion turnRotation = Quaternion.Euler (0f, turn, 0f);
 
                 // Apply this rotation to the rigidbody's rotation.
                 m_Rigidbody.MoveRotation (m_Rigidbody.rotation * turnRotation);
             }
 
             else if (m_isGrounded == false)
             {
                 Quaternion turnRotation = Quaternion.Euler (0f, 0f, 0f);
 
                 m_Rigidbody.MoveRotation (m_Rigidbody.rotation * turnRotation);
             }
         }
     }
 }


FixedUpdate (), Move (), and Turn () are the parts I'm working in.

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

2 Replies

· Add your reply
  • Sort: 
avatar image
0

Answer by felixfors · Jan 03, 2016 at 06:36 AM

you could make your own !isgrounded boolean by doing something like this let me know if this works

  if(m_Rigidbody.velocity.y <0 || m_Ridigbody.velocity >0)
     {
     inAir = true;
     }
     else // if we dont have any velocity on the y axis
     {
     inAir = false;
     }

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image
0

Answer by OncaLupe · Jan 03, 2016 at 07:58 AM

You're not actually doing a raycast in your pasted code.

On line 100, you create a Vector3 pointing along the local -y axis, then get it's magnitude on the next line. The magnitude will always be 1 (give or take floating point variances). What you need to do is use Physics.Raycast() to actually perform the test.

http://docs.unity3d.com/ScriptReference/Physics.Raycast.html

 private void FixedUpdate ()
 {
     //Create a ray starting from the center of the tank pointing down along it's local Y axis
     Ray m_Ray = new Ray(transform.position, -transform.up);//-transform.up is cleaner than doing TransformDirection()
 
     //Perform raycast with max distance m_MaxRay
     if(Physics.Raycast(m_Ray, m_MaxRay))
     {
         //If raycast returns true, it hit something.
         //Can optionally check what we hit by changing the Raycast call to
         //include the 'out hit' parameter. See scripting manual.
         m_isGrounded = true;
     }else{
         m_isGrounded = false;
     }
 
     // Adjust the rigidbodies position and orientation in FixedUpdate.
     Move ();
     Turn ();
 }

Also, in the Move() method when m_isGrounded is false, you're locking the tank into it's current position by using MovePosition, since you're telling the physics engine to move the rigidbody to it's current location. If the project is using gravity, you should instead not be doing anything if not grounded and let the physics engine do it's work.

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

5 People are following this question.

avatar image avatar image avatar image avatar image avatar image

Related Questions

Object shattering under a certain weight/force 3 Answers

How to add gravity without a rigidbody 2 Answers

Multiple Cars not working 1 Answer

Gravity is not working if i use rigidbody.velocity 1 Answer

Whenever I add a rigidbody and collider to my player, it interferes with the movement script and makes it teleport 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges