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 /
  • Help Room /
avatar image
0
Question by johnryan2242 · Nov 15, 2019 at 08:37 AM · rigidbody2dgravityphysics2d

How to make Smooth Gravity Transitions

I am trying to make a game where the player can manipulate gravity with button presses. W makes the players gravity pull upwards, D to the right, etc. The issue I have been running into for a while is that if the player is falling downwards and I press the button to make gravity pull right, instead of a smooth acceleration curve, the player stops in midair and then starts moving right. My goal is for the player to smoothly transition from falling straight down to falling sideways. i.e. I want a curve and not a right angle. I have tried using Vector2.Lerp but instead of smoothly transitioning between the current gravity vector and the desired gravity vector, it sets the gravity to zero and then moves towards the desired gravity vector. How do I avoid this? using System; using System.Collections; using System.Collections.Generic; using UnityEngine;

 public class PhysicsObject : MonoBehaviour
 {
 
     public float minGroundNormalY = .65f;
     public float minGroundNormalX = .65f;
     public float gravityModifier = 1f;
     public float gravityChangeTime = .5f;
    
 
     protected Vector2 targetVelocity;
     protected bool grounded;
     protected Vector2 groundNormal;
     protected Rigidbody2D rb2d;
     protected Vector2 velocity;
     protected ContactFilter2D contactFilter;
     protected RaycastHit2D[] hitBuffer = new RaycastHit2D[16];
     protected List<RaycastHit2D> hitBufferList = new List<RaycastHit2D>(16);
 
 
     //Information regarding the current gravitational orientation of the object.
     protected bool onFloor = true;
     protected bool rightWall = false;
     protected bool leftWall = false;
     protected bool ceiling = false;
     protected Dictionary<string, bool> orientations = new Dictionary<string, bool>();
     protected const string FLOOR = "onFloor";
     protected const string CEILING = "ceiling";
     protected const string LEFTWALL = "leftWall";
     protected const string RIGHTWALL = "rightWall";
     protected string currentOrientation = FLOOR;
 
     //Variables to store gravitational orientation
     protected Vector2 downwardGravity = new Vector2(0f, -10f);
     protected Vector2 upwardGravity = new Vector2(0f, 10f);
     protected Vector2 rightGravity = new Vector2(10f, 0f);
     protected Vector2 leftGravity = new Vector2(-10f, 0f);
     protected Vector2 gravity = new Vector2(0f, -10f);
     protected Dictionary<string, Vector2> directionalGravity = new Dictionary<string, Vector2>();
     protected Vector2 oldGravity;
     protected bool gravityJustChanged = false;
     protected string DESIRED_GRAVITY = FLOOR;
     float gravFrac = .1f;
     float gravFrac2 = .1f;
     private Vector2 gravitySum;
     int onlyRunAFewTimes = 0;
     bool gravEqualsSum = false;
 
     protected const float minMoveDistance = 0.001f;
     protected const float shellRadius = 0.01f;
 
     void OnEnable()
     {
         rb2d = GetComponent<Rigidbody2D>();
     }
 
     void Start()
     {
         contactFilter.useTriggers = false;
         contactFilter.SetLayerMask(Physics2D.GetLayerCollisionMask(gameObject.layer));
         contactFilter.useLayerMask = true;
         orientations.Add(FLOOR, onFloor);
         orientations.Add(RIGHTWALL, rightWall);
         orientations.Add(LEFTWALL, leftWall);
         orientations.Add(CEILING, ceiling);
         directionalGravity.Add(FLOOR, downwardGravity);
         directionalGravity.Add(CEILING, upwardGravity);
         directionalGravity.Add(RIGHTWALL, rightGravity);
         directionalGravity.Add(LEFTWALL, leftGravity);
     }
 
     void Update()
     {
         targetVelocity = Vector2.zero;
         
         ComputeVelocity();
 
         
         
        
 
     }
 
     protected void UpdateGravity(Vector2 startingGrav, Vector2 targetGrav)
     {
         Debug.Log(Vector2.Lerp(startingGrav, targetGrav, 0f));
         gravity = Vector2.Lerp(startingGrav, targetGrav, 1f);
     }
 
     protected virtual void ComputeVelocity()
     {
 
     }
 
     protected virtual void ChangeGravity()
     {
         //Should call ChangeOrientationBools in the derived class
     }
 
     protected void ChangeOreintationBools(string currentOrientation, string newOrientation)
     {
         oldGravity = directionalGravity[GetCurrentOrientation()];
         orientations[currentOrientation] = false;
         orientations[newOrientation] = true;
         DESIRED_GRAVITY = newOrientation;
         gravitySum = directionalGravity[DESIRED_GRAVITY] + gravity;
 
        
     }
 
 
     protected string GetCurrentOrientation()
     {
         foreach (var orientation in orientations)
        {
             if(orientation.Value == true)
             {
                 //Debug.Log(orientation.Key);
                 return orientation.Key;
             }
         }
         //This code should never run
         return "failed to find a true value";
     }
 
     void FixedUpdate()
     {
         if (gravity != directionalGravity[DESIRED_GRAVITY])
         {
             Debug.Log("We want the gravity to be" + directionalGravity[DESIRED_GRAVITY]);
             Debug.Log(gravity == directionalGravity[DESIRED_GRAVITY]);
             if (onlyRunAFewTimes < 10)
             {
                 Debug.Log("the gravity sum is: " + gravitySum);
                 Debug.Log("Moving to Sum");
                 UpdateGravity(directionalGravity[GetCurrentOrientation()], gravitySum * gravFrac2);
                 onlyRunAFewTimes++;
                 Debug.Log("gravity is: " + gravity);
                 gravFrac2 += .1f;
             }
             else if (gravitySum == gravity || gravEqualsSum)
             {
                 gravEqualsSum = true;
                 Debug.Log("We tryna update gravity mofo");
                 UpdateGravity(gravitySum, directionalGravity[DESIRED_GRAVITY] * gravFrac);
                 Debug.Log("gravity is: " + gravity);
                 gravFrac += .1f;
             }
             
 
 
         }
         else
         {
             onlyRunAFewTimes = 0;
             gravFrac = .1f;
             gravFrac2 = .1f;
             gravEqualsSum = true;
         }
         ChangeGravity();
         if (orientations[FLOOR])
         {
             HandleFloorMovement();
         }
         else if (orientations[CEILING])
         {
             HandleCeilingMovement();
         }
         else if (orientations[RIGHTWALL])
         {
             HandleRightWallMovement();
         }
         else if (orientations[LEFTWALL])
         {
             HandleLeftWallMovement();
         }
     }
 
     //The following functions are for if gravity is pulling the object down (towards the floor)
 
     private void HandleFloorMovement()
     {
         velocity += gravityModifier * gravity * Time.deltaTime;
         velocity.x = targetVelocity.x;
 
         grounded = false;
 
         Vector2 deltaPosition = velocity * Time.deltaTime;
 
         Vector2 moveAlongGround = new Vector2(groundNormal.y, -groundNormal.x);
 
         Vector2 move = moveAlongGround * deltaPosition.x;
 
         FloorMovement(move, false);
 
         move = Vector2.up * deltaPosition.y;
 
         FloorMovement(move, true);
     }
 
     void FloorMovement(Vector2 move, bool yMovement)
     {
         float distance = move.magnitude;
 
         if (distance > minMoveDistance)
         {
             int count = rb2d.Cast(move, contactFilter, hitBuffer, distance + shellRadius);
             hitBufferList.Clear();
             for (int i = 0; i < count; i++)
             {
                 hitBufferList.Add(hitBuffer[i]);
             }
 
             for (int i = 0; i < hitBufferList.Count; i++)
             {
                 Vector2 currentNormal = hitBufferList[i].normal;
                 if (currentNormal.y > minGroundNormalY)
                 {
                     grounded = true;
                     if (yMovement)
                     {
                         groundNormal = currentNormal;
                         currentNormal.x = 0;
                     }
                 }
 
                 float projection = Vector2.Dot(velocity, currentNormal);
                 if (projection < 0)
                 {
                     velocity = velocity - projection * currentNormal;
                 }
 
                 float modifiedDistance = hitBufferList[i].distance - shellRadius;
                 distance = modifiedDistance < distance ? modifiedDistance : distance;
             }
 
 
         }
 
         rb2d.position = rb2d.position + move.normalized * distance;
     }
 
 
     private void HandleCeilingMovement()
     {
         velocity += gravityModifier * gravity * Time.deltaTime;
         velocity.x = targetVelocity.x;
 
         grounded = false;
 
         Vector2 deltaPosition = velocity * Time.deltaTime;
 
         Vector2 moveAlongGround = new Vector2(groundNormal.y, -groundNormal.x);
 
         Vector2 move = moveAlongGround * deltaPosition.x;
 
         CeilingMovement(move, false);
 
         move = Vector2.up * deltaPosition.y;
 
         CeilingMovement(move, true);
     }
 
     private void CeilingMovement(Vector2 move, bool yMovement)
     {
         float distance = move.magnitude;
 
         if (distance > minMoveDistance)
         {
             int count = rb2d.Cast(move, contactFilter, hitBuffer, distance + shellRadius);
             hitBufferList.Clear();
             for (int i = 0; i < count; i++)
             {
                 hitBufferList.Add(hitBuffer[i]);
             }
 
             for (int i = 0; i < hitBufferList.Count; i++)
             {
                 Vector2 currentNormal = hitBufferList[i].normal;
                 //Debug.Log(currentNormal.y);
                 //Debug.Log(minGroundNormalY);
                 if (currentNormal.y < -minGroundNormalY) //This may need to be a < because if we are on the ceiling wont the y component of the normal vector be negative?
                 {
                     
                     grounded = true;
                     if (yMovement)
                     {
                         groundNormal = currentNormal;
                         currentNormal.x = 0;
                     }
                 }
 
                 float projection = Vector2.Dot(velocity, currentNormal);
                 if (projection < 0)
                 {
                     velocity = velocity - projection * currentNormal;
                 }
 
                 float modifiedDistance = hitBufferList[i].distance - shellRadius;
                 distance = modifiedDistance < distance ? modifiedDistance : distance;
             }
 
 
         }
 
         rb2d.position = rb2d.position + move.normalized * distance;
     }
 
     private void HandleLeftWallMovement()
     {
         velocity += gravityModifier * gravity * Time.deltaTime;
         velocity.y = targetVelocity.y;
 
         grounded = false;
 
         Vector2 deltaPosition = velocity * Time.deltaTime;
 
         Vector2 moveAlongWall = new Vector2(groundNormal.y, groundNormal.x);
 
         Vector2 move = moveAlongWall * deltaPosition.y;
 
         LeftWallMovement(move, false);
 
         move = Vector2.right * deltaPosition.x;
 
         LeftWallMovement(move, true);
     }
 
     private void LeftWallMovement(Vector2 move, bool xMovement)
     {
         float distance = move.magnitude;
 
         if (distance > minMoveDistance)
         {
             int count = rb2d.Cast(move, contactFilter, hitBuffer, distance + shellRadius);
             hitBufferList.Clear();
             for (int i = 0; i < count; i++)
             {
                 hitBufferList.Add(hitBuffer[i]);
             }
 
             for (int i = 0; i < hitBufferList.Count; i++)
             {
                 Vector2 currentNormal = hitBufferList[i].normal;
                 if (currentNormal.x > minGroundNormalX)
                 {
                     grounded = true;
                     if (xMovement)
                     {
                         groundNormal = currentNormal;
                         currentNormal.y = 0;
                     }
                 }
 
                 float projection = Vector2.Dot(velocity, currentNormal);
                 if (projection < 0)
                 {
                     velocity = velocity - projection * currentNormal;
                 }
 
                 float modifiedDistance = hitBufferList[i].distance - shellRadius;
                 distance = modifiedDistance < distance ? modifiedDistance : distance;
             }
 
 
         }
 
         rb2d.position = rb2d.position + move.normalized * distance;
     }
 
     private void HandleRightWallMovement()
     {
         velocity += gravityModifier * gravity * Time.deltaTime;
         velocity.y = targetVelocity.y;
 
         grounded = false;
 
         Vector2 deltaPosition = velocity * Time.deltaTime;
 
 
         Vector2 moveAlongWall = new Vector2(groundNormal.y, -groundNormal.x);
 
         Vector2 move = moveAlongWall * deltaPosition.y;
 
         RightWallMovement(move, false);
 
         move = Vector2.right * deltaPosition.x;
 
         RightWallMovement(move, true);
     }
 
     private void RightWallMovement(Vector2 move, bool xMovement)
     {
         float distance = move.magnitude;
 
         if (distance > minMoveDistance)
         {
             int count = rb2d.Cast(move, contactFilter, hitBuffer, distance + shellRadius);
             hitBufferList.Clear();
             for (int i = 0; i < count; i++)
             {
                 hitBufferList.Add(hitBuffer[i]);
             }
 
             for (int i = 0; i < hitBufferList.Count; i++)
             {
                 Vector2 currentNormal = hitBufferList[i].normal;
                 //Debug.Log(currentNormal.y);
                // Debug.Log(minGroundNormalY);
                 if (currentNormal.x < -minGroundNormalX) //May need to be a <
                 {
 
                     grounded = true;
                     if (xMovement)
                     {
                         groundNormal = currentNormal;
                         currentNormal.y = 0;
                     }
                 }
 
                 float projection = Vector2.Dot(velocity, currentNormal);
                 if (projection < 0)
                 {
                     velocity = velocity - projection * currentNormal;
                 }
 
                 float modifiedDistance = hitBufferList[i].distance - shellRadius;
                 distance = modifiedDistance < distance ? modifiedDistance : distance;
             }
 
 
         }
 
         rb2d.position = rb2d.position + move.normalized * distance;
     }
 
 
 }
 

I have been having this same problem for a few months now and I'm curious if such a thing is even possible in Unity.

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

0 Replies

· Add your reply
  • Sort: 

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

196 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Had to turn off gravity scale, but now player goes through walls 0 Answers

How to make instantiated rigidbodies continue moving the in the same direction as destroyed object? 1 Answer

Rigidbody2D.Cast() against mutiple colliders with a single Rigidbody2D 0 Answers

RigidBody.MovePosition won't stop even after reaching the destination 0 Answers

Uneven Jump Heights 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