Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Shooting through the floor

Discussion in 'Physics' started by Adien22, Aug 28, 2019.

  1. Adien22

    Adien22

    Joined:
    Aug 19, 2019
    Posts:
    44
    I know this is a bit long, but I'm stuck and can't find the problem. Can anyone see why my box shoots through the floor after a few seconds of playtime? Sometimes it will sit on the ground for a long time, but if I grab a box with this script and put the box down, it will stay on the ground for a short while then go through all the colliders to infinity.



    Code (csharp):
    1.  
    2. public class TestBox : MonoBehaviour
    3. {
    4.     public float minGroundNormalY = .65f;
    5.     public float gravMod = 1f;
    6.  
    7.  
    8.  
    9.     protected Vector2 groundNormal;
    10.     protected bool grounded;
    11.     protected Vector2 velocity;
    12.     protected Rigidbody2D rb;
    13.     protected const float minMoveDistance = 0.001f;
    14.     protected ContactFilter2D contactFilter;
    15.     protected RaycastHit2D[] hitBuffer = new RaycastHit2D[16];
    16.     protected const float shellRadius = 0.01f;
    17.     protected List<RaycastHit2D> hitBufferList = new List<RaycastHit2D>(16);
    18.     void OnEnable()
    19.     {
    20.         rb = GetComponent<Rigidbody2D>();
    21.     }
    22.  
    23.  
    24.     void Start()
    25.     {
    26.         contactFilter.useTriggers = false;
    27.         contactFilter.SetLayerMask(Physics2D.GetLayerCollisionMask(gameObject.layer));
    28.         contactFilter.useLayerMask = true;
    29.      
    30.     }
    31.  
    32.     // Update is called once per frame
    33.     void Update()
    34.     {
    35.      
    36.     }
    37.     void FixedUpdate()
    38.     {
    39.         velocity += gravMod * Physics2D.gravity * Time.fixedDeltaTime;
    40.      
    41.         grounded = false;
    42.    
    43.         Vector2 deltaPosition = velocity * Time.fixedDeltaTime;
    44.          
    45.  
    46.  
    47.         Vector2 move = Vector2.up * deltaPosition.y;
    48.  
    49.         Movement (move, true);
    50.  
    51.  
    52.     }
    53.     void Movement (Vector2 move, bool yMovement)
    54.     {
    55.         float distance = move.magnitude;
    56.         if (distance > minMoveDistance)
    57.         {
    58.           int count =  rb.Cast(move, contactFilter, hitBuffer, distance + shellRadius);
    59.             hitBufferList.Clear();
    60.             for (int i = 0; i < count; i++)
    61.             {
    62.                 hitBufferList.Add(hitBuffer[i]);
    63.             }
    64.  
    65.             for(int i = 0; i < hitBufferList.Count; i++)
    66.             {
    67.                 Vector2 currentNormal = hitBufferList[i].normal;
    68.                 if(currentNormal.y > minGroundNormalY)
    69.                 {
    70.                     grounded = true;
    71.                     if (yMovement)
    72.                     {
    73.                         groundNormal = currentNormal;
    74.                         currentNormal.x = 0;
    75.                     }
    76.                 }
    77.  
    78.                 float projection = Vector2.Dot(velocity, currentNormal);
    79.                 if (projection < 0)
    80.                 {
    81.                     velocity = velocity - projection * currentNormal;
    82.                 }
    83.  
    84.                 float modifiedDistance = hitBufferList[i].distance - shellRadius;
    85.                 distance = modifiedDistance < distance ? modifiedDistance : distance;
    86.  
    87.             }
    88.         }
    89.         rb.position = rb.position + move.normalized * distance;
    90.     }
    91.  
    92. }
    93.  
    94.  
     
    Last edited: Aug 28, 2019
  2. Adien22

    Adien22

    Joined:
    Aug 19, 2019
    Posts:
    44
    This is also what happens when I drop it off an edge lol I'm so confused where my code went wrong.
    P.S. I'll fix my animations later, yes I know it looks weird without them

     
  3. Aristonaut

    Aristonaut

    Joined:
    May 4, 2019
    Posts:
    15
    I didn't read too carefully, but I'm guessing you keep adding gravity to the box forever until it's downward velocity is so great that it can jump past the floor block. Also, if you have snap to grid set up, it will add gravity until it's great enough to snap to the next grid position.

    If you print out the box's velocity, you will probably get more clues
     
  4. Adien22

    Adien22

    Joined:
    Aug 19, 2019
    Posts:
    44
    Ok, so I finally figured out my problem with the snap and gravity not happening correctly. and my velocity problem is fixed. Now my final problem is corners. when I drop the box (just like in the video above) it will stick on the corner of either the first platform or the second just below. Everywhere else it works perfectly just as I want it. is it a simple swap of some code, do I need to add side checking as well, or something else?




    Code (csharp):
    1.  
    2. public class Snap: MonoBehaviour
    3. {
    4.        public float grid = 1f;
    5.        float x = 0f, y = 0f;
    6.  
    7.        [SerializeField] private LayerMask m_WhatIsGround;              
    8.  
    9.         private Transform m_GroundCheck;
    10.         const float k_GroundedRadius = .2f;
    11.         private bool m_Grounded;          
    12.         private Transform m_CeilingCheck;
    13.         const float k_CeilingRadius = .01f;
    14.         private Rigidbody2D m_Rigidbody2D;
    15.        
    16.     private void Awake()
    17.     {
    18.         // Setting up references.
    19.         m_GroundCheck = transform.Find("GroundCheck");
    20.         m_CeilingCheck = transform.Find("CeilingCheck");
    21.         m_Rigidbody2D = GetComponent<Rigidbody2D>();
    22.     }
    23.  
    24.        void FixedUpdate()
    25.     {
    26.         m_Grounded = false;
    27.         Collider2D[] colliders = Physics2D.OverlapCircleAll(m_GroundCheck.position, k_GroundedRadius, m_WhatIsGround);
    28.         for (int i = 0; i < colliders.Length; i++)
    29.         {
    30.            
    31.             if (colliders[i].gameObject != gameObject)
    32.             {
    33.                 m_Grounded = true;
    34.  
    35.                 float reciprocalGrid = 1f / grid;
    36.  
    37.                 x = Mathf.Round(transform.position.x * reciprocalGrid) / reciprocalGrid;
    38.                 y = Mathf.Round(transform.position.y * reciprocalGrid) / reciprocalGrid;
    39.  
    40.                 transform.position = new Vector2(x, y);
    41.             }
    42.         }
    43.      }
    44. }
    45.  
     
    Last edited: Aug 28, 2019
  5. Aristonaut

    Aristonaut

    Joined:
    May 4, 2019
    Posts:
    15
    My guess is that your collisions are just a little too tight. You kinda have to treat the physics engine as being a bit sloppy. I'd suggest just shrinking the collisions by 1 pixel. If you auto-generated the collisions using a tilemap collider, you can edit the per-tile collisions back in the sprite splitter window.