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

collider going in ah other collider

Discussion in '2D' started by joxthebest314, Apr 30, 2020.

  1. joxthebest314

    joxthebest314

    Joined:
    Mar 31, 2020
    Posts:
    95
    I am doing a 2D tank game and I noticed that the tank collider is going inside the wall collider.

    I goolged for some help and I understood that this was because of the movement method I use, but I cant find a way to change it without changing the gameplay. Here is the code :

    Code (CSharp):
    1.     void FixedUpdate()
    2.     {
    3.  
    4.         if(Input.GetKey(KeyCode.W))
    5.         {
    6.             transform.Translate(Vector3.right * speed * Time.deltaTime, Space.Self);
    7.         }
    8.  
    9.         if(Input.GetKey(KeyCode.D))
    10.         {
    11.             transform.Rotate(0,0,-rotationSpeed * Time.deltaTime, Space.Self);
    12.         }
    13.  
    14.         if(Input.GetKey(KeyCode.A))
    15.         {
    16.             transform.Rotate(0,0,rotationSpeed * Time.deltaTime, Space.Self);
    17.         }
    18.  
    19.         if(Input.GetKey(KeyCode.S))
    20.         {
    21.             transform.Translate(Vector3.right * -speed * Time.deltaTime, Space.Self);
    22.         }
    23.     }
    I also want to know if there is a way to avoid the player (a square box) to be stuck on square walls. ( I mean when the tank is going against an edge of the wall, the tank rotates because of the wall and I find this pretty annoying)

    Sans titre.png
    Sans titre1.png

    Thank you in advance.
     
  2. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,321
    Why did you add a Rigidbody2D? The answer should be so that it takes control of the Transform for you and updates it according to physics.

    The problem here is that you're bypassing that completely and stomping on the Transform.

    Use the Rigidbody2D API to interact with the body and indirectly the Transform.

    Presumably your Rigidbody2D has a Dynamic Body Type. If not, it should so it has a collision response; in your case ensuring it doesn't overlap walls.

    Use Rigidbody2D.MovePosition and Rigidbody2d.MoveRotation. Also, base your position and rotation from Rigidbody2D.position and Rigidbody2D.rotation and NOT the Transform.

    Finally, use Time.fixedDeltaTime even though Unity sneakily changes Time.deltaTime to be the same when called during the FixedUpdate (don't personally like this hack).
     
    joxthebest314 likes this.
  3. joxthebest314

    joxthebest314

    Joined:
    Mar 31, 2020
    Posts:
    95
    Thanks you a lot, I will try to apply these changes.
     
  4. joxthebest314

    joxthebest314

    Joined:
    Mar 31, 2020
    Posts:
    95
    I tried that but I struggle to find a way to make it relative to the players rotation. I used the Space.Self before to do it, is there a way to do the same with Rigidbody2D.MovePosition ?
     
  5. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,321
    Did you look at the docs, specifically the code example? For MovePosition/MoveRotation you simply specify the absolute position or angle you want. If you want it relative to (say) the rigidbody position you add your value to Rigidbody2D.position.

    I rearranged your code a little so that you only issue the MovePosition/Rotation once but this is roughly how it works:
    Code (CSharp):
    1.  
    2. public class MoveExample : MonoBehaviour
    3. {
    4.     public float Speed = 2f;
    5.     public float RotationSpeed = 30f;
    6.    
    7.     Rigidbody2D rb;
    8.    
    9.     void Start()
    10.     {
    11.         rb = GetComponent<Rigidbody2D>();
    12.     }
    13.  
    14.     void FixedUpdate()
    15.     {
    16.         var movePosition = Vector2.zero;
    17.         var moveRotation = 0f;
    18.        
    19.         // Move Right.
    20.         if(Input.GetKey(KeyCode.W))
    21.         {
    22.             movePosition += Vector2.right * Speed;
    23.         }
    24.  
    25.         // Move Left.
    26.         if(Input.GetKey(KeyCode.S))
    27.         {
    28.             movePosition += Vector2.left * Speed;
    29.         }
    30.  
    31.         // Rotate Anti-Clockwise.
    32.         if(Input.GetKey(KeyCode.A))
    33.         {
    34.             moveRotation += RotationSpeed;
    35.         }
    36.        
    37.         // Rotate Clockwise.
    38.         if(Input.GetKey(KeyCode.D))
    39.         {
    40.             moveRotation -= RotationSpeed;
    41.         }
    42.  
    43.         // Only issue a position move if we're effectively non-zero move.
    44.         if (Mathf.Abs(movePosition.sqrMagnitude) > Mathf.Epsilon)
    45.             rb.MovePosition(rb.position + movePosition * Time.fixedDeltaTime);
    46.  
    47.         // Only issue a rotation move if we're effectively non-zero rotation.
    48.         if (Mathf.Abs(moveRotation) > Mathf.Epsilon)
    49.             rb.MoveRotation(rb.rotation + moveRotation * Time.fixedDeltaTime);
    50.     }
    51. }
    52.  
     
    joxthebest314 likes this.
  6. joxthebest314

    joxthebest314

    Joined:
    Mar 31, 2020
    Posts:
    95

    Thanks this is very useful, but the reason why I wanted to move according to the self position is because when the tank rotates, he is supposed to move forward according to the rotation. This means that the forward movement is not always on the right, but it adapt to the rotation. Unfortunately, this is not what your code is doing. I also noticed that, when colliding with other objects, the tank starts spinning wery strangely.
     
  7. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,321
    I wasn't trying to fix your game TBH but simply show how the MovePosition/MoveRotation should be used so I didn't really pay much attention to the actual movement. I have very limited information on anything else in your game so I wouldn't expect what I posted above to "just work". Quite simply, don't modify the Transform; it just instantly positions you into overlaps which the solver has to then try to figure out.

    If you want to move in a certain direction then simply calculate that direction from the Rigidbody2d.rotation and replace the Vector2.right and Vector2.left above.

    Here's some rough code (not even tried in Unity) but I'm doing this blind without any other reference to your code so you'll need to read between the lines:

    Code (CSharp):
    1.  
    2. public class MoveExample : MonoBehaviour
    3. {
    4.     public float Speed = 2f;
    5.     public float RotationSpeed = 30f;
    6.    
    7.     Rigidbody2D rb;
    8.    
    9.     void Start()
    10.     {
    11.         rb = GetComponent<Rigidbody2D>();
    12.     }
    13.    
    14.     void FixedUpdate()
    15.     {
    16.         var moveRotation = 0f;
    17.    
    18.         // Rotate Anti-Clockwise.
    19.         if(Input.GetKey(KeyCode.A))
    20.         {
    21.             moveRotation += RotationSpeed;
    22.         }
    23.    
    24.         // Rotate Clockwise.
    25.         if(Input.GetKey(KeyCode.D))
    26.         {
    27.             moveRotation -= RotationSpeed;
    28.         }
    29.      
    30.         // Calculate new target rotation.
    31.         // NOTE: Technically we might not reach here if this is a dynamic body and we contact something.
    32.         var targetRotation = rb.rotation + moveRotation;
    33.    
    34.         // Only issue a rotation move if we're effectively non-zero rotation.
    35.         if (Mathf.Abs(moveRotation) > Mathf.Epsilon)
    36.             rb.MoveRotation(targetRotation * Time.fixedDeltaTime);
    37.      
    38.         // Calculate forward direction.
    39.         var forwardAngle = targetRotation * Mathf.Deg2Rad;
    40.         var forwardDirection = new Vector2(Mathf.Cos(forwardAngle) * Speed, Mathf.Sin(forwardAngle) * Speed);
    41.         var moveOffset = Vector2.zero;
    42.      
    43.         // Move Forward.
    44.         if(Input.GetKey(KeyCode.W))
    45.         {
    46.             moveOffset += forwardDirection;
    47.         }
    48.    
    49.         // Move Backward.
    50.         if(Input.GetKey(KeyCode.S))
    51.         {
    52.             moveOffset -= forwardDirection;
    53.         }
    54.      
    55.         // Only issue a position move if we're effectively non-zero move.
    56.         if (Mathf.Abs(moveOffset.sqrMagnitude) > Mathf.Epsilon)
    57.             rb.MovePosition(rb.position + moveOffset * Time.fixedDeltaTime);
    58.     }
    59. }
    60.  
     
    Last edited: May 2, 2020
    joxthebest314 likes this.
  8. joxthebest314

    joxthebest314

    Joined:
    Mar 31, 2020
    Posts:
    95
    Thank you very much for your code, it helped me figure out mine ! My problems are now resolved.
     
    MelvMay likes this.