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

Question Tilemaps Composite Collider 2D collision position

Discussion in '2D' started by DK_Kalach, Sep 20, 2023.

  1. DK_Kalach

    DK_Kalach

    Joined:
    Sep 2, 2021
    Posts:
    13
    I've got a Gird map and as a child, I have different game objects for certain objectives
    One of them is an actual border of the map with a tilemap collider 2D attached & with an additional Composite Collider 2D ( To make collisions more efficient )

    What I want: I have simple collider on the player which is not enough to prevent him from going through walls, so what I did is to apply another collider but this time a trigger collider that's slightly bigger, When he's hitting a certain layermask ( walls / door ) I want to get the collision position, the player position, and apply opposite force to push him away and overwrite the movement function so he can't interrupt.

    Code (CSharp):
    1.     private void OnTriggerStay2D(Collider2D collision)
    2.     {
    3.         if(collision.gameObject.layer == 6)
    4.         {
    5.             OverwriteMovement = true;
    6.             Vector2 DirToPush = (transform.position - collision.transform.position).normalized;
    7.             _rb.AddForce(DirToPush * _Speed);
    8.         }
    9.     }
    10.  
    11.     private void OnTriggerExit2D(Collider2D collision)
    12.     {
    13.         if(collision.gameObject.layer == 6)
    14.         {
    15.             _rb.velocity = _Movement * _Speed;
    16.             OverwriteMovement = false;
    17.         }
    18.     }

    The Problem: Since the gameobject has a composite collider which located at ( 0,0,0 ) , When hitting the layermask instead of getting the collision from the constant point, I've getting the transform of the gameonject which is ( You guessed it, ( 0,0,0 )). How can I achieve getting the position of the collision position using composite collider 2D

    Thanks
     
  2. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,513
    Then this is your problem. You're likely not using continuous collision detection and/or you're using the Transform to modify the Rigidbody2D position. Address why you feel the need to hack something in rather than try to hack the fallout of doing something hacky. :)
     
  3. DK_Kalach

    DK_Kalach

    Joined:
    Sep 2, 2021
    Posts:
    13
    I've tried using continuous collision detection but it didn't quite do the work.
    probably because the tiles are sometimes 2-3 pixels wide ( I would like to keep that if possible )

    Also I'm using a the rigidbody2d components to change the movement, I'll show the code
    Code (CSharp):
    1.     void Update()
    2.     {
    3. /////IMPORTANT FOR YOU!!!!!!!!!!!!!!!!!!
    4.         //Move
    5.         _Movement = new Vector2(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical"));
    6.         if (_Movement != Vector2.zero && OverwriteMovement == false)
    7.         {
    8.             _rb.velocity = _Movement * _Speed;
    9.         }
    10.         else if (OverwriteMovement == false)
    11.         {
    12.             _rb.velocity = Vector2.zero;
    13.         }
    14. //IMPORTANT FOR YOU!!!!!!!!!!!!!!
    15.         //rotate to mouse
    16.         Vector3 MousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition) - transform.position;
    17.         float angle = Mathf.Atan2(MousePos.y, MousePos.x) * Mathf.Rad2Deg - 90f;
    18.         transform.rotation = Quaternion.Euler(0, 0, angle);
    19.  
    20.         //Shoot bullets
    21.         if(Input.GetMouseButton(0) && Time.time > _TempFireRate)
    22.         {
    23.             _TempFireRate = Time.time + _FireRate;
    24.             Transform MyBullet = Instantiate(BulletPref, Firepoint.position, transform.rotation, BulletContainer);
    25.             MyBullet.GetComponent<Bullet>().SetBulletStats(gameObject, _Damage, _BulletSpeed);
    26.  
    27.         }
    28.  
    29.         //Pause / Unpause Game
    30.         if (Input.GetKeyDown(KeyCode.Escape) && _GameManager.IsGamePaused == false)
    31.         {
    32.             _GameManager.PauseGame();
    33.         }
    34.         else if (Input.GetKeyDown(KeyCode.Escape) && _GameManager.IsGamePaused == true)
    35.         {
    36.             _GameManager.UnpauseGame();
    37.             Debug.Log("Test");
    38.         }
    39.     }

    Here's also a video if that might help
     
  4. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,513
    Continuous works perfectly fine and is solid as a rock so you need to find why you're making it fail. The physics knows nothing about pixels; it doesn't matter what the dimensions are.

    Well not really....
    Code (CSharp):
    1. transform.rotation = Quaternion.Euler(0, 0, angle);
    You're causing overlaps here which is likely why you're tunnelling through colliders.

    Also, did you change physics to run per-frame because you're doing all this per-frame; by default physics isn't running then.

    Finally, note that Unity colliders don't have specific ways of using physics; they are all the same thing to the physics system; it knows nothing about BoxCollider2D, CompositeCollider2D, TilemapCollider2D etc. There are only 4 primitives it knows about which Unity colliders create: Circle, Capsule, Polygon & Edges. A CompositeCollider2D can produce either Polygon or Edge primitives depending on which geometry type you select.
     
  5. DK_Kalach

    DK_Kalach

    Joined:
    Sep 2, 2021
    Posts:
    13
    Wow, I feel so stupid now
    I'll change the code and see the results
    Code (CSharp):
    1.         _rb.rotation = angle;
    I believe you mean to run the code on FixedUpdate instead of update, Will try that now as well.

    using the continuous collision detection with everything mentioned above doesn't seem to work unfortunately
    The gameObject still can go through walls ( Simplely moved the Movement and Rotation function to fixedUpdate())

    Out of curiosity, Is it possible to get the position in world space of the trigger collision, So I can simply get the negative angle to push the gameObject, cause for some reason the collision doesn't seems to work for me as you see
     
  6. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,513
    No! :) When you change the Transform, it will simply do what you're doing here but it'll only happen when the simulation runs. It's still instantly changing the rotation i.e. not using any angular velocity.

    You're essentially allowing the ship to rotate to any angle without it being restricted so you'll cause overlaps. If this is a Dynamic Rigidbody2D then you can use "MoveRotation" however if it collides, it'll cause a collision which will stop it overlapping the wall but you may not want this response as it's essentially rotating quickly so might cause a lot of linear movement or stop it rotating unless you've got no friction on these surfaces.

    Well this won't cause issues in itself, it's just wasted effort. You have to understand that changing the velocity per-frame doesn't mean it's going to do anything per-frame unless you're running physics per-frame. At 500fps and using the default FixedUpdate of 50fps (Hz) you'll get 10 renders (updates) before the physics simulates.

    You can, of course, run physics per-frame at a variable frame-rate which means no interpolation is used and you do everything per-frame. It's just that it reduces determinism and if you have a very low frame-rate, the quality of the simulation can suffer although in later versions of Unity, there is automatic sub-stepping to stop this happening too.

    I don't know what "trigger" you're referring to. Triggers don't produce contact points because they're never used; it's all about overlapping or not overlapping. It's kind of a subject beyond this scope but you can use Kinematic Rigidbody2D (so you don't get a collision response) and use non-triggers then enable useFullKinematicContacts so you get OnCollisionXXX callbacks but again, no collision response. Using Kinematic means you need to solve any overlaps yourself or more precisely, use queries to ensure you don't ever move into overlap.
     
  7. DK_Kalach

    DK_Kalach

    Joined:
    Sep 2, 2021
    Posts:
    13
    Alright, I understand I've got some homework to do.
    For the meantime, I've tried The MoveRotation function and it seems to work. Thanks!

    Appreciate the response, You've helped me a lot.

    One more small thing if you wouldn't mind, I remember a long time I used a function for the same thing like MoveRotation but I also had one more parament to control Speed of the rotation, I'm pretty sure it wasn't a custom function. Do you have any idea what it could be?
     
  8. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,513
    Hard to say.

    You can set the linear and angular velocities directly though. Set the angular velocity if you wish it to turn at a certain rate then reset it to zero when you want it to stop turning.

    https://docs.unity3d.com/ScriptReference/Rigidbody2D-angularVelocity.html

    Note that a collision response will change this just like it changes the velocity so you'd need to constantly set it unless you know you're not colliding with anything.

    The only "danger" when setting things directly comes from what you expect to happen with collision responses. If you're turning then a collision response changes the linear/angular velocities but if you're constantly setting it, you're countering what it's trying to do. It all depends on you understanding this and how you want it to interact with the environment.
     
    DK_Kalach likes this.
  9. DK_Kalach

    DK_Kalach

    Joined:
    Sep 2, 2021
    Posts:
    13
    After a bit of testing, I found it. It's simply modifying the MoveRotation
    For anyone who might need it

    To achieve smooth rotation without passing through walls
    Code (CSharp):
    1. _rb.MoveRotation(Quaternion.Lerp(transform.rotation, Quaternion.Euler(0, 0, angle), _RotateSpeed * Time.deltaTime));
    My _RotateSpeed is at 10 for reference

    Really appreciate the support and glad with the results,
    Have a good day @MelvMay
     
    MelvMay likes this.
  10. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,513
    Note that you shouldn't be calling this per-frame because as previously mentioned, nothing in physics is updated until the simulation happens. It's just wasted effort so only the last one you called before the simulation runs will be actioned.