Unity Detecting Collisions With OnCollisionEnter2D Without IsTrigger

Viewed 502

I am trying to create a portal that can bring a player from one end to the other. So, if the player is 50% into the portal from end, his other 50% will be sticking out from the other end.

I am using two pre-made characters of the exact same sprite with the exact same components. Instead of substantiating new clones, the portals will be solely using these two pre-made characters.

The diagram below describes what I am trying to do with collider boxes in order to move them: Explanation

Just to clarify, I am using OnCollisionEnter2D to detect contact points to determine which side of the portal the player is entering from. As shown on the right side of the diagram above, the "guy entering" should be able to turn back at any time and not get removed while still being able to be removed when he leaves through the other side.

However, the issue I am facing with my code is that the OnCollisionEnter2D function will only work if IsTrigger is false. But when IsTrigger is false, my character is unable to pass through the portal and gets shoved into the ground and falls off the map.

I attempted to use Physics2D.IgnoreCollision, but it seems to have no effect.

The second character which gets moved into the exit portal gets shoved out instead of having a smooth transition.

public Transform PortalExit;
public CharacterController2D Player;

private GameObject Player1;
private CharacterController2D Player1Controller;
private Vector2 Player1Position;
private GameObject Player2;
private CharacterController2D Player2Controller;
private Vector2 Player2Position;

// Use this for initialization
void Start () {
    Player1 = GameObject.FindWithTag("Player1");
    Player1Controller = GameObject.FindWithTag("Player1").GetComponent<CharacterController2D>();
    Player1Position = Player1.transform.position;
    Player2 = GameObject.FindWithTag("Player2");
    Player2Controller = GameObject.FindWithTag("Player2").GetComponent<CharacterController2D>();
    Player2Position = Player2.transform.position;
}

// Update is called once per frame
void Update () {

}

void OnCollisionEnter2D (Collision2D collision) {

    Collider2D collider = collision.collider;

    if (collider.gameObject.tag == "Player1") {

        Vector3 contactPoint = collision.contacts[0].point;
        Vector3 center = collider.bounds.center;

        bool right = contactPoint.x > center.x;
        bool top = contactPoint.y > center.y;

        if (right) {
            // Physics2D.IgnoreCollision(GameObject.FindWithTag("Player1").GetComponent<Collider2D>(), GetComponent<Collider2D>());

            // change Player2's position into the other portal
            print("Hello!");
            Player2Position.x = 1.6f;
            Player2Position.y = PortalExit.position.y;
            Player2.transform.position = Player2Position;
        }

        if (!right) {
            print("Goodbye!");
            // puts Player1 into the detention center
            Player1Position.x = -5.55f;
            Player1Position.y = -6f;

            Player1.transform.position = Player1Position;
        }

    }

    if (collider.gameObject.tag == "Player2") {

        Vector3 contactPoint = collision.contacts[0].point;
        Vector3 center = collider.bounds.center;

        bool right = contactPoint.x > center.x;
        bool top = contactPoint.y > center.y;

        if (!right) {
            // change Player2's position into the other portal
            Player1Position.x = -3.6f;
            Player1Position.y = PortalExit.position.y;
            Player1.transform.position = Player1Position;
        }

        if (right) {
            // puts Player1 into the detention center
            Player2Position.x = -5.55f;
            Player2Position.y = -6f;

            Player2.transform.position = Player2Position;
        }

    }
}
1 Answers

You have two options:

1. Change the isTrigger to false then change the Rigidbody2D Body Type from Dynamic to Kinematic from the Editor or via script:

rb2d.bodyType = RigidbodyType2D.Kinematic;

By doing this, the rigidbody would stop reacting to gravity or forces from other object. You can then use your OnCollisionEnter2D to detect the collision event without the issues described in your question.


2. Change the isTrigger to true, Set the Rigidbody2D Gravity Scale to 0 so that it's not going through the ground. Now, you can use OnTriggerEnter2D to detect the trigger and Physics2D.Raycast to fake detecting the point since OnTriggerEnter2D can't provide the collision point:

void OnTriggerEnter2D(Collider2D collision)
{
    //Calculate layermask that excludes this GameObject we are raycasting from
    int layerMask = ~(1 << gameObject.layer);

    float distance = 100f;

    // Cast a ray straight down.
    RaycastHit2D hit = Physics2D.Raycast(transform.position, transform.forward, distance, layerMask);

    if (hit.collider != null)
    {
        Collider2D collider = hit.collider;

        Vector3 contactPoint = hit.point;
        Vector3 center = collider.bounds.center;


        //...........
    }
}

I suggest you try both of them and see which one you like best.

Related